@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 +78 -0
- package/dist/index.d.ts +23 -2
- package/dist/index.mjs +1558 -5
- package/dist/token-verifier.d.ts +52 -10
- package/package.json +19 -6
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;
|