@graphorin/protocol 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -1
- package/README.md +3 -3
- package/dist/client-message.d.ts +1 -1
- package/dist/client-message.js +2 -2
- package/dist/client-message.js.map +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/package.js +6 -0
- package/dist/package.js.map +1 -0
- package/dist/server-message.js +4 -4
- package/dist/server-message.js.map +1 -1
- package/dist/subprotocol.d.ts +2 -2
- package/dist/subprotocol.js +2 -2
- package/dist/subprotocol.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,28 @@
|
|
|
1
1
|
# @graphorin/protocol
|
|
2
2
|
|
|
3
|
+
## 0.6.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#142](https://github.com/o-stepper/graphorin/pull/142) [`436d6ca`](https://github.com/o-stepper/graphorin/commit/436d6ca5ebbd16df094e915682d3915c279a8430) Thanks [@o-stepper](https://github.com/o-stepper)! - Version constants and version-bearing strings now derive from each package's manifest at build time (`VERSION = pkg.version`; writer ids, client/server info, OTLP framework attributes, build-info metrics interpolate it). No behavioral change at the current version: the rendered strings are byte-identical. A release bump no longer edits source; the new `check-version-consistency` gate fails any reintroduced hardcoded framework version.
|
|
8
|
+
|
|
9
|
+
## 0.6.0
|
|
10
|
+
|
|
11
|
+
## 0.5.0
|
|
12
|
+
|
|
13
|
+
First version published to the npm registry (with Sigstore build
|
|
14
|
+
provenance). The 0.2.0, 0.3.0, and 0.4.0 versions were internal lockstep
|
|
15
|
+
milestones and were never published. All `@graphorin/*` packages release
|
|
16
|
+
lockstep at the same version; the full release notes for 0.2.0-0.5.0 live
|
|
17
|
+
in the repository-level
|
|
18
|
+
[CHANGELOG](https://github.com/o-stepper/graphorin/blob/main/CHANGELOG.md).
|
|
19
|
+
|
|
3
20
|
## 0.1.0
|
|
4
21
|
|
|
5
22
|
### Minor Changes
|
|
6
23
|
|
|
7
24
|
- Initial Phase 14b release: Zod schemas + TypeScript types for the
|
|
8
|
-
`graphorin.protocol.v1` WebSocket subprotocol
|
|
25
|
+
`graphorin.protocol.v1` WebSocket subprotocol - the discriminated
|
|
9
26
|
unions `ClientMessage` and `ServerMessage`, the JSON-RPC-shaped
|
|
10
27
|
control channel (`initialize` / `subscription.subscribe` /
|
|
11
28
|
`subscription.unsubscribe` / `run.cancel` / `ping`), the typed
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](./LICENSE)
|
|
6
6
|
[](https://nodejs.org)
|
|
7
7
|
|
|
8
|
-
- **Version:** v0.
|
|
8
|
+
- **Version:** v0.6.1
|
|
9
9
|
- **License:** [MIT](./LICENSE) (© 2026 Oleksiy Stepurenko)
|
|
10
10
|
- **Repository:** <https://github.com/o-stepper/graphorin/tree/main/packages/protocol>
|
|
11
11
|
- **Issues:** <https://github.com/o-stepper/graphorin/issues>
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
## Direct dependencies
|
|
26
26
|
|
|
27
|
-
- [`zod`](https://zod.dev) (`^3.25.0`)
|
|
27
|
+
- [`zod`](https://zod.dev) (`^3.25.0`) - runtime schema validation. The MIT-licensed Zod project supplies the discriminated union, strict-object, and `safeParse` primitives that back every `*Schema` export. No other runtime dependency exists; the package is otherwise pure TypeScript.
|
|
28
28
|
|
|
29
29
|
## Install
|
|
30
30
|
|
|
@@ -68,4 +68,4 @@ MIT © 2026 Oleksiy Stepurenko. See [`LICENSE`](./LICENSE).
|
|
|
68
68
|
|
|
69
69
|
---
|
|
70
70
|
|
|
71
|
-
**Project Graphorin** · v0.
|
|
71
|
+
**Project Graphorin** · v0.6.1 · MIT License · © 2026 Oleksiy Stepurenko · <https://github.com/o-stepper/graphorin>
|
package/dist/client-message.d.ts
CHANGED
|
@@ -456,7 +456,7 @@ type ClientMessage = z.infer<typeof ClientMessageSchema>;
|
|
|
456
456
|
*/
|
|
457
457
|
type ClientMessageId = z.infer<typeof RpcId>;
|
|
458
458
|
/**
|
|
459
|
-
* Type guard helpers
|
|
459
|
+
* Type guard helpers - one per `method` literal - so consumers can
|
|
460
460
|
* narrow the `ClientMessage` union without re-stringifying the
|
|
461
461
|
* discriminator.
|
|
462
462
|
*
|
package/dist/client-message.js
CHANGED
|
@@ -2,7 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
|
|
3
3
|
//#region src/client-message.ts
|
|
4
4
|
/**
|
|
5
|
-
* `ClientMessage`
|
|
5
|
+
* `ClientMessage` - discriminated union of every frame a Graphorin
|
|
6
6
|
* WebSocket client may send to the server. The wire is hybrid: the
|
|
7
7
|
* control plane uses JSON-RPC-shaped requests / notifications; the
|
|
8
8
|
* data plane uses typed push events emitted exclusively by the server
|
|
@@ -93,7 +93,7 @@ const ClientMessageSchema = z.discriminatedUnion("method", [
|
|
|
93
93
|
CancelledNotification
|
|
94
94
|
]);
|
|
95
95
|
/**
|
|
96
|
-
* Type guard helpers
|
|
96
|
+
* Type guard helpers - one per `method` literal - so consumers can
|
|
97
97
|
* narrow the `ClientMessage` union without re-stringifying the
|
|
98
98
|
* discriminator.
|
|
99
99
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-message.js","names":[],"sources":["../src/client-message.ts"],"sourcesContent":["/**\n * `ClientMessage`
|
|
1
|
+
{"version":3,"file":"client-message.js","names":[],"sources":["../src/client-message.ts"],"sourcesContent":["/**\n * `ClientMessage` - discriminated union of every frame a Graphorin\n * WebSocket client may send to the server. The wire is hybrid: the\n * control plane uses JSON-RPC-shaped requests / notifications; the\n * data plane uses typed push events emitted exclusively by the server\n * (see `./server-message.ts`).\n *\n * Every frame carries the `v: '1'` literal so future revisions can\n * negotiate forward-compatible additions without a subprotocol bump.\n * The matching subprotocol identifier is `graphorin.protocol.v1`\n * (see `./subprotocol.ts`).\n *\n * @packageDocumentation\n */\n\nimport { z } from 'zod';\n\nconst RpcId = z.union([z.string().min(1), z.number().int()]);\n\nconst InitializeParams = z\n .object({\n clientInfo: z\n .object({\n name: z.string().min(1),\n version: z.string().min(1),\n })\n .strict(),\n capabilities: z.record(z.string(), z.unknown()).optional(),\n })\n .strict();\n\nconst SubscribeParams = z\n .object({\n subject: z.string().min(1),\n // IP-21: `sinceEventId` is the resumption cursor. `lastSequenceId` was a\n // dead wire field - the client never set it and the server never read it.\n sinceEventId: z.string().min(1).optional(),\n })\n .strict();\n\nconst UnsubscribeParams = z\n .object({\n subscriptionId: z.string().min(1),\n })\n .strict();\n\nconst RunCancelParams = z\n .object({\n runId: z.string().min(1),\n reason: z.string().min(1).optional(),\n drain: z.boolean().optional(),\n onPendingApprovals: z.enum(['deny', 'preserve']).optional(),\n })\n .strict();\n\nconst PingParams = z\n .object({\n nonce: z.string().min(1).optional(),\n })\n .strict()\n .optional();\n\nconst InitializeRequest = z\n .object({\n v: z.literal('1'),\n jsonrpc: z.literal('2.0'),\n id: RpcId,\n method: z.literal('initialize'),\n params: InitializeParams,\n })\n .strict();\n\nconst SubscribeRequest = z\n .object({\n v: z.literal('1'),\n jsonrpc: z.literal('2.0'),\n id: RpcId,\n method: z.literal('subscription.subscribe'),\n params: SubscribeParams,\n })\n .strict();\n\nconst UnsubscribeRequest = z\n .object({\n v: z.literal('1'),\n jsonrpc: z.literal('2.0'),\n id: RpcId,\n method: z.literal('subscription.unsubscribe'),\n params: UnsubscribeParams,\n })\n .strict();\n\nconst RunCancelRequest = z\n .object({\n v: z.literal('1'),\n jsonrpc: z.literal('2.0'),\n id: RpcId,\n method: z.literal('run.cancel'),\n params: RunCancelParams,\n })\n .strict();\n\nconst PingRequest = z\n .object({\n v: z.literal('1'),\n jsonrpc: z.literal('2.0'),\n id: RpcId,\n method: z.literal('ping'),\n params: PingParams,\n })\n .strict();\n\nconst CancelledNotification = z\n .object({\n v: z.literal('1'),\n jsonrpc: z.literal('2.0'),\n method: z.literal('notifications/cancelled'),\n params: z.object({ requestId: z.string().min(1) }).strict(),\n })\n .strict();\n\n/**\n * Zod schema for every legal client → server frame. Use\n * {@link ClientMessageSchema}.safeParse() inside the server upgrade\n * handler before dispatching to the corresponding subscription /\n * cancel / ping handler.\n *\n * @stable\n */\nexport const ClientMessageSchema = z.discriminatedUnion('method', [\n InitializeRequest,\n SubscribeRequest,\n UnsubscribeRequest,\n RunCancelRequest,\n PingRequest,\n CancelledNotification,\n]);\n\n/**\n * Inferred TypeScript union for the `ClientMessage` discriminator. A\n * value satisfying this type round-trips through\n * {@link ClientMessageSchema} without throwing.\n *\n * @stable\n */\nexport type ClientMessage = z.infer<typeof ClientMessageSchema>;\n\n/**\n * Convenience type for the JSON-RPC `id` slot. Matches the Graphorin\n * subset (string + integer; no `null`, no float).\n *\n * @stable\n */\nexport type ClientMessageId = z.infer<typeof RpcId>;\n\n/**\n * Type guard helpers - one per `method` literal - so consumers can\n * narrow the `ClientMessage` union without re-stringifying the\n * discriminator.\n *\n * @stable\n */\nexport function isInitializeRequest(\n message: ClientMessage,\n): message is z.infer<typeof InitializeRequest> {\n return message.method === 'initialize';\n}\n\n/** @stable */\nexport function isSubscribeRequest(\n message: ClientMessage,\n): message is z.infer<typeof SubscribeRequest> {\n return message.method === 'subscription.subscribe';\n}\n\n/** @stable */\nexport function isUnsubscribeRequest(\n message: ClientMessage,\n): message is z.infer<typeof UnsubscribeRequest> {\n return message.method === 'subscription.unsubscribe';\n}\n\n/** @stable */\nexport function isRunCancelRequest(\n message: ClientMessage,\n): message is z.infer<typeof RunCancelRequest> {\n return message.method === 'run.cancel';\n}\n\n/** @stable */\nexport function isPingRequest(message: ClientMessage): message is z.infer<typeof PingRequest> {\n return message.method === 'ping';\n}\n\n/** @stable */\nexport function isCancelledNotification(\n message: ClientMessage,\n): message is z.infer<typeof CancelledNotification> {\n return message.method === 'notifications/cancelled';\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { PROTOCOL_VERSION, SUBPROTOCOL_NAME, TICKET_SUBPROTOCOL_PREFIX, formatTi
|
|
|
6
6
|
//#region src/index.d.ts
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* `@graphorin/protocol`
|
|
9
|
+
* `@graphorin/protocol` - wire-format contract for the Graphorin
|
|
10
10
|
* WebSocket subprotocol.
|
|
11
11
|
*
|
|
12
12
|
* The package is the **single source of truth** for the shape of
|
|
@@ -20,8 +20,7 @@ import { PROTOCOL_VERSION, SUBPROTOCOL_NAME, TICKET_SUBPROTOCOL_PREFIX, formatTi
|
|
|
20
20
|
*
|
|
21
21
|
* @packageDocumentation
|
|
22
22
|
*/
|
|
23
|
-
|
|
24
|
-
declare const VERSION = "0.5.0";
|
|
23
|
+
declare const VERSION: string;
|
|
25
24
|
//#endregion
|
|
26
25
|
export { CLOSE_CODE_VALUES, ClientMessage, ClientMessageId, ClientMessageSchema, GraphorinCloseReason, PROTOCOL_VERSION, RPC_ERROR_CODES, SUBPROTOCOL_NAME, ServerErrorFrame, ServerEventFrame, ServerLifecycleFrame, ServerMessage, ServerMessageSchema, ServerPongFrame, ServerReplayMarkerFrame, ServerRpcFailure, ServerRpcSuccess, ServerSubscribedFrame, ServerUnsubscribedFrame, TICKET_SUBPROTOCOL_PREFIX, VERSION, closeCodeFor, closeCodeReason, formatTicketSubprotocol, isCancelledNotification, isErrorFrame, isEventFrame, isInitializeRequest, isLifecycleFrame, isPingRequest, isPongFrame, isReplayMarkerFrame, isRpcFailure, isRpcSuccess, isRunCancelRequest, isSubscribeRequest, isSubscribedFrame, isUnsubscribeRequest, isUnsubscribedFrame, negotiateSubprotocol, parseTicketSubprotocol };
|
|
27
26
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;AAmBA;;;;;;;;;cAAa"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { version } from "./package.js";
|
|
1
2
|
import { ClientMessageSchema, isCancelledNotification, isInitializeRequest, isPingRequest, isRunCancelRequest, isSubscribeRequest, isUnsubscribeRequest } from "./client-message.js";
|
|
2
3
|
import { CLOSE_CODE_VALUES, closeCodeFor, closeCodeReason } from "./close-codes.js";
|
|
3
4
|
import { RPC_ERROR_CODES, ServerMessageSchema, isErrorFrame, isEventFrame, isLifecycleFrame, isPongFrame, isReplayMarkerFrame, isRpcFailure, isRpcSuccess, isSubscribedFrame, isUnsubscribedFrame } from "./server-message.js";
|
|
@@ -5,7 +6,7 @@ import { PROTOCOL_VERSION, SUBPROTOCOL_NAME, TICKET_SUBPROTOCOL_PREFIX, formatTi
|
|
|
5
6
|
|
|
6
7
|
//#region src/index.ts
|
|
7
8
|
/**
|
|
8
|
-
* `@graphorin/protocol`
|
|
9
|
+
* `@graphorin/protocol` - wire-format contract for the Graphorin
|
|
9
10
|
* WebSocket subprotocol.
|
|
10
11
|
*
|
|
11
12
|
* The package is the **single source of truth** for the shape of
|
|
@@ -19,8 +20,8 @@ import { PROTOCOL_VERSION, SUBPROTOCOL_NAME, TICKET_SUBPROTOCOL_PREFIX, formatTi
|
|
|
19
20
|
*
|
|
20
21
|
* @packageDocumentation
|
|
21
22
|
*/
|
|
22
|
-
/** Canonical version constant
|
|
23
|
-
const VERSION =
|
|
23
|
+
/** Canonical version constant, derived from `package.json` at build time. */
|
|
24
|
+
const VERSION = version;
|
|
24
25
|
|
|
25
26
|
//#endregion
|
|
26
27
|
export { CLOSE_CODE_VALUES, ClientMessageSchema, PROTOCOL_VERSION, RPC_ERROR_CODES, SUBPROTOCOL_NAME, ServerMessageSchema, TICKET_SUBPROTOCOL_PREFIX, VERSION, closeCodeFor, closeCodeReason, formatTicketSubprotocol, isCancelledNotification, isErrorFrame, isEventFrame, isInitializeRequest, isLifecycleFrame, isPingRequest, isPongFrame, isReplayMarkerFrame, isRpcFailure, isRpcSuccess, isRunCancelRequest, isSubscribeRequest, isSubscribedFrame, isUnsubscribeRequest, isUnsubscribedFrame, negotiateSubprotocol, parseTicketSubprotocol };
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * `@graphorin/protocol`
|
|
1
|
+
{"version":3,"file":"index.js","names":["VERSION: string","pkg.version"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * `@graphorin/protocol` - wire-format contract for the Graphorin\n * WebSocket subprotocol.\n *\n * The package is the **single source of truth** for the shape of\n * every frame exchanged over `wss://.../v1/ws`. Both\n * `@graphorin/server` and `@graphorin/client` import their schemas\n * from here so the two implementations cannot drift.\n *\n * Browser-friendly: the only runtime dependency is\n * [`zod`](https://zod.dev). No Node-only imports, no DOM-only\n * imports.\n *\n * @packageDocumentation\n */\n\n/** Canonical version constant, derived from `package.json` at build time. */\nimport pkg from '../package.json' with { type: 'json' };\n\nexport const VERSION: string = pkg.version;\n\nexport * from './client-message.js';\nexport * from './close-codes.js';\nexport * from './server-message.js';\nexport * from './subprotocol.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAmBA,MAAaA,UAAkBC"}
|
package/dist/package.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package.js","names":[],"sources":["../package.json"],"sourcesContent":["{\n \"name\": \"@graphorin/protocol\",\n \"version\": \"0.6.1\",\n \"description\": \"Wire protocol contract for the Graphorin framework: Zod schemas + TypeScript types for the WebSocket subprotocol `graphorin.protocol.v1`. Defines the `ClientMessage` and `ServerMessage` discriminated unions, the JSON-RPC-shaped control channel (`initialize` / `subscription.subscribe` / `subscription.unsubscribe` / `run.cancel` / `ping`), the typed event push frames (`{ kind: 'event', subject, type, payload, eventId }`), the asynchronous server-initiated error frames (`{ kind: 'error', code, message }`), the subprotocol negotiation helpers, and the close-code taxonomy (4001 auth.required, 4002 auth.invalid, 4003 auth.revoked, 4004 auth.scope_denied, 4005 rate.limited, 4006 flow.throttled, 4007 server.shutdown, 4008 protocol.violation). Browser-friendly: zero Node-only dependencies; the only runtime dependency is `zod`. Created and maintained by Oleksiy Stepurenko.\",\n \"license\": \"MIT\",\n \"author\": \"Oleksiy Stepurenko\",\n \"homepage\": \"https://github.com/o-stepper/graphorin/tree/main/packages/protocol\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/o-stepper/graphorin.git\",\n \"directory\": \"packages/protocol\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/o-stepper/graphorin/issues\"\n },\n \"keywords\": [\n \"graphorin\",\n \"ai\",\n \"agents\",\n \"framework\",\n \"protocol\",\n \"websocket\",\n \"subprotocol\",\n \"zod\",\n \"wire-format\",\n \"browser-friendly\"\n ],\n \"type\": \"module\",\n \"engines\": {\n \"node\": \">=22.0.0\"\n },\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"sideEffects\": false,\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n },\n \"./client-message\": {\n \"types\": \"./dist/client-message.d.ts\",\n \"import\": \"./dist/client-message.js\"\n },\n \"./server-message\": {\n \"types\": \"./dist/server-message.d.ts\",\n \"import\": \"./dist/server-message.js\"\n },\n \"./subprotocol\": {\n \"types\": \"./dist/subprotocol.d.ts\",\n \"import\": \"./dist/subprotocol.js\"\n },\n \"./close-codes\": {\n \"types\": \"./dist/close-codes.d.ts\",\n \"import\": \"./dist/close-codes.js\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"files\": [\n \"dist\",\n \"README.md\",\n \"CHANGELOG.md\",\n \"LICENSE\"\n ],\n \"scripts\": {\n \"build\": \"tsdown\",\n \"typecheck\": \"tsc --noEmit && tsc -p tsconfig.tests.json\",\n \"test\": \"vitest run\",\n \"lint\": \"biome check .\",\n \"clean\": \"rimraf dist .turbo *.tsbuildinfo\"\n },\n \"dependencies\": {\n \"zod\": \"^3.25.0\"\n },\n \"publishConfig\": {\n \"access\": \"public\",\n \"provenance\": true\n }\n}\n"],"mappings":";cAEa"}
|
package/dist/server-message.js
CHANGED
|
@@ -2,18 +2,18 @@ import { z } from "zod";
|
|
|
2
2
|
|
|
3
3
|
//#region src/server-message.ts
|
|
4
4
|
/**
|
|
5
|
-
* `ServerMessage`
|
|
5
|
+
* `ServerMessage` - discriminated union of every frame a Graphorin
|
|
6
6
|
* server may push to a client. Three families share the channel:
|
|
7
7
|
*
|
|
8
|
-
* 1. **RPC responses** (`{ jsonrpc, id, result | error }`)
|
|
8
|
+
* 1. **RPC responses** (`{ jsonrpc, id, result | error }`) -
|
|
9
9
|
* correlate with a previously-issued client request.
|
|
10
10
|
* 2. **Typed push events** (`{ kind: 'event', subject, type,
|
|
11
|
-
* payload, eventId }`)
|
|
11
|
+
* payload, eventId }`) - the streaming-first data plane;
|
|
12
12
|
* consumers ignore unknown `type` strings per the agent-event
|
|
13
13
|
* extensibility convention.
|
|
14
14
|
* 3. **Asynchronous server frames** (`{ kind: 'lifecycle' | 'error'
|
|
15
15
|
* | 'pong' | 'subscribed' | 'unsubscribed' | 'replay-marker' }`)
|
|
16
|
-
*
|
|
16
|
+
* - server-initiated messages that do not correlate with a
|
|
17
17
|
* single client RPC id.
|
|
18
18
|
*
|
|
19
19
|
* Every frame carries the `v: '1'` literal so future revisions can
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-message.js","names":[],"sources":["../src/server-message.ts"],"sourcesContent":["/**\n * `ServerMessage` — discriminated union of every frame a Graphorin\n * server may push to a client. Three families share the channel:\n *\n * 1. **RPC responses** (`{ jsonrpc, id, result | error }`) —\n * correlate with a previously-issued client request.\n * 2. **Typed push events** (`{ kind: 'event', subject, type,\n * payload, eventId }`) — the streaming-first data plane;\n * consumers ignore unknown `type` strings per the agent-event\n * extensibility convention.\n * 3. **Asynchronous server frames** (`{ kind: 'lifecycle' | 'error'\n * | 'pong' | 'subscribed' | 'unsubscribed' | 'replay-marker' }`)\n * — server-initiated messages that do not correlate with a\n * single client RPC id.\n *\n * Every frame carries the `v: '1'` literal so future revisions can\n * negotiate forward-compatible additions without a subprotocol bump.\n *\n * @packageDocumentation\n */\n\nimport { z } from 'zod';\n\nconst RpcId = z.union([z.string().min(1), z.number().int()]);\n\nconst RpcError = z\n .object({\n code: z.number().int(),\n message: z.string().min(1),\n data: z.unknown().optional(),\n })\n .strict();\n\nconst RpcSuccess = z\n .object({\n v: z.literal('1'),\n jsonrpc: z.literal('2.0'),\n id: RpcId,\n result: z.unknown(),\n })\n .strict();\n\nconst RpcFailure = z\n .object({\n v: z.literal('1'),\n jsonrpc: z.literal('2.0'),\n id: RpcId,\n error: RpcError,\n })\n .strict();\n\nconst SubscribedFrame = z\n .object({\n v: z.literal('1'),\n kind: z.literal('subscribed'),\n subscriptionId: z.string().min(1),\n subject: z.string().min(1),\n snapshotEventId: z.string().min(1).optional(),\n })\n .strict();\n\nconst UnsubscribedFrame = z\n .object({\n v: z.literal('1'),\n kind: z.literal('unsubscribed'),\n subscriptionId: z.string().min(1),\n })\n .strict();\n\nconst EventFrame = z\n .object({\n v: z.literal('1'),\n kind: z.literal('event'),\n eventId: z.string().min(1),\n subscriptionId: z.string().min(1),\n subject: z.string().min(1),\n type: z.string().min(1),\n payload: z.unknown(),\n })\n .strict();\n\nconst LifecycleFrame = z\n .object({\n v: z.literal('1'),\n kind: z.literal('lifecycle'),\n subscriptionId: z.string().min(1),\n status: z.enum(['running', 'paused', 'completed', 'aborted', 'failed']),\n reason: z.string().min(1).optional(),\n })\n .strict();\n\nconst ErrorFrame = z\n .object({\n v: z.literal('1'),\n kind: z.literal('error'),\n code: z.string().min(1),\n message: z.string().min(1),\n fatal: z.boolean().optional(),\n subscriptionId: z.string().min(1).optional(),\n data: z.unknown().optional(),\n })\n .strict();\n\nconst PongFrame = z\n .object({\n v: z.literal('1'),\n kind: z.literal('pong'),\n nonce: z.string().min(1).optional(),\n })\n .strict();\n\nconst ReplayMarkerFrame = z\n .object({\n v: z.literal('1'),\n kind: z.literal('replay-marker'),\n subscriptionId: z.string().min(1),\n eventId: z.string().min(1),\n droppedCount: z.number().int().nonnegative().optional(),\n note: z.string().min(1).optional(),\n })\n .strict();\n\nconst KindedFrame = z.discriminatedUnion('kind', [\n SubscribedFrame,\n UnsubscribedFrame,\n EventFrame,\n LifecycleFrame,\n ErrorFrame,\n PongFrame,\n ReplayMarkerFrame,\n]);\n\nconst RpcFrame = z.union([RpcSuccess, RpcFailure]);\n\n/**\n * Zod schema for every legal server → client frame. Validation runs\n * twice in the server pipeline: first when a route handler enqueues\n * the frame onto the dispatcher's send queue (so a malformed frame\n * never escapes the process), then again on the client side to\n * defend against protocol drift.\n *\n * @stable\n */\nexport const ServerMessageSchema = z.union([RpcFrame, KindedFrame]);\n\n/**\n * Inferred TypeScript union for the `ServerMessage` discriminator.\n *\n * @stable\n */\nexport type ServerMessage = z.infer<typeof ServerMessageSchema>;\n\n/**\n * Convenience type aliases for callers that want to reference an\n * individual variant without `z.infer<typeof X>`.\n *\n * @stable\n */\nexport type ServerEventFrame = z.infer<typeof EventFrame>;\n/** @stable */\nexport type ServerLifecycleFrame = z.infer<typeof LifecycleFrame>;\n/** @stable */\nexport type ServerErrorFrame = z.infer<typeof ErrorFrame>;\n/** @stable */\nexport type ServerSubscribedFrame = z.infer<typeof SubscribedFrame>;\n/** @stable */\nexport type ServerUnsubscribedFrame = z.infer<typeof UnsubscribedFrame>;\n/** @stable */\nexport type ServerPongFrame = z.infer<typeof PongFrame>;\n/** @stable */\nexport type ServerReplayMarkerFrame = z.infer<typeof ReplayMarkerFrame>;\n/** @stable */\nexport type ServerRpcSuccess = z.infer<typeof RpcSuccess>;\n/** @stable */\nexport type ServerRpcFailure = z.infer<typeof RpcFailure>;\n\n/**\n * Type guard helpers, one per discriminator. The narrow over the\n * `ServerMessage` union without forcing consumers to memorize the\n * exact field names.\n *\n * @stable\n */\nexport function isEventFrame(message: ServerMessage): message is ServerEventFrame {\n return 'kind' in message && message.kind === 'event';\n}\n\n/** @stable */\nexport function isLifecycleFrame(message: ServerMessage): message is ServerLifecycleFrame {\n return 'kind' in message && message.kind === 'lifecycle';\n}\n\n/** @stable */\nexport function isErrorFrame(message: ServerMessage): message is ServerErrorFrame {\n return 'kind' in message && message.kind === 'error';\n}\n\n/** @stable */\nexport function isSubscribedFrame(message: ServerMessage): message is ServerSubscribedFrame {\n return 'kind' in message && message.kind === 'subscribed';\n}\n\n/** @stable */\nexport function isUnsubscribedFrame(message: ServerMessage): message is ServerUnsubscribedFrame {\n return 'kind' in message && message.kind === 'unsubscribed';\n}\n\n/** @stable */\nexport function isPongFrame(message: ServerMessage): message is ServerPongFrame {\n return 'kind' in message && message.kind === 'pong';\n}\n\n/** @stable */\nexport function isReplayMarkerFrame(message: ServerMessage): message is ServerReplayMarkerFrame {\n return 'kind' in message && message.kind === 'replay-marker';\n}\n\n/** @stable */\nexport function isRpcSuccess(message: ServerMessage): message is ServerRpcSuccess {\n return 'jsonrpc' in message && message.jsonrpc === '2.0' && 'result' in message;\n}\n\n/** @stable */\nexport function isRpcFailure(message: ServerMessage): message is ServerRpcFailure {\n return 'jsonrpc' in message && message.jsonrpc === '2.0' && 'error' in message;\n}\n\n/**\n * Stable JSON-RPC error code catalogue used by the server when\n * surfacing routine failures (per JSON-RPC 2.0 § 5.1 + Graphorin\n * extensions). Application-level errors use codes in the\n * implementation-defined range (`-32000` … `-32099`).\n *\n * @stable\n */\nexport const RPC_ERROR_CODES = Object.freeze({\n PARSE_ERROR: -32700,\n INVALID_REQUEST: -32600,\n METHOD_NOT_FOUND: -32601,\n INVALID_PARAMS: -32602,\n INTERNAL_ERROR: -32603,\n AUTH_REQUIRED: -32001,\n AUTH_INVALID: -32002,\n SCOPE_DENIED: -32003,\n RATE_LIMITED: -32004,\n PROTOCOL_VIOLATION: -32005,\n RUN_NOT_FOUND: -32010,\n SUBSCRIPTION_NOT_FOUND: -32011,\n} as const);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server-message.js","names":[],"sources":["../src/server-message.ts"],"sourcesContent":["/**\n * `ServerMessage` - discriminated union of every frame a Graphorin\n * server may push to a client. Three families share the channel:\n *\n * 1. **RPC responses** (`{ jsonrpc, id, result | error }`) -\n * correlate with a previously-issued client request.\n * 2. **Typed push events** (`{ kind: 'event', subject, type,\n * payload, eventId }`) - the streaming-first data plane;\n * consumers ignore unknown `type` strings per the agent-event\n * extensibility convention.\n * 3. **Asynchronous server frames** (`{ kind: 'lifecycle' | 'error'\n * | 'pong' | 'subscribed' | 'unsubscribed' | 'replay-marker' }`)\n * - server-initiated messages that do not correlate with a\n * single client RPC id.\n *\n * Every frame carries the `v: '1'` literal so future revisions can\n * negotiate forward-compatible additions without a subprotocol bump.\n *\n * @packageDocumentation\n */\n\nimport { z } from 'zod';\n\nconst RpcId = z.union([z.string().min(1), z.number().int()]);\n\nconst RpcError = z\n .object({\n code: z.number().int(),\n message: z.string().min(1),\n data: z.unknown().optional(),\n })\n .strict();\n\nconst RpcSuccess = z\n .object({\n v: z.literal('1'),\n jsonrpc: z.literal('2.0'),\n id: RpcId,\n result: z.unknown(),\n })\n .strict();\n\nconst RpcFailure = z\n .object({\n v: z.literal('1'),\n jsonrpc: z.literal('2.0'),\n id: RpcId,\n error: RpcError,\n })\n .strict();\n\nconst SubscribedFrame = z\n .object({\n v: z.literal('1'),\n kind: z.literal('subscribed'),\n subscriptionId: z.string().min(1),\n subject: z.string().min(1),\n snapshotEventId: z.string().min(1).optional(),\n })\n .strict();\n\nconst UnsubscribedFrame = z\n .object({\n v: z.literal('1'),\n kind: z.literal('unsubscribed'),\n subscriptionId: z.string().min(1),\n })\n .strict();\n\nconst EventFrame = z\n .object({\n v: z.literal('1'),\n kind: z.literal('event'),\n eventId: z.string().min(1),\n subscriptionId: z.string().min(1),\n subject: z.string().min(1),\n type: z.string().min(1),\n payload: z.unknown(),\n })\n .strict();\n\nconst LifecycleFrame = z\n .object({\n v: z.literal('1'),\n kind: z.literal('lifecycle'),\n subscriptionId: z.string().min(1),\n status: z.enum(['running', 'paused', 'completed', 'aborted', 'failed']),\n reason: z.string().min(1).optional(),\n })\n .strict();\n\nconst ErrorFrame = z\n .object({\n v: z.literal('1'),\n kind: z.literal('error'),\n code: z.string().min(1),\n message: z.string().min(1),\n fatal: z.boolean().optional(),\n subscriptionId: z.string().min(1).optional(),\n data: z.unknown().optional(),\n })\n .strict();\n\nconst PongFrame = z\n .object({\n v: z.literal('1'),\n kind: z.literal('pong'),\n nonce: z.string().min(1).optional(),\n })\n .strict();\n\nconst ReplayMarkerFrame = z\n .object({\n v: z.literal('1'),\n kind: z.literal('replay-marker'),\n subscriptionId: z.string().min(1),\n eventId: z.string().min(1),\n droppedCount: z.number().int().nonnegative().optional(),\n note: z.string().min(1).optional(),\n })\n .strict();\n\nconst KindedFrame = z.discriminatedUnion('kind', [\n SubscribedFrame,\n UnsubscribedFrame,\n EventFrame,\n LifecycleFrame,\n ErrorFrame,\n PongFrame,\n ReplayMarkerFrame,\n]);\n\nconst RpcFrame = z.union([RpcSuccess, RpcFailure]);\n\n/**\n * Zod schema for every legal server → client frame. Validation runs\n * twice in the server pipeline: first when a route handler enqueues\n * the frame onto the dispatcher's send queue (so a malformed frame\n * never escapes the process), then again on the client side to\n * defend against protocol drift.\n *\n * @stable\n */\nexport const ServerMessageSchema = z.union([RpcFrame, KindedFrame]);\n\n/**\n * Inferred TypeScript union for the `ServerMessage` discriminator.\n *\n * @stable\n */\nexport type ServerMessage = z.infer<typeof ServerMessageSchema>;\n\n/**\n * Convenience type aliases for callers that want to reference an\n * individual variant without `z.infer<typeof X>`.\n *\n * @stable\n */\nexport type ServerEventFrame = z.infer<typeof EventFrame>;\n/** @stable */\nexport type ServerLifecycleFrame = z.infer<typeof LifecycleFrame>;\n/** @stable */\nexport type ServerErrorFrame = z.infer<typeof ErrorFrame>;\n/** @stable */\nexport type ServerSubscribedFrame = z.infer<typeof SubscribedFrame>;\n/** @stable */\nexport type ServerUnsubscribedFrame = z.infer<typeof UnsubscribedFrame>;\n/** @stable */\nexport type ServerPongFrame = z.infer<typeof PongFrame>;\n/** @stable */\nexport type ServerReplayMarkerFrame = z.infer<typeof ReplayMarkerFrame>;\n/** @stable */\nexport type ServerRpcSuccess = z.infer<typeof RpcSuccess>;\n/** @stable */\nexport type ServerRpcFailure = z.infer<typeof RpcFailure>;\n\n/**\n * Type guard helpers, one per discriminator. The narrow over the\n * `ServerMessage` union without forcing consumers to memorize the\n * exact field names.\n *\n * @stable\n */\nexport function isEventFrame(message: ServerMessage): message is ServerEventFrame {\n return 'kind' in message && message.kind === 'event';\n}\n\n/** @stable */\nexport function isLifecycleFrame(message: ServerMessage): message is ServerLifecycleFrame {\n return 'kind' in message && message.kind === 'lifecycle';\n}\n\n/** @stable */\nexport function isErrorFrame(message: ServerMessage): message is ServerErrorFrame {\n return 'kind' in message && message.kind === 'error';\n}\n\n/** @stable */\nexport function isSubscribedFrame(message: ServerMessage): message is ServerSubscribedFrame {\n return 'kind' in message && message.kind === 'subscribed';\n}\n\n/** @stable */\nexport function isUnsubscribedFrame(message: ServerMessage): message is ServerUnsubscribedFrame {\n return 'kind' in message && message.kind === 'unsubscribed';\n}\n\n/** @stable */\nexport function isPongFrame(message: ServerMessage): message is ServerPongFrame {\n return 'kind' in message && message.kind === 'pong';\n}\n\n/** @stable */\nexport function isReplayMarkerFrame(message: ServerMessage): message is ServerReplayMarkerFrame {\n return 'kind' in message && message.kind === 'replay-marker';\n}\n\n/** @stable */\nexport function isRpcSuccess(message: ServerMessage): message is ServerRpcSuccess {\n return 'jsonrpc' in message && message.jsonrpc === '2.0' && 'result' in message;\n}\n\n/** @stable */\nexport function isRpcFailure(message: ServerMessage): message is ServerRpcFailure {\n return 'jsonrpc' in message && message.jsonrpc === '2.0' && 'error' in message;\n}\n\n/**\n * Stable JSON-RPC error code catalogue used by the server when\n * surfacing routine failures (per JSON-RPC 2.0 § 5.1 + Graphorin\n * extensions). Application-level errors use codes in the\n * implementation-defined range (`-32000` … `-32099`).\n *\n * @stable\n */\nexport const RPC_ERROR_CODES = Object.freeze({\n PARSE_ERROR: -32700,\n INVALID_REQUEST: -32600,\n METHOD_NOT_FOUND: -32601,\n INVALID_PARAMS: -32602,\n INTERNAL_ERROR: -32603,\n AUTH_REQUIRED: -32001,\n AUTH_INVALID: -32002,\n SCOPE_DENIED: -32003,\n RATE_LIMITED: -32004,\n PROTOCOL_VIOLATION: -32005,\n RUN_NOT_FOUND: -32010,\n SUBSCRIPTION_NOT_FOUND: -32011,\n} as const);\n"],"mappings":"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"}
|
package/dist/subprotocol.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* `Sec-WebSocket-Protocol` upgrade header. The server is expected to
|
|
8
8
|
* pick exactly one and echo it back; mismatches abort the handshake
|
|
9
9
|
* per RFC 6455 § 4. Browsers also accept additional comma-separated
|
|
10
|
-
* tokens
|
|
10
|
+
* tokens - Graphorin uses this slot to attach a single-use ticket
|
|
11
11
|
* via the `ticket.<value>` form (the WebSocket browser API does not
|
|
12
12
|
* accept arbitrary headers, so the ticket has to ride the
|
|
13
13
|
* subprotocol channel).
|
|
@@ -60,7 +60,7 @@ declare function parseTicketSubprotocol(clientList: string | ReadonlyArray<strin
|
|
|
60
60
|
* Pick the single subprotocol the server should echo back. Returns
|
|
61
61
|
* `SUBPROTOCOL_NAME` when the client offered it, or `null` when no
|
|
62
62
|
* compatible variant was advertised. The function ignores `ticket.*`
|
|
63
|
-
* tokens
|
|
63
|
+
* tokens - those are handled separately via {@link parseTicketSubprotocol}.
|
|
64
64
|
*
|
|
65
65
|
* @stable
|
|
66
66
|
*/
|
package/dist/subprotocol.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* `Sec-WebSocket-Protocol` upgrade header. The server is expected to
|
|
8
8
|
* pick exactly one and echo it back; mismatches abort the handshake
|
|
9
9
|
* per RFC 6455 § 4. Browsers also accept additional comma-separated
|
|
10
|
-
* tokens
|
|
10
|
+
* tokens - Graphorin uses this slot to attach a single-use ticket
|
|
11
11
|
* via the `ticket.<value>` form (the WebSocket browser API does not
|
|
12
12
|
* accept arbitrary headers, so the ticket has to ride the
|
|
13
13
|
* subprotocol channel).
|
|
@@ -68,7 +68,7 @@ function parseTicketSubprotocol(clientList) {
|
|
|
68
68
|
* Pick the single subprotocol the server should echo back. Returns
|
|
69
69
|
* `SUBPROTOCOL_NAME` when the client offered it, or `null` when no
|
|
70
70
|
* compatible variant was advertised. The function ignores `ticket.*`
|
|
71
|
-
* tokens
|
|
71
|
+
* tokens - those are handled separately via {@link parseTicketSubprotocol}.
|
|
72
72
|
*
|
|
73
73
|
* @stable
|
|
74
74
|
*/
|
package/dist/subprotocol.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subprotocol.js","names":[],"sources":["../src/subprotocol.ts"],"sourcesContent":["/**\n * Subprotocol identifier + negotiation helpers for the Graphorin\n * WebSocket protocol.\n *\n * Clients announce supported subprotocols in the\n * `Sec-WebSocket-Protocol` upgrade header. The server is expected to\n * pick exactly one and echo it back; mismatches abort the handshake\n * per RFC 6455 § 4. Browsers also accept additional comma-separated\n * tokens
|
|
1
|
+
{"version":3,"file":"subprotocol.js","names":[],"sources":["../src/subprotocol.ts"],"sourcesContent":["/**\n * Subprotocol identifier + negotiation helpers for the Graphorin\n * WebSocket protocol.\n *\n * Clients announce supported subprotocols in the\n * `Sec-WebSocket-Protocol` upgrade header. The server is expected to\n * pick exactly one and echo it back; mismatches abort the handshake\n * per RFC 6455 § 4. Browsers also accept additional comma-separated\n * tokens - Graphorin uses this slot to attach a single-use ticket\n * via the `ticket.<value>` form (the WebSocket browser API does not\n * accept arbitrary headers, so the ticket has to ride the\n * subprotocol channel).\n *\n * @packageDocumentation\n */\n\n/**\n * Canonical subprotocol identifier for the v1 wire format.\n *\n * @stable\n */\nexport const SUBPROTOCOL_NAME = 'graphorin.protocol.v1';\n\n/**\n * Wire-format major version literal carried on every message body.\n * The pair `(SUBPROTOCOL_NAME, PROTOCOL_VERSION)` is the binding\n * contract a client commits to when it receives a successful upgrade.\n *\n * @stable\n */\nexport const PROTOCOL_VERSION = '1';\n\n/**\n * Prefix for the single-use ticket that browser clients attach to\n * the `Sec-WebSocket-Protocol` header. The server's upgrade handler\n * splits the comma-separated list, finds the first\n * `ticket.<value>` token, and validates the value against the\n * in-memory ticket store before granting the connection.\n *\n * @stable\n */\nexport const TICKET_SUBPROTOCOL_PREFIX = 'ticket.';\n\n/**\n * Format a ticket value as a `Sec-WebSocket-Protocol` token suitable\n * for browser clients (which cannot attach an `Authorization`\n * header on the WebSocket upgrade). The companion server helper is\n * {@link parseTicketSubprotocol}.\n *\n * @stable\n */\nexport function formatTicketSubprotocol(ticket: string): string {\n if (typeof ticket !== 'string' || ticket.length === 0) {\n throw new TypeError('formatTicketSubprotocol: ticket must be a non-empty string.');\n }\n return `${TICKET_SUBPROTOCOL_PREFIX}${ticket}`;\n}\n\n/**\n * Extract the ticket value from a single comma-separated client list\n * (e.g. `'graphorin.protocol.v1, ticket.abc-123'`). Returns\n * `undefined` if no `ticket.*` token is present. Whitespace around\n * each comma-separated token is ignored.\n *\n * @stable\n */\nexport function parseTicketSubprotocol(\n clientList: string | ReadonlyArray<string>,\n): string | undefined {\n for (const token of normalizeTokens(clientList)) {\n if (token.startsWith(TICKET_SUBPROTOCOL_PREFIX)) {\n const value = token.slice(TICKET_SUBPROTOCOL_PREFIX.length);\n if (value.length > 0) return value;\n }\n }\n return undefined;\n}\n\n/**\n * Pick the single subprotocol the server should echo back. Returns\n * `SUBPROTOCOL_NAME` when the client offered it, or `null` when no\n * compatible variant was advertised. The function ignores `ticket.*`\n * tokens - those are handled separately via {@link parseTicketSubprotocol}.\n *\n * @stable\n */\nexport function negotiateSubprotocol(clientList: string | ReadonlyArray<string>): string | null {\n for (const token of normalizeTokens(clientList)) {\n if (token === SUBPROTOCOL_NAME) return SUBPROTOCOL_NAME;\n }\n return null;\n}\n\nfunction normalizeTokens(input: string | ReadonlyArray<string>): ReadonlyArray<string> {\n if (Array.isArray(input)) {\n return input\n .flatMap((entry) => entry.split(','))\n .map((token) => token.trim())\n .filter((token) => token.length > 0);\n }\n if (typeof input !== 'string') return [];\n return input\n .split(',')\n .map((token) => token.trim())\n .filter((token) => token.length > 0);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,MAAa,mBAAmB;;;;;;;;AAShC,MAAa,mBAAmB;;;;;;;;;;AAWhC,MAAa,4BAA4B;;;;;;;;;AAUzC,SAAgB,wBAAwB,QAAwB;AAC9D,KAAI,OAAO,WAAW,YAAY,OAAO,WAAW,EAClD,OAAM,IAAI,UAAU,8DAA8D;AAEpF,QAAO,GAAG,4BAA4B;;;;;;;;;;AAWxC,SAAgB,uBACd,YACoB;AACpB,MAAK,MAAM,SAAS,gBAAgB,WAAW,CAC7C,KAAI,MAAM,WAAW,0BAA0B,EAAE;EAC/C,MAAM,QAAQ,MAAM,MAAM,EAAiC;AAC3D,MAAI,MAAM,SAAS,EAAG,QAAO;;;;;;;;;;;AAcnC,SAAgB,qBAAqB,YAA2D;AAC9F,MAAK,MAAM,SAAS,gBAAgB,WAAW,CAC7C,KAAI,UAAU,iBAAkB,QAAO;AAEzC,QAAO;;AAGT,SAAS,gBAAgB,OAA8D;AACrF,KAAI,MAAM,QAAQ,MAAM,CACtB,QAAO,MACJ,SAAS,UAAU,MAAM,MAAM,IAAI,CAAC,CACpC,KAAK,UAAU,MAAM,MAAM,CAAC,CAC5B,QAAQ,UAAU,MAAM,SAAS,EAAE;AAExC,KAAI,OAAO,UAAU,SAAU,QAAO,EAAE;AACxC,QAAO,MACJ,MAAM,IAAI,CACV,KAAK,UAAU,MAAM,MAAM,CAAC,CAC5B,QAAQ,UAAU,MAAM,SAAS,EAAE"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graphorin/protocol",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Wire protocol contract for the Graphorin framework: Zod schemas + TypeScript types for the WebSocket subprotocol `graphorin.protocol.v1`. Defines the `ClientMessage` and `ServerMessage` discriminated unions, the JSON-RPC-shaped control channel (`initialize` / `subscription.subscribe` / `subscription.unsubscribe` / `run.cancel` / `ping`), the typed event push frames (`{ kind: 'event', subject, type, payload, eventId }`), the asynchronous server-initiated error frames (`{ kind: 'error', code, message }`), the subprotocol negotiation helpers, and the close-code taxonomy (4001 auth.required, 4002 auth.invalid, 4003 auth.revoked, 4004 auth.scope_denied, 4005 rate.limited, 4006 flow.throttled, 4007 server.shutdown, 4008 protocol.violation). Browser-friendly: zero Node-only dependencies; the only runtime dependency is `zod`. Created and maintained by Oleksiy Stepurenko.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Oleksiy Stepurenko",
|