@claxedo/workspace-relay-protocol 0.1.0 → 0.5.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/README.md ADDED
@@ -0,0 +1,78 @@
1
+ # `@claxedo/workspace-relay-protocol`
2
+
3
+ Shared wire types and token-verifier contracts for Claxedo workspace relay
4
+ traffic. This package intentionally has no Hono, Bun, or server dependency so
5
+ workspace hosts and non-Node clients can validate tunnel frames without pulling
6
+ in the relay implementation.
7
+
8
+ ## Public Surface
9
+
10
+ | Export | Stability | Purpose |
11
+ | --- | --- | --- |
12
+ | `TUNNEL_PROTOCOL_VERSION` | Stable | Current tunnel protocol version. |
13
+ | `TunnelMessage` and message subtypes | Stable | Discriminated union for HTTP, WebSocket, heartbeat, flow-control, and error frames. |
14
+ | `validateTunnelMessage`, `isTunnelMessage` | Stable | Runtime validation for protocol, message type, and per-message payload shape. |
15
+ | `makeTunnelPong` | Stable | Helper for heartbeat replies. |
16
+ | `TokenVerifier` and claim types | Stable | Narrow verifier interface shared by relay/runtime boundaries. |
17
+ | `createClerkTokenVerifier` | Public beta | Verifies Clerk session tokens with issuer, audience, JWKS, and algorithm constraints. |
18
+ | `createHttpTokenVerifier` | Public beta | Calls an operator-controlled verifier endpoint over HTTP. |
19
+ | `createStaticTokenVerifier` | Test/single-tenant only | Fixed token table for tests and isolated self-hosted deployments. |
20
+
21
+ ## Tunnel Validation
22
+
23
+ `validateTunnelMessage(input)` rejects:
24
+
25
+ - non-objects;
26
+ - protocol mismatches;
27
+ - unknown message types;
28
+ - missing required fields for the selected message type;
29
+ - malformed header maps;
30
+ - invalid base64 fields;
31
+ - invalid HTTP status or WebSocket close-code fields.
32
+
33
+ The validator allows extra object fields for forward-compatible metadata, but
34
+ consumers should ignore fields they do not understand.
35
+
36
+ ## Token Verifiers
37
+
38
+ `TokenVerifier` is deliberately small:
39
+
40
+ ```ts
41
+ export type TokenVerifier<TClaims extends Record<string, unknown> = Record<string, unknown>> = {
42
+ verify(token: string): Promise<TokenClaims<TClaims>>
43
+ }
44
+ ```
45
+
46
+ Verifier implementations own issuer checks, audience checks, key selection,
47
+ expiry, replay policy, and any revocation/introspection calls. Relay and
48
+ runtime packages validate the returned claims again at their own boundaries.
49
+
50
+ ### HTTP Verifier Endpoint
51
+
52
+ `createHttpTokenVerifier({ endpoint })` posts `{ token }` to the configured
53
+ endpoint and expects `{ subject, scopes?, claims }` back. The endpoint is a
54
+ trusted operator configuration value. Do not derive it from a request, tenant
55
+ record, query string, workspace config, or other user-controlled input.
56
+
57
+ The endpoint should normally be an HTTPS URL on infrastructure you control. It
58
+ must enforce issuer, audience, expiry, key selection, and replay/revocation
59
+ policy before returning claims. Treat a compromised verifier endpoint as
60
+ equivalent to a compromised token issuer.
61
+
62
+ ### Static Verifier
63
+
64
+ `createStaticTokenVerifier` is for tests, local demos, and isolated
65
+ single-tenant deployments where tokens are provisioned out of band. It is not a
66
+ multi-tenant production verifier because it has no issuer rotation, expiry
67
+ enforcement, replay cache, or revocation source unless the caller adds those
68
+ outside the static table.
69
+
70
+ ## Compatibility Policy
71
+
72
+ The current wire version is `1`. Patch and minor releases may add optional
73
+ fields to existing message objects. They must not change the meaning or type of
74
+ existing fields within the same protocol version.
75
+
76
+ Breaking message changes require a new `TUNNEL_PROTOCOL_VERSION`. Relays and
77
+ hosts should reject unsupported protocol versions with a protocol-mismatch
78
+ error instead of trying to coerce frames across versions.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export declare const TUNNEL_PROTOCOL_VERSION = 1;
2
- export { type TokenClaims, type TokenVerifier, TokenVerifierError, type HttpTokenVerifierOptions, createHttpTokenVerifier, type StaticTokenVerifierOptions, createStaticTokenVerifier, } from "./token-verifier";
2
+ export { type TokenClaims, type TokenVerifierBaseClaims, type RuntimeAccessVerifierClaims, type RelayHostVerifierClaims, type TokenVerifier, type ClerkTokenVerifierClaims, TokenVerifierError, type ClerkTokenVerifierOptions, createClerkTokenVerifier, type HttpTokenVerifierOptions, createHttpTokenVerifier, type StaticTokenVerifierOptions, createStaticTokenVerifier, } from "./token-verifier";
3
3
  export type TunnelHeaderMap = Record<string, string>;
4
4
  export type TunnelPing = {
5
5
  type: "ping";
@@ -43,6 +43,13 @@ export type TunnelHttpResponseEnd = {
43
43
  protocol: typeof TUNNEL_PROTOCOL_VERSION;
44
44
  request_id: string;
45
45
  };
46
+ export type TunnelHttpResponseFlow = {
47
+ type: "http.response.flow";
48
+ protocol: typeof TUNNEL_PROTOCOL_VERSION;
49
+ request_id: string;
50
+ paused: boolean;
51
+ reason?: "slow_consumer" | "drained" | "closed";
52
+ };
46
53
  export type TunnelWsOpen = {
47
54
  type: "ws.open";
48
55
  protocol: typeof TUNNEL_PROTOCOL_VERSION;
@@ -73,6 +80,20 @@ export type TunnelError = {
73
80
  code: string;
74
81
  message: string;
75
82
  };
76
- export type TunnelMessage = TunnelPing | TunnelPong | TunnelHttpRequest | TunnelHttpResponseStart | TunnelHttpResponseChunk | TunnelHttpResponseEnd | TunnelWsOpen | TunnelWsFrame | TunnelWsClose | TunnelError;
83
+ export type TunnelMessage = TunnelPing | TunnelPong | TunnelHttpRequest | TunnelHttpResponseStart | TunnelHttpResponseChunk | TunnelHttpResponseEnd | TunnelHttpResponseFlow | TunnelWsOpen | TunnelWsFrame | TunnelWsClose | TunnelError;
84
+ export type TunnelMessageValidation = {
85
+ ok: true;
86
+ message: TunnelMessage;
87
+ } | {
88
+ ok: false;
89
+ reason: "protocol_mismatch";
90
+ expected_protocol: typeof TUNNEL_PROTOCOL_VERSION;
91
+ actual_protocol: unknown;
92
+ type?: string;
93
+ } | {
94
+ ok: false;
95
+ reason: "invalid";
96
+ };
97
+ export declare function validateTunnelMessage(input: unknown): TunnelMessageValidation;
77
98
  export declare function isTunnelMessage(input: unknown): input is TunnelMessage;
78
99
  export declare function makeTunnelPong(input: TunnelPing, receivedAt?: number): TunnelPong;