effect-cf 0.33.0 → 0.34.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 +12 -0
- package/README.md +31 -1079
- package/dist/{Artifacts-DnHQA-Ax.d.mts → Artifacts-B3r3RuTB.d.mts} +1 -48
- package/dist/{Artifacts-CSIk1Oml.mjs → Artifacts-CBxWGeZB.mjs} +2 -7
- package/dist/{Binding-pfilNJmP.mjs → Binding-C82jRhdr.mjs} +1 -2
- package/dist/{Binding-xJJJPmiD.d.mts → Binding-DKcLrQCM.d.mts} +0 -45
- package/dist/ComputerArtifacts.d.mts +1 -3
- package/dist/ComputerArtifacts.mjs +1 -2
- package/dist/ComputerWorkspace.d.mts +1 -10
- package/dist/ComputerWorkspace.mjs +1 -2
- package/dist/ComputerWorkspaceHost.d.mts +1 -9
- package/dist/{ContainerNamespace-CFjiLw8b.d.mts → ContainerNamespace-DbLaeFhN.d.mts} +1 -14
- package/dist/{DurableObjectState-BpRjz6-q.d.mts → DurableObjectState-CrEunfQ-.d.mts} +82 -252
- package/dist/{DurableObjectState-CVLLse69.mjs → DurableObjectState-De4ZojhY.mjs} +1 -39
- package/dist/{ErrorMessage-BM0K-Nik.mjs → ErrorMessage-Byx2OgNd.mjs} +0 -1
- package/dist/{Hyperdrive-z-9fFz15.d.mts → Hyperdrive-HrwFlZ6x.d.mts} +1 -4
- package/dist/HyperdrivePg.d.mts +2 -11
- package/dist/HyperdrivePg.mjs +0 -8
- package/dist/Sandbox.d.mts +2 -32
- package/dist/Sandbox.mjs +2 -11
- package/dist/Vitest.d.mts +3 -31
- package/dist/Vitest.mjs +2 -17
- package/dist/{WorkflowBinding-lBR4_-op.d.mts → WorkflowBinding-BumVQTuW.d.mts} +2 -5
- package/dist/index.d.mts +34 -480
- package/dist/index.mjs +174 -312
- package/package.json +1 -1
- package/src/AiGateway.ts +0 -6
- package/src/AnalyticsEngine.ts +0 -9
- package/src/Artifacts.ts +0 -47
- package/src/Binding.ts +0 -8
- package/src/BrowserRendering.ts +0 -4
- package/src/Cache.ts +0 -19
- package/src/CloudflareOtlp.ts +3 -39
- package/src/ComputerArtifacts.ts +0 -2
- package/src/ComputerWorkspace.ts +0 -9
- package/src/ComputerWorkspaceHost.ts +0 -8
- package/src/ContainerNamespace.ts +0 -13
- package/src/D1.ts +0 -22
- package/src/DurableObject.ts +45 -25
- package/src/DurableObjectAlarm.ts +6 -210
- package/src/DurableObjectDefinition.ts +8 -20
- package/src/DurableObjectNamespace.ts +57 -112
- package/src/DurableObjectRpcWebSocket.ts +3 -19
- package/src/DurableObjectSqlite.ts +0 -12
- package/src/DurableObjectState.ts +0 -18
- package/src/DurableObjectStorage.ts +2 -35
- package/src/DurableObjectWebSocket.ts +0 -31
- package/src/Email.ts +0 -12
- package/src/Environment.ts +0 -37
- package/src/Hyperdrive.ts +0 -3
- package/src/HyperdrivePg.ts +0 -9
- package/src/Images.ts +0 -5
- package/src/Kv.ts +0 -15
- package/src/QueueBinding.ts +0 -2
- package/src/R2.ts +0 -5
- package/src/RpcDefinition.ts +0 -2
- package/src/RpcTracing.ts +133 -0
- package/src/Sandbox.ts +0 -30
- package/src/ServiceBinding.ts +48 -125
- package/src/Vectorize.ts +0 -5
- package/src/Vitest.ts +0 -28
- package/src/WebTransport.ts +0 -15
- package/src/Worker.ts +36 -57
- package/src/WorkerDefinition.ts +5 -14
- package/src/WorkersAi.ts +0 -4
- package/src/Workflow.ts +0 -5
- package/src/WorkflowBinding.ts +0 -3
- package/src/index.ts +1 -0
- package/src/internal/Entrypoint.ts +23 -4
- package/src/internal/ErrorMessage.ts +0 -1
- package/src/internal/RpcInvocation.ts +18 -1
- package/src/internal/Runtime.ts +12 -7
- package/src/internal/WorkerContext.ts +0 -11
|
@@ -7,6 +7,7 @@ import type * as DurableObjectDefinition from "./DurableObjectDefinition";
|
|
|
7
7
|
import * as RpcDefinition from "./RpcDefinition";
|
|
8
8
|
import * as ErrorMessage from "./internal/ErrorMessage";
|
|
9
9
|
import * as RpcInvocation from "./internal/RpcInvocation";
|
|
10
|
+
import * as RpcTracing from "./RpcTracing";
|
|
10
11
|
|
|
11
12
|
const expectedDurableObjectNamespace =
|
|
12
13
|
"Durable Object namespace binding with getByName(), get(), idFromName(), idFromString(), newUniqueId(), and jurisdiction()";
|
|
@@ -39,29 +40,20 @@ export type DurableObjectStubClient<Api extends object> = DurableObjectFetcher &
|
|
|
39
40
|
readonly name?: string;
|
|
40
41
|
};
|
|
41
42
|
|
|
42
|
-
/**
|
|
43
|
-
* Native Durable Object namespace binding shape.
|
|
44
|
-
*/
|
|
45
43
|
export interface DurableObjectNamespaceClient<Api extends object> {
|
|
46
|
-
/** Creates a globally unique Durable Object id. */
|
|
47
44
|
newUniqueId(
|
|
48
45
|
options?: globalThis.DurableObjectNamespaceNewUniqueIdOptions,
|
|
49
46
|
): globalThis.DurableObjectId;
|
|
50
|
-
/** Deterministically maps a name to a Durable Object id. */
|
|
51
47
|
idFromName(name: string): globalThis.DurableObjectId;
|
|
52
|
-
/** Rehydrates a Durable Object id from its string form. */
|
|
53
48
|
idFromString(id: string): globalThis.DurableObjectId;
|
|
54
|
-
/** Returns a stub for an existing Durable Object id. */
|
|
55
49
|
get(
|
|
56
50
|
id: globalThis.DurableObjectId,
|
|
57
51
|
options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
|
|
58
52
|
): DurableObjectStubClient<Api>;
|
|
59
|
-
/** Returns a stub by deterministic name. */
|
|
60
53
|
getByName(
|
|
61
54
|
name: string,
|
|
62
55
|
options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
|
|
63
56
|
): DurableObjectStubClient<Api>;
|
|
64
|
-
/** Selects a namespace pinned to a specific jurisdiction. */
|
|
65
57
|
jurisdiction(
|
|
66
58
|
jurisdiction: globalThis.DurableObjectJurisdiction,
|
|
67
59
|
): DurableObjectNamespaceClient<Api>;
|
|
@@ -80,10 +72,10 @@ export interface DurableObjectNamespaceDefinition {
|
|
|
80
72
|
export interface DurableObjectNamespaceBindingDefinition<
|
|
81
73
|
Definition extends DurableObjectDefinition.Definition.Any | undefined = undefined,
|
|
82
74
|
> {
|
|
83
|
-
/** Binding name as configured in `wrangler.jsonc`. */
|
|
84
75
|
readonly binding: string;
|
|
85
|
-
/** Optional RPC schema used for argument/result encoding. */
|
|
86
76
|
readonly definition?: Definition;
|
|
77
|
+
/** Append live trace context only when the receiver also enables rpcTracing. */
|
|
78
|
+
readonly rpcTracing?: boolean;
|
|
87
79
|
}
|
|
88
80
|
|
|
89
81
|
/**
|
|
@@ -199,46 +191,22 @@ export type DurableObjectNamespaceEffectClient<
|
|
|
199
191
|
Api extends object,
|
|
200
192
|
Definition extends DurableObjectDefinition.Definition.Any | undefined = undefined,
|
|
201
193
|
> = DirectMethods<never, Api, Definition> & {
|
|
202
|
-
/** Creates a globally unique Durable Object id. */
|
|
203
194
|
readonly newUniqueId: (
|
|
204
195
|
options?: globalThis.DurableObjectNamespaceNewUniqueIdOptions,
|
|
205
196
|
) => Effect.Effect<globalThis.DurableObjectId>;
|
|
206
|
-
/** Deterministically maps a name to a Durable Object id. */
|
|
207
197
|
readonly idFromName: (name: string) => Effect.Effect<globalThis.DurableObjectId>;
|
|
208
|
-
/** Rehydrates a Durable Object id from its string form. */
|
|
209
198
|
readonly idFromString: (id: string) => Effect.Effect<globalThis.DurableObjectId>;
|
|
210
|
-
/** Returns a stub for an existing Durable Object id. */
|
|
211
199
|
readonly get: (
|
|
212
200
|
id: globalThis.DurableObjectId,
|
|
213
201
|
options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
|
|
214
202
|
) => Effect.Effect<DurableObjectStubClient<Api>>;
|
|
215
|
-
/** Returns a stub by deterministic name. */
|
|
216
203
|
readonly getByName: (
|
|
217
204
|
name: string,
|
|
218
205
|
options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions,
|
|
219
206
|
) => Effect.Effect<DurableObjectStubClient<Api>>;
|
|
220
|
-
/** Selects a namespace pinned to a specific jurisdiction. */
|
|
221
207
|
readonly jurisdiction: (
|
|
222
208
|
jurisdiction: globalThis.DurableObjectJurisdiction,
|
|
223
209
|
) => Effect.Effect<DurableObjectNamespaceClient<Api>>;
|
|
224
|
-
/**
|
|
225
|
-
* Forwards an HTTP request to a Durable Object stub.
|
|
226
|
-
*
|
|
227
|
-
* Use this for fetch-based Durable Object APIs, including WebSocket upgrade
|
|
228
|
-
* forwarding where the native response must be preserved.
|
|
229
|
-
*
|
|
230
|
-
* @example
|
|
231
|
-
* ```ts
|
|
232
|
-
* import { Effect } from "effect";
|
|
233
|
-
*
|
|
234
|
-
* const program = Effect.gen(function* () {
|
|
235
|
-
* const rooms = yield* ChatRooms;
|
|
236
|
-
* const room = yield* rooms.getByName("general");
|
|
237
|
-
*
|
|
238
|
-
* return yield* rooms.fetch(room, new Request("https://worker.example/room"));
|
|
239
|
-
* });
|
|
240
|
-
* ```
|
|
241
|
-
*/
|
|
242
210
|
readonly fetch: (
|
|
243
211
|
stub: DurableObjectStubClient<Api>,
|
|
244
212
|
input: RequestInfo | URL,
|
|
@@ -252,21 +220,6 @@ export type DurableObjectNamespaceEffectClient<
|
|
|
252
220
|
* promise-like value and it does not decode definition-backed success schemas.
|
|
253
221
|
*
|
|
254
222
|
* Most application code should use {@link call} instead.
|
|
255
|
-
*
|
|
256
|
-
* @example
|
|
257
|
-
* ```ts
|
|
258
|
-
* import { Effect } from "effect";
|
|
259
|
-
*
|
|
260
|
-
* const program = Effect.gen(function* () {
|
|
261
|
-
* const counters = yield* Counters;
|
|
262
|
-
* const counter = yield* counters.getByName("main");
|
|
263
|
-
*
|
|
264
|
-
* const result = yield* counters.rpc(counter, "get");
|
|
265
|
-
* const value = yield* Effect.promise(() => result);
|
|
266
|
-
*
|
|
267
|
-
* return value;
|
|
268
|
-
* });
|
|
269
|
-
* ```
|
|
270
223
|
*/
|
|
271
224
|
readonly rpc: <Method extends StubMethodKey<Api>>(
|
|
272
225
|
stub: DurableObjectStubClient<Api>,
|
|
@@ -278,18 +231,6 @@ export type DurableObjectNamespaceEffectClient<
|
|
|
278
231
|
* decodes the success value when the namespace was created from a definition.
|
|
279
232
|
*
|
|
280
233
|
* This is the normal choice when application code wants the final typed value.
|
|
281
|
-
*
|
|
282
|
-
* @example
|
|
283
|
-
* ```ts
|
|
284
|
-
* import { Effect } from "effect";
|
|
285
|
-
*
|
|
286
|
-
* const program = Effect.gen(function* () {
|
|
287
|
-
* const counters = yield* Counters;
|
|
288
|
-
* const counter = yield* counters.getByName("main");
|
|
289
|
-
*
|
|
290
|
-
* return yield* counters.call(counter, "increment", 1);
|
|
291
|
-
* });
|
|
292
|
-
* ```
|
|
293
234
|
*/
|
|
294
235
|
readonly call: <Method extends StubMethodKey<Api>>(
|
|
295
236
|
stub: DurableObjectStubClient<Api>,
|
|
@@ -304,21 +245,6 @@ export type DurableObjectNamespaceEffectClient<
|
|
|
304
245
|
*
|
|
305
246
|
* Use this for RPC methods that return Cloudflare RPC resources or other
|
|
306
247
|
* disposable objects whose lifetime should be tied to an Effect scope.
|
|
307
|
-
*
|
|
308
|
-
* @example
|
|
309
|
-
* ```ts
|
|
310
|
-
* import { Effect } from "effect";
|
|
311
|
-
*
|
|
312
|
-
* const program = Effect.scoped(
|
|
313
|
-
* Effect.gen(function* () {
|
|
314
|
-
* const rooms = yield* ChatRooms;
|
|
315
|
-
* const room = yield* rooms.getByName("general");
|
|
316
|
-
* const handle = yield* rooms.scopedCall(room, "openStream");
|
|
317
|
-
*
|
|
318
|
-
* return yield* handle.read();
|
|
319
|
-
* }),
|
|
320
|
-
* );
|
|
321
|
-
* ```
|
|
322
248
|
*/
|
|
323
249
|
readonly scopedCall: <Method extends StubMethodKey<Api>>(
|
|
324
250
|
stub: DurableObjectStubClient<Api>,
|
|
@@ -429,9 +355,11 @@ export const makeClient = <
|
|
|
429
355
|
catch: (cause) => new DurableObjectFetchError({ binding: definition.binding, cause }),
|
|
430
356
|
});
|
|
431
357
|
|
|
432
|
-
const rpc = Effect.
|
|
433
|
-
|
|
434
|
-
|
|
358
|
+
const rpc = Effect.fnUntraced(function* <Method extends StubMethodKey<Api>>(
|
|
359
|
+
stub: StubClient,
|
|
360
|
+
method: Method,
|
|
361
|
+
...args: StubMethodArgs<Api, Method>
|
|
362
|
+
): Effect.fn.Return<StubMethodCloudflareReturn<Api, Method>, DurableObjectRpcError> {
|
|
435
363
|
const methodName = String(method);
|
|
436
364
|
// SAFETY: the runtime definition and method name select the same method schemas as Method.
|
|
437
365
|
const encodedArgs =
|
|
@@ -452,11 +380,15 @@ export const makeClient = <
|
|
|
452
380
|
),
|
|
453
381
|
);
|
|
454
382
|
|
|
455
|
-
|
|
383
|
+
const nativeArgs = definition.rpcTracing
|
|
384
|
+
? yield* RpcTracing.withRpcTraceContext(encodedArgs)
|
|
385
|
+
: encodedArgs;
|
|
386
|
+
|
|
387
|
+
// SAFETY: domain arguments retain their encoded order; an opted-in receiver strips only valid trace metadata.
|
|
456
388
|
return yield* RpcInvocation.invokeRpcMethod(
|
|
457
389
|
stub,
|
|
458
390
|
method,
|
|
459
|
-
|
|
391
|
+
nativeArgs as StubMethodArgs<Api, Method>,
|
|
460
392
|
(cause) =>
|
|
461
393
|
new DurableObjectRpcError({
|
|
462
394
|
binding: definition.binding,
|
|
@@ -466,9 +398,10 @@ export const makeClient = <
|
|
|
466
398
|
);
|
|
467
399
|
});
|
|
468
400
|
|
|
469
|
-
const decodeSuccess = Effect.
|
|
470
|
-
|
|
471
|
-
|
|
401
|
+
const decodeSuccess = Effect.fnUntraced(function* <Method extends StubMethodKey<Api>>(
|
|
402
|
+
methodName: string,
|
|
403
|
+
value: Awaited<StubMethodCloudflareReturn<Api, Method>>,
|
|
404
|
+
): Effect.fn.Return<StubMethodSuccess<Api, Method>, DurableObjectRpcError> {
|
|
472
405
|
if (definition.definition === undefined) {
|
|
473
406
|
// SAFETY: without a schema codec, the native RPC result is already the declared success type.
|
|
474
407
|
return value as StubMethodSuccess<Api, Method>;
|
|
@@ -494,33 +427,45 @@ export const makeClient = <
|
|
|
494
427
|
return decoded as StubMethodSuccess<Api, Method>;
|
|
495
428
|
});
|
|
496
429
|
|
|
497
|
-
const call = Effect.
|
|
498
|
-
Method extends StubMethodKey<Api
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
430
|
+
const call = Effect.fnUntraced(
|
|
431
|
+
function* <Method extends StubMethodKey<Api>>(
|
|
432
|
+
stub: StubClient,
|
|
433
|
+
method: Method,
|
|
434
|
+
...args: StubMethodArgs<Api, Method>
|
|
435
|
+
): Effect.fn.Return<StubMethodSuccess<Api, Method>, DurableObjectRpcError> {
|
|
436
|
+
const methodName = String(method);
|
|
437
|
+
const value = yield* CloudflareRpc.resolve(yield* rpc(stub, method, ...args)).pipe(
|
|
438
|
+
Effect.mapError(
|
|
439
|
+
(cause) =>
|
|
440
|
+
new DurableObjectRpcError({
|
|
441
|
+
binding: definition.binding,
|
|
442
|
+
method: methodName,
|
|
443
|
+
cause,
|
|
444
|
+
}),
|
|
445
|
+
),
|
|
446
|
+
);
|
|
447
|
+
|
|
448
|
+
return yield* decodeSuccess<Method>(methodName, value);
|
|
449
|
+
},
|
|
450
|
+
(effect, ...args) =>
|
|
451
|
+
RpcTracing.withRpcClientSpan(effect, definition.binding, String(args[1])),
|
|
452
|
+
);
|
|
453
|
+
|
|
454
|
+
const scopedCall = Effect.fnUntraced(
|
|
455
|
+
function* <Method extends StubMethodKey<Api>>(
|
|
456
|
+
stub: StubClient,
|
|
457
|
+
method: Method,
|
|
458
|
+
...args: StubMethodArgs<Api, Method>
|
|
459
|
+
): Effect.fn.Return<StubMethodSuccess<Api, Method>, unknown, Scope.Scope> {
|
|
460
|
+
const methodName = String(method);
|
|
461
|
+
const result = yield* rpc(stub, method, ...args);
|
|
462
|
+
const value = yield* CloudflareRpc.scoped(result);
|
|
463
|
+
|
|
464
|
+
return yield* decodeSuccess<Method>(methodName, value);
|
|
465
|
+
},
|
|
466
|
+
(effect, ...args) =>
|
|
467
|
+
RpcTracing.withRpcClientSpan(effect, definition.binding, String(args[1])),
|
|
468
|
+
);
|
|
524
469
|
|
|
525
470
|
const directMethods = makeDirectMethods<never, Api, Definition>(definition.definition, {
|
|
526
471
|
call,
|
|
@@ -22,14 +22,12 @@ const serviceRestartReason = "Durable Object RPC activation reset";
|
|
|
22
22
|
/** Heartbeat handling for Effect's application-level RPC Ping messages. */
|
|
23
23
|
export type HeartbeatPolicy = "auto-response" | "passthrough";
|
|
24
24
|
|
|
25
|
-
/** Object-shaped application attachment fields that can coexist with adapter metadata. */
|
|
26
25
|
export type RpcWebSocketAttachment = object;
|
|
27
26
|
|
|
28
27
|
/** A resumable RPC stream declaration understood by the websocket transport. */
|
|
29
28
|
export interface ResumableStreamDeclaration<ResumeDescriptor = unknown, Checkpoint = unknown> {
|
|
30
29
|
/** Stable declaration identifier. Change it when the persisted representation changes. */
|
|
31
30
|
readonly id: string;
|
|
32
|
-
/** RPC tag matched against encoded client requests. */
|
|
33
31
|
readonly rpcTag: string;
|
|
34
32
|
/** Validates a resume descriptor restored from a websocket attachment. */
|
|
35
33
|
readonly resumeDescriptorSchema: Schema.Decoder<ResumeDescriptor>;
|
|
@@ -45,7 +43,6 @@ export interface ResumableStreamDeclaration<ResumeDescriptor = unknown, Checkpoi
|
|
|
45
43
|
readonly resumeDescriptor: ResumeDescriptor;
|
|
46
44
|
readonly acknowledgedCheckpoint: Checkpoint;
|
|
47
45
|
}>;
|
|
48
|
-
/** Rebuilds the encoded request fields used to restart a handler. */
|
|
49
46
|
readonly rebuild: (options: {
|
|
50
47
|
readonly subscriptionKey: string;
|
|
51
48
|
readonly resumeDescriptor: ResumeDescriptor;
|
|
@@ -80,9 +77,7 @@ export const resumableStream = <ResumeDescriptor, Checkpoint>(
|
|
|
80
77
|
* Configuration for {@link layer}.
|
|
81
78
|
*/
|
|
82
79
|
export interface LayerOptions {
|
|
83
|
-
/** Tag used to select hibernated sockets. */
|
|
84
80
|
readonly tag?: string | undefined;
|
|
85
|
-
/** Socket attachment namespace used to persist adapter metadata across hibernation. */
|
|
86
81
|
readonly attachmentKey?: string | undefined;
|
|
87
82
|
/**
|
|
88
83
|
* Heartbeat behavior. `"auto-response"` (the default) installs Cloudflare's
|
|
@@ -95,24 +90,16 @@ export interface LayerOptions {
|
|
|
95
90
|
* when RPC and unrelated websocket protocols share one object.
|
|
96
91
|
*/
|
|
97
92
|
readonly heartbeat?: HeartbeatPolicy | undefined;
|
|
98
|
-
/** Explicit stream declarations that may be reconstructed after activation loss. */
|
|
99
93
|
readonly resumableStreams?: ReadonlyArray<AnyResumableStreamDeclaration> | undefined;
|
|
100
94
|
}
|
|
101
95
|
|
|
102
|
-
/** Native websocket event payload accepted by Cloudflare Durable Objects. */
|
|
103
96
|
export type NativeWebSocketMessage = string | ArrayBuffer;
|
|
104
97
|
|
|
105
|
-
/**
|
|
106
|
-
* Service API used to wire websocket lifecycle events to Effect RPC server protocol.
|
|
107
|
-
*/
|
|
108
98
|
export interface DurableObjectRpcWebSocketService {
|
|
109
|
-
/**
|
|
99
|
+
/** Accept a server socket that has not already been accepted. */
|
|
110
100
|
readonly accept: (socket: DurableWebSocket, tags?: ReadonlyArray<string>) => Effect.Effect<void>;
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
* socket. Application attachment fields are shallow-merged with the adapter's
|
|
114
|
-
* metadata namespace.
|
|
115
|
-
*/
|
|
101
|
+
|
|
102
|
+
/** Shallow-merges application attachment fields with the adapter's metadata namespace. */
|
|
116
103
|
readonly acceptUpgrade: <Attachment extends RpcWebSocketAttachment = RpcWebSocketAttachment>(
|
|
117
104
|
options?: AcceptUpgradeOptions<Attachment>,
|
|
118
105
|
) => Effect.Effect<AcceptedUpgrade<Attachment>, DurableWebSocketAttachmentError>;
|
|
@@ -211,9 +198,6 @@ const ResumableAttachmentMetadataSchema = Schema.Struct({
|
|
|
211
198
|
|
|
212
199
|
const decodeResumableAttachment = Schema.decodeUnknownOption(ResumableAttachmentMetadataSchema);
|
|
213
200
|
|
|
214
|
-
/**
|
|
215
|
-
* Context tag for the Durable Object RPC websocket service.
|
|
216
|
-
*/
|
|
217
201
|
export class DurableObjectRpcWebSocket extends Context.Service<
|
|
218
202
|
DurableObjectRpcWebSocket,
|
|
219
203
|
DurableObjectRpcWebSocketService
|
|
@@ -4,20 +4,8 @@ import type { SqlClient } from "effect/unstable/sql";
|
|
|
4
4
|
|
|
5
5
|
import { DurableObjectState } from "./DurableObjectState";
|
|
6
6
|
|
|
7
|
-
/** Options forwarded to `@effect/sql-sqlite-do` when building a SQL client layer. */
|
|
8
7
|
export type SqliteLayerOptions = Omit<SqliteClient.SqliteClientConfig, "db" | "storage">;
|
|
9
8
|
|
|
10
|
-
/**
|
|
11
|
-
* Provides `effect/unstable/sql` from the current Durable Object SQLite storage.
|
|
12
|
-
*
|
|
13
|
-
* @example
|
|
14
|
-
* ```ts
|
|
15
|
-
* const RoomLayer = Layer.mergeAll(
|
|
16
|
-
* DurableObjectSqlite.layer(),
|
|
17
|
-
* OtherRoomServices,
|
|
18
|
-
* );
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
9
|
export const layer = (
|
|
22
10
|
options?: SqliteLayerOptions,
|
|
23
11
|
): Layer.Layer<SqliteClient.SqliteClient | SqlClient.SqlClient, never, DurableObjectState> =>
|
|
@@ -9,13 +9,9 @@ import { makeWaitUntilScheduler } from "./internal/WorkerContext";
|
|
|
9
9
|
* Effect-friendly wrapper around Cloudflare `DurableObjectState`.
|
|
10
10
|
*/
|
|
11
11
|
export interface DurableObjectStateService {
|
|
12
|
-
/** Underlying Cloudflare state instance. */
|
|
13
12
|
readonly raw: globalThis.DurableObjectState;
|
|
14
|
-
/** Durable Object id for the current instance. */
|
|
15
13
|
readonly id: globalThis.DurableObjectId;
|
|
16
|
-
/** Wrapped storage API. */
|
|
17
14
|
readonly storage: DurableObjectStorage;
|
|
18
|
-
/** Registers background work with Cloudflare's lifecycle. */
|
|
19
15
|
waitUntil(promise: Promise<unknown>): Effect.Effect<void>;
|
|
20
16
|
/**
|
|
21
17
|
* Runs a background Effect via Cloudflare's `waitUntil` with the caller's
|
|
@@ -47,21 +43,13 @@ export interface DurableObjectStateService {
|
|
|
47
43
|
* documented timeout (currently 30 seconds).
|
|
48
44
|
*/
|
|
49
45
|
blockConcurrencyWhileOrReset<A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R>;
|
|
50
|
-
/** Accepts a websocket connection for hibernation-capable Durable Objects. */
|
|
51
46
|
acceptWebSocket(ws: DurableWebSocket, tags?: Array<string>): Effect.Effect<void>;
|
|
52
|
-
/** Lists active sockets, optionally filtered by tag. */
|
|
53
47
|
getWebSockets(tag?: string): Effect.Effect<Array<DurableWebSocket>>;
|
|
54
|
-
/** Configures automatic request/response handling for sockets. */
|
|
55
48
|
setWebSocketAutoResponse(pair?: WebSocketRequestResponsePair): Effect.Effect<void>;
|
|
56
|
-
/** Gets the configured websocket auto-response pair. */
|
|
57
49
|
getWebSocketAutoResponse: Effect.Effect<WebSocketRequestResponsePair | null>;
|
|
58
|
-
/** Timestamp of the last automatic websocket response for a socket. */
|
|
59
50
|
getWebSocketAutoResponseTimestamp(ws: DurableWebSocket): Effect.Effect<Date | null>;
|
|
60
|
-
/** Sets the timeout for hibernatable websocket events. */
|
|
61
51
|
setHibernatableWebSocketEventTimeout(timeoutMs?: number): Effect.Effect<void>;
|
|
62
|
-
/** Gets the timeout for hibernatable websocket events. */
|
|
63
52
|
getHibernatableWebSocketEventTimeout: Effect.Effect<number | null>;
|
|
64
|
-
/** Reads tags attached to a websocket. */
|
|
65
53
|
getTags(ws: DurableWebSocket): Effect.Effect<Array<string>>;
|
|
66
54
|
/**
|
|
67
55
|
* Forcibly resets the Durable Object. Cloudflare logs an uncaught Error using
|
|
@@ -73,17 +61,11 @@ export interface DurableObjectStateService {
|
|
|
73
61
|
abort(reason?: string, options?: globalThis.DurableObjectAbortOptions): Effect.Effect<void>;
|
|
74
62
|
}
|
|
75
63
|
|
|
76
|
-
/**
|
|
77
|
-
* Context tag for accessing the current Durable Object state service.
|
|
78
|
-
*/
|
|
79
64
|
export class DurableObjectState extends Context.Service<
|
|
80
65
|
DurableObjectState,
|
|
81
66
|
DurableObjectStateService
|
|
82
67
|
>()("effect-cf/DurableObjectState") {}
|
|
83
68
|
|
|
84
|
-
/**
|
|
85
|
-
* Wraps a native Cloudflare `DurableObjectState` as a {@link DurableObjectStateService}.
|
|
86
|
-
*/
|
|
87
69
|
export const fromDurableObjectState = (
|
|
88
70
|
state: globalThis.DurableObjectState,
|
|
89
71
|
): DurableObjectStateService => {
|
|
@@ -2,10 +2,8 @@ import { Clock, Data, Duration, Effect, Exit, Option, Predicate, Schema as S } f
|
|
|
2
2
|
|
|
3
3
|
import * as ErrorMessage from "./internal/ErrorMessage";
|
|
4
4
|
|
|
5
|
-
/** Supported primitive value types for Durable Object SQL APIs. */
|
|
6
5
|
export type SqlStorageValue = globalThis.SqlStorageValue;
|
|
7
6
|
|
|
8
|
-
/** Error type used when a storage operation throws or rejects. */
|
|
9
7
|
export class StorageOperationError extends Data.TaggedError("StorageOperationError")<{
|
|
10
8
|
readonly operation: string;
|
|
11
9
|
readonly cause: unknown;
|
|
@@ -17,9 +15,6 @@ export class StorageOperationError extends Data.TaggedError("StorageOperationErr
|
|
|
17
15
|
|
|
18
16
|
type StorageEffect<A> = Effect.Effect<A, StorageOperationError>;
|
|
19
17
|
|
|
20
|
-
/**
|
|
21
|
-
* Effect wrapper for Cloudflare SQL cursor operations.
|
|
22
|
-
*/
|
|
23
18
|
export interface SqlCursor<T extends Record<string, SqlStorageValue>> {
|
|
24
19
|
next(): StorageEffect<{ done?: false; value: T } | { done: true; value?: never }>;
|
|
25
20
|
toArray(): StorageEffect<Array<T>>;
|
|
@@ -30,11 +25,7 @@ export interface SqlCursor<T extends Record<string, SqlStorageValue>> {
|
|
|
30
25
|
readonly rowsWritten: StorageEffect<number>;
|
|
31
26
|
}
|
|
32
27
|
|
|
33
|
-
/**
|
|
34
|
-
* Effect wrapper for Durable Object SQLite APIs.
|
|
35
|
-
*/
|
|
36
28
|
export interface SqlStorage {
|
|
37
|
-
/** Executes a SQL statement and returns a typed cursor. */
|
|
38
29
|
exec<T extends Record<string, SqlStorageValue>>(
|
|
39
30
|
query: string,
|
|
40
31
|
...bindings: Array<SqlStorageValue>
|
|
@@ -42,9 +33,6 @@ export interface SqlStorage {
|
|
|
42
33
|
readonly databaseSize: number;
|
|
43
34
|
}
|
|
44
35
|
|
|
45
|
-
/**
|
|
46
|
-
* Schema pair used by `SyncKvStorage.schema(...)`.
|
|
47
|
-
*/
|
|
48
36
|
export interface SyncKvDefinition<Key, Value, EncodedValue> {
|
|
49
37
|
readonly key: S.Codec<Key, string>;
|
|
50
38
|
readonly value: S.Codec<Value, EncodedValue>;
|
|
@@ -60,9 +48,6 @@ export interface SchemaBackedSyncKvStorage<Key, Value> {
|
|
|
60
48
|
list(options?: globalThis.SyncKvListOptions): Effect.Effect<Array<[Key, Value]>, unknown>;
|
|
61
49
|
}
|
|
62
50
|
|
|
63
|
-
/**
|
|
64
|
-
* Effect wrapper for synchronous KV attached to Durable Object SQLite storage.
|
|
65
|
-
*/
|
|
66
51
|
export interface SyncKvStorage {
|
|
67
52
|
get<T = unknown>(key: string): StorageEffect<T | undefined>;
|
|
68
53
|
put<T>(key: string, value: T): StorageEffect<void>;
|
|
@@ -99,7 +84,6 @@ export interface DurableObjectTransaction {
|
|
|
99
84
|
scheduledTime: number | Date,
|
|
100
85
|
options?: globalThis.DurableObjectSetAlarmOptions,
|
|
101
86
|
): StorageEffect<void>;
|
|
102
|
-
/** Schedules the alarm after a delay measured by the Effect clock. */
|
|
103
87
|
setAlarmAfter(
|
|
104
88
|
delay: Duration.Input,
|
|
105
89
|
options?: globalThis.DurableObjectSetAlarmOptions,
|
|
@@ -107,19 +91,6 @@ export interface DurableObjectTransaction {
|
|
|
107
91
|
deleteAlarm(options?: globalThis.DurableObjectSetAlarmOptions): StorageEffect<void>;
|
|
108
92
|
}
|
|
109
93
|
|
|
110
|
-
/**
|
|
111
|
-
* Effect wrapper around Cloudflare Durable Object storage.
|
|
112
|
-
*
|
|
113
|
-
* @example
|
|
114
|
-
* ```ts
|
|
115
|
-
* const program = Effect.gen(function* () {
|
|
116
|
-
* const state = yield* DurableObjectState;
|
|
117
|
-
* yield* state.storage.put("counter", 1);
|
|
118
|
-
* const value = yield* state.storage.get<number>("counter");
|
|
119
|
-
* return value;
|
|
120
|
-
* });
|
|
121
|
-
* ```
|
|
122
|
-
*/
|
|
123
94
|
export interface DurableObjectStorage {
|
|
124
95
|
get<T = unknown>(
|
|
125
96
|
key: string,
|
|
@@ -137,7 +108,6 @@ export interface DurableObjectStorage {
|
|
|
137
108
|
scheduledTime: number | Date,
|
|
138
109
|
options?: globalThis.DurableObjectSetAlarmOptions,
|
|
139
110
|
): StorageEffect<void>;
|
|
140
|
-
/** Schedules the alarm after a delay measured by the Effect clock. */
|
|
141
111
|
setAlarmAfter(
|
|
142
112
|
delay: Duration.Input,
|
|
143
113
|
options?: globalThis.DurableObjectSetAlarmOptions,
|
|
@@ -161,9 +131,9 @@ export interface DurableObjectStorage {
|
|
|
161
131
|
): Effect.Effect<A, E | StorageOperationError, R>;
|
|
162
132
|
/** Flushes pending writes to disk. */
|
|
163
133
|
sync(): StorageEffect<void>;
|
|
164
|
-
/** SQLite-backed Durable Object storage
|
|
134
|
+
/** Requires SQLite-backed Durable Object storage. */
|
|
165
135
|
getCurrentBookmark(): StorageEffect<string>;
|
|
166
|
-
/** SQLite-backed Durable Object storage
|
|
136
|
+
/** Requires SQLite-backed Durable Object storage. */
|
|
167
137
|
onNextSessionRestoreBookmark(bookmark: string): StorageEffect<string>;
|
|
168
138
|
readonly sql: SqlStorage;
|
|
169
139
|
readonly kv: SyncKvStorage;
|
|
@@ -329,9 +299,6 @@ const fromDurableObjectTransaction = (
|
|
|
329
299
|
tryStoragePromise("transaction.deleteAlarm", () => txn.deleteAlarm(options)),
|
|
330
300
|
}) as DurableObjectTransaction;
|
|
331
301
|
|
|
332
|
-
/**
|
|
333
|
-
* Wraps native Cloudflare storage APIs as Effect-returning helpers.
|
|
334
|
-
*/
|
|
335
302
|
export const fromDurableObjectStorage = (
|
|
336
303
|
storage: globalThis.DurableObjectStorage,
|
|
337
304
|
): DurableObjectStorage => ({
|
|
@@ -3,10 +3,8 @@ import { Data, Effect, Option, Result, Schema as S } from "effect";
|
|
|
3
3
|
import { DurableObjectState } from "./DurableObjectState";
|
|
4
4
|
import * as ErrorMessage from "./internal/ErrorMessage";
|
|
5
5
|
|
|
6
|
-
/** Data supported by Cloudflare websocket `send`. */
|
|
7
6
|
export type DurableWebSocketSendData = string | ArrayBuffer | ArrayBufferView;
|
|
8
7
|
|
|
9
|
-
/** Error raised when sending on a Durable Object websocket fails. */
|
|
10
8
|
export class DurableWebSocketSendError extends Data.TaggedError("DurableWebSocketSendError")<{
|
|
11
9
|
readonly cause: unknown;
|
|
12
10
|
}> {
|
|
@@ -15,7 +13,6 @@ export class DurableWebSocketSendError extends Data.TaggedError("DurableWebSocke
|
|
|
15
13
|
}
|
|
16
14
|
}
|
|
17
15
|
|
|
18
|
-
/** Error raised when closing a Durable Object websocket fails. */
|
|
19
16
|
export class DurableWebSocketCloseError extends Data.TaggedError("DurableWebSocketCloseError")<{
|
|
20
17
|
readonly cause: unknown;
|
|
21
18
|
}> {
|
|
@@ -36,13 +33,9 @@ export class DurableWebSocketAttachmentError extends Data.TaggedError(
|
|
|
36
33
|
}
|
|
37
34
|
}
|
|
38
35
|
|
|
39
|
-
/** Effect-native wrapper around a hibernatable Durable Object websocket. */
|
|
40
36
|
export interface DurableWebSocket<Attachment = unknown> {
|
|
41
|
-
/** Underlying Cloudflare websocket. */
|
|
42
37
|
readonly raw: WebSocket;
|
|
43
|
-
/** Sends a message through the socket. */
|
|
44
38
|
send(data: DurableWebSocketSendData): Effect.Effect<void, DurableWebSocketSendError>;
|
|
45
|
-
/** Closes the socket. */
|
|
46
39
|
close(code?: number, reason?: string): Effect.Effect<void, DurableWebSocketCloseError>;
|
|
47
40
|
/** Serializes hibernation attachment metadata onto the socket. */
|
|
48
41
|
serializeAttachment<A = Attachment>(
|
|
@@ -54,7 +47,6 @@ export interface DurableWebSocket<Attachment = unknown> {
|
|
|
54
47
|
|
|
55
48
|
const wrappers = new WeakMap<WebSocket, DurableWebSocket<unknown>>();
|
|
56
49
|
|
|
57
|
-
/** Wraps a native Cloudflare websocket in the Effect-native Durable Object API. */
|
|
58
50
|
export const fromWebSocket = <Attachment = unknown>(
|
|
59
51
|
raw: WebSocket,
|
|
60
52
|
): DurableWebSocket<Attachment> => {
|
|
@@ -94,37 +86,18 @@ export const fromWebSocket = <Attachment = unknown>(
|
|
|
94
86
|
return socket as DurableWebSocket<Attachment>;
|
|
95
87
|
};
|
|
96
88
|
|
|
97
|
-
/**
|
|
98
|
-
* Options for accepting an incoming websocket request in a Durable Object.
|
|
99
|
-
*/
|
|
100
89
|
export interface AcceptUpgradeOptions<Attachment = unknown> {
|
|
101
|
-
/** Optional websocket tags for Durable Object hibernation filtering. */
|
|
102
90
|
readonly tags?: ReadonlyArray<string> | undefined;
|
|
103
91
|
/** Optional attachment serialized onto the server socket. */
|
|
104
92
|
readonly attachment?: Attachment | undefined;
|
|
105
93
|
}
|
|
106
94
|
|
|
107
|
-
/**
|
|
108
|
-
* Result of a websocket upgrade accepted by {@link acceptUpgrade}.
|
|
109
|
-
*/
|
|
110
95
|
export interface AcceptedUpgrade<Attachment = unknown> {
|
|
111
96
|
readonly client: WebSocket;
|
|
112
97
|
readonly server: DurableWebSocket<Attachment>;
|
|
113
98
|
readonly response: Response;
|
|
114
99
|
}
|
|
115
100
|
|
|
116
|
-
/**
|
|
117
|
-
* Accepts a websocket upgrade and registers the server socket on `DurableObjectState`.
|
|
118
|
-
*
|
|
119
|
-
* @example
|
|
120
|
-
* ```ts
|
|
121
|
-
* const response = yield* DurableObjectWebSocket.acceptUpgrade({
|
|
122
|
-
* tags: ["room:general"],
|
|
123
|
-
* });
|
|
124
|
-
*
|
|
125
|
-
* return response.response;
|
|
126
|
-
* ```
|
|
127
|
-
*/
|
|
128
101
|
export const acceptUpgrade = Effect.fn("DurableObjectWebSocket.acceptUpgrade")(function* <
|
|
129
102
|
Attachment = unknown,
|
|
130
103
|
>(
|
|
@@ -158,9 +131,7 @@ export const acceptUpgrade = Effect.fn("DurableObjectWebSocket.acceptUpgrade")(f
|
|
|
158
131
|
export type AttachmentInvalidPolicy = "ignore" | "ignore-and-close" | "fail";
|
|
159
132
|
|
|
160
133
|
export interface AttachmentRehydrateOptions {
|
|
161
|
-
/** Optional Durable Object websocket tag filter. */
|
|
162
134
|
readonly tag?: string | undefined;
|
|
163
|
-
/** Invalid attachment behavior. Defaults to skipping invalid sockets. */
|
|
164
135
|
readonly onInvalid?: AttachmentInvalidPolicy | undefined;
|
|
165
136
|
}
|
|
166
137
|
|
|
@@ -187,7 +158,6 @@ export interface DurableWebSocketAttachment<Attachment, Encoded> {
|
|
|
187
158
|
readonly schema: S.Codec<Attachment, Encoded, never, never>;
|
|
188
159
|
}
|
|
189
160
|
|
|
190
|
-
/** Creates typed attachment helpers for accepted and rehydrated sockets. */
|
|
191
161
|
export const attachment = <const AttachmentSchema extends S.Codec<any, any, never, never>>(
|
|
192
162
|
schema: AttachmentSchema,
|
|
193
163
|
): DurableWebSocketAttachment<
|
|
@@ -267,7 +237,6 @@ export interface DurableWebSocketHandlers<R = never, E = unknown> {
|
|
|
267
237
|
readonly error?: (socket: DurableWebSocket, cause: unknown) => Effect.Effect<void, E, R>;
|
|
268
238
|
}
|
|
269
239
|
|
|
270
|
-
/** Maps compact websocket lifecycle handler names to `DurableObject.make` options. */
|
|
271
240
|
export const handlers = <R = never, E = unknown>(options: DurableWebSocketHandlers<R, E>) => ({
|
|
272
241
|
webSocketMessage: options.message,
|
|
273
242
|
webSocketClose: options.close,
|