From c4b2ffad9c88588e672e317d978cd149b39edfcb Mon Sep 17 00:00:00 2001 From: Harvmaster Date: Mon, 27 Jul 2026 10:44:50 +0000 Subject: [PATCH] remove demo app md --- docs/demo-app-transport-migration.md | 267 --------------------------- 1 file changed, 267 deletions(-) delete mode 100644 docs/demo-app-transport-migration.md diff --git a/docs/demo-app-transport-migration.md b/docs/demo-app-transport-migration.md deleted file mode 100644 index d32b24b..0000000 --- a/docs/demo-app-transport-migration.md +++ /dev/null @@ -1,267 +0,0 @@ -# Demo App Transport Migration - -This guide describes the client-facing protocol for the route-agnostic transport -architecture. - -## Connection Model - -HTTP, SSE, and WebSocket do not authenticate at the transport layer. Do not send -request-auth headers such as `X-PublicKey`, `X-Signature`, or `X-Timestamp` -for normal route dispatch. - -Authentication is scoped to each resource operation. Every written resource -carries its own `publicKey`, `timestamp`, and `signature`. - -All route input belongs in the request body. Paths are exact route names; there -are no path parameters, query parameters, or alternate HTTP methods. - -## Request Size Limit - -The server accepts at most 1048576 encoded bytes per HTTP request body or -complete WebSocket message by default. Deployments can change this with -`SERVER_MAX_REQUEST_BODY_BYTES`. The count is over the Extended JSON wire text, -so hexadecimal `Uint8Array` values use approximately twice their decoded byte -length. - -HTTP limits use Hono's built-in `bodyLimit` middleware and return `413`. -WebSocket messages do not pass through HTTP middleware; Hono's Node adapter uses -`ws`, whose native `maxPayload` option rejects oversized frames before the -application message handler. Response bodies are not limited. - -## HTTP Requests - -All application HTTP routes use POST. - -Read: - -```http -POST /data/get -Content-Type: application/json - -{ - "resourceId": ["resource-a", "resource-b"] -} -``` - -Write: - -```http -POST /data/write -Content-Type: application/json - -{ - "resources": [ - { - "id": "resource-a", - "publicKey": "...hex...", - "timestamp": 1730000000000, - "signature": "...der-hex...", - "value": "" - } - ] -} -``` - -Write response: - -```json -{ - "resources": [ - { - "id": "resource-a", - "publicKey": "...hex...", - "blob": "", - "timestamp": 1730000001000 - } - ] -} -``` - -If any item has invalid authorization, the whole batch fails. - -## SSE Subscriptions - -The client explicitly requests SSE using `Accept: text/event-stream`: - -```http -POST /data/subscribe -Accept: text/event-stream -Content-Type: application/json - -{ - "resourceId": ["resource-a"] -} -``` - -A subscription without this Accept header receives a `406` JSON error. - -The server keeps the SSE request open while its resource topics remain -subscribed. Subscribing sends no current state; it only enables future -publications. Request current state separately through `/data/get` when needed. - -SSE publication: - -```text -id: 1730000001000 -event: instance-changed -data: {"resourceId":"resource-a"} -``` - -After SSE begins, failures arrive as error events and the server closes that SSE -connection: - -```text -event: error -data: {"statusCode":500,"error":"Internal Server Error"} -``` - -To change an SSE subscription, abort the existing request and open a new -`/data/subscribe` request with the complete desired `resourceId` list. - -## WebSocket - -Connect without a connection-auth message: - -```ts -const ws = new WebSocket("ws://host:port/ws"); -``` - -Every client message uses this strict envelope. Messages may execute -concurrently; the server binds `id` and `body` to each individual dispatch so -responses remain correctly correlated even when they finish out of order: - -```ts -type WsRequest = { - id?: string; - path: string; - body?: unknown; -}; -``` - -Old fields such as `event`, `type`, `url`, `method`, `headers`, -`params`, and `data` are rejected. - -Read: - -```json -{ - "id": "read-1", - "path": "/data/get", - "body": { - "resourceId": ["resource-a", "resource-b"] - } -} -``` - -Write: - -```json -{ - "id": "write-1", - "path": "/data/write", - "body": { - "resources": [ - { - "id": "resource-a", - "publicKey": "...hex...", - "timestamp": 1730000000000, - "signature": "...der-hex...", - "value": "" - } - ] - } -} -``` - -Subscribe: - -```json -{ - "id": "sub-1", - "path": "/data/subscribe", - "body": { - "resourceId": ["resource-a"] - } -} -``` - -The subscribe request sends no immediate message. Its dispatch remains active -until those topics are removed or the connection closes. Request current state -separately through `/data/get` when needed. - -The client should consolidate its local subscribers and send only the topic set -needed by the shared WebSocket. - -Unsubscribe selected resources without closing the socket: - -```json -{ - "id": "unsub-1", - "path": "/data/unsubscribe", - "body": { - "resourceId": ["resource-a"] - } -} -``` - -Unsubscribe is idempotent. The response is a normal correlated response: - -```json -{ - "id": "unsub-1", - "type": "response", - "statusCode": 200, - "body": {} -} -``` - -Normal response: - -```json -{ - "id": "write-1", - "type": "response", - "statusCode": 200, - "body": {} -} -``` - -Error response: - -```json -{ - "id": "write-1", - "type": "error", - "statusCode": 400, - "error": "Validation Error", - "details": [] -} -``` - -Message-level errors do not close the WebSocket. The client decides whether to -retry, alter its subscription, or reconnect. - -Published events retain the shared stream shape: - -```json -{ - "id": "server-event-id", - "type": "instance-changed", - "data": {} -} -``` - -## Signing - -For each written resource, sign this canonical payload: - -```ts -`${timestamp}${resourceId}${canonicalBody(value)}`; -``` - -`value` is the `Uint8Array` payload. `canonicalBody(value)` uses the same -Extended JSON rules as the server: - -```json -"" -```