effect-cf 0.25.3 → 0.27.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/CHANGELOG.md +16 -0
- package/README.md +213 -1
- package/dist/Artifacts-BhWrdyqX.mjs +241 -0
- package/dist/Artifacts-DcoXcRP5.d.mts +231 -0
- package/dist/ComputerArtifacts.d.mts +55 -0
- package/dist/ComputerArtifacts.mjs +95 -0
- package/dist/ComputerWorkspace.d.mts +279 -0
- package/dist/ComputerWorkspace.mjs +545 -0
- package/dist/ComputerWorkspaceHost.d.mts +71 -0
- package/dist/ComputerWorkspaceHost.mjs +74 -0
- package/dist/ComputerWorkspaceHostRegistry-CY5Fv4Ng.mjs +8 -0
- package/dist/{DurableObjectState-CEh0DVw7.mjs → DurableObjectState-Dux8KfjG.mjs} +3 -48
- package/dist/{WorkflowBinding-D5iWzCUa.d.mts → DurableObjectState-biHrHwrh.d.mts} +7 -81
- package/dist/ErrorMessage-_lg53p3W.mjs +49 -0
- package/dist/Vitest.d.mts +2 -1
- package/dist/Vitest.mjs +2 -1
- package/dist/WorkflowBinding-zlRPCXVf.d.mts +79 -0
- package/dist/index.d.mts +80 -2
- package/dist/index.mjs +72 -123
- package/package.json +23 -1
- package/src/Artifacts.ts +519 -0
- package/src/ComputerArtifacts.ts +255 -0
- package/src/ComputerWorkspace.ts +1098 -0
- package/src/ComputerWorkspaceHost.ts +216 -0
- package/src/WebTransport.ts +123 -0
- package/src/index.ts +2 -0
- package/src/internal/ComputerWorkspaceHostRegistry.ts +10 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { createGitClient, type GitClientFactory } from "@cloudflare/computer/git";
|
|
2
|
+
import {
|
|
3
|
+
type DurableObjectStorageLike,
|
|
4
|
+
type WithWorkspaceCtor,
|
|
5
|
+
type WorkspaceHandle,
|
|
6
|
+
type WorkspaceObserver,
|
|
7
|
+
type WorkspaceOptions,
|
|
8
|
+
type WorkspaceRegisteredBackend,
|
|
9
|
+
type WorkspaceRetryPendingSyncResult,
|
|
10
|
+
type WorkspaceSpan,
|
|
11
|
+
type WorkspaceAttributes,
|
|
12
|
+
type WorkspaceAttributeValue,
|
|
13
|
+
type SyncRetryIntent,
|
|
14
|
+
type SyncRetryOptions,
|
|
15
|
+
type SyncRetryScheduler,
|
|
16
|
+
withWorkspace,
|
|
17
|
+
} from "@cloudflare/computer";
|
|
18
|
+
import {
|
|
19
|
+
WorkerShellBackend,
|
|
20
|
+
type ShellModuleGroup,
|
|
21
|
+
type WorkerShellBackendOptions,
|
|
22
|
+
type WorkerShellLoader,
|
|
23
|
+
type WorkspaceEgressPolicy,
|
|
24
|
+
} from "@cloudflare/computer/backends/worker-shell";
|
|
25
|
+
|
|
26
|
+
import type * as Artifacts from "./Artifacts";
|
|
27
|
+
import * as HostRegistry from "./internal/ComputerWorkspaceHostRegistry";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The worker-shell backend resolves this exact export through
|
|
31
|
+
* `ctx.exports.WorkspaceServiceProxy`. Every Worker that configures
|
|
32
|
+
* {@link withComputerWorkspace} with `shell` must re-export it from its main
|
|
33
|
+
* module.
|
|
34
|
+
*/
|
|
35
|
+
export { WorkspaceServiceProxy } from "@cloudflare/computer";
|
|
36
|
+
|
|
37
|
+
export type {
|
|
38
|
+
ShellModuleGroup,
|
|
39
|
+
SyncRetryIntent,
|
|
40
|
+
SyncRetryOptions,
|
|
41
|
+
SyncRetryScheduler,
|
|
42
|
+
WorkspaceAttributeValue,
|
|
43
|
+
WorkspaceAttributes,
|
|
44
|
+
WorkspaceEgressPolicy,
|
|
45
|
+
WorkspaceObserver,
|
|
46
|
+
WorkspaceRetryPendingSyncResult,
|
|
47
|
+
WorkspaceSpan,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/** The value of a `worker_loaders` binding. */
|
|
51
|
+
export type DynamicWorkerLoader = WorkerShellLoader;
|
|
52
|
+
|
|
53
|
+
/** Default author and committer identity for workspace Git operations. */
|
|
54
|
+
export interface ComputerWorkspaceGitIdentity {
|
|
55
|
+
readonly name: string;
|
|
56
|
+
readonly email: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Session-scoped Artifacts configuration passed through to `Workspace`. */
|
|
60
|
+
export interface ComputerWorkspaceArtifactsOptions {
|
|
61
|
+
readonly binding: Artifacts.ArtifactsBinding;
|
|
62
|
+
/**
|
|
63
|
+
* Session prefix for repository names. When omitted, `sessionId` from the
|
|
64
|
+
* enclosing host configuration is used.
|
|
65
|
+
*/
|
|
66
|
+
readonly sessionId?: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Worker-shell backend options with the loopback workspace wiring named in
|
|
71
|
+
* Durable Object terms.
|
|
72
|
+
*/
|
|
73
|
+
export interface ComputerWorkspaceShellOptions extends Omit<
|
|
74
|
+
WorkerShellBackendOptions,
|
|
75
|
+
"source" | "loader" | "workspace" | "ctx" | "egress"
|
|
76
|
+
> {
|
|
77
|
+
readonly loader: DynamicWorkerLoader;
|
|
78
|
+
/** Durable Object namespace binding that points back to the wrapped class. */
|
|
79
|
+
readonly hostBinding: string;
|
|
80
|
+
/** Current Durable Object id, normally `ctx.id.toString()`. */
|
|
81
|
+
readonly hostId: string;
|
|
82
|
+
/** Current Durable Object execution context, normally `ctx`. */
|
|
83
|
+
readonly executionContext: unknown;
|
|
84
|
+
/** Dynamic Worker egress policy. Defaults to `{ mode: "none" }`. */
|
|
85
|
+
readonly egress?: WorkspaceEgressPolicy;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Configuration accepted by {@link withComputerWorkspace}. */
|
|
89
|
+
export interface ComputerWorkspaceHostConfig {
|
|
90
|
+
/** Native SQLite-backed Durable Object storage (`ctx.storage`). */
|
|
91
|
+
readonly storage: globalThis.DurableObjectStorage | DurableObjectStorageLike;
|
|
92
|
+
/** Stable workspace id used by mounts and as the default Artifacts session. */
|
|
93
|
+
readonly sessionId?: string;
|
|
94
|
+
readonly gitIdentity?: ComputerWorkspaceGitIdentity;
|
|
95
|
+
/** Override the default `createGitClient()` factory. */
|
|
96
|
+
readonly git?: GitClientFactory;
|
|
97
|
+
/** Additional container, Worker JavaScript, shell, or custom backends. */
|
|
98
|
+
readonly backends?: ReadonlyArray<WorkspaceRegisteredBackend>;
|
|
99
|
+
/** Convenience wiring for one Worker Shell backend. */
|
|
100
|
+
readonly shell?: ComputerWorkspaceShellOptions;
|
|
101
|
+
readonly mounts?: WorkspaceOptions["mounts"];
|
|
102
|
+
readonly observer?: WorkspaceOptions["observer"];
|
|
103
|
+
readonly retryScheduler?: WorkspaceOptions["retryScheduler"];
|
|
104
|
+
readonly retry?: WorkspaceOptions["retry"];
|
|
105
|
+
readonly assets?: WorkspaceOptions["assets"];
|
|
106
|
+
readonly artifacts?: ComputerWorkspaceArtifactsOptions;
|
|
107
|
+
readonly now?: WorkspaceOptions["now"];
|
|
108
|
+
readonly useThink?: WorkspaceOptions["useThink"];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const toWorkspaceOptions = (config: ComputerWorkspaceHostConfig): WorkspaceOptions => {
|
|
112
|
+
const backends = [...(config.backends ?? [])];
|
|
113
|
+
|
|
114
|
+
if (config.shell !== undefined) {
|
|
115
|
+
const { egress, executionContext, hostBinding, hostId, loader, ...shellOptions } = config.shell;
|
|
116
|
+
|
|
117
|
+
backends.push(
|
|
118
|
+
new WorkerShellBackend({
|
|
119
|
+
...shellOptions,
|
|
120
|
+
loader,
|
|
121
|
+
workspace: { binding: hostBinding, id: hostId },
|
|
122
|
+
ctx: executionContext,
|
|
123
|
+
egress: egress ?? { mode: "none" },
|
|
124
|
+
}),
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
storage: config.storage as DurableObjectStorageLike,
|
|
130
|
+
git: config.git ?? createGitClient(),
|
|
131
|
+
...(config.gitIdentity === undefined ? {} : { defaultGitIdentity: config.gitIdentity }),
|
|
132
|
+
...(backends.length === 0 ? {} : { backends }),
|
|
133
|
+
...(config.sessionId === undefined ? {} : { sessionId: config.sessionId }),
|
|
134
|
+
...(config.mounts === undefined ? {} : { mounts: config.mounts }),
|
|
135
|
+
...(config.observer === undefined ? {} : { observer: config.observer }),
|
|
136
|
+
...(config.retryScheduler === undefined ? {} : { retryScheduler: config.retryScheduler }),
|
|
137
|
+
...(config.retry === undefined ? {} : { retry: config.retry }),
|
|
138
|
+
...(config.assets === undefined ? {} : { assets: config.assets }),
|
|
139
|
+
...(config.artifacts === undefined
|
|
140
|
+
? {}
|
|
141
|
+
: {
|
|
142
|
+
artifacts: {
|
|
143
|
+
binding: config.artifacts.binding as unknown as NonNullable<
|
|
144
|
+
WorkspaceOptions["artifacts"]
|
|
145
|
+
>["binding"],
|
|
146
|
+
...(config.artifacts.sessionId === undefined
|
|
147
|
+
? {}
|
|
148
|
+
: { sessionId: config.artifacts.sessionId }),
|
|
149
|
+
},
|
|
150
|
+
}),
|
|
151
|
+
...(config.now === undefined ? {} : { now: config.now }),
|
|
152
|
+
...(config.useThink === undefined ? {} : { useThink: config.useThink }),
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// Cloudflare constructs Durable Objects with `(state, env)`. Keeping the
|
|
157
|
+
// remaining tuple open preserves arbitrary Effect-backed base constructors.
|
|
158
|
+
type DurableObjectConstructor = new (...args: Array<any>) => object;
|
|
159
|
+
|
|
160
|
+
const HostArguments = Symbol("effect-cf/ComputerWorkspaceHost/arguments");
|
|
161
|
+
|
|
162
|
+
interface CapturedHostArguments {
|
|
163
|
+
readonly state: globalThis.DurableObjectState;
|
|
164
|
+
readonly env: unknown;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
interface HostArgumentsInstance {
|
|
168
|
+
readonly [HostArguments]: CapturedHostArguments;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Wraps a Durable Object class with one SQLite-backed Cloudflare Computer
|
|
173
|
+
* workspace and registers that local workspace for {@link ComputerWorkspace}
|
|
174
|
+
* to acquire through its Effect layer.
|
|
175
|
+
*
|
|
176
|
+
* The class must use a `new_sqlite_classes` migration. If `shell` is present,
|
|
177
|
+
* its Worker must also configure a `worker_loaders` binding, enable the
|
|
178
|
+
* `experimental` compatibility flag, and export `WorkspaceServiceProxy`.
|
|
179
|
+
*/
|
|
180
|
+
export const withComputerWorkspace = <TBase extends DurableObjectConstructor>(
|
|
181
|
+
Base: TBase,
|
|
182
|
+
config: (
|
|
183
|
+
self: InstanceType<TBase>,
|
|
184
|
+
state: globalThis.DurableObjectState,
|
|
185
|
+
env: ConstructorParameters<TBase>[1],
|
|
186
|
+
) => ComputerWorkspaceHostConfig,
|
|
187
|
+
): WithWorkspaceCtor<TBase> => {
|
|
188
|
+
const CapturedBase = class extends (Base as DurableObjectConstructor) {
|
|
189
|
+
readonly [HostArguments]: CapturedHostArguments;
|
|
190
|
+
|
|
191
|
+
constructor(...args: Array<any>) {
|
|
192
|
+
super(...args);
|
|
193
|
+
this[HostArguments] = {
|
|
194
|
+
state: args[0] as globalThis.DurableObjectState,
|
|
195
|
+
env: args[1],
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const WithWorkspace = withWorkspace(CapturedBase, (self) => {
|
|
201
|
+
const { env, state } = (self as HostArgumentsInstance)[HostArguments];
|
|
202
|
+
|
|
203
|
+
return toWorkspaceOptions(
|
|
204
|
+
config(self as InstanceType<TBase>, state, env as ConstructorParameters<TBase>[1]),
|
|
205
|
+
);
|
|
206
|
+
}) as unknown as DurableObjectConstructor;
|
|
207
|
+
|
|
208
|
+
class WithComputerWorkspace extends WithWorkspace {
|
|
209
|
+
constructor(...args: Array<any>) {
|
|
210
|
+
super(...args);
|
|
211
|
+
HostRegistry.register(args[0] as globalThis.DurableObjectState, this as WorkspaceHandle);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return WithComputerWorkspace as unknown as WithWorkspaceCtor<TBase>;
|
|
216
|
+
};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Truthful WebTransport / HTTP/3 boundary for Cloudflare Workers.
|
|
3
|
+
*
|
|
4
|
+
* What Cloudflare supports today (verified against primary sources, August
|
|
5
|
+
* 2026):
|
|
6
|
+
*
|
|
7
|
+
* - Inbound HTTP/3 is a zone-level setting. Cloudflare's edge terminates the
|
|
8
|
+
* QUIC connection and invokes the Worker with an ordinary `fetch` Request;
|
|
9
|
+
* the inbound protocol is surfaced only as metadata on `request.cf`
|
|
10
|
+
* ({@link inboundTransport}).
|
|
11
|
+
* - There is no runtime API for inbound WebTransport sessions — nothing
|
|
12
|
+
* analogous to `WebSocketPair`. workerd contains no QUIC/HTTP-3 stack, and
|
|
13
|
+
* the maintainers state WebTransport support "is not currently on our
|
|
14
|
+
* priority list" (cloudflare/workerd#6451, discussion #6454).
|
|
15
|
+
* - There is no outbound WebTransport/QUIC/UDP client capability either;
|
|
16
|
+
* `cloudflare:sockets` `connect()` is TCP-only, and
|
|
17
|
+
* `@cloudflare/workers-types` contains no WebTransport types.
|
|
18
|
+
* - Workers and Durable Objects can accept inbound WebSocket connections;
|
|
19
|
+
* Durable Objects additionally support hibernation (`acceptWebSocket`,
|
|
20
|
+
* `webSocketMessage`, `webSocketClose`).
|
|
21
|
+
*
|
|
22
|
+
* Consequently a browser's WebTransport session can never reach Worker code:
|
|
23
|
+
* clients should attempt WebTransport only against origins that actually
|
|
24
|
+
* speak it, and fall back to WebSockets for Cloudflare-hosted endpoints (see
|
|
25
|
+
* the `effect-webtransport` package's `Fallback` module). This module gives
|
|
26
|
+
* that reality a typed shape: {@link capabilities} feature-detects what the
|
|
27
|
+
* current runtime provides, {@link inboundSessionsUnsupported} is the
|
|
28
|
+
* explicit typed boundary for the missing inbound API, and
|
|
29
|
+
* {@link inboundTransport} decodes the HTTP/3-relevant request metadata that
|
|
30
|
+
* the edge does provide.
|
|
31
|
+
*/
|
|
32
|
+
import type { Request as CloudflareRequest } from "@cloudflare/workers-types";
|
|
33
|
+
import { Data, Effect, Option, Result, Schema as S } from "effect";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Metadata Cloudflare's edge reports about the inbound client connection.
|
|
37
|
+
*
|
|
38
|
+
* `httpProtocol` and `clientTcpRtt` are declared in
|
|
39
|
+
* `@cloudflare/workers-types`; `clientQuicRtt` is documented by Cloudflare
|
|
40
|
+
* ("only present when the client connected over QUIC (HTTP/3)") but not yet
|
|
41
|
+
* present in the published types, so it is decoded from the open
|
|
42
|
+
* `Record<string, unknown>` side of `request.cf`.
|
|
43
|
+
*/
|
|
44
|
+
export class InboundTransport extends S.Class<InboundTransport>("InboundTransport")({
|
|
45
|
+
/** The HTTP protocol the client used, e.g. `"HTTP/2"` or `"HTTP/3"`. */
|
|
46
|
+
httpProtocol: S.String,
|
|
47
|
+
/** Client round-trip time; only present for QUIC (HTTP/3) connections. */
|
|
48
|
+
clientQuicRtt: S.optional(S.Number),
|
|
49
|
+
/** Client round-trip time; only present for TCP (HTTP/1.x, HTTP/2) connections. */
|
|
50
|
+
clientTcpRtt: S.optional(S.Number),
|
|
51
|
+
}) {}
|
|
52
|
+
|
|
53
|
+
const decodeInboundTransport = S.decodeUnknownResult(InboundTransport);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Decodes the inbound transport metadata from `request.cf`.
|
|
57
|
+
*
|
|
58
|
+
* Returns `None` when the metadata is absent (for example in local `wrangler
|
|
59
|
+
* dev` or when a Worker invokes another Worker directly) or does not match
|
|
60
|
+
* the expected shape.
|
|
61
|
+
*/
|
|
62
|
+
export const inboundTransport = (
|
|
63
|
+
request: Pick<CloudflareRequest, "cf">,
|
|
64
|
+
): Option.Option<InboundTransport> => Result.getSuccess(decodeInboundTransport(request.cf));
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Returns `true` when the client reached Cloudflare's edge over QUIC
|
|
68
|
+
* (HTTP/3). Prefers the documented QUIC signal (`clientQuicRtt` is only
|
|
69
|
+
* present for QUIC connections) and falls back to the `httpProtocol` string.
|
|
70
|
+
*
|
|
71
|
+
* Note this describes the browser→edge hop only: the edge always terminates
|
|
72
|
+
* QUIC, and the Worker still handles an ordinary `fetch` Request.
|
|
73
|
+
*/
|
|
74
|
+
export const isHttp3 = (transport: InboundTransport): boolean =>
|
|
75
|
+
transport.clientQuicRtt !== undefined || transport.httpProtocol === "HTTP/3";
|
|
76
|
+
|
|
77
|
+
/** WebTransport-related capabilities of the current Workers runtime. */
|
|
78
|
+
export interface Capabilities {
|
|
79
|
+
/**
|
|
80
|
+
* Whether Worker code can accept inbound WebTransport sessions. Typed as
|
|
81
|
+
* literally `false`: no such runtime API exists (cloudflare/workerd#6451),
|
|
82
|
+
* so this can only change through a breaking, deliberate update when
|
|
83
|
+
* Cloudflare ships one.
|
|
84
|
+
*/
|
|
85
|
+
readonly inboundSessions: false;
|
|
86
|
+
/**
|
|
87
|
+
* Whether the runtime exposes a client `WebTransport` constructor global.
|
|
88
|
+
* Feature-detected at runtime; `false` in workerd today, which has no
|
|
89
|
+
* QUIC stack.
|
|
90
|
+
*/
|
|
91
|
+
readonly outboundSessions: boolean;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Feature-detects the WebTransport capabilities of the current runtime. */
|
|
95
|
+
export const capabilities: Effect.Effect<Capabilities> = Effect.sync(() => ({
|
|
96
|
+
inboundSessions: false,
|
|
97
|
+
outboundSessions: typeof (globalThis as Record<string, unknown>)["WebTransport"] === "function",
|
|
98
|
+
}));
|
|
99
|
+
|
|
100
|
+
/** WebTransport capability missing from the current Workers runtime. */
|
|
101
|
+
export type WebTransportCapability = "inbound-sessions" | "outbound-sessions";
|
|
102
|
+
|
|
103
|
+
/** Raised when a WebTransport capability is unavailable in this runtime. */
|
|
104
|
+
export class WebTransportUnsupportedError extends Data.TaggedError("WebTransportUnsupportedError")<{
|
|
105
|
+
readonly capability: WebTransportCapability;
|
|
106
|
+
}> {
|
|
107
|
+
override get message(): string {
|
|
108
|
+
return this.capability === "inbound-sessions"
|
|
109
|
+
? "Cloudflare Workers cannot accept inbound WebTransport sessions: the edge terminates QUIC and no runtime session API exists (cloudflare/workerd#6451). Use Durable Object WebSockets for bidirectional push."
|
|
110
|
+
: "This Workers runtime provides no WebTransport client: workerd has no QUIC stack and cloudflare:sockets is TCP-only.";
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The explicit typed boundary for inbound WebTransport sessions.
|
|
116
|
+
*
|
|
117
|
+
* Always fails with {@link WebTransportUnsupportedError} today. Route the
|
|
118
|
+
* code path that would accept a session through this effect so the
|
|
119
|
+
* limitation is visible in the type system and greppable when Cloudflare
|
|
120
|
+
* ships a real API.
|
|
121
|
+
*/
|
|
122
|
+
export const inboundSessionsUnsupported: Effect.Effect<never, WebTransportUnsupportedError> =
|
|
123
|
+
Effect.fail(new WebTransportUnsupportedError({ capability: "inbound-sessions" }));
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * as AiGateway from "./AiGateway";
|
|
2
2
|
export * as AnalyticsEngine from "./AnalyticsEngine";
|
|
3
|
+
export * as Artifacts from "./Artifacts";
|
|
3
4
|
export * as Binding from "./Binding";
|
|
4
5
|
export * as BrowserRendering from "./BrowserRendering";
|
|
5
6
|
export * as Cache from "./Cache";
|
|
@@ -28,6 +29,7 @@ export * as Rpc from "./Rpc";
|
|
|
28
29
|
export * as RpcDefinition from "./RpcDefinition";
|
|
29
30
|
export * as ServiceBinding from "./ServiceBinding";
|
|
30
31
|
export * as Vectorize from "./Vectorize";
|
|
32
|
+
export * as WebTransport from "./WebTransport";
|
|
31
33
|
export * as Worker from "./Worker";
|
|
32
34
|
export * as WorkerDefinition from "./WorkerDefinition";
|
|
33
35
|
export * as WorkersAi from "./WorkersAi";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { WorkspaceHandle } from "@cloudflare/computer";
|
|
2
|
+
|
|
3
|
+
const hosts = new WeakMap<globalThis.DurableObjectState, WorkspaceHandle>();
|
|
4
|
+
|
|
5
|
+
export const register = (state: globalThis.DurableObjectState, host: WorkspaceHandle): void => {
|
|
6
|
+
hosts.set(state, host);
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const lookup = (state: globalThis.DurableObjectState): WorkspaceHandle | undefined =>
|
|
10
|
+
hosts.get(state);
|