@claxedo/workspace-relay 0.10.1 → 0.10.3
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 +68 -19
- package/dist/auth.d.ts +10 -12
- package/dist/cloudflare.d.ts +11 -30
- package/dist/host-tunnel-forwarding.d.ts +0 -2
- package/dist/http.d.ts +0 -2
- package/dist/index.mjs +541 -364
- package/dist/relay-bytes.d.ts +10 -0
- package/dist/relay-location.d.ts +19 -10
- package/dist/relay-log.d.ts +61 -0
- package/dist/relay-trace.d.ts +5 -0
- package/dist/resolver-clients.d.ts +19 -4
- package/dist/server.d.ts +6 -14
- package/dist/socket-frames.d.ts +47 -0
- package/dist/stream-standing.d.ts +24 -0
- package/dist/worker.d.ts +35 -15
- package/dist/workerd-fixture/boot.d.ts +5 -13
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ signed identity to match the current ready lease; otherwise it returns 401
|
|
|
34
34
|
|
|
35
35
|
Target lookups are keyed by workspace, host and routing identity. A resolved
|
|
36
36
|
cloud or host-tunnel target is kept for `CLAXEDO_RELAY_TARGET_CACHE_TTL_MS`
|
|
37
|
-
(
|
|
37
|
+
(30 s), the same lag the revocation cache allows; a workspace still starting is
|
|
38
38
|
asked about on every request. A `durable-object` target is kept for 30 minutes,
|
|
39
39
|
the longest life of a Runtime Access Token, because the host id names the
|
|
40
40
|
session's object and the object never moves; revocation is still asked about
|
|
@@ -52,10 +52,25 @@ relay implements it by calling the control plane or an equivalent
|
|
|
52
52
|
authority on every new HTTP request and WebSocket upgrade. A false result
|
|
53
53
|
rejects before forwarding to the host.
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
The answer is held for 30 s (`CLAXEDO_RELAY_REVOCATION_CACHE_TTL_MS`), which is
|
|
56
|
+
the bound on how late a revocation is seen: no byte is forwarded on an answer
|
|
57
|
+
older than that.
|
|
58
|
+
|
|
59
|
+
- **A request** is checked when it arrives.
|
|
60
|
+
- **A WebSocket frame**, in either direction, is checked as it passes. The socket
|
|
61
|
+
itself is swept every 30 s by the room's alarm and closed `1008` once revoked
|
|
62
|
+
or expired, so an idle socket can stay open that long while carrying nothing.
|
|
63
|
+
- **A response stream** (SSE) keeps its answer fresh while it is open
|
|
64
|
+
(`guardStreamStanding`): the room asks the authority again 2 s before the
|
|
65
|
+
held answer reaches the bound, and ends the stream when the token is revoked
|
|
66
|
+
or expires. Ending cancels the tunnel stream, which frees its slot and tells
|
|
67
|
+
the host to stop. This costs one lookup every 28 s for each
|
|
68
|
+
token with a stream open, shared by all of that token's streams and requests.
|
|
69
|
+
|
|
70
|
+
An authority that cannot be reached is given `resolverOutageGraceAttempts`
|
|
71
|
+
consecutive failures (3) before a stream or socket is closed over it, and a
|
|
72
|
+
failed re-read leaves a still-valid held answer in place; the token's `exp`
|
|
73
|
+
ends every path regardless.
|
|
59
74
|
|
|
60
75
|
### Host Tunnel Serving-Generation Fence
|
|
61
76
|
|
|
@@ -130,7 +145,8 @@ Re-exported from [`src/index.ts`](src/index.ts):
|
|
|
130
145
|
| Concern | Module | Notable exports |
|
|
131
146
|
| --- | --- | --- |
|
|
132
147
|
| Token issuance / verification | [`src/auth.ts`](src/auth.ts) | `mintRuntimeAccessToken`, `verifyRuntimeAccessToken`, `mintRelayHostToken`, `verifyRelayHostToken`, `mintHostTunnelToken`, `verifyHostTunnelToken`, types `RelayRole`, `RelayBacking`, `RelayJwtAlgorithm`, `RuntimeAccessTokenClaims`, `RelayKey`, `RelayKeyResolver`, error class `WorkspaceRelayAuthError` |
|
|
133
|
-
| Request authorization and forwarding | [`src/server.ts`](src/server.ts) | `authorizeWorkspaceRelayRequest`, `workspaceRelayForwardRequestInit`, `workspaceRelayTargetUrl`,
|
|
148
|
+
| Request authorization and forwarding | [`src/server.ts`](src/server.ts) | `authorizeWorkspaceRelayRequest`, `workspaceRelayForwardRequestInit`, `workspaceRelayTargetUrl`, types `WorkspaceRelayOptions`, `WorkspaceRelayTarget`, `WorkspaceRelayAuditEvent` |
|
|
149
|
+
| Resolver clients | [`src/resolver-clients.ts`](src/resolver-clients.ts) | `createCachedRevocationClient`, `createCachedTargetClient`, `createCachedHostGenerationClient`, `runtimeAccessTokenRevocationDelayMs`, type `RuntimeAccessTokenActiveResult` |
|
|
134
150
|
| CORS policy | [`src/cors-origins.ts`](src/cors-origins.ts) | `DEFAULT_RELAY_APP_ORIGINS`, `RELAY_ALLOWED_REQUEST_HEADERS`, `createOriginMatcher`, `parseAllowedOrigins` |
|
|
135
151
|
| Active-host directory | [`src/directory.ts`](src/directory.ts) | `createWorkspaceRelayDirectory`, types `WorkspaceRelayDirectory`, `HostTunnelPresence` |
|
|
136
152
|
| Cloudflare Worker gateway and room | [`src/cloudflare.ts`](src/cloudflare.ts) | `createWorkspaceRelayDurableObjectGateway`, `createWorkspaceRelayDurableObjectRoom` |
|
|
@@ -143,8 +159,14 @@ implement the tunnel protocol without pulling Jose.
|
|
|
143
159
|
|
|
144
160
|
## Configuration
|
|
145
161
|
|
|
146
|
-
All knobs are environment variables
|
|
147
|
-
|
|
162
|
+
All knobs are environment variables. `wrangler.toml` declares what every
|
|
163
|
+
deployment shares; `scripts/deploy-cloudflare.ts` renders it with one
|
|
164
|
+
deployment's names (`CLAXEDO_RELAY_WORKER_NAME`, the session host
|
|
165
|
+
`CLAXEDO_SESSION_HOST_WORKER_NAME` that `SESSION_HOST` binds, an optional
|
|
166
|
+
`CLAXEDO_RELAY_TUNNEL_CHANNEL_CAP`, and the custom domain when
|
|
167
|
+
`CLAXEDO_RELAY_URL` is not on `workers.dev`), passes the deployment's vars
|
|
168
|
+
(`CLAXEDO_CENTRAL_URL`, `CLAXEDO_APP_ORIGINS`, `CLAXEDO_CONTROL_PLANE_JWKS_URL`)
|
|
169
|
+
and uploads its secrets.
|
|
148
170
|
|
|
149
171
|
| Env var | Purpose |
|
|
150
172
|
| --- | --- |
|
|
@@ -152,7 +174,8 @@ All knobs are environment variables: Worker vars and secrets in
|
|
|
152
174
|
| `CLAXEDO_RELAY_RESOLVER_TOKEN` | Bearer token the relay sends to the resolver. The Worker refuses to start without it. |
|
|
153
175
|
| `CLAXEDO_RELAY_HOST_GENERATION_URL` | Optional absolute URL of the host-generation lookup. Unset (the normal case) derives `<CLAXEDO_RELAY_RESOLVER_URL>/host-generation`; set it only when the lookup lives at a different origin than the rest of the resolver. There is no way to turn the fence off on a resolver-backed relay. |
|
|
154
176
|
| `CLAXEDO_RELAY_HOST_GENERATION_CACHE_TTL_MS` | Cache TTL for host-generation answers. Defaults to 10000. A superseded tunnel closes within the re-check interval (30 s) plus this TTL. |
|
|
155
|
-
| `CLAXEDO_RELAY_REVOCATION_CACHE_TTL_MS` | Cache TTL for `/revocation` answers (default 10000 ms).
|
|
177
|
+
| `CLAXEDO_RELAY_REVOCATION_CACHE_TTL_MS` | Cache TTL for `/revocation` answers (default 10000 ms). |
|
|
178
|
+
| `CLAXEDO_RELAY_TARGET_CACHE_TTL_MS` | Cache TTL for a resolved cloud or host-tunnel target (default 10000 ms). A workspace still starting is not cached. |
|
|
156
179
|
| `CLAXEDO_CONTROL_PLANE_JWKS_URL` | Remote JWKS the relay uses to verify runtime-access and host-tunnel tokens. |
|
|
157
180
|
| `CLAXEDO_RUNTIME_ACCESS_TOKEN_PUBLIC_KEY_PEM` | Inline public key (alternative to JWKS). |
|
|
158
181
|
| `CLAXEDO_RELAY_HOST_SIGNING_KEY_PEM` | Private PEM the relay uses to mint relay-host tokens. The Worker publishes its public half at `/.well-known/jwks.json`. |
|
|
@@ -164,9 +187,9 @@ Cloudflare Worker tracing knobs (Durable Object deployment):
|
|
|
164
187
|
| --- | --- |
|
|
165
188
|
| `CLAXEDO_RELAY_TRACE_SAMPLE_RATE` | 0–1 sampling rate for request traces. Only sampled requests emit `Server-Timing` phase headers and structured trace logs; unsampled responses carry just the `x-claxedo-trace-id` correlation header. Defaults to 0 (off). |
|
|
166
189
|
| `CLAXEDO_RELAY_TRACE_FORCE_SECRET` | Optional operator secret. When set, a request with `x-claxedo-relay-trace: <secret>` forces sampling for that request (targeted debugging). Unset (default) means the force header is ignored — clients can never force tracing or timing emission. |
|
|
167
|
-
| `CLAXEDO_APP_ORIGINS` |
|
|
190
|
+
| `CLAXEDO_APP_ORIGINS` | **Additive** origin entries layered on top of the base allowlist; `CLAXEDO_RELAY_ALLOWED_ORIGINS` replaces the base list itself. |
|
|
168
191
|
|
|
169
|
-
Token verification is pluggable
|
|
192
|
+
Token verification is pluggable via the
|
|
170
193
|
`RelayKey | RelayKeyResolver` pair on `verifyRuntimeAccessToken` and
|
|
171
194
|
friends, **and** via the unified
|
|
172
195
|
[`TokenVerifier`](../workspace-relay-protocol/src/token-verifier.ts)
|
|
@@ -200,10 +223,38 @@ the crypto authority and must enforce issuer, audience, expiry, key selection,
|
|
|
200
223
|
and replay policy before returning claims. Treat the endpoint as trusted
|
|
201
224
|
operator configuration, not as tenant/user input.
|
|
202
225
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
226
|
+
## Path And Room Placement
|
|
227
|
+
|
|
228
|
+
A request for a connected machine crosses these hops, and each one is there for a reason:
|
|
229
|
+
|
|
230
|
+
1. **Edge.** Wherever the caller's connection lands. Cloudflare and the caller's ISP decide it; nothing here can.
|
|
231
|
+
2. **App Worker**, on the app's origin, strips `/relay` and calls this Worker over a service binding in the same
|
|
232
|
+
data center. It exists so a browser makes one same-origin request with no preflight. Measured at 4 ms.
|
|
233
|
+
3. **Gateway**, this Worker's stateless half, in that same data center. It names the workspace's room and passes the
|
|
234
|
+
request to it.
|
|
235
|
+
4. **Room**, one Durable Object per workspace, named `relay-room:<workspaceId>`. It is the only place a browser's
|
|
236
|
+
connection and a machine's outbound tunnel can meet, because the machine cannot be dialed.
|
|
237
|
+
5. **Tunnel**, the machine's one long-lived WebSocket to the room.
|
|
238
|
+
|
|
239
|
+
A room is created by the first request that names it, takes its location from that request's hint, and never
|
|
240
|
+
moves. `relayRoomPlacement` decides the hint:
|
|
241
|
+
|
|
242
|
+
- a session host's room goes beside its Durable Object (`enam`);
|
|
243
|
+
- a cloud runtime's room goes to the region the request declares, which is where its sandbox runs;
|
|
244
|
+
- a person's machine has no region. Its room goes by the edge country of whoever reaches it first with a verified
|
|
245
|
+
credential: the machine's own dial, or its owner's browser. A region anyone else declares for it is ignored. The
|
|
246
|
+
control plane sends the deployment's default region for every workspace, and a room placed by that default sat
|
|
247
|
+
228 ms from a machine and owner who were both in India.
|
|
248
|
+
|
|
249
|
+
No Indian data center hosts Durable Objects; `apac` from India lands in Singapore. Measured from India on
|
|
250
|
+
2026-11-10, a relayed GET costs about 270 ms with the room in Singapore and cost 765 ms with it in eastern North
|
|
251
|
+
America. The numbers and the rig are in `docs/perf/2026-11-10-relay-baseline.md`.
|
|
252
|
+
|
|
253
|
+
Renaming rooms moves them, at a price: a room the gateway no longer names still holds its machine's tunnel, and a
|
|
254
|
+
machine with a healthy tunnel does not dial again. Such a room closes its sockets on its next alarm
|
|
255
|
+
(`WorkspaceRelayRoom.alarm`), which took about two minutes on staging. Deploying a Worker that names rooms
|
|
256
|
+
differently from the one running, in either direction, strands tunnels for that long, or until the connector
|
|
257
|
+
restarts if the deployed code has no such release.
|
|
207
258
|
|
|
208
259
|
## Tunnel Lifecycle
|
|
209
260
|
|
|
@@ -243,14 +294,14 @@ the request and forwards it to the resolved cloud target or machine tunnel.
|
|
|
243
294
|
| --- | --- | --- |
|
|
244
295
|
| Layer | Control-plane auth | Tunnel transport |
|
|
245
296
|
| Trust | Authenticates the relay process itself (loopback or bearer) | Authenticates the user's runtime-access token |
|
|
246
|
-
| Routes | `GET /internal/relay/target`, `GET /internal/relay/revocation` | WS upgrade + tunnel framing |
|
|
297
|
+
| Routes | `GET /internal/relay/target`, `GET /internal/relay/revocation`, `GET /internal/relay/host-generation` | WS upgrade + tunnel framing |
|
|
247
298
|
| Owners | `claxedo-server` (depends on the workspace authority, the identity provider, audit log) | `workspace-relay` (no authority or identity-provider dependency) |
|
|
248
299
|
| Lives in | `packages/claxedo-server/` (server-side only) | `packages/workspace-relay/` (Worker and Durable Object) |
|
|
249
300
|
|
|
250
301
|
This split is deliberate: the relay never reads the workspace authority or the
|
|
251
302
|
identity provider directly. It calls back to `claxedo-server` over HTTP for resolver
|
|
252
303
|
decisions. The decision data crosses the seam as
|
|
253
|
-
`RuntimeAccessTokenActiveResult` (defined in `
|
|
304
|
+
`RuntimeAccessTokenActiveResult` (defined in `resolver-clients.ts`).
|
|
254
305
|
|
|
255
306
|
## Development
|
|
256
307
|
|
|
@@ -259,8 +310,6 @@ bun --cwd packages/workspace-relay test # unit suites, including the work
|
|
|
259
310
|
bun --cwd packages/workspace-relay typecheck
|
|
260
311
|
```
|
|
261
312
|
|
|
262
|
-
The TS error baseline for this package is **0** — keep it that way.
|
|
263
|
-
|
|
264
313
|
## Boundary rule
|
|
265
314
|
|
|
266
315
|
Consumers outside this package import `@claxedo/workspace-relay` only —
|
package/dist/auth.d.ts
CHANGED
|
@@ -186,25 +186,23 @@ export declare function deriveRelayHostPublicKey(privateKey: CryptoKey): Promise
|
|
|
186
186
|
* WebCrypto rather than `node:crypto` so the workerd bundle can use it.
|
|
187
187
|
*/
|
|
188
188
|
export declare function deriveRelayHostKid(publicKey: CryptoKey): Promise<string>;
|
|
189
|
-
/**
|
|
190
|
-
* Mint variants accept only a signing key — never a resolver. Resolvers are
|
|
191
|
-
* verification-only. This narrowed alias keeps the mint signatures unchanged.
|
|
192
|
-
*/
|
|
193
189
|
type RelaySigningKey = CryptoKey | Uint8Array;
|
|
194
190
|
export declare function mintRuntimeAccessToken(input: RuntimeInput, key: RelaySigningKey, alg: RelayJwtAlgorithm): Promise<string>;
|
|
195
191
|
export declare function verifyRuntimeAccessToken(token: string, key: RelayKey, expected: ExpectedTarget): Promise<RuntimeAccessTokenClaims>;
|
|
196
192
|
export declare function validateRuntimeAccessTokenClaims(input: Record<string, unknown>, expected: ExpectedTarget): RuntimeAccessTokenClaims;
|
|
197
193
|
export declare function mintHostTunnelToken(input: HostTunnelInput, key: RelaySigningKey, alg: RelayJwtAlgorithm): Promise<string>;
|
|
198
194
|
export declare function verifyHostTunnelToken(token: string, key: RelayKey, expected: ExpectedHostTunnel): Promise<HostTunnelTokenClaims>;
|
|
199
|
-
/**
|
|
200
|
-
* Validates a claims result a custom `authorizeHostTunnel` policy returns.
|
|
201
|
-
* The policy decides WHO the tunnel is; the binding is the relay's: the
|
|
202
|
-
* claims' `host_id` must equal the requested host and its `workspace_ids`
|
|
203
|
-
* must cover every requested workspace, so a permissive policy cannot widen
|
|
204
|
-
* the identity its own claims assert.
|
|
205
|
-
*/
|
|
206
195
|
/** What a Relay Host Token minted from a verified Runtime Access Token carries over from it. */
|
|
207
196
|
export declare function relayHostInputFromRuntimeClaims(claims: RuntimeAccessTokenClaims): Omit<RelayHostInput, "backing" | "hostId" | "workspaceId">;
|
|
197
|
+
/**
|
|
198
|
+
* A Relay Host Token authenticates one HTTP request or WebSocket upgrade from
|
|
199
|
+
* the relay to the host, and the relay mints a fresh one for every request.
|
|
200
|
+
* Its 60 s life bounds replay while tolerating clock skew. A long-lived socket
|
|
201
|
+
* (PTY, SSE, event stream) outlives it: the token admits the connection, the
|
|
202
|
+
* host's own session bounds its life, and a reconnect mints a new token.
|
|
203
|
+
* Refreshing mid-stream would put the relay, and the control plane behind its
|
|
204
|
+
* resolver, in the streaming path for no security gain.
|
|
205
|
+
*/
|
|
208
206
|
export declare function mintRelayHostToken(input: RelayHostInput, key: RelaySigningKey, alg: RelayJwtAlgorithm): Promise<string>;
|
|
209
207
|
export declare function verifyRelayHostToken(token: string, key: RelayKey, expected: ExpectedTarget): Promise<RelayHostTokenClaims>;
|
|
210
208
|
export declare function tokenScopePayload(sessionId: string | undefined): {
|
|
@@ -214,11 +212,11 @@ export declare function tokenScopePayload(sessionId: string | undefined): {
|
|
|
214
212
|
scope: "session";
|
|
215
213
|
session_id: string;
|
|
216
214
|
};
|
|
217
|
-
/** The token's reach, or nothing when it names neither the workspace nor exactly one session. */
|
|
218
215
|
/** The purpose claim, or undefined when it names a purpose this build does not know. */
|
|
219
216
|
export declare function tokenPurposeClaims(payload: Record<string, unknown>): {
|
|
220
217
|
purpose?: TokenPurpose;
|
|
221
218
|
} | undefined;
|
|
219
|
+
/** The token's reach, or nothing when it names neither the workspace nor exactly one session. */
|
|
222
220
|
export declare function tokenScopeClaims(payload: Record<string, unknown>): {
|
|
223
221
|
scope: TokenScope;
|
|
224
222
|
session_id?: string;
|
package/dist/cloudflare.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type AuthorizedWorkspaceRelayRequest, type WorkspaceRelayOptions } from "./server";
|
|
2
|
+
import { type StreamStandingOptions } from "./stream-standing";
|
|
2
3
|
import { type SessionHostNamespace } from "./session-host-forwarding";
|
|
3
|
-
import { type
|
|
4
|
+
import { type RelayLog } from "./relay-log";
|
|
5
|
+
import { type RelayTraceSampling, type WorkspaceRelayTraceLogEvent } from "./relay-trace";
|
|
4
6
|
export type { WorkspaceRelayTraceLogEvent } from "./relay-trace";
|
|
5
7
|
export type WorkspaceRelayDurableObjectId = unknown;
|
|
6
8
|
export type WorkspaceRelayDurableObjectStub = {
|
|
@@ -41,7 +43,7 @@ export type WorkspaceRelayDurableObjectSocketPair = {
|
|
|
41
43
|
export type WorkspaceRelayDurableObjectConnectWebSocket = (url: string, init: {
|
|
42
44
|
headers: Record<string, string>;
|
|
43
45
|
}) => WorkspaceRelayDurableObjectSocket | Promise<WorkspaceRelayDurableObjectSocket>;
|
|
44
|
-
export type WorkspaceRelayDurableObjectRoomOptions = WorkspaceRelayOptions & {
|
|
46
|
+
export type WorkspaceRelayDurableObjectRoomOptions = WorkspaceRelayOptions & RelayTraceSampling & {
|
|
45
47
|
sessionHost?: SessionHostNamespace;
|
|
46
48
|
createWebSocketPair?: () => WorkspaceRelayDurableObjectSocketPair;
|
|
47
49
|
connectWebSocket?: WorkspaceRelayDurableObjectConnectWebSocket;
|
|
@@ -60,7 +62,7 @@ export type WorkspaceRelayDurableObjectRoomOptions = WorkspaceRelayOptions & {
|
|
|
60
62
|
* Defaults to 30s; 0 disables the re-check. Because the check may answer
|
|
61
63
|
* from the revocation lookup's cache, a revoked token closes the socket
|
|
62
64
|
* within this interval plus the lookup's cache TTL — see
|
|
63
|
-
* `runtimeAccessTokenRevocationDelayMs` in `./
|
|
65
|
+
* `runtimeAccessTokenRevocationDelayMs` in `./resolver-clients`. A resolver outage
|
|
64
66
|
* gets `resolverOutageGraceAttempts` and never extends the socket past the
|
|
65
67
|
* token's `exp`, which the watcher enforces locally.
|
|
66
68
|
*/
|
|
@@ -91,9 +93,12 @@ export type WorkspaceRelayDurableObjectRoomOptions = WorkspaceRelayOptions & {
|
|
|
91
93
|
* non-hibernating path and in tests that do not exercise it.
|
|
92
94
|
*/
|
|
93
95
|
alarms?: WorkspaceRelayDurableObjectAlarms;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
/** How an open response stream's token is kept inside the revocation bound; absent, streams are not re-checked. */
|
|
97
|
+
streamStanding?: Pick<StreamStandingOptions, "standing" | "boundMs">;
|
|
98
|
+
/** Where a fault of the room's own code is reported: a frame handler or the revocation alarm throwing. */
|
|
99
|
+
report: (error: unknown, task: string) => void;
|
|
96
100
|
traceLog?: (event: WorkspaceRelayTraceLogEvent) => void;
|
|
101
|
+
relayLog?: RelayLog;
|
|
97
102
|
now?: () => number;
|
|
98
103
|
};
|
|
99
104
|
export type WorkspaceRelayDurableObjectHibernation = {
|
|
@@ -141,30 +146,6 @@ export type WorkspaceRelayDurableObjectDrainController = {
|
|
|
141
146
|
remaining: number;
|
|
142
147
|
}>;
|
|
143
148
|
};
|
|
144
|
-
/**
|
|
145
|
-
* Exported for `relay-base64.test.ts`, which proves byte-equality against a
|
|
146
|
-
* per-byte reference across the chunk boundaries. This sits on the path every
|
|
147
|
-
* frame pays, so its equivalence is worth asserting directly rather than
|
|
148
|
-
* inferring from a round-trip.
|
|
149
|
-
*/
|
|
150
|
-
export declare function bytesToBase64(bytes: Uint8Array): string;
|
|
151
|
-
/**
|
|
152
|
-
* Runs the two frame decoders over one runtime-delivered `event.data` and
|
|
153
|
-
* reports what they produced.
|
|
154
|
-
*
|
|
155
|
-
* Exists so `relay-workerd-binary.test.ts` can assert the decoders against what
|
|
156
|
-
* REAL workerd delivers. The rest of the suite drives hand-rolled socket
|
|
157
|
-
* doubles, which by construction hand us whatever we chose to hand ourselves —
|
|
158
|
-
* so they cannot catch the hazard that binary `event.data` becomes a `Blob` at
|
|
159
|
-
* `compatibility_date >= 2026-03-17`. Test-support surface, not a relay path.
|
|
160
|
-
*/
|
|
161
|
-
export declare function relayFrameDiagnostics(data: unknown): Promise<{
|
|
162
|
-
frameDropped: boolean;
|
|
163
|
-
payloadDropped: boolean;
|
|
164
|
-
binary?: boolean | undefined;
|
|
165
|
-
dataBase64?: string | undefined;
|
|
166
|
-
payloadBase64: string | undefined;
|
|
167
|
-
}>;
|
|
168
149
|
export declare function workspaceRelayDurableObjectRoomName(workspaceId: string): string;
|
|
169
150
|
export declare function workspaceRelayDurableObjectWorkspaceId(request: Request): string | undefined;
|
|
170
151
|
export declare function createWorkspaceRelayDurableObjectGateway(options?: WorkspaceRelayDurableObjectGatewayOptions): {
|
|
@@ -179,7 +160,7 @@ export declare function createWorkspaceRelayDurableObjectRoom(options: Workspace
|
|
|
179
160
|
*/
|
|
180
161
|
alarm(): Promise<void>;
|
|
181
162
|
webSocketClose(socket: WorkspaceRelayDurableObjectSocket, code: number, reason: string): void;
|
|
182
|
-
webSocketError(socket: WorkspaceRelayDurableObjectSocket): void;
|
|
163
|
+
webSocketError(socket: WorkspaceRelayDurableObjectSocket, error?: unknown): void;
|
|
183
164
|
state(): {
|
|
184
165
|
hostTunnelCount: number;
|
|
185
166
|
clientCount: number;
|
|
@@ -21,8 +21,6 @@ export declare function socketKindFor(target: {
|
|
|
21
21
|
* risks leaking session data to it. A cloud-vm sits behind a dedicated network
|
|
22
22
|
* boundary where a session cookie may legitimately be needed, so it passes
|
|
23
23
|
* `Cookie` through unchanged.
|
|
24
|
-
*
|
|
25
|
-
* Returns a new `Headers` instance; `headers` is not mutated.
|
|
26
24
|
*/
|
|
27
25
|
export declare function forwardHeadersFor(target: {
|
|
28
26
|
backing: RelayBacking;
|
package/dist/http.d.ts
CHANGED
|
@@ -6,7 +6,5 @@ export declare function errorBody(code: string, message: string): {
|
|
|
6
6
|
message: string;
|
|
7
7
|
};
|
|
8
8
|
};
|
|
9
|
-
/** The host a tunnel request names, `/host-tunnels/<hostId>`. */
|
|
10
9
|
export declare function hostIdFromTunnelPath(pathname: string): string | undefined;
|
|
11
|
-
/** The workspaces a tunnel request registers for, under either spelling of the query name. */
|
|
12
10
|
export declare function workspaceIdsFromSearch(url: URL): string[];
|