effect-cf 0.0.4 → 0.2.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/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./chunk-CfYAbeIz.mjs";
2
- import { Cause, Config, ConfigProvider, Context, Data, Effect, Exit, Layer, ManagedRuntime, Option, Queue, Schema } from "effect";
3
- import { DurableObject, RpcStub, RpcTarget, WorkerEntrypoint } from "cloudflare:workers";
2
+ import { Cause, Clock, Config, ConfigProvider, Context, Data, DateTime, Duration, Effect, Exit, Layer, ManagedRuntime, Option, Queue, Schema } from "effect";
3
+ import { DurableObject, RpcStub, RpcTarget, WorkerEntrypoint, WorkflowEntrypoint } from "cloudflare:workers";
4
4
  import { HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
5
5
  import * as RpcMessage from "effect/unstable/rpc/RpcMessage";
6
6
  import * as RpcSerialization from "effect/unstable/rpc/RpcSerialization";
@@ -28,11 +28,11 @@ let WorkerConfig;
28
28
  var Binding_exports = /* @__PURE__ */ __exportAll({
29
29
  BindingNotFoundError: () => BindingNotFoundError,
30
30
  BindingValidationError: () => BindingValidationError,
31
- Service: () => Service$3,
32
- TypeId: () => TypeId$3
31
+ Service: () => Service$5,
32
+ TypeId: () => TypeId$5
33
33
  });
34
34
  /** Internal type id marker used by binding helper services. */
35
- const TypeId$3 = "effect-cf/Binding";
35
+ const TypeId$5 = "effect-cf/Binding";
36
36
  /** Error raised when a configured binding does not exist on `env`. */
37
37
  var BindingNotFoundError = class extends Data.TaggedError("BindingNotFoundError") {};
38
38
  /** Error raised when a binding exists but does not match the expected shape. */
@@ -48,18 +48,167 @@ const getBinding = (env, binding, isResource) => Effect.gen(function* () {
48
48
  /**
49
49
  * Creates a Context tag + layer for reading and validating a Cloudflare binding.
50
50
  */
51
- const Service$3 = () => (id, binding, isResource) => {
51
+ const Service$5 = () => (id, binding, isResource) => {
52
52
  const tag = Context.Service()(id);
53
53
  const layer = Layer.effect(tag, Effect.gen(function* () {
54
54
  return yield* getBinding(yield* WorkerEnvironment, binding, isResource);
55
55
  }));
56
56
  return Object.assign(tag, {
57
- [TypeId$3]: TypeId$3,
57
+ [TypeId$5]: TypeId$5,
58
58
  binding,
59
59
  layer
60
60
  });
61
61
  };
62
62
  //#endregion
63
+ //#region src/QueueBinding.ts
64
+ var QueueBinding_exports = /* @__PURE__ */ __exportAll({
65
+ QueueOperationError: () => QueueOperationError,
66
+ Service: () => Service$4,
67
+ make: () => make$10
68
+ });
69
+ const TypeId$4 = "effect-cf/QueueBinding";
70
+ var QueueOperationError = class extends Data.TaggedError("QueueOperationError") {};
71
+ const queueError = (binding, operation, cause) => new QueueOperationError({
72
+ binding,
73
+ operation,
74
+ cause
75
+ });
76
+ const tryQueuePromise = (binding, operation, evaluate) => Effect.tryPromise({
77
+ try: evaluate,
78
+ catch: (cause) => queueError(binding, operation, cause)
79
+ });
80
+ const isQueue = (value) => {
81
+ if (typeof value !== "object" || value === null) return false;
82
+ const resource = value;
83
+ return typeof resource.send === "function" && typeof resource.sendBatch === "function" && typeof resource.metrics === "function";
84
+ };
85
+ /** Creates a typed Queue binding service tag plus Effect helpers. */
86
+ const make$10 = (id, definition) => Service$4()(id, definition);
87
+ /**
88
+ * Builds an Effect service around a Cloudflare Queue producer binding.
89
+ */
90
+ const Service$4 = () => (id, definition) => {
91
+ const tag = Service$5()(id, definition.binding, (value) => isQueue(value));
92
+ const encodeMessage = Schema.encodeEffect(definition.message);
93
+ const send = Effect.fnUntraced(function* (message, options) {
94
+ const queue = yield* tag;
95
+ const encoded = yield* encodeMessage(message);
96
+ return yield* tryQueuePromise(definition.binding, "send", () => queue.send(encoded, options));
97
+ });
98
+ const sendBatch = Effect.fnUntraced(function* (messages, options) {
99
+ const queue = yield* tag;
100
+ const encodedMessages = [];
101
+ for (const message of messages) encodedMessages.push({
102
+ ...message,
103
+ body: yield* encodeMessage(message.body)
104
+ });
105
+ return yield* tryQueuePromise(definition.binding, "sendBatch", () => queue.sendBatch(encodedMessages, options));
106
+ });
107
+ const metrics = Effect.fnUntraced(function* () {
108
+ const queue = yield* tag;
109
+ return yield* tryQueuePromise(definition.binding, "metrics", () => queue.metrics());
110
+ });
111
+ return Object.assign(tag, {
112
+ [TypeId$4]: TypeId$4,
113
+ binding: definition.binding,
114
+ send,
115
+ sendBatch,
116
+ metrics
117
+ });
118
+ };
119
+ //#endregion
120
+ //#region src/QueueDefinition.ts
121
+ var QueueDefinition_exports = /* @__PURE__ */ __exportAll({
122
+ Queue: () => Queue$1,
123
+ Tag: () => Tag$7,
124
+ implement: () => implement$7,
125
+ make: () => make$9
126
+ });
127
+ const makeDefinition$3 = (id, definition) => {
128
+ const queueDefinition = {
129
+ id,
130
+ message: definition.message
131
+ };
132
+ return Object.assign(queueDefinition, {
133
+ make: (layer, options) => make$6(layer, {
134
+ ...options,
135
+ queue: wrapHandler$1(queueDefinition, options.queue)
136
+ }),
137
+ Binding: () => (bindingId, binding) => Service$4()(bindingId, {
138
+ ...binding,
139
+ message: definition.message
140
+ }),
141
+ binding: (bindingId, binding) => Service$4()(bindingId, {
142
+ ...binding,
143
+ message: definition.message
144
+ })
145
+ });
146
+ };
147
+ const make$9 = makeDefinition$3;
148
+ const Tag$7 = () => (id, definition) => {
149
+ const queueDefinition = makeDefinition$3(id, definition);
150
+ class QueueDefinitionClass {
151
+ static id = queueDefinition.id;
152
+ static message = queueDefinition.message;
153
+ static make = queueDefinition.make;
154
+ static Binding = queueDefinition.Binding;
155
+ static binding = queueDefinition.binding;
156
+ }
157
+ return QueueDefinitionClass;
158
+ };
159
+ const Queue$1 = Tag$7;
160
+ const wrapHandler$1 = (definition, handler) => {
161
+ const decodeBody = Schema.decodeUnknownEffect(definition.message);
162
+ return (batch) => Effect.gen(function* () {
163
+ yield* handler(yield* decodeBatch(batch.raw, decodeBody));
164
+ });
165
+ };
166
+ const implement$7 = (_definition, handler) => handler;
167
+ //#endregion
168
+ //#region src/Queue.ts
169
+ var Queue_exports = /* @__PURE__ */ __exportAll({
170
+ QueueMessageDecodeError: () => QueueMessageDecodeError,
171
+ Tag: () => Tag$6,
172
+ decodeBatch: () => decodeBatch,
173
+ fromMessage: () => fromMessage,
174
+ fromMessageBatch: () => fromMessageBatch,
175
+ implement: () => implement$6
176
+ });
177
+ var QueueMessageDecodeError = class extends Data.TaggedError("QueueMessageDecodeError") {};
178
+ const fromMessage = (message, body) => ({
179
+ raw: message,
180
+ id: message.id,
181
+ timestamp: message.timestamp,
182
+ body,
183
+ attempts: message.attempts,
184
+ ack: Effect.sync(() => message.ack()),
185
+ retry: (options) => Effect.sync(() => message.retry(options))
186
+ });
187
+ const fromMessageBatch = (batch, messages) => ({
188
+ raw: batch,
189
+ messages,
190
+ queue: batch.queue,
191
+ metadata: batch.metadata,
192
+ ackAll: Effect.sync(() => batch.ackAll()),
193
+ retryAll: (options) => Effect.sync(() => batch.retryAll(options))
194
+ });
195
+ const decodeBatch = (batch, decodeBody) => Effect.gen(function* () {
196
+ const messages = [];
197
+ for (let index = 0; index < batch.messages.length; index++) {
198
+ const message = batch.messages[index];
199
+ const body = yield* decodeBody(message.body).pipe(Effect.mapError((cause) => new QueueMessageDecodeError({
200
+ queue: batch.queue,
201
+ messageId: message.id,
202
+ index,
203
+ cause
204
+ })));
205
+ messages.push(fromMessage(message, body));
206
+ }
207
+ return fromMessageBatch(batch, messages);
208
+ });
209
+ const Tag$6 = Tag$7;
210
+ const implement$6 = implement$7;
211
+ //#endregion
63
212
  //#region src/RpcDefinition.ts
64
213
  var RpcDefinition_exports = /* @__PURE__ */ __exportAll({
65
214
  ReservedMethodNameError: () => ReservedMethodNameError,
@@ -75,7 +224,7 @@ var RpcDefinition_exports = /* @__PURE__ */ __exportAll({
75
224
  decodeSuccess: () => decodeSuccess,
76
225
  encodeArgs: () => encodeArgs,
77
226
  encodeSuccess: () => encodeSuccess,
78
- make: () => make$5,
227
+ make: () => make$8,
79
228
  method: () => method$4,
80
229
  reservedMethodNames: () => reservedMethodNames$4
81
230
  });
@@ -178,7 +327,7 @@ const decodeSuccess = (definition, methodName, value) => {
178
327
  cause
179
328
  })));
180
329
  };
181
- const make$5 = (id, methods) => {
330
+ const make$8 = (id, methods) => {
182
331
  const definition = {
183
332
  id,
184
333
  methods
@@ -232,11 +381,11 @@ const invokeRpcMethod = (target, method, args, makeError) => Effect.gen(function
232
381
  //#endregion
233
382
  //#region src/ServiceBinding.ts
234
383
  var ServiceBinding_exports = /* @__PURE__ */ __exportAll({
235
- Service: () => Service$2,
384
+ Service: () => Service$3,
236
385
  ServiceBindingFetchError: () => ServiceBindingFetchError,
237
386
  ServiceBindingRpcError: () => ServiceBindingRpcError
238
387
  });
239
- const TypeId$2 = "effect-cf/ServiceBinding";
388
+ const TypeId$3 = "effect-cf/ServiceBinding";
240
389
  /**
241
390
  * Failure raised when calling `fetch` on a service binding.
242
391
  */
@@ -271,8 +420,8 @@ var ServiceBindingRpcError = class extends Data.TaggedError("ServiceBindingRpcEr
271
420
  * });
272
421
  * ```
273
422
  */
274
- const Service$2 = () => (id, definition) => {
275
- const tag = Service$3()(id, definition.binding, (value) => typeof value === "object" && value !== null && "fetch" in value);
423
+ const Service$3 = () => (id, definition) => {
424
+ const tag = Service$5()(id, definition.binding, (value) => typeof value === "object" && value !== null && "fetch" in value);
276
425
  const fetch = (input, init) => Effect.gen(function* () {
277
426
  const service = yield* tag;
278
427
  return yield* Effect.tryPromise({
@@ -315,7 +464,7 @@ const Service$2 = () => (id, definition) => {
315
464
  });
316
465
  const directMethods = makeDirectMethods$1(definition.definition, call);
317
466
  return Object.assign(tag, directMethods, {
318
- [TypeId$2]: TypeId$2,
467
+ [TypeId$3]: TypeId$3,
319
468
  definition,
320
469
  fetch,
321
470
  rpc,
@@ -331,10 +480,10 @@ const makeDirectMethods$1 = (rpcDefinition, call) => {
331
480
  //#endregion
332
481
  //#region src/WorkerDefinition.ts
333
482
  var WorkerDefinition_exports = /* @__PURE__ */ __exportAll({
334
- Tag: () => Tag$3,
483
+ Tag: () => Tag$5,
335
484
  Worker: () => Worker,
336
- implement: () => implement$3,
337
- make: () => make$4,
485
+ implement: () => implement$5,
486
+ make: () => make$7,
338
487
  method: () => method$3
339
488
  });
340
489
  const reservedMethodNames$3 = new Set([
@@ -342,6 +491,12 @@ const reservedMethodNames$3 = new Set([
342
491
  "dup",
343
492
  "fetch",
344
493
  "connect",
494
+ "queue",
495
+ "scheduled",
496
+ "tail",
497
+ "tailStream",
498
+ "test",
499
+ "trace",
345
500
  "alarm",
346
501
  "webSocketMessage",
347
502
  "webSocketClose",
@@ -364,27 +519,27 @@ const method$3 = method$4;
364
519
  * });
365
520
  * ```
366
521
  */
367
- const makeDefinition$1 = (id, methods) => {
522
+ const makeDefinition$2 = (id, methods) => {
368
523
  assertNoReservedMethods("Worker", methods, reservedMethodNames$3);
369
- const definition = make$5(id, methods);
524
+ const definition = make$8(id, methods);
370
525
  return Object.assign(definition, {
371
- make: (layer, options) => make$3(layer, {
526
+ make: (layer, options) => make$6(layer, {
372
527
  ...options,
373
528
  rpc: wrapHandlers$1(definition, options.rpc)
374
529
  }),
375
- Binding: () => (bindingId, binding) => Service$2()(bindingId, {
530
+ Binding: () => (bindingId, binding) => Service$3()(bindingId, {
376
531
  ...binding,
377
532
  definition
378
533
  }),
379
- binding: (bindingId, binding) => Service$2()(bindingId, {
534
+ binding: (bindingId, binding) => Service$3()(bindingId, {
380
535
  ...binding,
381
536
  definition
382
537
  })
383
538
  });
384
539
  };
385
- const make$4 = makeDefinition$1;
386
- const Tag$3 = () => (id, methods) => {
387
- const definition = makeDefinition$1(id, methods);
540
+ const make$7 = makeDefinition$2;
541
+ const Tag$5 = () => (id, methods) => {
542
+ const definition = makeDefinition$2(id, methods);
388
543
  class WorkerDefinitionClass {
389
544
  static id = definition.id;
390
545
  static methods = definition.methods;
@@ -394,7 +549,7 @@ const Tag$3 = () => (id, methods) => {
394
549
  }
395
550
  return WorkerDefinitionClass;
396
551
  };
397
- const Worker = Tag$3;
552
+ const Worker = Tag$5;
398
553
  const wrapHandlers$1 = (definition, handlers) => {
399
554
  const wrapped = {};
400
555
  for (const key of Object.keys(definition.methods)) {
@@ -408,7 +563,7 @@ const wrapHandlers$1 = (definition, handlers) => {
408
563
  /**
409
564
  * Helper for implementing handlers with the exact method shape of a definition.
410
565
  */
411
- const implement$3 = (_definition, handlers) => handlers;
566
+ const implement$5 = (_definition, handlers) => handlers;
412
567
  //#endregion
413
568
  //#region src/internal/Entrypoint.ts
414
569
  const provideEntrypointServices = (layer, services) => layer.pipe(Layer.provideMerge(services));
@@ -424,34 +579,43 @@ const defineEntrypointRpcMethods = (target, prototype, rpc, reservedMethodNames,
424
579
  };
425
580
  const assumeEntrypointClass = (entrypoint) => entrypoint;
426
581
  //#endregion
582
+ //#region src/internal/WorkerContext.ts
583
+ const causeError = (cause) => new Error(Cause.pretty(cause));
584
+ const failureHandler = (cause, options) => (options?.onFailure?.(cause) ?? Effect.logError("WorkerContext.waitUntil failed", Cause.pretty(cause))).pipe(Effect.catchCause((handlerCause) => Effect.logError("WorkerContext.waitUntil failure handler failed", Cause.pretty(cause), Cause.pretty(handlerCause))));
585
+ const fromExecutionContext = (ctx, runPromiseExit) => {
586
+ const schedule = (effect, options, mode) => Effect.context().pipe(Effect.flatMap((context) => Effect.sync(() => {
587
+ const runHandler = (cause) => runPromiseExit(Effect.scoped(Effect.provideContext(failureHandler(cause, options), context))).then((exit) => {
588
+ if (Exit.isFailure(exit)) console.error("WorkerContext.waitUntil failure handler failed", Cause.pretty(exit.cause));
589
+ });
590
+ ctx.waitUntil(runPromiseExit(Effect.scoped(Effect.provideContext(effect, context))).then(async (exit) => {
591
+ if (Exit.isSuccess(exit)) return;
592
+ await runHandler(exit.cause);
593
+ if (mode === "propagate") throw causeError(exit.cause);
594
+ }));
595
+ })));
596
+ return {
597
+ raw: ctx,
598
+ waitUntil: (effect, options) => schedule(effect, options, options?.mode ?? "observe"),
599
+ waitUntilPropagating: (effect, options) => schedule(effect, options, "propagate"),
600
+ passThroughOnException: Effect.sync(() => ctx.passThroughOnException())
601
+ };
602
+ };
603
+ //#endregion
427
604
  //#region src/Worker.ts
428
605
  var Worker_exports = /* @__PURE__ */ __exportAll({
429
606
  ExecutionContext: () => ExecutionContext,
430
607
  NativeRequest: () => NativeRequest,
431
- Tag: () => Tag$2,
608
+ Tag: () => Tag$4,
432
609
  WorkerContext: () => WorkerContext,
433
- implement: () => implement$2,
610
+ implement: () => implement$4,
434
611
  isWebSocketUpgrade: () => isWebSocketUpgrade,
435
- make: () => make$3,
612
+ make: () => make$6,
436
613
  makeFetchHandler: () => makeFetchHandler,
437
614
  method: () => method$2,
438
615
  renderHttpResponse: () => renderHttpResponse
439
616
  });
440
617
  var ExecutionContext = class extends Context.Service()("effect-cf/ExecutionContext") {};
441
618
  var WorkerContext = class extends Context.Service()("effect-cf/WorkerContext") {};
442
- const fromExecutionContext = (ctx, runPromiseExit) => ({
443
- raw: ctx,
444
- waitUntil: (effect, options) => Effect.context().pipe(Effect.flatMap((context) => Effect.sync(() => {
445
- const observed = Effect.exit(effect).pipe(Effect.flatMap((exit) => {
446
- if (Exit.isSuccess(exit)) return Effect.void;
447
- return (options?.onFailure?.(exit.cause) ?? Effect.logError("WorkerContext.waitUntil failed", Cause.pretty(exit.cause))).pipe(Effect.catchCause((handlerCause) => Effect.logError("WorkerContext.waitUntil failure handler failed", Cause.pretty(exit.cause), Cause.pretty(handlerCause))));
448
- }));
449
- ctx.waitUntil(runPromiseExit(Effect.scoped(Effect.provideContext(observed, context))).then((exit) => {
450
- if (Exit.isFailure(exit)) console.error("WorkerContext.waitUntil failure handler failed", Cause.pretty(exit.cause));
451
- }));
452
- }))),
453
- passThroughOnException: Effect.sync(() => ctx.passThroughOnException())
454
- });
455
619
  var NativeRequest = class extends Context.Service()("effect-cf/NativeRequest") {};
456
620
  const isWebSocketUpgrade = (request) => request.headers.get("Upgrade")?.toLowerCase() === "websocket";
457
621
  const reservedMethodNames$2 = new Set([
@@ -459,6 +623,12 @@ const reservedMethodNames$2 = new Set([
459
623
  "dup",
460
624
  "fetch",
461
625
  "connect",
626
+ "queue",
627
+ "scheduled",
628
+ "tail",
629
+ "tailStream",
630
+ "test",
631
+ "trace",
462
632
  "alarm",
463
633
  "webSocketMessage",
464
634
  "webSocketClose",
@@ -467,12 +637,14 @@ const reservedMethodNames$2 = new Set([
467
637
  const RunSymbol$1 = Symbol.for("effect-cf/Worker/run");
468
638
  const renderHttpResponse = (effect) => Effect.flatMap(effect, (response) => Effect.map(Effect.context(), (context) => HttpServerResponse.toWeb(response, { context })));
469
639
  const renderFetchSuccess = (effect) => Effect.flatMap(effect, (response) => response instanceof Response ? Effect.succeed(response) : Effect.map(Effect.context(), (context) => HttpServerResponse.toWeb(response, { context })));
470
- const make$3 = (layer, options) => {
640
+ const isWorkerOptions = (options) => typeof options === "object" && options !== null && ("fetch" in options || "queue" in options || "rpc" in options);
641
+ function make$6(layer, optionsOrFetch) {
642
+ const options = isWorkerOptions(optionsOrFetch) ? optionsOrFetch : { fetch: optionsOrFetch };
471
643
  class EffectWorker extends WorkerEntrypoint {
472
644
  runtime;
473
645
  constructor(ctx, env) {
474
646
  super(ctx, env);
475
- let runWaitUntilEffect = () => Promise.resolve(Exit.die(/* @__PURE__ */ new Error("WorkerContext runtime is not initialized")));
647
+ let runWaitUntilEffect = () => Promise.reject(/* @__PURE__ */ new Error("WorkerContext runtime is not initialized"));
476
648
  const runtimeLayer = provideEntrypointServices(layer, Layer.mergeAll(Layer.succeed(ExecutionContext, ctx), ConfigProvider.layer(Effect.succeed(WorkerConfig.providerFromEnv(env))), Layer.succeed(WorkerContext, fromExecutionContext(ctx, (effect) => runWaitUntilEffect(effect))), Layer.succeed(WorkerEnvironment, env)));
477
649
  this.runtime = ManagedRuntime.make(runtimeLayer);
478
650
  runWaitUntilEffect = (effect) => this.runtime.runPromiseExit(effect);
@@ -486,17 +658,23 @@ const make$3 = (layer, options) => {
486
658
  const requestServices = Layer.mergeAll(Layer.succeed(NativeRequest, request), Layer.succeed(HttpServerRequest.HttpServerRequest, HttpServerRequest.fromWeb(request)));
487
659
  return this[RunSymbol$1](renderFetchSuccess(fetchHandler).pipe(Effect.provide(requestServices)));
488
660
  }
661
+ queue(batch) {
662
+ const queueHandler = options.queue;
663
+ if (queueHandler === void 0) return Promise.resolve();
664
+ const messages = batch.messages.map((message) => fromMessage(message, message.body));
665
+ return this[RunSymbol$1](queueHandler(fromMessageBatch(batch, messages)));
666
+ }
489
667
  }
490
668
  defineEntrypointRpcMethods("Worker", EffectWorker.prototype, options.rpc, reservedMethodNames$2, (self, effect) => self[RunSymbol$1](effect));
491
669
  return assumeEntrypointClass(EffectWorker);
492
- };
670
+ }
493
671
  const makeFetchHandler = (layer, options) => {
494
- const WorkerClass = make$3(layer, options);
672
+ const WorkerClass = make$6(layer, options);
495
673
  return { fetch: (request, env, ctx) => Promise.resolve(new WorkerClass(ctx, env).fetch(request)) };
496
674
  };
497
- const Tag$2 = Tag$3;
675
+ const Tag$4 = Tag$5;
498
676
  const method$2 = method$3;
499
- const implement$2 = implement$3;
677
+ const implement$4 = implement$5;
500
678
  //#endregion
501
679
  //#region src/DurableObjectStorage.ts
502
680
  var DurableObjectStorage_exports = /* @__PURE__ */ __exportAll({
@@ -620,6 +798,138 @@ const fromDurableObjectStorage = (storage) => ({
620
798
  kv: fromSyncKvStorage(storage.kv)
621
799
  });
622
800
  //#endregion
801
+ //#region src/DurableObjectWebSocket.ts
802
+ var DurableObjectWebSocket_exports = /* @__PURE__ */ __exportAll({
803
+ DurableWebSocketAttachmentError: () => DurableWebSocketAttachmentError,
804
+ DurableWebSocketCloseError: () => DurableWebSocketCloseError,
805
+ DurableWebSocketSendError: () => DurableWebSocketSendError,
806
+ acceptUpgrade: () => acceptUpgrade,
807
+ attachment: () => attachment,
808
+ fromWebSocket: () => fromWebSocket,
809
+ handlers: () => handlers
810
+ });
811
+ /** Error raised when sending on a Durable Object websocket fails. */
812
+ var DurableWebSocketSendError = class extends Data.TaggedError("DurableWebSocketSendError") {};
813
+ /** Error raised when closing a Durable Object websocket fails. */
814
+ var DurableWebSocketCloseError = class extends Data.TaggedError("DurableWebSocketCloseError") {};
815
+ /** Error raised when serializing or deserializing a websocket attachment fails. */
816
+ var DurableWebSocketAttachmentError = class extends Data.TaggedError("DurableWebSocketAttachmentError") {};
817
+ const wrappers = /* @__PURE__ */ new WeakMap();
818
+ /** Wraps a native Cloudflare websocket in the Effect-native Durable Object API. */
819
+ const fromWebSocket = (raw) => {
820
+ const existing = wrappers.get(raw);
821
+ if (existing !== void 0) return existing;
822
+ const socket = {
823
+ raw,
824
+ send: (data) => Effect.try({
825
+ try: () => raw.send(data),
826
+ catch: (cause) => new DurableWebSocketSendError({ cause })
827
+ }),
828
+ close: (code, reason) => Effect.try({
829
+ try: () => raw.close(code, reason),
830
+ catch: (cause) => new DurableWebSocketCloseError({ cause })
831
+ }),
832
+ serializeAttachment: (value) => Effect.try({
833
+ try: () => raw.serializeAttachment(value),
834
+ catch: (cause) => new DurableWebSocketAttachmentError({
835
+ operation: "serialize",
836
+ cause
837
+ })
838
+ }),
839
+ deserializeAttachment: Effect.try({
840
+ try: () => raw.deserializeAttachment(),
841
+ catch: (cause) => new DurableWebSocketAttachmentError({
842
+ operation: "deserialize",
843
+ cause
844
+ })
845
+ })
846
+ };
847
+ wrappers.set(raw, socket);
848
+ return socket;
849
+ };
850
+ /**
851
+ * Accepts a websocket upgrade and registers the server socket on `DurableObjectState`.
852
+ *
853
+ * @example
854
+ * ```ts
855
+ * const response = yield* DurableObjectWebSocket.acceptUpgrade({
856
+ * tags: ["room:general"],
857
+ * });
858
+ *
859
+ * return response.response;
860
+ * ```
861
+ */
862
+ const acceptUpgrade = (options = {}) => Effect.gen(function* () {
863
+ const state = yield* DurableObjectState;
864
+ const pair = new WebSocketPair();
865
+ const client = pair[0];
866
+ const server = fromWebSocket(pair[1]);
867
+ if (options.attachment !== void 0) server.raw.serializeAttachment(options.attachment);
868
+ yield* state.acceptWebSocket(server, options.tags === void 0 ? void 0 : [...options.tags]);
869
+ return {
870
+ client,
871
+ server,
872
+ response: new Response(null, {
873
+ status: 101,
874
+ webSocket: client
875
+ })
876
+ };
877
+ });
878
+ /** Creates typed attachment helpers for accepted and rehydrated sockets. */
879
+ const attachment = (schema) => {
880
+ const serialize = (socket, value) => Schema.encodeEffect(schema)(value).pipe(Effect.mapError((cause) => new DurableWebSocketAttachmentError({
881
+ operation: "serialize",
882
+ cause
883
+ })), Effect.flatMap((encoded) => socket.serializeAttachment(encoded)));
884
+ const deserialize = (socket) => Effect.gen(function* () {
885
+ const value = yield* socket.deserializeAttachment;
886
+ if (value == null) return Option.none();
887
+ return Option.some(yield* Schema.decodeUnknownEffect(schema)(value).pipe(Effect.mapError((cause) => new DurableWebSocketAttachmentError({
888
+ operation: "deserialize",
889
+ cause
890
+ }))));
891
+ });
892
+ const rehydrate = (options = {}) => Effect.gen(function* () {
893
+ const sockets = yield* (yield* DurableObjectState).getWebSockets(options.tag);
894
+ const restored = [];
895
+ const onInvalid = options.onInvalid ?? "ignore";
896
+ for (const socket of sockets) {
897
+ const decoded = yield* deserialize(socket).pipe(Effect.match({
898
+ onFailure: (error) => ({
899
+ _tag: "Failure",
900
+ error
901
+ }),
902
+ onSuccess: (value) => ({
903
+ _tag: "Success",
904
+ value
905
+ })
906
+ }));
907
+ if (decoded._tag === "Success" && Option.isSome(decoded.value)) {
908
+ restored.push({
909
+ socket,
910
+ attachment: decoded.value.value
911
+ });
912
+ continue;
913
+ }
914
+ if (decoded._tag === "Failure" && onInvalid === "fail") return yield* Effect.fail(decoded.error);
915
+ if (decoded._tag === "Failure" && onInvalid === "ignore-and-close") yield* socket.close(1008, "invalid websocket attachment").pipe(Effect.ignore);
916
+ }
917
+ return restored;
918
+ });
919
+ return {
920
+ serialize,
921
+ deserialize,
922
+ rehydrate,
923
+ schema
924
+ };
925
+ };
926
+ /** Adapts wrapped websocket lifecycle handlers to `DurableObject.make` raw callbacks. */
927
+ const handlers = (options) => ({
928
+ webSocketMessage: options.message === void 0 ? void 0 : (socket, message) => options.message?.(fromWebSocket(socket), message) ?? Effect.void,
929
+ webSocketClose: options.close === void 0 ? void 0 : (socket, code, reason, wasClean) => options.close?.(fromWebSocket(socket), code, reason, wasClean) ?? Effect.void,
930
+ webSocketError: options.error === void 0 ? void 0 : (socket, error) => options.error?.(fromWebSocket(socket), error) ?? Effect.void
931
+ });
932
+ //#endregion
623
933
  //#region src/DurableObjectState.ts
624
934
  var DurableObjectState_exports = /* @__PURE__ */ __exportAll({
625
935
  DurableObjectState: () => DurableObjectState,
@@ -639,14 +949,14 @@ const fromDurableObjectState = (state) => ({
639
949
  waitUntil: (promise) => Effect.sync(() => state.waitUntil(promise)),
640
950
  blockConcurrencyWhile: (effect) => Effect.context().pipe(Effect.flatMap((context) => Effect.promise(() => state.blockConcurrencyWhile(() => runPromiseExitPreservingTypedFailures(Effect.provideContext(effect, context))))), Effect.flatten),
641
951
  blockConcurrencyWhileOrReset: (effect) => Effect.context().pipe(Effect.flatMap((context) => Effect.promise(() => state.blockConcurrencyWhile(() => Effect.runPromise(Effect.provideContext(effect, context)))))),
642
- acceptWebSocket: (ws, tags) => Effect.sync(() => state.acceptWebSocket(ws, tags)),
643
- getWebSockets: (tag) => Effect.sync(() => state.getWebSockets(tag)),
952
+ acceptWebSocket: (ws, tags) => Effect.sync(() => state.acceptWebSocket(ws.raw, tags)),
953
+ getWebSockets: (tag) => Effect.sync(() => state.getWebSockets(tag).map((socket) => fromWebSocket(socket))),
644
954
  setWebSocketAutoResponse: (pair) => Effect.sync(() => state.setWebSocketAutoResponse(pair)),
645
955
  getWebSocketAutoResponse: Effect.sync(() => state.getWebSocketAutoResponse()),
646
- getWebSocketAutoResponseTimestamp: (ws) => Effect.sync(() => state.getWebSocketAutoResponseTimestamp(ws)),
956
+ getWebSocketAutoResponseTimestamp: (ws) => Effect.sync(() => state.getWebSocketAutoResponseTimestamp(ws.raw)),
647
957
  setHibernatableWebSocketEventTimeout: (timeoutMs) => Effect.sync(() => state.setHibernatableWebSocketEventTimeout(timeoutMs)),
648
958
  getHibernatableWebSocketEventTimeout: Effect.sync(() => state.getHibernatableWebSocketEventTimeout()),
649
- getTags: (ws) => Effect.sync(() => state.getTags(ws)),
959
+ getTags: (ws) => Effect.sync(() => state.getTags(ws.raw)),
650
960
  abort: (reason) => Effect.sync(() => state.abort(reason))
651
961
  });
652
962
  const runPromiseExitPreservingTypedFailures = async (effect) => {
@@ -659,9 +969,9 @@ const runPromiseExitPreservingTypedFailures = async (effect) => {
659
969
  var DurableObjectNamespace_exports = /* @__PURE__ */ __exportAll({
660
970
  DurableObjectFetchError: () => DurableObjectFetchError,
661
971
  DurableObjectRpcError: () => DurableObjectRpcError,
662
- Service: () => Service$1
972
+ Service: () => Service$2
663
973
  });
664
- const TypeId$1 = "effect-cf/DurableObjectNamespace";
974
+ const TypeId$2 = "effect-cf/DurableObjectNamespace";
665
975
  /**
666
976
  * Failure raised when invoking an RPC method on a Durable Object stub.
667
977
  */
@@ -693,10 +1003,10 @@ var DurableObjectFetchError = class extends Data.TaggedError("DurableObjectFetch
693
1003
  * });
694
1004
  * ```
695
1005
  */
696
- const Service$1 = () => (id, definition) => {
1006
+ const Service$2 = () => (id, definition) => {
697
1007
  const hasFunction = (value, key) => typeof Reflect.get(value, key) === "function";
698
1008
  const isDurableObjectNamespaceClient = (value) => typeof value === "object" && value !== null && hasFunction(value, "getByName") && hasFunction(value, "get") && hasFunction(value, "idFromName") && hasFunction(value, "idFromString") && hasFunction(value, "newUniqueId") && hasFunction(value, "jurisdiction");
699
- const tag = Service$3()(id, definition.binding, (value) => isDurableObjectNamespaceClient(value));
1009
+ const tag = Service$5()(id, definition.binding, (value) => isDurableObjectNamespaceClient(value));
700
1010
  const newUniqueId = Effect.fnUntraced(function* (options) {
701
1011
  return (yield* tag).newUniqueId(options);
702
1012
  });
@@ -758,7 +1068,7 @@ const Service$1 = () => (id, definition) => {
758
1068
  getByName
759
1069
  });
760
1070
  return Object.assign(tag, directMethods, {
761
- [TypeId$1]: TypeId$1,
1071
+ [TypeId$2]: TypeId$2,
762
1072
  definition,
763
1073
  newUniqueId,
764
1074
  idFromName,
@@ -796,9 +1106,9 @@ const makeDirectMethods = (rpcDefinition, helpers) => {
796
1106
  //#region src/DurableObjectDefinition.ts
797
1107
  var DurableObjectDefinition_exports = /* @__PURE__ */ __exportAll({
798
1108
  DurableObject: () => DurableObject$1,
799
- Tag: () => Tag$1,
800
- implement: () => implement$1,
801
- make: () => make$2,
1109
+ Tag: () => Tag$3,
1110
+ implement: () => implement$3,
1111
+ make: () => make$5,
802
1112
  method: () => method$1
803
1113
  });
804
1114
  const reservedMethodNames$1 = new Set([
@@ -827,27 +1137,27 @@ const method$1 = method$4;
827
1137
  * });
828
1138
  * ```
829
1139
  */
830
- const makeDefinition = (id, methods) => {
1140
+ const makeDefinition$1 = (id, methods) => {
831
1141
  assertNoReservedMethods("Durable Object", methods, reservedMethodNames$1);
832
- const definition = make$5(id, methods);
1142
+ const definition = make$8(id, methods);
833
1143
  return Object.assign(definition, {
834
- make: (layer, options) => make$1(layer, {
1144
+ make: (layer, options) => make$4(layer, {
835
1145
  ...options,
836
1146
  rpc: wrapHandlers(definition, options.rpc)
837
1147
  }),
838
- Namespace: () => (bindingId, binding) => Service$1()(bindingId, {
1148
+ Namespace: () => (bindingId, binding) => Service$2()(bindingId, {
839
1149
  ...binding,
840
1150
  definition
841
1151
  }),
842
- namespace: (bindingId, binding) => Service$1()(bindingId, {
1152
+ namespace: (bindingId, binding) => Service$2()(bindingId, {
843
1153
  ...binding,
844
1154
  definition
845
1155
  })
846
1156
  });
847
1157
  };
848
- const make$2 = makeDefinition;
849
- const Tag$1 = () => (id, methods) => {
850
- const definition = makeDefinition(id, methods);
1158
+ const make$5 = makeDefinition$1;
1159
+ const Tag$3 = () => (id, methods) => {
1160
+ const definition = makeDefinition$1(id, methods);
851
1161
  class DurableObjectDefinitionClass {
852
1162
  static id = definition.id;
853
1163
  static methods = definition.methods;
@@ -857,7 +1167,7 @@ const Tag$1 = () => (id, methods) => {
857
1167
  }
858
1168
  return DurableObjectDefinitionClass;
859
1169
  };
860
- const DurableObject$1 = Tag$1;
1170
+ const DurableObject$1 = Tag$3;
861
1171
  const wrapHandlers = (definition, handlers) => {
862
1172
  const wrapped = {};
863
1173
  for (const key of Object.keys(definition.methods)) {
@@ -871,13 +1181,13 @@ const wrapHandlers = (definition, handlers) => {
871
1181
  /**
872
1182
  * Helper for implementing handlers with the exact method shape of a definition.
873
1183
  */
874
- const implement$1 = (_definition, handlers) => handlers;
1184
+ const implement$3 = (_definition, handlers) => handlers;
875
1185
  //#endregion
876
1186
  //#region src/DurableObject.ts
877
1187
  var DurableObject_exports = /* @__PURE__ */ __exportAll({
878
- Tag: () => Tag,
879
- implement: () => implement,
880
- make: () => make$1,
1188
+ Tag: () => Tag$2,
1189
+ implement: () => implement$2,
1190
+ make: () => make$4,
881
1191
  method: () => method
882
1192
  });
883
1193
  const reservedMethodNames = new Set([
@@ -893,7 +1203,7 @@ const RunSymbol = Symbol.for("effect-cf/DurableObject/run");
893
1203
  /**
894
1204
  * Creates a Durable Object class backed by a single managed Effect runtime.
895
1205
  */
896
- const make$1 = (layer, options = {}) => {
1206
+ const make$4 = (layer, options = {}) => {
897
1207
  class EffectDurableObject extends DurableObject {
898
1208
  runtime;
899
1209
  constructor(state, env) {
@@ -910,7 +1220,14 @@ const make$1 = (layer, options = {}) => {
910
1220
  return this[RunSymbol](Effect.provideService(fetchHandler, NativeRequest, request));
911
1221
  }
912
1222
  alarm(alarmInfo) {
913
- if (options.alarm !== void 0) return this[RunSymbol](options.alarm(alarmInfo));
1223
+ const logicalAlarms = options.alarms?.pipe(Effect.asVoid);
1224
+ const rawAlarm = options.alarm?.(alarmInfo);
1225
+ if (logicalAlarms !== void 0 && rawAlarm !== void 0) return this[RunSymbol](Effect.gen(function* () {
1226
+ yield* logicalAlarms;
1227
+ yield* rawAlarm;
1228
+ }));
1229
+ if (logicalAlarms !== void 0) return this[RunSymbol](logicalAlarms);
1230
+ if (rawAlarm !== void 0) return this[RunSymbol](rawAlarm);
914
1231
  }
915
1232
  webSocketMessage(socket, message) {
916
1233
  if (options.webSocketMessage !== void 0) return this[RunSymbol](options.webSocketMessage(socket, message));
@@ -925,9 +1242,331 @@ const make$1 = (layer, options = {}) => {
925
1242
  defineEntrypointRpcMethods("Durable Object", EffectDurableObject.prototype, options.rpc, reservedMethodNames, (self, effect) => self[RunSymbol](effect));
926
1243
  return assumeEntrypointClass(EffectDurableObject);
927
1244
  };
928
- const Tag = Tag$1;
1245
+ const Tag$2 = Tag$3;
929
1246
  const method = method$1;
930
- const implement = implement$1;
1247
+ const implement$2 = implement$3;
1248
+ //#endregion
1249
+ //#region src/DurableObjectAlarm.ts
1250
+ var DurableObjectAlarm_exports = /* @__PURE__ */ __exportAll({
1251
+ DurableObjectAlarm: () => DurableObjectAlarm,
1252
+ DurableObjectAlarmEvent: () => DurableObjectAlarmEvent,
1253
+ InvalidAlarmPayloadError: () => InvalidAlarmPayloadError,
1254
+ InvalidAlarmRefError: () => InvalidAlarmRefError,
1255
+ InvalidProcessDueAlarmsOptionsError: () => InvalidProcessDueAlarmsOptionsError,
1256
+ InvalidRepeatEveryError: () => InvalidRepeatEveryError,
1257
+ StoredAlarmDecodeError: () => StoredAlarmDecodeError,
1258
+ define: () => define,
1259
+ process: () => process,
1260
+ processDue: () => processDue
1261
+ });
1262
+ const INIT_TABLE_SQL = `
1263
+ CREATE TABLE IF NOT EXISTS effect_cf_scheduled_alarms (
1264
+ storage_id TEXT PRIMARY KEY,
1265
+ alarm_id TEXT NOT NULL,
1266
+ tag TEXT NOT NULL,
1267
+ run_at INTEGER NOT NULL,
1268
+ repeat_every_ms INTEGER,
1269
+ payload TEXT NOT NULL
1270
+ );
1271
+ CREATE INDEX IF NOT EXISTS idx_effect_cf_scheduled_alarms_run_at_storage_id
1272
+ ON effect_cf_scheduled_alarms (run_at, storage_id);
1273
+ `;
1274
+ const DEFAULT_PROCESS_DUE_ALARMS_LIMIT = 100;
1275
+ const DEFAULT_PROCESS_DUE_ALARMS_FAILURE_RESCHEDULE_AFTER = "30 seconds";
1276
+ const getScheduledEventId = (input) => `effect-cf-alarm:${encodeURIComponent(input.tag)}:${encodeURIComponent(input.id)}`;
1277
+ var InvalidAlarmRefError = class extends Data.TaggedError("InvalidAlarmRefError") {};
1278
+ var InvalidAlarmPayloadError = class extends Data.TaggedError("InvalidAlarmPayloadError") {};
1279
+ var InvalidRepeatEveryError = class extends Data.TaggedError("InvalidRepeatEveryError") {};
1280
+ var InvalidProcessDueAlarmsOptionsError = class extends Data.TaggedError("InvalidProcessDueAlarmsOptionsError") {};
1281
+ var StoredAlarmDecodeError = class extends Data.TaggedError("StoredAlarmDecodeError") {};
1282
+ /**
1283
+ * Events handled by `processDueAlarms`.
1284
+ *
1285
+ * `AlarmDue` represents one durable alarm whose scheduled time is now due. The
1286
+ * `tag` is the consumer-owned routing key, while `id` is the stable alarm id
1287
+ * within that tag.
1288
+ *
1289
+ * `scheduledAt` is the logical due-after timestamp from durable storage. It is
1290
+ * not expected to match the current Durable Object alarm invocation time,
1291
+ * especially during retries. Retries re-scan durable rows with `run_at <= now`
1292
+ * and identify logical events by `{ tag, id }`.
1293
+ *
1294
+ * @example Handling events by tag
1295
+ * ```ts
1296
+ * yield* durableObjectAlarm.processDueAlarms((event) =>
1297
+ * event.tag === "heartbeat"
1298
+ * ? heartbeatManager.handleAlarmEvent(event).pipe(Effect.asVoid)
1299
+ * : Effect.void
1300
+ * );
1301
+ * ```
1302
+ */
1303
+ const DurableObjectAlarmEvent = Schema.TaggedUnion({ AlarmDue: {
1304
+ id: Schema.NonEmptyString,
1305
+ payload: Schema.Json,
1306
+ scheduledAt: Schema.DateTimeUtc,
1307
+ tag: Schema.NonEmptyString
1308
+ } });
1309
+ const AlarmRefSchema = Schema.Struct({
1310
+ id: Schema.NonEmptyString,
1311
+ tag: Schema.NonEmptyString
1312
+ });
1313
+ const decodeAlarmRef = (input) => Schema.decodeUnknownEffect(AlarmRefSchema)(input).pipe(Effect.mapError((cause) => new InvalidAlarmRefError({ cause })));
1314
+ const StoredPayloadString = Schema.fromJsonString(Schema.Json);
1315
+ const decodeStoredPayload = (row) => Schema.decodeUnknownEffect(StoredPayloadString)(row.payload).pipe(Effect.mapError((cause) => new StoredAlarmDecodeError({
1316
+ cause,
1317
+ storageId: row.storage_id
1318
+ })));
1319
+ const encodeStoredPayload = (payload) => Schema.encodeEffect(StoredPayloadString)(payload).pipe(Effect.mapError((cause) => new InvalidAlarmPayloadError({ cause })));
1320
+ const ensureTable = (state) => state.storage.sql.exec(INIT_TABLE_SQL).pipe(Effect.asVoid);
1321
+ const toRepeatEveryMillis = (input) => {
1322
+ if (input === void 0) return Effect.succeed(null);
1323
+ return Effect.try({
1324
+ try: () => {
1325
+ const millis = Duration.toMillis(Duration.fromInputUnsafe(input));
1326
+ if (!Number.isFinite(millis) || millis <= 0) throw new Error("Alarm repeatEvery must be a positive finite duration");
1327
+ return Math.ceil(millis);
1328
+ },
1329
+ catch: (cause) => new InvalidRepeatEveryError({ cause })
1330
+ });
1331
+ };
1332
+ const toAlarmDue = (row) => Effect.gen(function* () {
1333
+ if (!Number.isFinite(row.run_at)) return yield* Effect.fail(new StoredAlarmDecodeError({
1334
+ cause: /* @__PURE__ */ new Error("Stored alarm run_at must be a finite number"),
1335
+ storageId: row.storage_id
1336
+ }));
1337
+ return DurableObjectAlarmEvent.make({
1338
+ _tag: "AlarmDue",
1339
+ id: row.alarm_id,
1340
+ payload: yield* decodeStoredPayload(row),
1341
+ scheduledAt: DateTime.toUtc(DateTime.makeUnsafe(row.run_at)),
1342
+ tag: row.tag
1343
+ });
1344
+ });
1345
+ const getProcessLimit = (options) => {
1346
+ const limit = options?.limit ?? DEFAULT_PROCESS_DUE_ALARMS_LIMIT;
1347
+ if (!Number.isSafeInteger(limit) || limit <= 0) return Effect.fail(new InvalidProcessDueAlarmsOptionsError({ cause: /* @__PURE__ */ new Error("processDueAlarms limit must be a positive safe integer") }));
1348
+ return Effect.succeed(limit);
1349
+ };
1350
+ const toFailureRescheduleMillis = (input) => Effect.try({
1351
+ try: () => {
1352
+ const millis = Duration.toMillis(Duration.fromInputUnsafe(input));
1353
+ if (!Number.isFinite(millis) || millis <= 0) throw new Error("Alarm failure rescheduleAfter must be a positive finite duration");
1354
+ return Math.ceil(millis);
1355
+ },
1356
+ catch: (cause) => new InvalidProcessDueAlarmsOptionsError({ cause })
1357
+ });
1358
+ const getFailureRetryDelay = (options) => toFailureRescheduleMillis(options?.retryFailedAfter ?? DEFAULT_PROCESS_DUE_ALARMS_FAILURE_RESCHEDULE_AFTER);
1359
+ const getFailureActionMode = (action) => typeof action === "string" ? action : action.mode;
1360
+ const getFailureActionRetryDelay = (action) => typeof action === "string" || action.mode !== "retry" ? void 0 : action.retryFailedAfter;
1361
+ const processDue = (handle, options = {}) => Effect.gen(function* () {
1362
+ return yield* (yield* DurableObjectAlarm).processDueAlarms(handle, options);
1363
+ });
1364
+ const process = processDue;
1365
+ const isAlarmDefinitionConfig = (definition) => typeof definition === "object" && definition !== null && "payload" in definition;
1366
+ const getAlarmDefinitionSchema = (definition) => isAlarmDefinitionConfig(definition) ? definition.payload : definition;
1367
+ const getAlarmDefinitionFailureAction = (definition) => {
1368
+ if (definition === void 0 || !isAlarmDefinitionConfig(definition)) return;
1369
+ if (definition.failure === void 0) return;
1370
+ return definition.failure === "retry" ? {
1371
+ mode: "retry",
1372
+ retryFailedAfter: definition.retry?.initialDelay
1373
+ } : { mode: definition.failure };
1374
+ };
1375
+ const define = (definitions) => ({ handlers: (handlers, options) => processDue((event) => Effect.gen(function* () {
1376
+ const definition = definitions[event.tag];
1377
+ if (definition === void 0) return;
1378
+ const schema = getAlarmDefinitionSchema(definition);
1379
+ const payload = yield* Schema.decodeUnknownEffect(schema)(event.payload).pipe(Effect.mapError((cause) => new StoredAlarmDecodeError({
1380
+ cause,
1381
+ storageId: getScheduledEventId(event)
1382
+ })));
1383
+ const handler = handlers[event.tag];
1384
+ yield* handler({
1385
+ ...event,
1386
+ payload
1387
+ });
1388
+ }), {
1389
+ ...options,
1390
+ onFailure: (failure) => Effect.gen(function* () {
1391
+ const action = getAlarmDefinitionFailureAction(definitions[failure.tag]);
1392
+ const optionAction = options?.onFailure === void 0 ? void 0 : yield* options.onFailure(failure);
1393
+ return action ?? optionAction;
1394
+ })
1395
+ }) });
1396
+ /**
1397
+ * SQLite-backed Durable Object alarm scheduler.
1398
+ *
1399
+ * `DurableObjectAlarm` stores alarms in the current Durable Object's SQLite storage
1400
+ * and keeps the platform alarm set to the earliest pending scheduled alarm. The
1401
+ * platform alarm timestamp is only a wake-up hint; logical event identity comes
1402
+ * from persisted `{ tag, id }` rows.
1403
+ *
1404
+ * Retry safety depends on acknowledgement ordering. `processDueAlarms` runs the
1405
+ * caller's handler first and only then conditionally deletes or advances the
1406
+ * same selected row. By default, handler failures are isolated: the failed row
1407
+ * is retried after a delay, later due rows continue, and the platform alarm is
1408
+ * reconciled once at the end. Use `mode: "ordered"` for strict workflows where
1409
+ * one failed logical alarm should block later due alarms.
1410
+ *
1411
+ * Provide `DurableObjectAlarm.layer` anywhere `DurableObjectState` is available.
1412
+ *
1413
+ * @example Providing the service
1414
+ * ```ts
1415
+ * const program = Effect.gen(function* () {
1416
+ * const durableObjectAlarm = yield* DurableObjectAlarm;
1417
+ * const now = yield* DateTime.now;
1418
+ *
1419
+ * yield* durableObjectAlarm.scheduleAlarm({
1420
+ * tag: "heartbeat",
1421
+ * id: "heartbeat-check",
1422
+ * runAt: DateTime.add(now, { seconds: 5 }),
1423
+ * repeatEvery: Duration.seconds(5),
1424
+ * payload: null,
1425
+ * });
1426
+ * }).pipe(Effect.provide(DurableObjectAlarm.layer));
1427
+ * ```
1428
+ *
1429
+ * @example Processing due alarms
1430
+ * ```ts
1431
+ * const handledEvents = yield* durableObjectAlarm.processDueAlarms((event) =>
1432
+ * Effect.gen(function* () {
1433
+ * if (event.tag === "heartbeat") {
1434
+ * yield* heartbeatManager.handleAlarmEvent(event);
1435
+ * }
1436
+ * })
1437
+ * );
1438
+ * ```
1439
+ */
1440
+ var DurableObjectAlarm = class DurableObjectAlarm extends Context.Service()("effect-cf/DurableObjectAlarm") {
1441
+ static layer = Layer.effect(DurableObjectAlarm, Effect.gen(function* () {
1442
+ const state = yield* DurableObjectState;
1443
+ const reconcileAlarm = Effect.fn("DurableObjectAlarm.reconcileAlarm")(function* () {
1444
+ const next = (yield* (yield* state.storage.sql.exec(`SELECT run_at FROM effect_cf_scheduled_alarms ORDER BY run_at ASC, storage_id ASC LIMIT 1`)).toArray())[0];
1445
+ if (next === void 0) {
1446
+ yield* state.storage.deleteAlarm();
1447
+ return;
1448
+ }
1449
+ yield* state.storage.setAlarm(next.run_at);
1450
+ });
1451
+ const rescheduleFailedAlarm = Effect.fn("DurableObjectAlarm.rescheduleFailedAlarm")(function* (row, retryDelayMillis) {
1452
+ const retryAt = (yield* Clock.currentTimeMillis) + retryDelayMillis;
1453
+ if (row.repeat_every_ms === null) {
1454
+ yield* (yield* state.storage.sql.exec(`UPDATE effect_cf_scheduled_alarms
1455
+ SET run_at = ?
1456
+ WHERE storage_id = ?
1457
+ AND run_at = ?
1458
+ AND repeat_every_ms IS NULL
1459
+ AND payload = ?`, retryAt, row.storage_id, row.run_at, row.payload)).rowsWritten;
1460
+ return;
1461
+ }
1462
+ yield* (yield* state.storage.sql.exec(`UPDATE effect_cf_scheduled_alarms
1463
+ SET run_at = ?
1464
+ WHERE storage_id = ?
1465
+ AND run_at = ?
1466
+ AND repeat_every_ms = ?
1467
+ AND payload = ?`, retryAt, row.storage_id, row.run_at, row.repeat_every_ms, row.payload)).rowsWritten;
1468
+ });
1469
+ const acknowledgeAlarm = Effect.fn("DurableObjectAlarm.acknowledgeAlarm")(function* (row) {
1470
+ if (row.repeat_every_ms === null) {
1471
+ yield* (yield* state.storage.sql.exec(`DELETE FROM effect_cf_scheduled_alarms
1472
+ WHERE storage_id = ?
1473
+ AND run_at = ?
1474
+ AND repeat_every_ms IS NULL
1475
+ AND payload = ?`, row.storage_id, row.run_at, row.payload)).rowsWritten;
1476
+ return;
1477
+ }
1478
+ const acknowledgedAt = yield* Clock.currentTimeMillis;
1479
+ yield* (yield* state.storage.sql.exec(`UPDATE effect_cf_scheduled_alarms
1480
+ SET run_at = ?
1481
+ WHERE storage_id = ?
1482
+ AND run_at = ?
1483
+ AND repeat_every_ms = ?
1484
+ AND payload = ?`, acknowledgedAt + row.repeat_every_ms, row.storage_id, row.run_at, row.repeat_every_ms, row.payload)).rowsWritten;
1485
+ });
1486
+ const cancelAlarm = Effect.fn("DurableObjectAlarm.cancelAlarm")(function* (input) {
1487
+ const ref = yield* decodeAlarmRef(input);
1488
+ yield* state.storage.transaction(() => Effect.gen(function* () {
1489
+ yield* ensureTable(state);
1490
+ yield* state.storage.sql.exec(`DELETE FROM effect_cf_scheduled_alarms WHERE storage_id = ?`, getScheduledEventId(ref)).pipe(Effect.asVoid);
1491
+ yield* reconcileAlarm();
1492
+ }));
1493
+ });
1494
+ const scheduleAlarm = Effect.fn("DurableObjectAlarm.scheduleAlarm")(function* (input) {
1495
+ const ref = yield* decodeAlarmRef(input);
1496
+ const repeatEveryMillis = yield* toRepeatEveryMillis(input.repeatEvery);
1497
+ const payload = yield* encodeStoredPayload(input.payload);
1498
+ const runAt = DateTime.toEpochMillis(input.runAt);
1499
+ yield* state.storage.transaction(() => Effect.gen(function* () {
1500
+ yield* ensureTable(state);
1501
+ yield* state.storage.sql.exec(`INSERT OR REPLACE INTO effect_cf_scheduled_alarms
1502
+ (storage_id, alarm_id, tag, run_at, repeat_every_ms, payload)
1503
+ VALUES (?, ?, ?, ?, ?, ?)`, getScheduledEventId(ref), ref.id, ref.tag, runAt, repeatEveryMillis, payload).pipe(Effect.asVoid);
1504
+ yield* reconcileAlarm();
1505
+ }));
1506
+ });
1507
+ const processDueAlarms = Effect.fn("DurableObjectAlarm.processDueAlarms")(function* (handle, options) {
1508
+ yield* ensureTable(state);
1509
+ const mode = options?.mode ?? "isolated";
1510
+ const limit = yield* getProcessLimit(options);
1511
+ const now = yield* Clock.currentTimeMillis;
1512
+ const dueRows = yield* (yield* state.storage.sql.exec(`SELECT storage_id, alarm_id, tag, run_at, repeat_every_ms, payload
1513
+ FROM effect_cf_scheduled_alarms
1514
+ WHERE run_at <= ?
1515
+ ORDER BY run_at ASC, storage_id ASC
1516
+ LIMIT ?`, now, limit)).toArray();
1517
+ const handled = [];
1518
+ const failed = [];
1519
+ const handleFailure = function* (row, event, cause) {
1520
+ const failure = {
1521
+ cause,
1522
+ event,
1523
+ id: row.alarm_id,
1524
+ storageId: row.storage_id,
1525
+ tag: row.tag
1526
+ };
1527
+ failed.push(failure);
1528
+ const failureAction = options?.onFailure === void 0 ? void 0 : yield* options.onFailure(failure);
1529
+ const actionMode = failureAction === void 0 ? mode : getFailureActionMode(failureAction);
1530
+ if (actionMode === "retry" || actionMode === "isolated") {
1531
+ const actionRetryDelay = failureAction === void 0 ? void 0 : getFailureActionRetryDelay(failureAction);
1532
+ yield* rescheduleFailedAlarm(row, actionRetryDelay === void 0 ? yield* getFailureRetryDelay(options) : yield* toFailureRescheduleMillis(actionRetryDelay));
1533
+ return "continue";
1534
+ }
1535
+ if (actionMode === "skip-and-advance-repeat") {
1536
+ yield* acknowledgeAlarm(row);
1537
+ return "continue";
1538
+ }
1539
+ yield* reconcileAlarm();
1540
+ return "stop";
1541
+ };
1542
+ for (const row of dueRows) {
1543
+ const eventExit = yield* Effect.exit(toAlarmDue(row));
1544
+ if (Exit.isFailure(eventExit)) {
1545
+ if ((yield* handleFailure(row, void 0, eventExit.cause)) === "stop") return yield* Effect.failCause(eventExit.cause);
1546
+ continue;
1547
+ }
1548
+ const event = eventExit.value;
1549
+ const handleExit = yield* Effect.exit(handle(event));
1550
+ if (Exit.isFailure(handleExit)) {
1551
+ if ((yield* handleFailure(row, event, handleExit.cause)) === "stop") return yield* Effect.failCause(handleExit.cause);
1552
+ continue;
1553
+ }
1554
+ yield* acknowledgeAlarm(row);
1555
+ handled.push(event);
1556
+ }
1557
+ yield* reconcileAlarm();
1558
+ return {
1559
+ failed,
1560
+ handled
1561
+ };
1562
+ });
1563
+ return DurableObjectAlarm.of({
1564
+ cancelAlarm,
1565
+ processDueAlarms,
1566
+ scheduleAlarm
1567
+ });
1568
+ }).pipe(Effect.withSpan("DurableObjectAlarm.layer")));
1569
+ };
931
1570
  //#endregion
932
1571
  //#region src/DurableObjectRpcWebSocket.ts
933
1572
  var DurableObjectRpcWebSocket_exports = /* @__PURE__ */ __exportAll({
@@ -955,32 +1594,32 @@ const layer = (options = {}) => Layer.effectContext(Effect.gen(function* () {
955
1594
  let nextClientId = 0;
956
1595
  let writeRequest;
957
1596
  const reserveClientId = (socket) => {
958
- const attachment = readAttachment(socket, attachmentKey);
1597
+ const attachment = readAttachment(socket.raw, attachmentKey);
959
1598
  if (attachment !== void 0) {
960
1599
  nextClientId = Math.max(nextClientId, attachment + 1);
961
1600
  return attachment;
962
1601
  }
963
1602
  const id = nextClientId++;
964
- writeAttachment(socket, attachmentKey, id);
1603
+ writeAttachment(socket.raw, attachmentKey, id);
965
1604
  return id;
966
1605
  };
967
1606
  const register = (socket) => {
968
- const existing = connectionsBySocket.get(socket);
1607
+ const existing = connectionsBySocket.get(socket.raw);
969
1608
  if (existing !== void 0) return existing;
970
1609
  const connection = {
971
1610
  id: reserveClientId(socket),
972
1611
  socket,
973
1612
  parser: serialization.makeUnsafe()
974
1613
  };
975
- connectionsBySocket.set(socket, connection);
1614
+ connectionsBySocket.set(socket.raw, connection);
976
1615
  connectionsById.set(connection.id, connection);
977
1616
  clientIds.add(connection.id);
978
1617
  return connection;
979
1618
  };
980
1619
  const unregister = (socket) => Effect.sync(() => {
981
- const connection = connectionsBySocket.get(socket);
1620
+ const connection = connectionsBySocket.get(socket.raw);
982
1621
  if (connection === void 0) return;
983
- connectionsBySocket.delete(socket);
1622
+ connectionsBySocket.delete(socket.raw);
984
1623
  connectionsById.delete(connection.id);
985
1624
  clientIds.delete(connection.id);
986
1625
  Queue.offerUnsafe(disconnects, connection.id);
@@ -989,10 +1628,10 @@ const layer = (options = {}) => Layer.effectContext(Effect.gen(function* () {
989
1628
  const send = (connection, response) => Effect.sync(() => {
990
1629
  try {
991
1630
  const encoded = connection.parser.encode(response);
992
- if (encoded !== void 0) connection.socket.send(encoded);
1631
+ if (encoded !== void 0) connection.socket.raw.send(encoded);
993
1632
  } catch (cause) {
994
1633
  const encoded = connection.parser.encode(RpcMessage.ResponseDefectEncoded(cause));
995
- if (encoded !== void 0) connection.socket.send(encoded);
1634
+ if (encoded !== void 0) connection.socket.raw.send(encoded);
996
1635
  }
997
1636
  });
998
1637
  const protocol = yield* RpcServer.Protocol.make((writeRequest_) => {
@@ -1004,7 +1643,7 @@ const layer = (options = {}) => Layer.effectContext(Effect.gen(function* () {
1004
1643
  return connection === void 0 ? Effect.void : send(connection, response);
1005
1644
  },
1006
1645
  end: (clientId) => Effect.sync(() => {
1007
- connectionsById.get(clientId)?.socket.close();
1646
+ connectionsById.get(clientId)?.socket.raw.close();
1008
1647
  }),
1009
1648
  clientIds: Effect.sync(() => clientIds),
1010
1649
  initialMessage: Effect.succeed(Option.none()),
@@ -1055,44 +1694,13 @@ const writeAttachment = (socket, key, clientId) => {
1055
1694
  });
1056
1695
  };
1057
1696
  //#endregion
1058
- //#region src/DurableObjectWebSocket.ts
1059
- var DurableObjectWebSocket_exports = /* @__PURE__ */ __exportAll({ acceptUpgrade: () => acceptUpgrade });
1060
- /**
1061
- * Accepts a websocket upgrade and registers the server socket on `DurableObjectState`.
1062
- *
1063
- * @example
1064
- * ```ts
1065
- * const response = yield* DurableObjectWebSocket.acceptUpgrade({
1066
- * tags: ["room:general"],
1067
- * });
1068
- *
1069
- * return response.response;
1070
- * ```
1071
- */
1072
- const acceptUpgrade = (options = {}) => Effect.gen(function* () {
1073
- const state = yield* DurableObjectState;
1074
- const pair = new WebSocketPair();
1075
- const client = pair[0];
1076
- const server = pair[1];
1077
- if (options.attachment !== void 0) server.serializeAttachment(options.attachment);
1078
- yield* state.acceptWebSocket(server, options.tags === void 0 ? void 0 : [...options.tags]);
1079
- return {
1080
- client,
1081
- server,
1082
- response: new Response(null, {
1083
- status: 101,
1084
- webSocket: client
1085
- })
1086
- };
1087
- });
1088
- //#endregion
1089
1697
  //#region src/Kv.ts
1090
1698
  var Kv_exports = /* @__PURE__ */ __exportAll({
1091
1699
  KvOperationError: () => KvOperationError,
1092
- Service: () => Service,
1093
- make: () => make
1700
+ Service: () => Service$1,
1701
+ make: () => make$3
1094
1702
  });
1095
- const TypeId = "effect-cf/Kv";
1703
+ const TypeId$1 = "effect-cf/Kv";
1096
1704
  /** Error raised when a KV operation fails. */
1097
1705
  var KvOperationError = class extends Data.TaggedError("KvOperationError") {};
1098
1706
  const maybeString = (value) => value == null ? Option.none() : Option.some(value);
@@ -1109,7 +1717,7 @@ const tryKvPromise = (binding, operation, evaluate) => Effect.tryPromise({
1109
1717
  /**
1110
1718
  * Creates a typed KV service tag plus Effect helpers.
1111
1719
  */
1112
- const make = (id, definition) => Service()(id, definition);
1720
+ const make$3 = (id, definition) => Service$1()(id, definition);
1113
1721
  /**
1114
1722
  * Builds a KV service around a Cloudflare KV namespace binding.
1115
1723
  *
@@ -1130,8 +1738,8 @@ const make = (id, definition) => Service()(id, definition);
1130
1738
  * });
1131
1739
  * ```
1132
1740
  */
1133
- const Service = () => (id, definition) => {
1134
- const tag = Service$3()(id, definition.binding, (value) => {
1741
+ const Service$1 = () => (id, definition) => {
1742
+ const tag = Service$5()(id, definition.binding, (value) => {
1135
1743
  if (typeof value !== "object" || value === null) return false;
1136
1744
  const resource = value;
1137
1745
  return typeof resource.get === "function" && typeof resource.put === "function" && typeof resource.delete === "function" && typeof resource.getWithMetadata === "function" && typeof resource.list === "function";
@@ -1196,7 +1804,7 @@ const Service = () => (id, definition) => {
1196
1804
  return yield* tag;
1197
1805
  });
1198
1806
  return Object.assign(tag, {
1199
- [TypeId]: TypeId,
1807
+ [TypeId$1]: TypeId$1,
1200
1808
  definition,
1201
1809
  put,
1202
1810
  get,
@@ -1207,4 +1815,214 @@ const Service = () => (id, definition) => {
1207
1815
  });
1208
1816
  };
1209
1817
  //#endregion
1210
- export { Binding_exports as Binding, DurableObject_exports as DurableObject, DurableObjectDefinition_exports as DurableObjectDefinition, DurableObjectNamespace_exports as DurableObjectNamespace, DurableObjectRpcWebSocket_exports as DurableObjectRpcWebSocket, DurableObjectState_exports as DurableObjectState, DurableObjectStorage_exports as DurableObjectStorage, DurableObjectWebSocket_exports as DurableObjectWebSocket, Kv_exports as Kv, Rpc_exports as Rpc, RpcDefinition_exports as RpcDefinition, ServiceBinding_exports as ServiceBinding, Worker_exports as Worker, WorkerConfig, WorkerDefinition_exports as WorkerDefinition, WorkerEnvironment };
1818
+ //#region src/WorkflowBinding.ts
1819
+ var WorkflowBinding_exports = /* @__PURE__ */ __exportAll({
1820
+ Service: () => Service,
1821
+ WorkflowOperationError: () => WorkflowOperationError,
1822
+ WorkflowResultDecodeError: () => WorkflowResultDecodeError,
1823
+ make: () => make$2
1824
+ });
1825
+ const TypeId = "effect-cf/WorkflowBinding";
1826
+ var WorkflowOperationError = class extends Data.TaggedError("WorkflowOperationError") {};
1827
+ var WorkflowResultDecodeError = class extends Data.TaggedError("WorkflowResultDecodeError") {};
1828
+ const workflowError = (binding, operation, cause) => new WorkflowOperationError({
1829
+ binding,
1830
+ operation,
1831
+ cause
1832
+ });
1833
+ const tryWorkflowPromise = (binding, operation, evaluate) => Effect.tryPromise({
1834
+ try: evaluate,
1835
+ catch: (cause) => workflowError(binding, operation, cause)
1836
+ });
1837
+ const isWorkflow = (value) => {
1838
+ if (typeof value !== "object" || value === null) return false;
1839
+ const resource = value;
1840
+ return typeof resource.create === "function" && typeof resource.createBatch === "function" && typeof resource.get === "function";
1841
+ };
1842
+ const make$2 = (id, definition) => Service()(id, definition);
1843
+ const Service = () => (id, definition) => {
1844
+ const tag = Service$5()(id, definition.binding, (value) => isWorkflow(value));
1845
+ const encodePayload = Schema.encodeEffect(definition.payload);
1846
+ const decodeResult = Schema.decodeUnknownEffect(definition.result);
1847
+ const wrapInstance = (raw) => {
1848
+ const operation = (name, evaluate) => tryWorkflowPromise(definition.binding, name, evaluate);
1849
+ return {
1850
+ raw,
1851
+ id: raw.id,
1852
+ pause: operation("pause", () => raw.pause()),
1853
+ resume: operation("resume", () => raw.resume()),
1854
+ terminate: operation("terminate", () => raw.terminate()),
1855
+ restart: (options) => operation("restart", () => raw.restart(options)),
1856
+ status: operation("status", () => raw.status()).pipe(Effect.flatMap((status) => Effect.gen(function* () {
1857
+ const output = status.output === void 0 ? Option.none() : Option.some(yield* decodeResult(status.output).pipe(Effect.mapError((cause) => new WorkflowResultDecodeError({
1858
+ binding: definition.binding,
1859
+ instanceId: raw.id,
1860
+ cause
1861
+ }))));
1862
+ return {
1863
+ status: status.status,
1864
+ output,
1865
+ error: status.error === void 0 ? Option.none() : Option.some(status.error)
1866
+ };
1867
+ }))),
1868
+ sendEvent: (event) => operation("sendEvent", () => raw.sendEvent(event))
1869
+ };
1870
+ };
1871
+ const create = Effect.fnUntraced(function* (payload, options) {
1872
+ const workflow = yield* tag;
1873
+ const encoded = yield* encodePayload(payload);
1874
+ return wrapInstance(yield* tryWorkflowPromise(definition.binding, "create", () => workflow.create({
1875
+ ...options,
1876
+ params: encoded
1877
+ })));
1878
+ });
1879
+ const createBatch = Effect.fnUntraced(function* (batch) {
1880
+ const workflow = yield* tag;
1881
+ const encodedBatch = [];
1882
+ for (const item of batch) {
1883
+ const { payload, ...options } = item;
1884
+ encodedBatch.push({
1885
+ ...options,
1886
+ params: yield* encodePayload(payload)
1887
+ });
1888
+ }
1889
+ return (yield* tryWorkflowPromise(definition.binding, "createBatch", () => workflow.createBatch(encodedBatch))).map(wrapInstance);
1890
+ });
1891
+ const get = Effect.fnUntraced(function* (instanceId) {
1892
+ const workflow = yield* tag;
1893
+ return wrapInstance(yield* tryWorkflowPromise(definition.binding, "get", () => workflow.get(instanceId)));
1894
+ });
1895
+ return Object.assign(tag, {
1896
+ [TypeId]: TypeId,
1897
+ binding: definition.binding,
1898
+ create,
1899
+ createBatch,
1900
+ get
1901
+ });
1902
+ };
1903
+ //#endregion
1904
+ //#region src/WorkflowDefinition.ts
1905
+ var WorkflowDefinition_exports = /* @__PURE__ */ __exportAll({
1906
+ Tag: () => Tag$1,
1907
+ Workflow: () => Workflow,
1908
+ implement: () => implement$1,
1909
+ make: () => make$1
1910
+ });
1911
+ const makeDefinition = (id, definition) => {
1912
+ const workflowDefinition = {
1913
+ id,
1914
+ payload: definition.payload,
1915
+ result: definition.result
1916
+ };
1917
+ return Object.assign(workflowDefinition, {
1918
+ make: (layer, options) => make(layer, { run: wrapHandler(workflowDefinition, options.run) }),
1919
+ Binding: () => (bindingId, binding) => Service()(bindingId, {
1920
+ ...binding,
1921
+ payload: definition.payload,
1922
+ result: definition.result
1923
+ }),
1924
+ binding: (bindingId, binding) => Service()(bindingId, {
1925
+ ...binding,
1926
+ payload: definition.payload,
1927
+ result: definition.result
1928
+ })
1929
+ });
1930
+ };
1931
+ const make$1 = makeDefinition;
1932
+ const Tag$1 = () => (id, definition) => {
1933
+ const workflowDefinition = makeDefinition(id, definition);
1934
+ class WorkflowDefinitionClass {
1935
+ static id = workflowDefinition.id;
1936
+ static payload = workflowDefinition.payload;
1937
+ static result = workflowDefinition.result;
1938
+ static make = workflowDefinition.make;
1939
+ static Binding = workflowDefinition.Binding;
1940
+ static binding = workflowDefinition.binding;
1941
+ }
1942
+ return WorkflowDefinitionClass;
1943
+ };
1944
+ const Workflow = Tag$1;
1945
+ const wrapHandler = (definition, handler) => {
1946
+ const decodePayload = Schema.decodeUnknownEffect(definition.payload);
1947
+ const encodeResult = Schema.encodeEffect(definition.result);
1948
+ return (payload) => Effect.gen(function* () {
1949
+ const decodedPayload = yield* decodePayload(payload);
1950
+ const decodedEvent = {
1951
+ ...yield* WorkflowEvent$1,
1952
+ payload: decodedPayload
1953
+ };
1954
+ return yield* encodeResult(yield* handler(decodedPayload).pipe(Effect.provideService(WorkflowEvent$1, decodedEvent)));
1955
+ });
1956
+ };
1957
+ const implement$1 = (_definition, handler) => handler;
1958
+ //#endregion
1959
+ //#region src/Workflow.ts
1960
+ var Workflow_exports = /* @__PURE__ */ __exportAll({
1961
+ Tag: () => Tag,
1962
+ WorkflowEvent: () => WorkflowEvent$1,
1963
+ WorkflowStep: () => WorkflowStep$1,
1964
+ WorkflowStepContext: () => WorkflowStepContext$1,
1965
+ implement: () => implement,
1966
+ make: () => make,
1967
+ sleep: () => sleep,
1968
+ sleepUntil: () => sleepUntil,
1969
+ step: () => step,
1970
+ waitForEvent: () => waitForEvent
1971
+ });
1972
+ var WorkflowEvent$1 = class extends Context.Service()("effect-cf/WorkflowEvent") {};
1973
+ var WorkflowStep$1 = class extends Context.Service()("effect-cf/WorkflowStep") {};
1974
+ var WorkflowStepContext$1 = class extends Context.Service()("effect-cf/WorkflowStepContext") {};
1975
+ const fromWorkflowEvent = (event) => ({
1976
+ raw: event,
1977
+ payload: event.payload,
1978
+ timestamp: event.timestamp,
1979
+ instanceId: event.instanceId
1980
+ });
1981
+ const fromWorkflowStep = (step, runPromise) => ({
1982
+ raw: step,
1983
+ do: (name, effect, config) => Effect.context().pipe(Effect.flatMap((context) => Effect.tryPromise({
1984
+ try: () => {
1985
+ const run = (stepContext) => runPromise(Effect.scoped(Effect.provideService(Effect.provideContext(effect, context), WorkflowStepContext$1, stepContext)));
1986
+ const rawStep = step;
1987
+ return config === void 0 ? rawStep.do(name, run) : rawStep.do(name, config, run);
1988
+ },
1989
+ catch: (cause) => cause
1990
+ }))),
1991
+ sleep: (name, duration) => Effect.tryPromise({
1992
+ try: () => step.sleep(name, duration),
1993
+ catch: (cause) => cause
1994
+ }),
1995
+ sleepUntil: (name, timestamp) => Effect.tryPromise({
1996
+ try: () => step.sleepUntil(name, timestamp),
1997
+ catch: (cause) => cause
1998
+ }),
1999
+ waitForEvent: (name, options) => Effect.tryPromise({
2000
+ try: () => step.waitForEvent(name, options),
2001
+ catch: (cause) => cause
2002
+ })
2003
+ });
2004
+ const make = (layer, options) => {
2005
+ class EffectWorkflow extends WorkflowEntrypoint {
2006
+ runtime;
2007
+ constructor(ctx, env) {
2008
+ super(ctx, env);
2009
+ let runWaitUntilEffect = () => Promise.reject(/* @__PURE__ */ new Error("WorkerContext runtime is not initialized"));
2010
+ const runtimeLayer = provideEntrypointServices(layer, Layer.mergeAll(Layer.succeed(ExecutionContext, ctx), ConfigProvider.layer(Effect.succeed(WorkerConfig.providerFromEnv(env))), Layer.succeed(WorkerContext, fromExecutionContext(ctx, (effect) => runWaitUntilEffect(effect))), Layer.succeed(WorkerEnvironment, env)));
2011
+ this.runtime = ManagedRuntime.make(runtimeLayer);
2012
+ runWaitUntilEffect = (effect) => this.runtime.runPromiseExit(effect);
2013
+ }
2014
+ run(event, step) {
2015
+ const workflowServices = Layer.mergeAll(Layer.succeed(WorkflowEvent$1, fromWorkflowEvent(event)), Layer.succeed(WorkflowStep$1, fromWorkflowStep(step, (effect) => this.runtime.runPromise(effect))));
2016
+ return this.runtime.runPromise(Effect.scoped(options.run(event.payload).pipe(Effect.provide(workflowServices))));
2017
+ }
2018
+ }
2019
+ return assumeEntrypointClass(EffectWorkflow);
2020
+ };
2021
+ const step = (name, effect, config) => Effect.flatMap(WorkflowStep$1.asEffect(), (workflowStep) => workflowStep.do(name, effect, config));
2022
+ const sleep = (name, duration) => Effect.flatMap(WorkflowStep$1.asEffect(), (workflowStep) => workflowStep.sleep(name, duration));
2023
+ const sleepUntil = (name, timestamp) => Effect.flatMap(WorkflowStep$1.asEffect(), (workflowStep) => workflowStep.sleepUntil(name, timestamp));
2024
+ const waitForEvent = (name, options) => Effect.flatMap(WorkflowStep$1.asEffect(), (workflowStep) => workflowStep.waitForEvent(name, options));
2025
+ const Tag = Tag$1;
2026
+ const implement = implement$1;
2027
+ //#endregion
2028
+ export { Binding_exports as Binding, DurableObject_exports as DurableObject, DurableObjectAlarm_exports as DurableObjectAlarm, DurableObjectDefinition_exports as DurableObjectDefinition, DurableObjectNamespace_exports as DurableObjectNamespace, DurableObjectRpcWebSocket_exports as DurableObjectRpcWebSocket, DurableObjectState_exports as DurableObjectState, DurableObjectStorage_exports as DurableObjectStorage, DurableObjectWebSocket_exports as DurableObjectWebSocket, Kv_exports as Kv, Queue_exports as Queue, QueueBinding_exports as QueueBinding, QueueDefinition_exports as QueueDefinition, Rpc_exports as Rpc, RpcDefinition_exports as RpcDefinition, ServiceBinding_exports as ServiceBinding, Worker_exports as Worker, WorkerConfig, WorkerDefinition_exports as WorkerDefinition, WorkerEnvironment, Workflow_exports as Workflow, WorkflowBinding_exports as WorkflowBinding, WorkflowDefinition_exports as WorkflowDefinition };