effect-cf 0.39.1 → 0.40.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effect-cf",
3
- "version": "0.39.1",
3
+ "version": "0.40.0",
4
4
  "description": "Effect-native primitives for Cloudflare Workers and bindings.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -4,6 +4,11 @@ import { Effect, Layer, type ManagedRuntime, type Scope, Tracer } from "effect";
4
4
  import { NativeRequest } from "./Worker";
5
5
  import { WorkerEnvironment, type WorkerEnv } from "./Environment";
6
6
  import { DurableObjectState, fromDurableObjectState } from "./DurableObjectState";
7
+ import {
8
+ DurableObjectAlarm,
9
+ type AlarmRegistration,
10
+ type AlarmService,
11
+ } from "./DurableObjectAlarm";
7
12
  import { fromWebSocket, type DurableWebSocket } from "./DurableObjectWebSocket";
8
13
  import * as RpcDefinition from "./RpcDefinition";
9
14
  import * as Entrypoint from "./internal/Entrypoint";
@@ -13,7 +18,11 @@ import type { ReceiverOptions, RpcInvocationInfo } from "./RpcTracing";
13
18
 
14
19
  const reservedMethodNames: ReadonlySet<string> = RpcDefinition.reservedMethodNames;
15
20
 
16
- type RuntimeContext<ROut> = DurableObjectState | WorkerEnvironment | ROut;
21
+ export type RuntimeContext<ROut> =
22
+ | DurableObjectState
23
+ | DurableObjectAlarm
24
+ | WorkerEnvironment
25
+ | ROut;
17
26
 
18
27
  type HandlerContext<ROut> = RuntimeContext<ROut> | Scope.Scope;
19
28
 
@@ -80,11 +89,12 @@ export type RpcHandlers<ROut, Api> = {
80
89
  : never;
81
90
  };
82
91
 
83
- export interface DurableObjectOptions<
92
+ interface DurableObjectOptionsBase<
84
93
  RRuntime,
85
94
  REvent = never,
86
95
  EventLayerError = never,
87
- Rpc extends DurableObjectRpc<RRuntime | REvent> = Record<never, never>,
96
+ Rpc extends DurableObjectRpc<RRuntime | REvent | RAlarm> = Record<never, never>,
97
+ RAlarm = never,
88
98
  > {
89
99
  /**
90
100
  * Layer provided around each Cloudflare event handled by this Durable Object.
@@ -96,7 +106,7 @@ export interface DurableObjectOptions<
96
106
  readonly eventLayer?: Layer.Layer<
97
107
  REvent,
98
108
  EventLayerError,
99
- DurableObjectState | WorkerEnvironment | RRuntime
109
+ RuntimeContext<NoInfer<RRuntime | RAlarm>>
100
110
  >;
101
111
  /**
102
112
  * Effect run when Cloudflare loads this Durable Object instance into memory.
@@ -106,7 +116,7 @@ export interface DurableObjectOptions<
106
116
  * the same Durable Object id again after eviction or restart; use Durable
107
117
  * Object storage if work must happen only once per id.
108
118
  */
109
- readonly initialize?: Effect.Effect<void, unknown, HandlerContext<RRuntime>>;
119
+ readonly initialize?: Effect.Effect<void, unknown, HandlerContext<NoInfer<RRuntime | RAlarm>>>;
110
120
  /**
111
121
  * Optional RPC methods exposed as Durable Object instance methods.
112
122
  *
@@ -118,9 +128,20 @@ export interface DurableObjectOptions<
118
128
  readonly rpc?: Rpc;
119
129
  /** Accept live native trace metadata. The client must also enable rpcTracing. */
120
130
  readonly rpcTracing?: ReceiverOptions;
121
- readonly fetch?: Effect.Effect<Response, unknown, FetchContext<RRuntime | REvent>>;
131
+ readonly fetch?: Effect.Effect<
132
+ Response,
133
+ unknown,
134
+ FetchContext<NoInfer<RRuntime | REvent | RAlarm>>
135
+ >;
122
136
 
123
- readonly alarms?: Effect.Effect<unknown, unknown, HandlerContext<RRuntime | REvent>>;
137
+ /** Register handlers to provide their typed scheduler to application layers and all DO events. */
138
+ readonly alarms?:
139
+ | Effect.Effect<unknown, unknown, HandlerContext<NoInfer<RRuntime> | REvent | NoInfer<RAlarm>>>
140
+ | AlarmRegistration<
141
+ RAlarm,
142
+ HandlerContext<NoInfer<RRuntime> | REvent | NoInfer<RAlarm>>,
143
+ unknown
144
+ >;
124
145
  /**
125
146
  * Optional raw alarm handler.
126
147
  *
@@ -131,23 +152,58 @@ export interface DurableObjectOptions<
131
152
  */
132
153
  readonly alarm?: (
133
154
  alarmInfo?: globalThis.AlarmInvocationInfo,
134
- ) => Effect.Effect<void, unknown, HandlerContext<RRuntime | REvent>>;
155
+ ) => Effect.Effect<void, unknown, HandlerContext<NoInfer<RRuntime> | REvent | NoInfer<RAlarm>>>;
135
156
  readonly webSocketMessage?: (
136
157
  socket: DurableWebSocket,
137
158
  message: string | ArrayBuffer,
138
- ) => Effect.Effect<void, unknown, HandlerContext<RRuntime | REvent>>;
159
+ ) => Effect.Effect<void, unknown, HandlerContext<NoInfer<RRuntime> | REvent | NoInfer<RAlarm>>>;
139
160
  readonly webSocketClose?: (
140
161
  socket: DurableWebSocket,
141
162
  code: number,
142
163
  reason: string,
143
164
  wasClean: boolean,
144
- ) => Effect.Effect<void, unknown, HandlerContext<RRuntime | REvent>>;
165
+ ) => Effect.Effect<void, unknown, HandlerContext<NoInfer<RRuntime> | REvent | NoInfer<RAlarm>>>;
145
166
  readonly webSocketError?: (
146
167
  socket: DurableWebSocket,
147
168
  cause: unknown,
148
- ) => Effect.Effect<void, unknown, HandlerContext<RRuntime | REvent>>;
169
+ ) => Effect.Effect<void, unknown, HandlerContext<NoInfer<RRuntime> | REvent | NoInfer<RAlarm>>>;
149
170
  }
150
171
 
172
+ // Providing a scheduler through an ordinary layer does not install its dispatcher.
173
+ type CheckAlarmRegistration<RProvided, RAlarm> = [
174
+ Exclude<Extract<NoInfer<RProvided>, AlarmService>, NoInfer<RAlarm>>,
175
+ ] extends [never]
176
+ ? unknown
177
+ : never;
178
+
179
+ /** A declared event or alarm service must have its corresponding provider. */
180
+ export type DurableObjectOptions<
181
+ RRuntime,
182
+ REvent = never,
183
+ EventLayerError = never,
184
+ Rpc extends DurableObjectRpc<RRuntime | REvent | RAlarm> = Record<never, never>,
185
+ RAlarm = never,
186
+ > = DurableObjectOptionsBase<RRuntime, REvent, EventLayerError, Rpc, RAlarm> &
187
+ CheckAlarmRegistration<RRuntime | REvent, RAlarm> &
188
+ ([Exclude<REvent, RuntimeContext<RRuntime | RAlarm> | Scope.Scope>] extends [never]
189
+ ? unknown
190
+ : {
191
+ readonly eventLayer: Layer.Layer<
192
+ REvent,
193
+ EventLayerError,
194
+ RuntimeContext<NoInfer<RRuntime | RAlarm>>
195
+ >;
196
+ }) &
197
+ ([RAlarm] extends [never]
198
+ ? unknown
199
+ : {
200
+ readonly alarms: AlarmRegistration<
201
+ RAlarm,
202
+ HandlerContext<NoInfer<RRuntime> | REvent | NoInfer<RAlarm>>,
203
+ unknown
204
+ >;
205
+ });
206
+
151
207
  /**
152
208
  * Cloudflare `DurableObject` constructor produced by {@link make}.
153
209
  */
@@ -168,27 +224,62 @@ export type DurableObjectClass<Rpc extends DurableObjectRpc<ROut>, ROut> = new (
168
224
  * that layer are not guaranteed to run. Put resources that require timely
169
225
  * release in `eventLayer`, whose scope closes after each handled event.
170
226
  */
171
- export const make = <
227
+ export function make<ROut, LayerError>(
228
+ layer: Layer.Layer<ROut, LayerError, RuntimeContext<never>> & CheckAlarmRegistration<ROut, never>,
229
+ ): DurableObjectClass<Record<never, never>, ROut>;
230
+ export function make<
231
+ ROut,
232
+ LayerError,
233
+ REvent = never,
234
+ EventLayerError = never,
235
+ const Rpc extends DurableObjectRpc<NoInfer<ROut> | REvent | NoInfer<RAlarm>> = Record<
236
+ never,
237
+ never
238
+ >,
239
+ RAlarm = never,
240
+ >(
241
+ layer: Layer.Layer<ROut, LayerError, RuntimeContext<NoInfer<RAlarm>>>,
242
+ options: DurableObjectOptions<ROut, REvent, EventLayerError, Rpc, RAlarm>,
243
+ ): DurableObjectClass<Rpc, ROut | REvent | RAlarm>;
244
+ export function make<
172
245
  ROut,
173
246
  LayerError,
174
247
  REvent = never,
175
248
  EventLayerError = never,
176
- const Rpc extends DurableObjectRpc<ROut | REvent> = Record<never, never>,
249
+ const Rpc extends DurableObjectRpc<NoInfer<ROut> | REvent | NoInfer<RAlarm>> = Record<
250
+ never,
251
+ never
252
+ >,
253
+ RAlarm = never,
177
254
  >(
178
- layer: Layer.Layer<ROut, LayerError, DurableObjectState | WorkerEnvironment>,
179
- options: DurableObjectOptions<ROut, REvent, EventLayerError, Rpc> = {},
180
- ): DurableObjectClass<Rpc, ROut | REvent> => {
255
+ layer: Layer.Layer<ROut, LayerError, RuntimeContext<NoInfer<RAlarm>>>,
256
+ options: DurableObjectOptionsBase<ROut, REvent, EventLayerError, Rpc, RAlarm> = {},
257
+ ): DurableObjectClass<Rpc, ROut | REvent | RAlarm> {
258
+ const registration =
259
+ options.alarms !== undefined && !Effect.isEffect(options.alarms) ? options.alarms : undefined;
260
+ const logicalAlarms = (
261
+ registration?.run ?? (Effect.isEffect(options.alarms) ? options.alarms : undefined)
262
+ )?.pipe(Effect.asVoid);
263
+
181
264
  class EffectDurableObject extends CloudflareDurableObject<WorkerEnv> {
182
- readonly runtime: ManagedRuntime.ManagedRuntime<RuntimeContext<ROut>, LayerError>;
265
+ readonly runtime: ManagedRuntime.ManagedRuntime<RuntimeContext<ROut | RAlarm>, LayerError>;
183
266
 
184
267
  constructor(state: globalThis.DurableObjectState, env: WorkerEnv) {
185
268
  super(state, env);
186
269
 
187
- this.runtime = Runtime.makeEntrypointRuntime<ROut, LayerError, DurableObjectState>(
188
- layer,
189
- env,
190
- Layer.succeed(DurableObjectState, fromDurableObjectState(state)),
270
+ const baseServices = DurableObjectAlarm.layer.pipe(
271
+ Layer.provideMerge(Layer.succeed(DurableObjectState, fromDurableObjectState(state))),
191
272
  );
273
+ // SAFETY: RAlarm is inferred only from the registration's layer; without a registration it is never.
274
+ const services = (registration?.layer ?? Layer.empty).pipe(
275
+ Layer.provideMerge(baseServices),
276
+ ) as Layer.Layer<DurableObjectState | DurableObjectAlarm | RAlarm>;
277
+
278
+ this.runtime = Runtime.makeEntrypointRuntime<
279
+ ROut,
280
+ LayerError,
281
+ DurableObjectState | DurableObjectAlarm | RAlarm
282
+ >(layer, env, services);
192
283
 
193
284
  const initialize = options.initialize;
194
285
 
@@ -198,7 +289,7 @@ export const make = <
198
289
  }
199
290
 
200
291
  [RunSymbol]<A, E>(
201
- effect: Effect.Effect<A, E, HandlerContext<ROut | REvent>>,
292
+ effect: Effect.Effect<A, E, HandlerContext<ROut | REvent | RAlarm>>,
202
293
  runOptions: RunOptions = {},
203
294
  ): Promise<A> {
204
295
  const eventLayer = runOptions.eventLayer === false ? undefined : options.eventLayer;
@@ -206,11 +297,11 @@ export const make = <
206
297
  const parentSpan = parent === undefined ? undefined : Tracer.externalSpan(parent);
207
298
 
208
299
  if (eventLayer === undefined) {
209
- // SAFETY: event-layer bypass is used only for initialize; otherwise an absent layer means REvent is never.
300
+ // SAFETY: initialize cannot require event services; without an event layer, all requirements are already provided.
210
301
  return Runtime.runEventPromise(
211
302
  this.runtime,
212
303
  // @effect-diagnostics-next-line unsafeEffectTypeAssertion:off
213
- effect as Effect.Effect<A, E, HandlerContext<ROut>>,
304
+ effect as Effect.Effect<A, E, HandlerContext<ROut | RAlarm>>,
214
305
  undefined,
215
306
  parentSpan,
216
307
  );
@@ -219,7 +310,7 @@ export const make = <
219
310
  return Runtime.runEventPromise<
220
311
  A,
221
312
  E,
222
- RuntimeContext<ROut>,
313
+ RuntimeContext<ROut | RAlarm>,
223
314
  REvent,
224
315
  EventLayerError,
225
316
  LayerError
@@ -239,7 +330,6 @@ export const make = <
239
330
  }
240
331
 
241
332
  alarm(alarmInfo?: globalThis.AlarmInvocationInfo): Promise<void> | void {
242
- const logicalAlarms = options.alarms?.pipe(Effect.asVoid);
243
333
  const rawAlarm = options.alarm?.(alarmInfo);
244
334
  const alarmEffect =
245
335
  logicalAlarms !== undefined && rawAlarm !== undefined
@@ -297,10 +387,10 @@ export const make = <
297
387
  options.rpcTracing,
298
388
  );
299
389
 
300
- return Entrypoint.assumeEntrypointClass<DurableObjectClass<Rpc, ROut | REvent>>(
390
+ return Entrypoint.assumeEntrypointClass<DurableObjectClass<Rpc, ROut | REvent | RAlarm>>(
301
391
  EffectDurableObject,
302
392
  );
303
- };
393
+ }
304
394
 
305
395
  export type {
306
396
  Api,
@@ -368,6 +368,63 @@ export type DefinedAlarmHandlers<Definitions extends AlarmDefinitions, R = never
368
368
  ) => Effect.Effect<void, E, R>;
369
369
  };
370
370
 
371
+ /** A discriminated union keeps each tag paired with its decoded payload type. */
372
+ export type DefinedScheduleAlarmInput<Definitions extends AlarmDefinitions> = {
373
+ readonly [Tag in keyof Definitions & string]: Omit<ScheduleAlarmInput<Tag>, "payload"> & {
374
+ readonly payload: AlarmDefinitionPayload<Definitions[Tag]>;
375
+ };
376
+ }[keyof Definitions & string];
377
+
378
+ export interface DefinedAlarmTransaction<Definitions extends AlarmDefinitions> {
379
+ readonly scheduleAlarm: (
380
+ input: DefinedScheduleAlarmInput<Definitions>,
381
+ ) => ReturnType<AlarmScheduler["scheduleAlarm"]>;
382
+ readonly cancelAlarm: (
383
+ input: AlarmRef<keyof Definitions & string>,
384
+ ) => ReturnType<AlarmScheduler["cancelAlarm"]>;
385
+ }
386
+
387
+ const TypedAlarmSchedulerTypeId: unique symbol = Symbol.for(
388
+ "effect-cf/DurableObjectAlarm/TypedScheduler",
389
+ );
390
+
391
+ /** Identifies service requirements whose scheduler needs a registered dispatcher. */
392
+ export interface AlarmService {
393
+ readonly Service: {
394
+ readonly [TypedAlarmSchedulerTypeId]: typeof TypedAlarmSchedulerTypeId;
395
+ };
396
+ }
397
+
398
+ export interface DefinedAlarmScheduler<
399
+ Definitions extends AlarmDefinitions,
400
+ > extends DefinedAlarmTransaction<Definitions> {
401
+ readonly [TypedAlarmSchedulerTypeId]: typeof TypedAlarmSchedulerTypeId;
402
+ readonly transaction: <A, E, R>(
403
+ closure: (alarms: DefinedAlarmTransaction<Definitions>) => Effect.Effect<A, E, R>,
404
+ ) => Effect.Effect<A, E | StorageOperationError, R>;
405
+ }
406
+
407
+ /** Registers a dispatcher and the service authorized to schedule its alarms. */
408
+ export interface AlarmRegistration<Self, R = never, E = never> {
409
+ readonly layer: Layer.Layer<Self, never, DurableObjectAlarm>;
410
+ readonly run: Effect.Effect<
411
+ ProcessDueAlarmsResult,
412
+ E | DurableObjectAlarmError,
413
+ R | DurableObjectAlarm
414
+ >;
415
+ }
416
+
417
+ export interface AlarmTagClass<
418
+ Self,
419
+ Id extends string,
420
+ Definitions extends AlarmDefinitions,
421
+ > extends Context.ServiceClass<Self, Id, DefinedAlarmScheduler<Definitions>> {
422
+ readonly handlers: <R = never, E = never>(
423
+ handlers: DefinedAlarmHandlers<Definitions, R, E>,
424
+ options?: ProcessDueAlarmsOptions<R, E>,
425
+ ) => AlarmRegistration<Self, R, E>;
426
+ }
427
+
371
428
  const isAlarmDefinitionConfig = (
372
429
  definition: AlarmDefinitionEntry,
373
430
  ): definition is AlarmDefinitionConfig => Predicate.isObject(definition) && "payload" in definition;
@@ -391,55 +448,133 @@ const getAlarmDefinitionFailureAction = (
391
448
  : { mode: definition.failure };
392
449
  };
393
450
 
394
- export const define = <const Definitions extends AlarmDefinitions>(definitions: Definitions) => ({
395
- handlers: <R = never, E = never>(
396
- handlers: DefinedAlarmHandlers<Definitions, R, E>,
397
- options?: ProcessDueAlarmsOptions<R, E>,
398
- ) =>
399
- processDue(
400
- (event) =>
401
- Effect.gen(function* () {
402
- const definition = definitions[event.tag];
451
+ const makeDefinition = <const Definitions extends AlarmDefinitions>(definitions: Definitions) => {
452
+ const definitionFor = (tag: string) =>
453
+ Object.hasOwn(definitions, tag) ? definitions[tag] : undefined;
403
454
 
404
- if (definition === undefined) {
405
- return;
406
- }
455
+ const bind = (mutations: AlarmTransaction): DefinedAlarmTransaction<Definitions> => ({
456
+ scheduleAlarm: Effect.fn("DefinedAlarms.scheduleAlarm")(function* (
457
+ input: DefinedScheduleAlarmInput<Definitions>,
458
+ ) {
459
+ const definition = definitionFor(input.tag);
460
+
461
+ if (definition === undefined) {
462
+ return yield* Effect.fail(
463
+ new InvalidAlarmRefError({
464
+ cause: new Error(`Unknown alarm tag "${input.tag}"`),
465
+ }),
466
+ );
467
+ }
468
+ const payload = yield* S.encodeEffect(getAlarmDefinitionSchema(definition))(
469
+ input.payload,
470
+ ).pipe(
471
+ Effect.flatMap(S.decodeUnknownEffect(S.Json)),
472
+ Effect.mapError((cause) => new InvalidAlarmPayloadError({ cause })),
473
+ );
407
474
 
408
- const schema = getAlarmDefinitionSchema(definition);
409
- // SAFETY: schema is selected from the same tagged definition used to select its handler.
410
- const payload = yield* (
411
- S.decodeUnknownEffect(schema)(event.payload) as Effect.Effect<
412
- AlarmDefinitionPayload<Definitions[keyof Definitions & string]>,
413
- unknown
414
- >
415
- ).pipe(
416
- Effect.mapError(
417
- (cause) =>
475
+ yield* mutations.scheduleAlarm({ ...input, payload });
476
+ }),
477
+ cancelAlarm: Effect.fn("DefinedAlarms.cancelAlarm")(function* (
478
+ input: AlarmRef<keyof Definitions & string>,
479
+ ) {
480
+ if (definitionFor(input.tag) === undefined) {
481
+ return yield* Effect.fail(
482
+ new InvalidAlarmRefError({
483
+ cause: new Error(`Unknown alarm tag "${input.tag}"`),
484
+ }),
485
+ );
486
+ }
487
+
488
+ yield* mutations.cancelAlarm(input);
489
+ }),
490
+ });
491
+
492
+ return {
493
+ make: (alarms: AlarmScheduler): DefinedAlarmScheduler<Definitions> => ({
494
+ [TypedAlarmSchedulerTypeId]: TypedAlarmSchedulerTypeId,
495
+ ...bind(alarms),
496
+ transaction: (closure) => alarms.transaction((tx) => closure(bind(tx))),
497
+ }),
498
+ handlers: <R = never, E = never>(
499
+ handlers: DefinedAlarmHandlers<Definitions, R, E>,
500
+ options?: ProcessDueAlarmsOptions<R, E>,
501
+ ) =>
502
+ processDue(
503
+ (event) =>
504
+ Effect.gen(function* () {
505
+ const definition = definitionFor(event.tag);
506
+
507
+ if (definition === undefined) {
508
+ return yield* Effect.fail(
418
509
  new StoredAlarmDecodeError({
419
- cause,
510
+ cause: new Error(`Unknown alarm tag "${event.tag}"`),
420
511
  storageId: getScheduledEventId(event),
421
512
  }),
422
- ),
423
- );
424
- const handler = handlers[event.tag];
513
+ );
514
+ }
425
515
 
426
- // SAFETY: event.tag indexes the matching definition and handler, whose payload schema was decoded above.
427
- yield* handler({ ...event, payload } as never);
428
- }),
429
- {
430
- ...options,
431
- onFailure: (failure) =>
432
- Effect.gen(function* () {
433
- const action = getAlarmDefinitionFailureAction(definitions[failure.tag]);
434
- const optionAction =
435
- options?.onFailure === undefined ? undefined : yield* options.onFailure(failure);
516
+ const schema = getAlarmDefinitionSchema(definition);
517
+ // SAFETY: schema is selected from the same tagged definition used to select its handler.
518
+ const payload = yield* (
519
+ S.decodeUnknownEffect(schema)(event.payload) as Effect.Effect<
520
+ AlarmDefinitionPayload<Definitions[keyof Definitions & string]>,
521
+ unknown
522
+ >
523
+ ).pipe(
524
+ Effect.mapError(
525
+ (cause) =>
526
+ new StoredAlarmDecodeError({
527
+ cause,
528
+ storageId: getScheduledEventId(event),
529
+ }),
530
+ ),
531
+ );
532
+ const handler = handlers[event.tag];
436
533
 
437
- return action ?? optionAction;
534
+ // SAFETY: event.tag indexes the matching definition and handler, whose payload schema was decoded above.
535
+ yield* handler({ ...event, payload } as never);
438
536
  }),
439
- },
440
- ),
537
+ {
538
+ ...options,
539
+ onFailure: (failure) =>
540
+ Effect.gen(function* () {
541
+ const action = getAlarmDefinitionFailureAction(definitionFor(failure.tag));
542
+ const optionAction =
543
+ options?.onFailure === undefined ? undefined : yield* options.onFailure(failure);
544
+
545
+ return action ?? optionAction;
546
+ }),
547
+ },
548
+ ),
549
+ };
550
+ };
551
+
552
+ /** Handler-only definitions for applications using the raw scheduler. Prefer Tag for typed scheduling. */
553
+ export const define = <const Definitions extends AlarmDefinitions>(definitions: Definitions) => ({
554
+ handlers: makeDefinition(definitions).handlers,
441
555
  });
442
556
 
557
+ /** The typed scheduler becomes available when its handlers are registered on a Durable Object. */
558
+ export const Tag =
559
+ <Self>() =>
560
+ <const Id extends string, const Definitions extends AlarmDefinitions>(
561
+ id: Id,
562
+ definitions: Definitions,
563
+ ): AlarmTagClass<Self, Id, Definitions> => {
564
+ const tag = Context.Service<Self, DefinedAlarmScheduler<Definitions>>()(id);
565
+ const definition = makeDefinition(definitions);
566
+
567
+ return Object.assign(tag, {
568
+ handlers: <R = never, E = never>(
569
+ handlers: DefinedAlarmHandlers<Definitions, R, E>,
570
+ options?: ProcessDueAlarmsOptions<R, E>,
571
+ ): AlarmRegistration<Self, R, E> => ({
572
+ layer: Layer.effect(tag, Effect.map(DurableObjectAlarm, definition.make)),
573
+ run: definition.handlers(handlers, options),
574
+ }),
575
+ });
576
+ };
577
+
443
578
  export class DurableObjectAlarm extends Context.Service<DurableObjectAlarm, AlarmScheduler>()(
444
579
  "effect-cf/DurableObjectAlarm",
445
580
  ) {
@@ -723,6 +858,6 @@ export class DurableObjectAlarm extends Context.Service<DurableObjectAlarm, Alar
723
858
  scheduleAlarm: (input) => transaction((alarms) => alarms.scheduleAlarm(input)),
724
859
  transaction,
725
860
  });
726
- }).pipe(Effect.withSpan("DurableObjectAlarm.layer")),
861
+ }),
727
862
  );
728
863
  }
@@ -4,7 +4,6 @@ import type * as Binding from "./Binding";
4
4
  import * as DurableObjectEntrypoint from "./DurableObject";
5
5
  import type { DurableObjectHandler } from "./DurableObject";
6
6
  import * as DurableObjectNamespace from "./DurableObjectNamespace";
7
- import type { DurableObjectState } from "./DurableObjectState";
8
7
  import type * as Rpc from "./Rpc";
9
8
  import * as RpcDefinition from "./RpcDefinition";
10
9
  import { recordDecodedArgs } from "./internal/RpcInvocation";
@@ -118,22 +117,21 @@ type MutableBoundaryHandlers<ROut, Self extends Definition.Any> = {
118
117
  /**
119
118
  * Durable Object constructor options for a specific RPC definition.
120
119
  */
121
- export interface Options<
120
+ export type Options<
122
121
  ROut,
123
122
  Self extends Definition.Any,
124
123
  REvent = never,
125
124
  EventLayerError = never,
126
- > extends Omit<
127
- DurableObjectEntrypoint.DurableObjectOptions<
128
- ROut,
129
- REvent,
130
- EventLayerError,
131
- Handlers<ROut | REvent, Self>
132
- >,
133
- "rpc"
134
- > {
135
- readonly rpc: Handlers<ROut | REvent, Self>;
136
- }
125
+ RAlarm = never,
126
+ > = DurableObjectEntrypoint.DurableObjectOptions<
127
+ ROut,
128
+ REvent,
129
+ EventLayerError,
130
+ Handlers<NoInfer<ROut> | REvent | NoInfer<RAlarm>, Self>,
131
+ RAlarm
132
+ > & {
133
+ readonly rpc: Handlers<NoInfer<ROut> | REvent | NoInfer<RAlarm>, Self>;
134
+ };
137
135
 
138
136
  export type LayerOptions = {
139
137
  readonly binding: string;
@@ -159,12 +157,12 @@ export type TagClass<
159
157
  > & {
160
158
  readonly id: Id;
161
159
  readonly methods: MethodDefinitions;
162
- readonly make: <ROut, LayerError, REvent = never, EventLayerError = never>(
163
- layer: Layer.Layer<ROut, LayerError, DurableObjectState | WorkerEnvironment>,
164
- options: Options<ROut, Definition<Id, MethodDefinitions>, REvent, EventLayerError>,
160
+ readonly make: <ROut, LayerError, REvent = never, EventLayerError = never, RAlarm = never>(
161
+ layer: Layer.Layer<ROut, LayerError, DurableObjectEntrypoint.RuntimeContext<NoInfer<RAlarm>>>,
162
+ options: Options<ROut, Definition<Id, MethodDefinitions>, REvent, EventLayerError, RAlarm>,
165
163
  ) => DurableObjectEntrypoint.DurableObjectClass<
166
- Handlers<ROut | REvent, Definition<Id, MethodDefinitions>>,
167
- ROut | REvent
164
+ Handlers<ROut | REvent | RAlarm, Definition<Id, MethodDefinitions>>,
165
+ ROut | REvent | RAlarm
168
166
  >;
169
167
  readonly layer: (
170
168
  options: LayerOptions,
@@ -201,9 +199,9 @@ const makeDefinition = <Id extends string, const MethodDefinitions extends Metho
201
199
  const definition: SelfDefinition = RpcDefinition.make(id, methods);
202
200
 
203
201
  return Object.assign(definition, {
204
- make: <ROut, LayerError, REvent = never, EventLayerError = never>(
205
- layer: Layer.Layer<ROut, LayerError, DurableObjectState | WorkerEnvironment>,
206
- options: Options<ROut, SelfDefinition, REvent, EventLayerError>,
202
+ make: <ROut, LayerError, REvent = never, EventLayerError = never, RAlarm = never>(
203
+ layer: Layer.Layer<ROut, LayerError, DurableObjectEntrypoint.RuntimeContext<NoInfer<RAlarm>>>,
204
+ options: Options<ROut, SelfDefinition, REvent, EventLayerError, RAlarm>,
207
205
  ) =>
208
206
  DurableObjectEntrypoint.make(layer, {
209
207
  ...options,