Define the /ws/edge/v1 gateway uplink protocol
continuum-proxy and continuum-backend each had their own idea of what the edge WebSocket carried, and the two did not overlap anywhere: the backend expected an `auth` handshake the gateway never sends, telemetry shaped one printer per message where the gateway sends a batch, and UUID printer ids a gateway has no way to know. Neither end had a command path that matched the other. Nothing failed, because nothing was written down for both sides to mirror. This is that document. schemas/continuum/v1/edge/ is canonical: client_message, server_message, printer_telemetry and printer_command. packages/ts-types gets its first real TypeBox mirror - the placeholder there said to add one "once something actually consumes it", and continuum-backend's edge route now does. The Rust mirror stays in continuum-proxy/src/uplink/protocol.rs rather than packages/rust-types, since the gateway is its only Rust consumer. Two decisions worth recording: Field names are snake_case, unlike the backend's HTTP routes. The other end is serde-derived Rust, and snake_case is what those structs produce without a rename attribute on every field. It is also what the rest of this repository already uses. Optional fields accept an explicit null as well as being absent. A gateway omits what it has no value for, which is what these schemas describe - but serde emits null by default unless every field is annotated, and a single such field would otherwise fail validation and take a whole farm's telemetry batch down with it. Strict in what we send, liberal in what we accept; the contract tests on both sides pin down each half. Also bumps this package's @sinclair/typebox to ^0.33.12 to match what continuum-backend already pins. It was on ^0.32.0, which resolved to a separate 0.32.37 install - two TypeBox versions means two incompatible TSchema identities, and Elysia rejected every schema from here on those grounds alone.
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.octoturge.com/Continuum/continuum-schemas/raw/branch/main/schemas/continuum/v1/edge/server_message.schema.json",
|
||||
"title": "EdgeServerMessage",
|
||||
"description": "What continuum-backend sends back down the same WebSocket. Discriminated on 'type'; snake_case for the same reason as EdgeClientMessage.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"title": "HelloAck",
|
||||
"properties": {
|
||||
"type": { "const": "hello_ack" },
|
||||
"session_id": { "type": "string" }
|
||||
},
|
||||
"required": ["type", "session_id"]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"title": "HelloError",
|
||||
"description": "The handshake was rejected. The connection closes immediately after this.",
|
||||
"properties": {
|
||||
"type": { "const": "hello_error" },
|
||||
"message": { "type": "string" }
|
||||
},
|
||||
"required": ["type", "message"]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"title": "HeartbeatAck",
|
||||
"properties": {
|
||||
"type": { "const": "heartbeat_ack" },
|
||||
"seq": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"description": "Echoes the seq from the heartbeat being acknowledged."
|
||||
}
|
||||
},
|
||||
"required": ["type", "seq"]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"title": "Command",
|
||||
"description": "Do something to one printer on this gateway. Answered with a client command_result carrying the same command_id.",
|
||||
"properties": {
|
||||
"type": { "const": "command" },
|
||||
"command_id": { "type": "string" },
|
||||
"printer_id": {
|
||||
"type": "string",
|
||||
"description": "The gateway's own printer id, not the backend UUID - the backend translates on the way out, so a gateway never has to know its printers' cloud identities."
|
||||
},
|
||||
"command": { "$ref": "./printer_command.schema.json" }
|
||||
},
|
||||
"required": ["type", "command_id", "printer_id", "command"]
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user