@claxedo/workspace-relay 0.8.0 → 0.10.0
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 +92 -223
- package/dist/auth.d.ts +94 -35
- package/dist/cloudflare.d.ts +15 -45
- package/dist/cors-origins.d.ts +2 -0
- package/dist/directory.d.ts +5 -38
- package/dist/gateway-placement.d.ts +7 -0
- package/dist/host-tunnel-failure.d.ts +7 -0
- package/dist/host-tunnel-forwarding.d.ts +29 -0
- package/dist/http.d.ts +4 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.mjs +901 -835
- package/dist/relay-audit.d.ts +4 -0
- package/dist/relay-cors.d.ts +12 -0
- package/dist/relay-location.d.ts +93 -0
- package/dist/relay-target.d.ts +25 -0
- package/dist/resolver-clients.d.ts +116 -0
- package/dist/server.d.ts +27 -286
- package/dist/session-host-forwarding.d.ts +22 -0
- package/dist/test-support/unfenced-host-token.d.ts +6 -0
- package/dist/worker.d.ts +3 -3
- package/package.json +6 -25
- package/dist/bun.d.ts +0 -225
- package/dist/bun.mjs +0 -2492
- package/dist/main.d.ts +0 -255
- package/dist/main.mjs +0 -23713
- package/dist/synthetic.d.ts +0 -60
- package/dist/upstream-websocket.d.ts +0 -34
- package/dist/user-hosted-forwarding.d.ts +0 -40
package/dist/auth.d.ts
CHANGED
|
@@ -5,23 +5,47 @@ export declare const runtimeAccessTokenAudience = "workspace-relay";
|
|
|
5
5
|
export declare const hostTunnelTokenAudience = "workspace-relay-host-tunnel";
|
|
6
6
|
export declare const relayHostTokenIssuer = "workspace-relay";
|
|
7
7
|
export declare const relayHostTokenAudience = "workspace-host-service";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
export type RelayAccess = RelayClaimPair["access"];
|
|
16
|
-
export type RelayBacking = RelayClaimPair["backing"];
|
|
8
|
+
/**
|
|
9
|
+
* Where the host behind a relayed request runs: the provisioner's machine
|
|
10
|
+
* (`cloud-vm`), an enrolled one (`local-worktree`), or one session's Durable
|
|
11
|
+
* Object (`durable-object`). The only placement word on the relay wire; the
|
|
12
|
+
* control plane stores the first two as a workspace's backing.
|
|
13
|
+
*/
|
|
14
|
+
export type RelayBacking = "cloud-vm" | "local-worktree" | "durable-object";
|
|
17
15
|
export type RelayJwtAlgorithm = (typeof algorithms)[number];
|
|
18
16
|
export type RelayRole = "viewer" | "editor" | "admin" | "owner";
|
|
19
17
|
export type ActorKind = "human" | "agent";
|
|
18
|
+
/**
|
|
19
|
+
* Earliest `iat` a Runtime Access Token may carry (2026-09-21T00:00:00Z).
|
|
20
|
+
*
|
|
21
|
+
* Tokens minted before channel provenance existed carry no `channel_identity`,
|
|
22
|
+
* so a channel-issued one among them is indistinguishable from an app token
|
|
23
|
+
* and there is no binding generation to check it against. The whole vintage is
|
|
24
|
+
* refused rather than trusted until it expires.
|
|
25
|
+
*/
|
|
26
|
+
export declare const RUNTIME_ACCESS_TOKEN_ISSUED_AT_FLOOR_SECONDS = 1789948800;
|
|
27
|
+
/** The channel binding that authorized a token, as the token carries it. */
|
|
28
|
+
export type ChannelIdentityClaim = {
|
|
29
|
+
channel: string;
|
|
30
|
+
external_user_id: string;
|
|
31
|
+
identity_version: number;
|
|
32
|
+
};
|
|
33
|
+
/** The same binding as a mint argument. */
|
|
34
|
+
export type ChannelIdentityInput = {
|
|
35
|
+
channel: string;
|
|
36
|
+
externalUserId: string;
|
|
37
|
+
identityVersion: number;
|
|
38
|
+
};
|
|
39
|
+
export declare function toChannelIdentityClaim(input: ChannelIdentityInput): ChannelIdentityClaim;
|
|
40
|
+
export type TokenScope = "workspace" | "session";
|
|
41
|
+
/** A token minted for one job; only the routes serving that job accept it. */
|
|
42
|
+
export type TokenPurpose = "turn-execution";
|
|
20
43
|
export type RuntimeAccessTokenClaims = {
|
|
21
44
|
iss: typeof runtimeAccessTokenIssuer;
|
|
22
45
|
aud: typeof runtimeAccessTokenAudience;
|
|
23
46
|
principal_kind: "user" | "service";
|
|
24
47
|
actor_id: string;
|
|
48
|
+
user_id?: string;
|
|
25
49
|
actor_kind: "human" | "agent";
|
|
26
50
|
actor_public_id?: string;
|
|
27
51
|
actor_name?: string;
|
|
@@ -30,6 +54,17 @@ export type RuntimeAccessTokenClaims = {
|
|
|
30
54
|
workspace_id: string;
|
|
31
55
|
host_id: string;
|
|
32
56
|
role: RelayRole;
|
|
57
|
+
/**
|
|
58
|
+
* What the token reaches: the whole workspace (its owner's token) or the one
|
|
59
|
+
* session `session_id` names (a share holder's). A token naming neither is
|
|
60
|
+
* refused, so a token minted before reach was named reaches nothing.
|
|
61
|
+
*/
|
|
62
|
+
scope: TokenScope;
|
|
63
|
+
session_id?: string;
|
|
64
|
+
purpose?: TokenPurpose;
|
|
65
|
+
channel_identity?: ChannelIdentityClaim;
|
|
66
|
+
/** Present for cloud workspaces; assigned atomically with the sandbox address. */
|
|
67
|
+
routing_id?: string;
|
|
33
68
|
exp: number;
|
|
34
69
|
iat: number;
|
|
35
70
|
jti: string;
|
|
@@ -39,6 +74,7 @@ export type RelayHostTokenClaims = {
|
|
|
39
74
|
aud: typeof relayHostTokenAudience;
|
|
40
75
|
principal_kind: "user" | "service";
|
|
41
76
|
actor_id: string;
|
|
77
|
+
user_id?: string;
|
|
42
78
|
actor_kind: "human" | "agent";
|
|
43
79
|
actor_public_id?: string;
|
|
44
80
|
actor_name?: string;
|
|
@@ -47,38 +83,37 @@ export type RelayHostTokenClaims = {
|
|
|
47
83
|
workspace_id: string;
|
|
48
84
|
host_id: string;
|
|
49
85
|
role: RelayRole;
|
|
86
|
+
scope: TokenScope;
|
|
87
|
+
session_id?: string;
|
|
88
|
+
purpose?: TokenPurpose;
|
|
89
|
+
channel_identity?: ChannelIdentityClaim;
|
|
50
90
|
exp: number;
|
|
51
91
|
iat: number;
|
|
52
92
|
jti: string;
|
|
53
93
|
/** Durable parent Runtime Access Token id used for revocation checks. */
|
|
54
94
|
parent_jti: string;
|
|
55
|
-
|
|
95
|
+
backing: RelayBacking;
|
|
96
|
+
};
|
|
56
97
|
export type HostTunnelTokenClaims = {
|
|
57
98
|
iss: typeof runtimeAccessTokenIssuer;
|
|
58
99
|
aud: typeof hostTunnelTokenAudience;
|
|
59
100
|
sub: string;
|
|
60
101
|
host_id: string;
|
|
61
102
|
workspace_ids: string[];
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
* `enrollment_id`; a relay with a host-generation resolver refuses a token
|
|
65
|
-
* whose generation is below the enrollment's current one. A token without a
|
|
66
|
-
* generation is admitted exactly as before the fence existed, which is what
|
|
67
|
-
* desktop and self-hosted mints still produce.
|
|
68
|
-
*/
|
|
69
|
-
enrollment_id?: string;
|
|
70
|
-
generation?: number;
|
|
103
|
+
enrollment_id: string;
|
|
104
|
+
generation: number;
|
|
71
105
|
exp: number;
|
|
72
106
|
iat: number;
|
|
73
107
|
jti: string;
|
|
74
108
|
};
|
|
75
109
|
export declare class WorkspaceRelayAuthError extends Error {
|
|
76
|
-
readonly code: "invalid_relay_token" | "relay_token_workspace_mismatch" | "relay_token_host_mismatch" | "relay_token_claims_invalid";
|
|
77
|
-
constructor(code: "invalid_relay_token" | "relay_token_workspace_mismatch" | "relay_token_host_mismatch" | "relay_token_claims_invalid", message: string);
|
|
110
|
+
readonly code: "runtime_access_token_invalid" | "invalid_relay_token" | "relay_token_workspace_mismatch" | "relay_token_host_mismatch" | "relay_token_claims_invalid";
|
|
111
|
+
constructor(code: "runtime_access_token_invalid" | "invalid_relay_token" | "relay_token_workspace_mismatch" | "relay_token_host_mismatch" | "relay_token_claims_invalid", message: string);
|
|
78
112
|
}
|
|
79
113
|
type RuntimeInput = {
|
|
80
114
|
principalKind: "user" | "service";
|
|
81
115
|
actorId: string;
|
|
116
|
+
userId?: string;
|
|
82
117
|
actorKind: ActorKind;
|
|
83
118
|
actorPublicId?: string;
|
|
84
119
|
actorName?: string;
|
|
@@ -87,11 +122,16 @@ type RuntimeInput = {
|
|
|
87
122
|
workspaceId: string;
|
|
88
123
|
hostId: string;
|
|
89
124
|
role: RelayRole;
|
|
125
|
+
sessionId?: string;
|
|
126
|
+
purpose?: TokenPurpose;
|
|
127
|
+
channelIdentity?: ChannelIdentityInput;
|
|
128
|
+
routingId?: string;
|
|
90
129
|
ttlSeconds?: number;
|
|
91
130
|
jti?: string;
|
|
92
131
|
now?: number;
|
|
93
132
|
};
|
|
94
|
-
type RelayHostInput = RuntimeInput &
|
|
133
|
+
type RelayHostInput = RuntimeInput & {
|
|
134
|
+
backing: RelayBacking;
|
|
95
135
|
/** The Runtime Access Token jti from which this one-request RHT is derived. */
|
|
96
136
|
parentJti: string;
|
|
97
137
|
/**
|
|
@@ -107,8 +147,8 @@ type HostTunnelInput = {
|
|
|
107
147
|
subject: string;
|
|
108
148
|
hostId: string;
|
|
109
149
|
workspaceIds: string[];
|
|
110
|
-
enrollmentId
|
|
111
|
-
generation
|
|
150
|
+
enrollmentId: string;
|
|
151
|
+
generation: number;
|
|
112
152
|
ttlSeconds?: number;
|
|
113
153
|
jti?: string;
|
|
114
154
|
now?: number;
|
|
@@ -122,10 +162,7 @@ type ExpectedHostTunnel = {
|
|
|
122
162
|
workspaceIds: string[];
|
|
123
163
|
};
|
|
124
164
|
export declare function isHostGeneration(value: unknown): value is number;
|
|
125
|
-
export declare function
|
|
126
|
-
access?: unknown;
|
|
127
|
-
backing?: unknown;
|
|
128
|
-
}): input is RelayClaimPair;
|
|
165
|
+
export declare function isRelayBacking(input: unknown): input is RelayBacking;
|
|
129
166
|
/**
|
|
130
167
|
* Resolver function returned by `createRemoteJWKSet` / `createLocalJWKSet`.
|
|
131
168
|
* Accepted by `jwtVerify` directly — jose dispatches based on whether the
|
|
@@ -138,18 +175,15 @@ export type RelayKey = CryptoKey | Uint8Array | RelayKeyResolver;
|
|
|
138
175
|
*
|
|
139
176
|
* `importJWK` is declared `Promise<CryptoKey | Uint8Array>` because a symmetric
|
|
140
177
|
* (`oct`) JWK imports as raw bytes. An EdDSA public JWK never does, so the byte
|
|
141
|
-
* branch is a configuration error worth failing loudly on
|
|
142
|
-
* (`main.ts` for Bun, `worker.ts` for Cloudflare) previously asserted it away
|
|
143
|
-
* with their own copies of this round-trip.
|
|
178
|
+
* branch is a configuration error worth failing loudly on.
|
|
144
179
|
*/
|
|
145
180
|
export declare function deriveRelayHostPublicKey(privateKey: CryptoKey): Promise<CryptoKey>;
|
|
146
181
|
/**
|
|
147
182
|
* The relay-host key id, derived from the key's public component.
|
|
148
183
|
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
* `node:crypto` so the workerd bundle can use it too.
|
|
184
|
+
* Signing with the same key must always publish the same `kid`, or a token
|
|
185
|
+
* minted under one build fails key lookup at the next. Written against
|
|
186
|
+
* WebCrypto rather than `node:crypto` so the workerd bundle can use it.
|
|
153
187
|
*/
|
|
154
188
|
export declare function deriveRelayHostKid(publicKey: CryptoKey): Promise<string>;
|
|
155
189
|
/**
|
|
@@ -162,6 +196,31 @@ export declare function verifyRuntimeAccessToken(token: string, key: RelayKey, e
|
|
|
162
196
|
export declare function validateRuntimeAccessTokenClaims(input: Record<string, unknown>, expected: ExpectedTarget): RuntimeAccessTokenClaims;
|
|
163
197
|
export declare function mintHostTunnelToken(input: HostTunnelInput, key: RelaySigningKey, alg: RelayJwtAlgorithm): Promise<string>;
|
|
164
198
|
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
|
+
/** What a Relay Host Token minted from a verified Runtime Access Token carries over from it. */
|
|
207
|
+
export declare function relayHostInputFromRuntimeClaims(claims: RuntimeAccessTokenClaims): Omit<RelayHostInput, "backing" | "hostId" | "workspaceId">;
|
|
165
208
|
export declare function mintRelayHostToken(input: RelayHostInput, key: RelaySigningKey, alg: RelayJwtAlgorithm): Promise<string>;
|
|
166
209
|
export declare function verifyRelayHostToken(token: string, key: RelayKey, expected: ExpectedTarget): Promise<RelayHostTokenClaims>;
|
|
210
|
+
export declare function tokenScopePayload(sessionId: string | undefined): {
|
|
211
|
+
scope: "workspace";
|
|
212
|
+
session_id?: undefined;
|
|
213
|
+
} | {
|
|
214
|
+
scope: "session";
|
|
215
|
+
session_id: string;
|
|
216
|
+
};
|
|
217
|
+
/** The token's reach, or nothing when it names neither the workspace nor exactly one session. */
|
|
218
|
+
/** The purpose claim, or undefined when it names a purpose this build does not know. */
|
|
219
|
+
export declare function tokenPurposeClaims(payload: Record<string, unknown>): {
|
|
220
|
+
purpose?: TokenPurpose;
|
|
221
|
+
} | undefined;
|
|
222
|
+
export declare function tokenScopeClaims(payload: Record<string, unknown>): {
|
|
223
|
+
scope: TokenScope;
|
|
224
|
+
session_id?: string;
|
|
225
|
+
} | undefined;
|
|
167
226
|
export {};
|
package/dist/cloudflare.d.ts
CHANGED
|
@@ -1,54 +1,17 @@
|
|
|
1
1
|
import { type AuthorizedWorkspaceRelayRequest, type WorkspaceRelayOptions } from "./server";
|
|
2
|
+
import { type SessionHostNamespace } from "./session-host-forwarding";
|
|
2
3
|
export type WorkspaceRelayDurableObjectId = unknown;
|
|
3
4
|
export type WorkspaceRelayDurableObjectStub = {
|
|
4
5
|
fetch: (request: Request) => Promise<Response>;
|
|
5
6
|
};
|
|
6
7
|
export type WorkspaceRelayDurableObjectGetOptions = {
|
|
8
|
+
/** Cloudflare's placement hint, honoured on the room's first creation only: beside the workspace's runtime (`workspaceRelayRoomPlacement`). */
|
|
7
9
|
locationHint?: string;
|
|
8
10
|
};
|
|
9
11
|
export type WorkspaceRelayDurableObjectNamespace = {
|
|
10
12
|
idFromName: (name: string) => WorkspaceRelayDurableObjectId;
|
|
11
13
|
get: (id: WorkspaceRelayDurableObjectId, options?: WorkspaceRelayDurableObjectGetOptions) => WorkspaceRelayDurableObjectStub;
|
|
12
14
|
};
|
|
13
|
-
export declare const DEFAULT_RELAY_LOCATION_HINT = "apac";
|
|
14
|
-
/**
|
|
15
|
-
* The complete set of Cloudflare Durable Object location hints.
|
|
16
|
-
*
|
|
17
|
-
* Cloudflare rejects an unknown hint, and a rejected `get()` fails the request —
|
|
18
|
-
* so an unrecognised region must fall back rather than be passed through. This
|
|
19
|
-
* list is the validator for that.
|
|
20
|
-
*/
|
|
21
|
-
export declare const RELAY_LOCATION_HINTS: readonly ["wnam", "enam", "sam", "weur", "eeur", "apac", "oc", "afr", "me"];
|
|
22
|
-
export type RelayLocationHint = typeof RELAY_LOCATION_HINTS[number];
|
|
23
|
-
/** A workspace region carried on the request, if the caller supplied one. */
|
|
24
|
-
export declare const RELAY_REGION_HEADER = "x-claxedo-workspace-region";
|
|
25
|
-
/**
|
|
26
|
-
* Chooses the location hint for a workspace's Durable Object.
|
|
27
|
-
*
|
|
28
|
-
* This decision is PERMANENT: a DO's location is fixed at first creation and
|
|
29
|
-
* never migrates, so a workspace created with the wrong hint pays the extra
|
|
30
|
-
* ocean crossing on every frame for its entire life. That is why an
|
|
31
|
-
* unrecognised value falls back to the configured default instead of being
|
|
32
|
-
* passed through or guessed at.
|
|
33
|
-
*
|
|
34
|
-
* Precedence, most authoritative first:
|
|
35
|
-
* 1. the workspace's own region (header or `?region=`), which is what the
|
|
36
|
-
* control plane knows and the only signal tied to the WORKSPACE rather than
|
|
37
|
-
* to whoever happens to be connecting first;
|
|
38
|
-
* 2. the requesting user's Cloudflare edge country, a decent proxy when the
|
|
39
|
-
* workspace has no region yet;
|
|
40
|
-
* 3. the deployment-wide configured hint (`CLAXEDO_RELAY_LOCATION_HINT`), then
|
|
41
|
-
* `DEFAULT_RELAY_LOCATION_HINT`.
|
|
42
|
-
*/
|
|
43
|
-
export declare function relayLocationHint(input: {
|
|
44
|
-
configured?: string;
|
|
45
|
-
region?: string;
|
|
46
|
-
country?: string;
|
|
47
|
-
}): string;
|
|
48
|
-
/** The workspace region a request declares, if any. */
|
|
49
|
-
export declare function relayRequestRegion(request: Request): string | undefined;
|
|
50
|
-
/** The Cloudflare edge country for the request, when running on Cloudflare. */
|
|
51
|
-
export declare function relayRequestCountry(request: Request): string | undefined;
|
|
52
15
|
export type WorkspaceRelayDurableObjectEnv = Record<string, unknown>;
|
|
53
16
|
export type WorkspaceRelayDurableObjectGatewayOptions = {
|
|
54
17
|
bindingName?: string;
|
|
@@ -77,6 +40,7 @@ export type WorkspaceRelayDurableObjectConnectWebSocket = (url: string, init: {
|
|
|
77
40
|
headers: Record<string, string>;
|
|
78
41
|
}) => WorkspaceRelayDurableObjectSocket | Promise<WorkspaceRelayDurableObjectSocket>;
|
|
79
42
|
export type WorkspaceRelayDurableObjectRoomOptions = WorkspaceRelayOptions & {
|
|
43
|
+
sessionHost?: SessionHostNamespace;
|
|
80
44
|
createWebSocketPair?: () => WorkspaceRelayDurableObjectSocketPair;
|
|
81
45
|
connectWebSocket?: WorkspaceRelayDurableObjectConnectWebSocket;
|
|
82
46
|
hibernation?: WorkspaceRelayDurableObjectHibernation;
|
|
@@ -89,6 +53,15 @@ export type WorkspaceRelayDurableObjectRoomOptions = WorkspaceRelayOptions & {
|
|
|
89
53
|
tunnelResponseBodyMaxBytes?: number;
|
|
90
54
|
slowConsumerHighWaterMarkBytes?: number;
|
|
91
55
|
slowConsumerTimeoutMs?: number;
|
|
56
|
+
/**
|
|
57
|
+
* How often established client WebSockets are re-checked for revocation.
|
|
58
|
+
* Defaults to 30s; 0 disables the re-check. Because the check may answer
|
|
59
|
+
* from the revocation lookup's cache, a revoked token closes the socket
|
|
60
|
+
* within this interval plus the lookup's cache TTL — see
|
|
61
|
+
* `runtimeAccessTokenRevocationDelayMs` in `./server`. A resolver outage
|
|
62
|
+
* gets `resolverOutageGraceAttempts` and never extends the socket past the
|
|
63
|
+
* token's `exp`, which the watcher enforces locally.
|
|
64
|
+
*/
|
|
92
65
|
runtimeAccessTokenActiveCheckIntervalMs?: number;
|
|
93
66
|
workspaceTargetActiveCheckIntervalMs?: number;
|
|
94
67
|
/**
|
|
@@ -154,13 +127,12 @@ export type WorkspaceRelaySocketAttachment = {
|
|
|
154
127
|
hostId: string;
|
|
155
128
|
workspaceIds: string[];
|
|
156
129
|
connectedAt: number;
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
generation?: number;
|
|
130
|
+
enrollmentId: string;
|
|
131
|
+
generation: number;
|
|
160
132
|
/** Consecutive unavailable generation lookups, persisted so hibernation cannot reset the outage grace. */
|
|
161
133
|
generationCheckFailures?: number;
|
|
162
134
|
} | {
|
|
163
|
-
kind: "
|
|
135
|
+
kind: "host-tunnel-client";
|
|
164
136
|
channelId: string;
|
|
165
137
|
claims: RuntimeAccessAttachmentClaims;
|
|
166
138
|
target: WorkspaceRelayTargetAttachment;
|
|
@@ -204,8 +176,6 @@ export declare function relayFrameDiagnostics(data: unknown): Promise<{
|
|
|
204
176
|
}>;
|
|
205
177
|
export declare function workspaceRelayDurableObjectRoomName(workspaceId: string): string;
|
|
206
178
|
export declare function workspaceRelayDurableObjectWorkspaceId(request: Request): string | undefined;
|
|
207
|
-
export declare function setWorkspaceRelayAppOrigins(raw: string | undefined): void;
|
|
208
|
-
export declare function setWorkspaceRelayAllowedOrigins(raw: string | undefined): void;
|
|
209
179
|
export declare function createWorkspaceRelayDurableObjectGateway(options?: WorkspaceRelayDurableObjectGatewayOptions): {
|
|
210
180
|
fetch(request: Request, env?: WorkspaceRelayDurableObjectEnv): Promise<Response>;
|
|
211
181
|
};
|
package/dist/cors-origins.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export declare const DEFAULT_RELAY_APP_ORIGINS: string[];
|
|
2
|
+
/** Request headers a browser may send on relayed workspace requests, as the `access-control-allow-headers` value. */
|
|
3
|
+
export declare const RELAY_ALLOWED_REQUEST_HEADERS: string;
|
|
2
4
|
export declare function parseAllowedOrigins(raw: string | undefined): string[] | undefined;
|
|
3
5
|
export declare function createOriginMatcher(patterns: string[]): (origin: string) => boolean;
|
package/dist/directory.d.ts
CHANGED
|
@@ -11,56 +11,23 @@ export type HostTunnelPresence = {
|
|
|
11
11
|
expiresAt: number;
|
|
12
12
|
};
|
|
13
13
|
/**
|
|
14
|
-
* Presence is keyed by (host, workspace)
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* and `disconnectHost` take the optional workspace set for the same reason —
|
|
18
|
-
* without it they act on every entry of the host, which is what a
|
|
19
|
-
* single-workspace Cloudflare room wants.
|
|
14
|
+
* Presence is keyed by (host, workspace), so a later registration for a
|
|
15
|
+
* workspace takes that workspace over without touching the host's other
|
|
16
|
+
* entries. `recordPong` and `disconnectHost` act on every entry of the host.
|
|
20
17
|
*/
|
|
21
18
|
export type WorkspaceRelayDirectory = {
|
|
22
19
|
registerHostTunnel(input: {
|
|
23
20
|
hostId: string;
|
|
24
21
|
workspaceIds: string[];
|
|
25
22
|
}): HostTunnelPresence;
|
|
26
|
-
recordPong(hostId: string
|
|
27
|
-
disconnectHost(hostId: string
|
|
23
|
+
recordPong(hostId: string): HostTunnelPresence | undefined;
|
|
24
|
+
disconnectHost(hostId: string): void;
|
|
28
25
|
activeHost(input: {
|
|
29
26
|
hostId: string;
|
|
30
27
|
workspaceId: string;
|
|
31
28
|
}): HostTunnelPresence | undefined;
|
|
32
|
-
/**
|
|
33
|
-
* Manually run an expiry sweep over the presence map. Removes any entry
|
|
34
|
-
* whose `expiresAt <= now()`. Safe to call on a fresh/empty directory.
|
|
35
|
-
* Useful in tests; the production path runs this on a timer (see
|
|
36
|
-
* `sweepIntervalMs`).
|
|
37
|
-
*/
|
|
38
|
-
sweep(): void;
|
|
39
|
-
/**
|
|
40
|
-
* Stop the active sweep timer (if one was started). Safe to call multiple
|
|
41
|
-
* times and on directories that were created with `sweepIntervalMs: 0`.
|
|
42
|
-
*/
|
|
43
|
-
dispose(): void;
|
|
44
|
-
/**
|
|
45
|
-
* Count of hosts with at least one non-expired presence entry, taken as a
|
|
46
|
-
* snapshot without evicting. Surfaced via `/metrics` as
|
|
47
|
-
* `directory.activeHostCount`.
|
|
48
|
-
*/
|
|
49
|
-
size(): number;
|
|
50
29
|
};
|
|
51
30
|
export declare function createWorkspaceRelayDirectory(options?: {
|
|
52
31
|
ttlMs?: number;
|
|
53
32
|
now?: () => number;
|
|
54
|
-
/**
|
|
55
|
-
* Interval in milliseconds at which a background sweep runs to evict
|
|
56
|
-
* expired host presence entries. Defaults to 30_000. Set to `0` to disable
|
|
57
|
-
* the timer entirely (useful for tests; callers can still drive cleanup
|
|
58
|
-
* manually via `sweep()`).
|
|
59
|
-
*/
|
|
60
|
-
sweepIntervalMs?: number;
|
|
61
33
|
}): WorkspaceRelayDirectory;
|
|
62
|
-
/**
|
|
63
|
-
* Convenience companion to `createWorkspaceRelayDirectory` for callers that
|
|
64
|
-
* prefer a free function over a method. Equivalent to `directory.dispose()`.
|
|
65
|
-
*/
|
|
66
|
-
export declare function disposeWorkspaceRelayDirectory(directory: WorkspaceRelayDirectory): void;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { WorkspaceRelayDurableObjectEnv } from "./cloudflare";
|
|
2
|
+
/**
|
|
3
|
+
* Where the gateway creates the room of the request's workspace. The room's
|
|
4
|
+
* location is fixed at its first creation and never migrates, so this
|
|
5
|
+
* decision is permanent for the workspace.
|
|
6
|
+
*/
|
|
7
|
+
export declare function workspaceRelayRoomPlacement(request: Request, env: WorkspaceRelayDurableObjectEnv, workspaceId: string): Promise<import("./relay-location").RelayRoomPlacement>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type HostTunnelFailureCode = "host_tunnel_timeout" | "host_tunnel_response_body_too_large" | "host_tunnel_unavailable";
|
|
2
|
+
export declare function hostTunnelFailure(code: HostTunnelFailureCode): Error & {
|
|
3
|
+
code: HostTunnelFailureCode;
|
|
4
|
+
status: number;
|
|
5
|
+
retryable: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare function hostTunnelFailureResponse(error: unknown): Response;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { RelayBacking } from "./auth";
|
|
2
|
+
/**
|
|
3
|
+
* Whether a relay target is reached through a host tunnel.
|
|
4
|
+
*
|
|
5
|
+
* A `local-worktree` placement runs on an enrolled machine that dials the
|
|
6
|
+
* relay and multiplexes its traffic over that one socket; a `cloud-vm`
|
|
7
|
+
* placement runs on the provisioner's machine, which the relay reaches by a
|
|
8
|
+
* direct upstream connection.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isHostTunnelTarget(target: {
|
|
11
|
+
backing: RelayBacking;
|
|
12
|
+
}): boolean;
|
|
13
|
+
export type WorkspaceRelaySocketKind = "host-tunnel-client" | "client";
|
|
14
|
+
export declare function socketKindFor(target: {
|
|
15
|
+
backing: RelayBacking;
|
|
16
|
+
}): WorkspaceRelaySocketKind;
|
|
17
|
+
/**
|
|
18
|
+
* Privacy rule: never forward the browser's `Cookie` header through a host
|
|
19
|
+
* tunnel. The host process runs on a machine somebody uses, whose cookie jar
|
|
20
|
+
* the browser may share (localhost dev tooling), so passing cookies verbatim
|
|
21
|
+
* risks leaking session data to it. A cloud-vm sits behind a dedicated network
|
|
22
|
+
* boundary where a session cookie may legitimately be needed, so it passes
|
|
23
|
+
* `Cookie` through unchanged.
|
|
24
|
+
*
|
|
25
|
+
* Returns a new `Headers` instance; `headers` is not mutated.
|
|
26
|
+
*/
|
|
27
|
+
export declare function forwardHeadersFor(target: {
|
|
28
|
+
backing: RelayBacking;
|
|
29
|
+
}, headers: Headers): Headers;
|
package/dist/http.d.ts
CHANGED
|
@@ -6,3 +6,7 @@ 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
|
+
export declare function hostIdFromTunnelPath(pathname: string): string | undefined;
|
|
11
|
+
/** The workspaces a tunnel request registers for, under either spelling of the query name. */
|
|
12
|
+
export declare function workspaceIdsFromSearch(url: URL): string[];
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
export * from "./auth";
|
|
2
2
|
export * from "./cloudflare";
|
|
3
|
+
export * from "./relay-cors";
|
|
3
4
|
export * from "./cors-origins";
|
|
4
5
|
export * from "./directory";
|
|
6
|
+
export * from "./gateway-placement";
|
|
7
|
+
export * from "./relay-location";
|
|
8
|
+
export * from "./relay-target";
|
|
5
9
|
export * from "./server";
|
|
10
|
+
export * from "./resolver-clients";
|