@claxedo/workspace-relay 0.7.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 +114 -191
- package/dist/auth.d.ts +130 -20
- package/dist/cloudflare.d.ts +26 -43
- package/dist/cors-origins.d.ts +2 -0
- package/dist/directory.d.ts +10 -32
- 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 +6 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.mjs +1285 -2049
- 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 +51 -188
- 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 +32 -4
- package/dist/workerd-fixture/boot.d.ts +18 -0
- package/package.json +9 -20
- package/dist/bun.d.ts +0 -170
- package/dist/main.d.ts +0 -246
- package/dist/main.mjs +0 -23219
- package/dist/synthetic.d.ts +0 -60
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
|
/**
|
|
@@ -100,8 +73,16 @@ export type WorkspaceRelayDurableObjectRoomOptions = WorkspaceRelayOptions & {
|
|
|
100
73
|
/**
|
|
101
74
|
* Interval for the alarm-based revocation re-check that covers hibernated
|
|
102
75
|
* connections, where `setInterval` watchers cannot survive. 0 disables it.
|
|
76
|
+
* The hibernated host-generation check rides the same alarm.
|
|
103
77
|
*/
|
|
104
78
|
hibernatedRevocationCheckIntervalMs?: number;
|
|
79
|
+
/**
|
|
80
|
+
* How often an established host tunnel's serving generation is re-checked
|
|
81
|
+
* against `resolveHostGeneration` on the non-hibernating path. Defaults to
|
|
82
|
+
* 30s; 0 disables it. The lookup may answer from its cache, so a superseded
|
|
83
|
+
* tunnel closes within this interval plus the lookup's cache TTL.
|
|
84
|
+
*/
|
|
85
|
+
hostGenerationCheckIntervalMs?: number;
|
|
105
86
|
/**
|
|
106
87
|
* Durable Object alarm surface, supplied by the Worker (`state.storage`) so the
|
|
107
88
|
* room can schedule the hibernation-safe revocation re-check. Absent on the
|
|
@@ -146,8 +127,12 @@ export type WorkspaceRelaySocketAttachment = {
|
|
|
146
127
|
hostId: string;
|
|
147
128
|
workspaceIds: string[];
|
|
148
129
|
connectedAt: number;
|
|
130
|
+
enrollmentId: string;
|
|
131
|
+
generation: number;
|
|
132
|
+
/** Consecutive unavailable generation lookups, persisted so hibernation cannot reset the outage grace. */
|
|
133
|
+
generationCheckFailures?: number;
|
|
149
134
|
} | {
|
|
150
|
-
kind: "
|
|
135
|
+
kind: "host-tunnel-client";
|
|
151
136
|
channelId: string;
|
|
152
137
|
claims: RuntimeAccessAttachmentClaims;
|
|
153
138
|
target: WorkspaceRelayTargetAttachment;
|
|
@@ -191,8 +176,6 @@ export declare function relayFrameDiagnostics(data: unknown): Promise<{
|
|
|
191
176
|
}>;
|
|
192
177
|
export declare function workspaceRelayDurableObjectRoomName(workspaceId: string): string;
|
|
193
178
|
export declare function workspaceRelayDurableObjectWorkspaceId(request: Request): string | undefined;
|
|
194
|
-
export declare function setWorkspaceRelayAppOrigins(raw: string | undefined): void;
|
|
195
|
-
export declare function setWorkspaceRelayAllowedOrigins(raw: string | undefined): void;
|
|
196
179
|
export declare function createWorkspaceRelayDurableObjectGateway(options?: WorkspaceRelayDurableObjectGatewayOptions): {
|
|
197
180
|
fetch(request: Request, env?: WorkspaceRelayDurableObjectEnv): Promise<Response>;
|
|
198
181
|
};
|
|
@@ -201,7 +184,7 @@ export declare function createWorkspaceRelayDurableObjectRoom(options: Workspace
|
|
|
201
184
|
webSocketMessage(socket: WorkspaceRelayDurableObjectSocket, message: string | ArrayBuffer): Promise<void>;
|
|
202
185
|
/**
|
|
203
186
|
* Durable Object alarm entry point. Runs the hibernation-safe revocation
|
|
204
|
-
* sweep
|
|
187
|
+
* sweep. The Worker must forward `alarm()` here.
|
|
205
188
|
*/
|
|
206
189
|
alarm(): Promise<void>;
|
|
207
190
|
webSocketClose(socket: WorkspaceRelayDurableObjectSocket, code: number, reason: string): void;
|
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
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One tunnel's presence, recorded once per workspace it serves. `workspaceIds`
|
|
3
|
+
* is the full set that tunnel registered, so a reader that found the entry
|
|
4
|
+
* through one workspace still sees the others.
|
|
5
|
+
*/
|
|
1
6
|
export type HostTunnelPresence = {
|
|
2
7
|
hostId: string;
|
|
3
8
|
workspaceIds: string[];
|
|
@@ -5,6 +10,11 @@ export type HostTunnelPresence = {
|
|
|
5
10
|
lastPongAt: number;
|
|
6
11
|
expiresAt: number;
|
|
7
12
|
};
|
|
13
|
+
/**
|
|
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.
|
|
17
|
+
*/
|
|
8
18
|
export type WorkspaceRelayDirectory = {
|
|
9
19
|
registerHostTunnel(input: {
|
|
10
20
|
hostId: string;
|
|
@@ -16,40 +26,8 @@ export type WorkspaceRelayDirectory = {
|
|
|
16
26
|
hostId: string;
|
|
17
27
|
workspaceId: string;
|
|
18
28
|
}): HostTunnelPresence | undefined;
|
|
19
|
-
/**
|
|
20
|
-
* Manually run an expiry sweep over the presence map. Removes any entry
|
|
21
|
-
* whose `expiresAt <= now()`. Safe to call on a fresh/empty directory.
|
|
22
|
-
* Useful in tests; the production path runs this on a timer (see
|
|
23
|
-
* `sweepIntervalMs`).
|
|
24
|
-
*/
|
|
25
|
-
sweep(): void;
|
|
26
|
-
/**
|
|
27
|
-
* Stop the active sweep timer (if one was started). Safe to call multiple
|
|
28
|
-
* times and on directories that were created with `sweepIntervalMs: 0`.
|
|
29
|
-
*/
|
|
30
|
-
dispose(): void;
|
|
31
|
-
/**
|
|
32
|
-
* T31: count of currently-active (non-expired) host presence entries.
|
|
33
|
-
* Equivalent to running `sweep()` then returning the residual map size, but
|
|
34
|
-
* implemented as a single pass without mutating eviction state when the
|
|
35
|
-
* caller only wants a snapshot. Surfaced via the `/metrics` endpoint as
|
|
36
|
-
* `directory.activeHostCount`.
|
|
37
|
-
*/
|
|
38
|
-
size(): number;
|
|
39
29
|
};
|
|
40
30
|
export declare function createWorkspaceRelayDirectory(options?: {
|
|
41
31
|
ttlMs?: number;
|
|
42
32
|
now?: () => number;
|
|
43
|
-
/**
|
|
44
|
-
* Interval in milliseconds at which a background sweep runs to evict
|
|
45
|
-
* expired host presence entries. Defaults to 30_000. Set to `0` to disable
|
|
46
|
-
* the timer entirely (useful for tests; callers can still drive cleanup
|
|
47
|
-
* manually via `sweep()`).
|
|
48
|
-
*/
|
|
49
|
-
sweepIntervalMs?: number;
|
|
50
33
|
}): WorkspaceRelayDirectory;
|
|
51
|
-
/**
|
|
52
|
-
* Convenience companion to `createWorkspaceRelayDirectory` for callers that
|
|
53
|
-
* prefer a free function over a method. Equivalent to `directory.dispose()`.
|
|
54
|
-
*/
|
|
55
|
-
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
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
import { bearerToken } from "@claxedo/helpers/string";
|
|
2
|
+
export { bearerToken };
|
|
2
3
|
export declare function errorBody(code: string, message: string): {
|
|
3
4
|
error: {
|
|
4
5
|
code: string;
|
|
5
6
|
message: string;
|
|
6
7
|
};
|
|
7
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,6 +1,10 @@
|
|
|
1
1
|
export * from "./auth";
|
|
2
|
-
export * from "./bun";
|
|
3
2
|
export * from "./cloudflare";
|
|
3
|
+
export * from "./relay-cors";
|
|
4
4
|
export * from "./cors-origins";
|
|
5
5
|
export * from "./directory";
|
|
6
|
+
export * from "./gateway-placement";
|
|
7
|
+
export * from "./relay-location";
|
|
8
|
+
export * from "./relay-target";
|
|
6
9
|
export * from "./server";
|
|
10
|
+
export * from "./resolver-clients";
|