@effect-agent/platform-cloudflare 0.1.0-beta.47 → 0.1.0-beta.48

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/Alarm.d.mts CHANGED
@@ -59,11 +59,11 @@ declare class DurableAlarmService extends DurableAlarmService_base {
59
59
  static readonly layer: Layer.Layer<DurableAlarmService, never, DurableObjectContext>;
60
60
  }
61
61
  declare const MaintenancePassReport_base: Schema.Class<MaintenancePassReport, Schema.Struct<{
62
- /** `caught-up` is generation-only; `actionable` ran recovery and one bounded drain. */
62
+ /** `caught-up` is generation-only; `actionable` ran recovery and at most one head Attempt. */
63
63
  readonly phase: Schema.Literals<readonly ["caught-up", "actionable"]>;
64
64
  /** Recovery decisions executed (or deferred) BEFORE any new claim in this pass. */
65
65
  readonly recovered: Schema.Int;
66
- /** Settlements the drain pass finalized. */
66
+ /** Whether the head Attempt settled. Joined input may settle with that head. */
67
67
  readonly settled: Schema.Int;
68
68
  /** Submissions still nonterminal after the pass (suspended/unknown lanes stay honest). */
69
69
  readonly nonterminal: Schema.Int;
@@ -101,11 +101,12 @@ declare const ThreadMaintenance_base: Context.ServiceClass<ThreadMaintenance, "@
101
101
  /**
102
102
  * Incremental, quiescent maintenance over a durable dirty/processed generation (issue #93).
103
103
  *
104
- * `pass` = generation snapshot/pre-arm → recovery → bounded drain → generation acknowledgement:
104
+ * `pass` = generation snapshot/pre-arm → recovery → one head Attempt → generation acknowledgement:
105
105
  *
106
106
  * 1. One storage transaction reads dirty/processed and re-arms before work. A caught-up forced
107
107
  * alarm takes an O(1) path without recovery, ledger scans, or canonical-history reads.
108
- * 2. Recovery still strictly precedes a new claim, and one bounded drain advances the lane.
108
+ * 2. Recovery strictly precedes a new claim. One head Attempt advances the lane and requests
109
+ * a safe yield after ten minutes. The whole event has a fourteen-minute cooperative timeout.
109
110
  * 3. The final transaction acknowledges only the generation observed at pass start. A racing
110
111
  * mutation therefore remains `dirty > processed` and retains its atomically-established alarm.
111
112
  * 4. Stable external waits acknowledge and clear. Autonomous retry, indeterminate, and lease
package/dist/Alarm.mjs CHANGED
@@ -5,7 +5,7 @@ import { r as safeCauseMessage } from "./boundary-BguazVkh.mjs";
5
5
  import "@effect-agent/thread/AgentRegistration";
6
6
  import { DurableAgentRuntime } from "@effect-agent/thread/DurableAgentRuntime";
7
7
  import { SubmissionLedger } from "@effect-agent/thread/SubmissionLedger";
8
- import { Clock, Context, Effect, Layer, Option, Random, Ref, Schema, Semaphore, Stream } from "effect";
8
+ import { Clock, Context, DateTime, Effect, Layer, Option, Random, Ref, Schema, Semaphore, Stream } from "effect";
9
9
  //#region src/Alarm.ts
10
10
  var Alarm_exports = /* @__PURE__ */ __exportAll({
11
11
  DurableAlarmError: () => DurableAlarmError,
@@ -74,11 +74,11 @@ var DurableAlarmService = class DurableAlarmService extends Context.Service()("@
74
74
  };
75
75
  /** What one maintenance pass did — auditable evidence mirroring `NodeDurableHost`'s report. */
76
76
  var MaintenancePassReport = class extends Schema.Class("@effect-agent/platform-cloudflare/MaintenancePassReport")({
77
- /** `caught-up` is generation-only; `actionable` ran recovery and one bounded drain. */
77
+ /** `caught-up` is generation-only; `actionable` ran recovery and at most one head Attempt. */
78
78
  phase: Schema.Literals(["caught-up", "actionable"]),
79
79
  /** Recovery decisions executed (or deferred) BEFORE any new claim in this pass. */
80
80
  recovered: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
81
- /** Settlements the drain pass finalized. */
81
+ /** Whether the head Attempt settled. Joined input may settle with that head. */
82
82
  settled: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
83
83
  /** Submissions still nonterminal after the pass (suspended/unknown lanes stay honest). */
84
84
  nonterminal: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
@@ -139,11 +139,12 @@ const stableExternalWait = (snapshot, reports) => {
139
139
  /**
140
140
  * Incremental, quiescent maintenance over a durable dirty/processed generation (issue #93).
141
141
  *
142
- * `pass` = generation snapshot/pre-arm → recovery → bounded drain → generation acknowledgement:
142
+ * `pass` = generation snapshot/pre-arm → recovery → one head Attempt → generation acknowledgement:
143
143
  *
144
144
  * 1. One storage transaction reads dirty/processed and re-arms before work. A caught-up forced
145
145
  * alarm takes an O(1) path without recovery, ledger scans, or canonical-history reads.
146
- * 2. Recovery still strictly precedes a new claim, and one bounded drain advances the lane.
146
+ * 2. Recovery strictly precedes a new claim. One head Attempt advances the lane and requests
147
+ * a safe yield after ten minutes. The whole event has a fourteen-minute cooperative timeout.
147
148
  * 3. The final transaction acknowledges only the generation observed at pass start. A racing
148
149
  * mutation therefore remains `dirty > processed` and retains its atomically-established alarm.
149
150
  * 4. Stable external waits acknowledge and clear. Autonomous retry, indeterminate, and lease
@@ -235,7 +236,7 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
235
236
  const jittered = Math.ceil(backoff / 2 + backoff / 2 * jitter);
236
237
  return Math.min(jittered, config.wakeScanInterval);
237
238
  });
238
- const pass = Effect.fn("ThreadMaintenance.pass")(function* () {
239
+ const pass = Effect.fn("ThreadMaintenance.pass")(function* (yieldAfter) {
239
240
  const annotate = (report) => Effect.annotateCurrentSpan({
240
241
  phase: report.phase,
241
242
  recovered: report.recovered,
@@ -258,7 +259,7 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
258
259
  alarm: "cleared"
259
260
  }));
260
261
  const recovered = yield* runtime.runRecovery;
261
- const settlements = yield* runtime.processThreadResolved(identity.threadId);
262
+ const settlement = yield* runtime.processThreadHead(identity.threadId, { yieldAfter });
262
263
  const remaining = yield* Stream.runCollect(ledger.scanNonterminal);
263
264
  const reports = new Map(recovered.map((report) => [report.submissionId, report]));
264
265
  const head = remaining[0];
@@ -267,7 +268,7 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
267
268
  if (index > 0 && headWaiting && snapshot.state === "ready" && reports.get(snapshot.submissionId)?.decision._tag === "ApplyInput") return false;
268
269
  return !stableExternalWait(snapshot, reports);
269
270
  });
270
- const progressed = settlements.length > 0 || recovered.some((report) => report.disposition === "repaired");
271
+ const progressed = Option.isSome(settlement) || recovered.some((report) => report.disposition === "repaired");
271
272
  const delay = autonomous ? yield* rearmDelay(progressed) : 0;
272
273
  const now = yield* Clock.currentTimeMillis;
273
274
  yield* failpoint.hit("maintenance:finish:before");
@@ -299,13 +300,22 @@ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effe
299
300
  return yield* annotate(MaintenancePassReport.make({
300
301
  phase: "actionable",
301
302
  recovered: recovered.length,
302
- settled: settlements.length,
303
+ settled: Option.isSome(settlement) ? 1 : 0,
303
304
  nonterminal: remaining.length,
304
305
  alarm: alarmDisposition
305
306
  }));
306
307
  });
307
308
  return ThreadMaintenance.of({
308
- pass: alarm.withWakesDeferred(maintenancePassGate.withPermit(pass())),
309
+ pass: Effect.gen(function* () {
310
+ const yieldAfter = DateTime.makeUnsafe((yield* Clock.currentTimeMillis) + 6e5);
311
+ return yield* alarm.withWakesDeferred(maintenancePassGate.withPermit(pass(yieldAfter)));
312
+ }).pipe(Effect.timeoutOrElse({
313
+ duration: "14 minutes",
314
+ orElse: () => DurableAlarmError.make({
315
+ operation: "maintenance pass deadline",
316
+ message: "The maintenance event exceeded its 14 minute deadline; durable recovery remains pending"
317
+ })
318
+ })),
309
319
  ensureAlarm: ensureAlarm(),
310
320
  withMutation
311
321
  });
@@ -1 +1 @@
1
- {"version":3,"file":"Alarm.mjs","names":[],"sources":["../src/Alarm.ts"],"sourcesContent":["import { type DurableBindingFailure } from \"@effect-agent/thread/AgentRegistration\";\nimport {\n DurableAgentRuntime,\n type DurableWorkerFailure,\n type RecoveryReport,\n} from \"@effect-agent/thread/DurableAgentRuntime\";\nimport { SubmissionLedger, type SubmissionSnapshot } from \"@effect-agent/thread/SubmissionLedger\";\nimport {\n Clock,\n Context,\n Effect,\n Layer,\n Option,\n Random,\n Ref,\n Schema,\n Semaphore,\n Stream,\n} from \"effect\";\n\nimport { ThreadObjectIdentity, DurableObjectContext } from \"./CloudflareBindings.ts\";\nimport { CloudflareDurableRuntimeConfig } from \"./CloudflareConfig.ts\";\nimport { safeCauseMessage } from \"./internal/boundary.ts\";\n\n/**\n * The single multiplexed Durable Object alarm (decision D-P6-2). A Durable Object has ONE\n * alarm slot; every cadence the Node host ran on fibers (wake scan, lease expiry, settlement\n * and abort re-checks, retry backoff) multiplexes into one idempotent maintenance pass, and\n * the slot always holds the EARLIEST deadline any caller asked for.\n *\n * The alarm invariant (plan §1.4): every committed actionable mutation carries a newer durable\n * maintenance generation and a committed alarm. Stable externally-driven waits may be\n * nonterminal without retaining an alarm; their resolving mutation advances the generation and\n * restores the alarm atomically.\n */\n\n/** The Durable Object alarm API failed; surfaces on host entry points as a typed refusal. */\nexport class DurableAlarmError extends Schema.TaggedError<DurableAlarmError>()(\n \"DurableAlarmError\",\n {\n operation: Schema.String,\n message: Schema.String,\n cause: Schema.optionalKey(Schema.Defect()),\n },\n) {}\n\nconst alarmFailure =\n (operation: string) =>\n (cause: unknown): DurableAlarmError =>\n DurableAlarmError.make({\n operation,\n message: safeCauseMessage(cause, \"The Cloudflare alarm API failed without a diagnostic\"),\n cause,\n });\n\n/** `ctx.storage` alarm slot as an Effect service; storage is truth, never a memory field. */\nexport class DurableAlarmService extends Context.Service<\n DurableAlarmService,\n {\n /** The scheduled deadline in epoch milliseconds, if any. */\n readonly scheduled: Effect.Effect<Option.Option<number>, DurableAlarmError>;\n /** Replace the slot with this deadline. */\n readonly scheduleAt: (epochMillis: number) => Effect.Effect<void, DurableAlarmError>;\n /** Keep the EARLIER of the existing deadline and this one (the multiplexing rule). */\n readonly ensureScheduledBy: (epochMillis: number) => Effect.Effect<void, DurableAlarmError>;\n /**\n * Arm an immediate alarm (the durable, coalescing local wake) — DEFERRED while a\n * maintenance pass is executing. Workerd cancels an in-flight alarm handler when a new\n * EARLIER deadline is written during its execution (`requestScheduledAlarm`), and the\n * maintenance pass runs INSIDE the alarm handler: an immediate wake landing mid-pass\n * (a routed port mutation, a sibling's `wake()`, the coordinator's own local notify)\n * would kill the running Attempt — manufacturing an ownership loss no real eviction\n * caused, and routing open uncertain-class Tool Calls into spurious Unknown Outcomes.\n * Deferral is contract-safe: wakes are droppable hints, every mutating entry point\n * pre-arms BEFORE its first durable mutation (the alarm invariant never rests on this\n * call). The pass's durable generation check observes any racing mutation, so the\n * in-memory hint does not need to be flushed after a stable wait is acknowledged.\n */\n readonly scheduleNow: Effect.Effect<void, DurableAlarmError>;\n /**\n * Run one maintenance pass with wake deferral (see `scheduleNow`). Calls made while `body`\n * executes are droppable promptness hints; correctness rests on the durable generation.\n */\n readonly withWakesDeferred: <A, E, R>(body: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;\n /** Clear the slot; correctness-sensitive clears live in maintenance generation transactions. */\n readonly cancel: Effect.Effect<void, DurableAlarmError>;\n }\n>()(\"@effect-agent/platform-cloudflare/DurableAlarmService\") {\n static readonly layer: Layer.Layer<DurableAlarmService, never, DurableObjectContext> =\n Layer.effect(DurableAlarmService)(\n Effect.gen(function* () {\n const { ctx } = yield* DurableObjectContext;\n /**\n * In-memory pass bookkeeping — a pure CACHE, never state: a fresh incarnation has no\n * running pass, and a deferred wake lost to eviction was only ever a promptness hint\n * on top of the already-committed pre-armed alarm.\n */\n const runningPasses = yield* Ref.make(0);\n\n const scheduled = Effect.tryPromise({\n try: () => ctx.storage.getAlarm(),\n catch: alarmFailure(\"get alarm\"),\n }).pipe(\n Effect.map((deadline) =>\n deadline === null ? Option.none<number>() : Option.some(deadline),\n ),\n );\n\n const scheduleAt = (epochMillis: number) =>\n Effect.tryPromise({\n try: () => ctx.storage.setAlarm(epochMillis),\n catch: alarmFailure(\"set alarm\"),\n });\n\n const ensureScheduledBy = (epochMillis: number) =>\n scheduled.pipe(\n Effect.flatMap((existing) =>\n Option.isSome(existing) && existing.value <= epochMillis\n ? Effect.void\n : scheduleAt(epochMillis),\n ),\n );\n\n const armNow = Clock.currentTimeMillis.pipe(\n Effect.flatMap((now) => ensureScheduledBy(now)),\n );\n\n const scheduleNow = Ref.get(runningPasses).pipe(\n Effect.flatMap((passes) => (passes > 0 ? Effect.void : armNow)),\n );\n\n const withWakesDeferred = <A, E, R>(body: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>\n Ref.update(runningPasses, (passes) => passes + 1).pipe(\n Effect.andThen(body),\n Effect.ensuring(Ref.update(runningPasses, (passes) => passes - 1)),\n );\n\n const cancel = Effect.tryPromise({\n try: () => ctx.storage.deleteAlarm(),\n catch: alarmFailure(\"delete alarm\"),\n });\n\n return DurableAlarmService.of({\n scheduled,\n scheduleAt,\n ensureScheduledBy,\n scheduleNow,\n withWakesDeferred,\n cancel,\n });\n }),\n );\n}\n\n/** What one maintenance pass did — auditable evidence mirroring `NodeDurableHost`'s report. */\nexport class MaintenancePassReport extends Schema.Class<MaintenancePassReport>(\n \"@effect-agent/platform-cloudflare/MaintenancePassReport\",\n)({\n /** `caught-up` is generation-only; `actionable` ran recovery and one bounded drain. */\n phase: Schema.Literals([\"caught-up\", \"actionable\"]),\n /** Recovery decisions executed (or deferred) BEFORE any new claim in this pass. */\n recovered: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n /** Settlements the drain pass finalized. */\n settled: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n /** Submissions still nonterminal after the pass (suspended/unknown lanes stay honest). */\n nonterminal: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n /** `rearmed` for dirty/autonomous work, `cleared` for stable waits or settlement. */\n alarm: Schema.Literals([\"rearmed\", \"cleared\"]),\n}) {}\n\n/** Fault boundaries around every maintenance-owned durable mutation. */\nexport type ThreadMaintenanceFailpointLocation =\n | \"maintenance:dirty:before\"\n | \"maintenance:dirty:after\"\n | \"maintenance:mutation:armed\"\n | \"maintenance:mutation:finished\"\n | \"maintenance:ensure:before\"\n | \"maintenance:ensure:after\"\n | \"maintenance:begin:before\"\n | \"maintenance:begin:after\"\n | \"maintenance:finish:before\"\n | \"maintenance:finish:after\";\n\nexport type ThreadMaintenanceFailpointHandler = (\n location: ThreadMaintenanceFailpointLocation,\n) => Effect.Effect<void>;\n\n/** Test-only fault authority; production uses the inert layer. */\nexport class ThreadMaintenanceFailpoint extends Context.Service<\n ThreadMaintenanceFailpoint,\n {\n readonly hit: ThreadMaintenanceFailpointHandler;\n }\n>()(\"@effect-agent/platform-cloudflare/ThreadMaintenanceFailpoint\") {\n static readonly layer = Layer.succeed(this)({ hit: () => Effect.void });\n}\n\nconst MaintenanceGeneration = Schema.BigIntFromString.check(\n Schema.isGreaterThanOrEqualToBigInt(0n),\n);\n\n/** Versioned, platform-private maintenance state stored through Durable Object KV. */\nclass ThreadMaintenanceState extends Schema.Class<ThreadMaintenanceState>(\n \"@effect-agent/platform-cloudflare/ThreadMaintenanceState\",\n)({\n schemaVersion: Schema.Literal(1),\n dirty: MaintenanceGeneration,\n processed: MaintenanceGeneration,\n nonterminal: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n}) {}\n\nconst MAINTENANCE_STATE_KEY = \"effect-agent:thread-maintenance:v1\";\nconst decodeMaintenanceState = Schema.decodeUnknownSync(ThreadMaintenanceState);\nconst encodeMaintenanceState = Schema.encodeSync(ThreadMaintenanceState);\n\nconst initialMaintenanceState = (): ThreadMaintenanceState =>\n ThreadMaintenanceState.make({\n schemaVersion: 1,\n // Bootstrap Objects created by the pre-generation release without scanning the ledger in\n // the constructor. One useful pass classifies and acknowledges any existing obligation.\n dirty: 1n,\n processed: 0n,\n nonterminal: 0,\n });\n\nconst readMaintenanceState = async (\n transaction: DurableObjectTransaction,\n): Promise<{ readonly state: ThreadMaintenanceState; readonly initialized: boolean }> => {\n const encoded = await transaction.get(MAINTENANCE_STATE_KEY);\n\n return encoded === undefined\n ? { state: initialMaintenanceState(), initialized: false }\n : { state: decodeMaintenanceState(encoded), initialized: true };\n};\n\nconst ensureTransactionAlarmBy = async (\n transaction: DurableObjectTransaction,\n deadline: number,\n): Promise<void> => {\n const scheduled = await transaction.getAlarm();\n\n if (scheduled === null || scheduled > deadline) {\n await transaction.setAlarm(deadline);\n }\n};\n\nconst stableExternalWait = (\n snapshot: SubmissionSnapshot,\n reports: ReadonlyMap<string, RecoveryReport>,\n): boolean => {\n const decision = reports.get(snapshot.submissionId)?.decision._tag;\n\n // An accepted abort still owes cleanup/settlement even if its claim was deferred this pass.\n if (decision === \"SettleAborted\") return false;\n switch (snapshot.state) {\n case \"suspended\":\n case \"joined\":\n return true;\n case \"unknown\":\n return decision === \"AwaitUnknownResolution\" || decision === \"MarkUnknown\";\n case \"admitted\":\n return reports.get(snapshot.submissionId)?.decision._tag === \"AwaitParentEstablishment\";\n case \"input-applied\":\n case \"joining\":\n case \"ready\":\n case \"running\":\n case \"settled\":\n case \"terminalizing\":\n return false;\n }\n};\n\nexport type MaintenancePassFailure =\n | DurableWorkerFailure\n | DurableBindingFailure\n | DurableAlarmError;\n\n/**\n * Incremental, quiescent maintenance over a durable dirty/processed generation (issue #93).\n *\n * `pass` = generation snapshot/pre-arm → recovery → bounded drain → generation acknowledgement:\n *\n * 1. One storage transaction reads dirty/processed and re-arms before work. A caught-up forced\n * alarm takes an O(1) path without recovery, ledger scans, or canonical-history reads.\n * 2. Recovery still strictly precedes a new claim, and one bounded drain advances the lane.\n * 3. The final transaction acknowledges only the generation observed at pass start. A racing\n * mutation therefore remains `dirty > processed` and retains its atomically-established alarm.\n * 4. Stable external waits acknowledge and clear. Autonomous retry, indeterminate, and lease\n * recovery states leave their generation dirty and retain bounded backoff rearming.\n */\nexport class ThreadMaintenance extends Context.Service<\n ThreadMaintenance,\n {\n /** One idempotent maintenance pass; failures propagate so workerd retries the alarm. */\n readonly pass: Effect.Effect<MaintenancePassReport, MaintenancePassFailure>;\n /**\n * Constructor gate: initialize/inspect only the O(1) maintenance record and ensure a dirty\n * generation has an alarm. It never scans the ledger or canonical history.\n */\n readonly ensureAlarm: Effect.Effect<void, MaintenancePassFailure>;\n /**\n * Serialize the pre-arm boundary with pass acknowledgement, advance the durable dirty\n * generation and arm the alarm in one transaction BEFORE running the caller's mutation.\n * A pass cannot acknowledge while that mutation remains in flight.\n */\n readonly withMutation: <A, E, R>(\n body: Effect.Effect<A, E, R>,\n ) => Effect.Effect<A, E | DurableAlarmError, R>;\n }\n>()(\"@effect-agent/platform-cloudflare/ThreadMaintenance\") {\n static readonly layer: Layer.Layer<\n ThreadMaintenance,\n never,\n | DurableAgentRuntime\n | SubmissionLedger\n | DurableAlarmService\n | ThreadMaintenanceFailpoint\n | CloudflareDurableRuntimeConfig\n | ThreadObjectIdentity\n | DurableObjectContext\n > = Layer.effect(ThreadMaintenance)(\n Effect.gen(function* () {\n const runtime = yield* DurableAgentRuntime;\n const ledger = yield* SubmissionLedger;\n const alarm = yield* DurableAlarmService;\n const config = yield* CloudflareDurableRuntimeConfig;\n const identity = yield* ThreadObjectIdentity;\n const { ctx } = yield* DurableObjectContext;\n const failpoint = yield* ThreadMaintenanceFailpoint;\n\n /**\n * Consecutive no-progress passes — an in-memory CACHE, not state: a fresh incarnation\n * restarts at zero and merely re-arms sooner than a long-lived one would have.\n */\n const stalls = yield* Ref.make(0);\n /**\n * Incarnation-local mutation count guarded with the generation transactions below. It is\n * deliberately not durable: after eviction every begun mutation has stopped, while its\n * pre-armed dirty generation remains durable for recovery. The short gate never spans the\n * caller's mutation or cross-Object I/O.\n */\n const activeMutations = yield* Ref.make(0);\n const generationGate = yield* Semaphore.make(1);\n // At-least-once deliveries are idempotent, but overlapping pass bodies could otherwise\n // acknowledge state while a sibling pass is still mutating it. Port/RPC mutations do not\n // take this permit, so cross-Object I/O cannot deadlock the maintenance serialization.\n const maintenancePassGate = yield* Semaphore.make(1);\n const minimumAlarmDelay = Math.max(1, Math.ceil(config.alarmBackoffBase / 2));\n\n const runTransaction = <A>(\n operation: string,\n transaction: () => Promise<A>,\n ): Effect.Effect<A, DurableAlarmError> =>\n Effect.tryPromise({\n try: transaction,\n catch: alarmFailure(operation),\n });\n\n const beginMutation = Effect.fn(\"ThreadMaintenance.beginMutation\")(function* () {\n yield* failpoint.hit(\"maintenance:dirty:before\");\n const now = yield* Clock.currentTimeMillis;\n\n yield* runTransaction(\"advance maintenance generation\", () =>\n ctx.storage.transaction(async (transaction) => {\n const { state } = await readMaintenanceState(transaction);\n\n const next = ThreadMaintenanceState.make({\n ...state,\n dirty: state.dirty + 1n,\n });\n\n await transaction.put(MAINTENANCE_STATE_KEY, encodeMaintenanceState(next));\n // The earliest configured retry bounds a newly actionable mutation without relying\n // on its best-effort immediate wake hint.\n await ensureTransactionAlarmBy(transaction, now + minimumAlarmDelay);\n }),\n );\n yield* failpoint.hit(\"maintenance:dirty:after\");\n yield* Ref.update(activeMutations, (active) => active + 1);\n });\n\n const endMutation = generationGate.withPermit(\n Ref.update(activeMutations, (active) => Math.max(0, active - 1)),\n );\n\n const withMutation = <A, E, R>(\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<A, E | DurableAlarmError, R> =>\n Effect.acquireUseRelease(\n generationGate.withPermit(beginMutation()),\n () =>\n failpoint.hit(\"maintenance:mutation:armed\").pipe(\n Effect.andThen(body),\n Effect.tap(() => failpoint.hit(\"maintenance:mutation:finished\")),\n ),\n () => endMutation,\n );\n\n const ensureAlarm = Effect.fn(\"ThreadMaintenance.ensureAlarm\")(function* () {\n yield* failpoint.hit(\"maintenance:ensure:before\");\n const now = yield* Clock.currentTimeMillis;\n\n yield* runTransaction(\"ensure maintenance alarm\", () =>\n ctx.storage.transaction(async (transaction) => {\n const { state, initialized } = await readMaintenanceState(transaction);\n\n if (!initialized) {\n await transaction.put(MAINTENANCE_STATE_KEY, encodeMaintenanceState(state));\n }\n if (state.dirty > state.processed) {\n await ensureTransactionAlarmBy(transaction, now + config.wakeScanInterval);\n }\n }),\n );\n yield* failpoint.hit(\"maintenance:ensure:after\");\n });\n\n const beginPass = Effect.fn(\"ThreadMaintenance.beginPass\")(function* () {\n yield* failpoint.hit(\"maintenance:begin:before\");\n const now = yield* Clock.currentTimeMillis;\n\n const result = yield* runTransaction(\"begin maintenance pass\", () =>\n ctx.storage.transaction(async (transaction) => {\n const { state, initialized } = await readMaintenanceState(transaction);\n\n if (!initialized) {\n await transaction.put(MAINTENANCE_STATE_KEY, encodeMaintenanceState(state));\n }\n if (state.processed >= state.dirty) {\n await transaction.deleteAlarm();\n\n return { _tag: \"CaughtUp\" as const, nonterminal: state.nonterminal };\n }\n // Pre-arm the earliest retry before recovery. A successful finish may move this slot\n // LATER to its bounded backoff, which does not cancel the running handler.\n await ensureTransactionAlarmBy(transaction, now + minimumAlarmDelay);\n\n return { _tag: \"Actionable\" as const, generation: state.dirty };\n }),\n );\n\n yield* failpoint.hit(\"maintenance:begin:after\");\n\n return result;\n });\n\n const rearmDelay = Effect.fn(\"ThreadMaintenance.rearmDelay\")(function* (progressed: boolean) {\n const priorStalls = yield* Ref.getAndUpdate(stalls, (count) =>\n progressed ? 0 : count + 1,\n );\n\n if (progressed) return config.alarmBackoffBase;\n const exponent = Math.min(priorStalls, 30);\n const backoff = Math.min(config.alarmBackoffCap, config.alarmBackoffBase * 2 ** exponent);\n const jitter = yield* Random.next;\n // Full jitter over [backoff/2, backoff]: desynchronizes retry storms without ever\n // waiting longer than the deterministic bound.\n const jittered = Math.ceil(backoff / 2 + (backoff / 2) * jitter);\n\n return Math.min(jittered, config.wakeScanInterval);\n });\n\n const pass = Effect.fn(\"ThreadMaintenance.pass\")(function* (): Effect.fn.Return<\n MaintenancePassReport,\n MaintenancePassFailure\n > {\n const annotate = (report: MaintenancePassReport) =>\n Effect.annotateCurrentSpan({\n phase: report.phase,\n recovered: report.recovered,\n settled: report.settled,\n nonterminal: report.nonterminal,\n alarm: report.alarm,\n }).pipe(Effect.as(report));\n\n const started = yield* generationGate.withPermit(\n Effect.gen(function* () {\n const activeAtStart = yield* Ref.get(activeMutations);\n const generation = yield* beginPass();\n\n return { ...generation, activeAtStart };\n }),\n );\n\n if (started._tag === \"CaughtUp\") {\n return yield* annotate(\n MaintenancePassReport.make({\n phase: \"caught-up\",\n recovered: 0,\n settled: 0,\n nonterminal: started.nonterminal,\n alarm: \"cleared\",\n }),\n );\n }\n // Step 2 — reconciliation strictly precedes new work in this pass (exit gate).\n const recovered: ReadonlyArray<RecoveryReport> = yield* runtime.runRecovery;\n // Step 3 — one bounded drain pass over this Object's own lane.\n const settlements = yield* runtime.processThreadResolved(identity.threadId);\n // Observe residual state before acknowledging this exact pass-start generation.\n const remaining = yield* Stream.runCollect(ledger.scanNonterminal);\n const reports = new Map(recovered.map((report) => [report.submissionId, report]));\n const head = remaining[0];\n const headWaiting = head !== undefined && stableExternalWait(head, reports);\n\n const autonomous = remaining.some((snapshot, index) => {\n // FIFO followers cannot execute through a stable external wait. Only plain queued\n // input is dormant here; admission repairs and accepted aborts still need a pass.\n if (\n index > 0 &&\n headWaiting &&\n snapshot.state === \"ready\" &&\n reports.get(snapshot.submissionId)?.decision._tag === \"ApplyInput\"\n )\n return false;\n\n return !stableExternalWait(snapshot, reports);\n });\n\n const progressed =\n settlements.length > 0 || recovered.some((report) => report.disposition === \"repaired\");\n\n const delay = autonomous ? yield* rearmDelay(progressed) : 0;\n const now = yield* Clock.currentTimeMillis;\n\n yield* failpoint.hit(\"maintenance:finish:before\");\n\n const alarmDisposition = yield* generationGate.withPermit(\n Effect.gen(function* () {\n const active = yield* Ref.get(activeMutations);\n\n return yield* runTransaction(\"finish maintenance pass\", () =>\n ctx.storage.transaction(async (transaction) => {\n const { state } = await readMaintenanceState(transaction);\n\n // Autonomous work and in-flight mutations intentionally leave the observed\n // generation dirty. Otherwise acknowledge only the pass-start generation.\n const processed =\n autonomous || started.activeAtStart > 0 || active > 0\n ? state.processed\n : state.processed > started.generation\n ? state.processed\n : started.generation;\n\n const next = ThreadMaintenanceState.make({\n ...state,\n processed,\n nonterminal: remaining.length,\n });\n\n await transaction.put(MAINTENANCE_STATE_KEY, encodeMaintenanceState(next));\n if (autonomous) {\n // Replace the crash-fallback slot with this pass's bounded backoff. The target\n // is never earlier than the begin-pass fallback, so workerd does not cancel\n // this running alarm handler before its report/span can complete.\n await transaction.setAlarm(now + delay);\n\n return \"rearmed\" as const;\n }\n if (started.activeAtStart > 0 || active > 0 || next.dirty > next.processed) {\n // A mutation overlapped this pass's observation window or raced\n // acknowledgement. It stays dirty and its pre-armed bounded alarm survives;\n // unseen effects are never acknowledged. Do not accelerate that future alarm\n // from inside the current handler: workerd cancels a running handler when it\n // writes an earlier slot.\n await ensureTransactionAlarmBy(transaction, now + config.wakeScanInterval);\n\n return \"rearmed\" as const;\n }\n await transaction.deleteAlarm();\n\n return \"cleared\" as const;\n }),\n );\n }),\n );\n\n yield* failpoint.hit(\"maintenance:finish:after\");\n if (alarmDisposition === \"cleared\") {\n yield* Ref.set(stalls, 0);\n }\n\n return yield* annotate(\n MaintenancePassReport.make({\n phase: \"actionable\",\n recovered: recovered.length,\n settled: settlements.length,\n nonterminal: remaining.length,\n alarm: alarmDisposition,\n }),\n );\n });\n\n return ThreadMaintenance.of({\n // A mid-pass immediate hint is droppable; durable dirty state decides the final alarm.\n pass: alarm.withWakesDeferred(maintenancePassGate.withPermit(pass())),\n ensureAlarm: ensureAlarm(),\n withMutation,\n });\n }),\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Alarm.mjs","names":[],"sources":["../src/Alarm.ts"],"sourcesContent":["import { type DurableBindingFailure } from \"@effect-agent/thread/AgentRegistration\";\nimport {\n DurableAgentRuntime,\n type DurableWorkerFailure,\n type RecoveryReport,\n} from \"@effect-agent/thread/DurableAgentRuntime\";\nimport { SubmissionLedger, type SubmissionSnapshot } from \"@effect-agent/thread/SubmissionLedger\";\nimport {\n Clock,\n Context,\n DateTime,\n Effect,\n Layer,\n Option,\n Random,\n Ref,\n Schema,\n Semaphore,\n Stream,\n} from \"effect\";\n\nimport { ThreadObjectIdentity, DurableObjectContext } from \"./CloudflareBindings.ts\";\nimport { CloudflareDurableRuntimeConfig } from \"./CloudflareConfig.ts\";\nimport { safeCauseMessage } from \"./internal/boundary.ts\";\n\n/**\n * The single multiplexed Durable Object alarm (decision D-P6-2). A Durable Object has ONE\n * alarm slot; every cadence the Node host ran on fibers (wake scan, lease expiry, settlement\n * and abort re-checks, retry backoff) multiplexes into one idempotent maintenance pass, and\n * the slot always holds the EARLIEST deadline any caller asked for.\n *\n * The alarm invariant (plan §1.4): every committed actionable mutation carries a newer durable\n * maintenance generation and a committed alarm. Stable externally-driven waits may be\n * nonterminal without retaining an alarm; their resolving mutation advances the generation and\n * restores the alarm atomically.\n */\n\n/** The Durable Object alarm API failed; surfaces on host entry points as a typed refusal. */\nexport class DurableAlarmError extends Schema.TaggedError<DurableAlarmError>()(\n \"DurableAlarmError\",\n {\n operation: Schema.String,\n message: Schema.String,\n cause: Schema.optionalKey(Schema.Defect()),\n },\n) {}\n\nconst alarmFailure =\n (operation: string) =>\n (cause: unknown): DurableAlarmError =>\n DurableAlarmError.make({\n operation,\n message: safeCauseMessage(cause, \"The Cloudflare alarm API failed without a diagnostic\"),\n cause,\n });\n\n/** `ctx.storage` alarm slot as an Effect service; storage is truth, never a memory field. */\nexport class DurableAlarmService extends Context.Service<\n DurableAlarmService,\n {\n /** The scheduled deadline in epoch milliseconds, if any. */\n readonly scheduled: Effect.Effect<Option.Option<number>, DurableAlarmError>;\n /** Replace the slot with this deadline. */\n readonly scheduleAt: (epochMillis: number) => Effect.Effect<void, DurableAlarmError>;\n /** Keep the EARLIER of the existing deadline and this one (the multiplexing rule). */\n readonly ensureScheduledBy: (epochMillis: number) => Effect.Effect<void, DurableAlarmError>;\n /**\n * Arm an immediate alarm (the durable, coalescing local wake) — DEFERRED while a\n * maintenance pass is executing. Workerd cancels an in-flight alarm handler when a new\n * EARLIER deadline is written during its execution (`requestScheduledAlarm`), and the\n * maintenance pass runs INSIDE the alarm handler: an immediate wake landing mid-pass\n * (a routed port mutation, a sibling's `wake()`, the coordinator's own local notify)\n * would kill the running Attempt — manufacturing an ownership loss no real eviction\n * caused, and routing open uncertain-class Tool Calls into spurious Unknown Outcomes.\n * Deferral is contract-safe: wakes are droppable hints, every mutating entry point\n * pre-arms BEFORE its first durable mutation (the alarm invariant never rests on this\n * call). The pass's durable generation check observes any racing mutation, so the\n * in-memory hint does not need to be flushed after a stable wait is acknowledged.\n */\n readonly scheduleNow: Effect.Effect<void, DurableAlarmError>;\n /**\n * Run one maintenance pass with wake deferral (see `scheduleNow`). Calls made while `body`\n * executes are droppable promptness hints; correctness rests on the durable generation.\n */\n readonly withWakesDeferred: <A, E, R>(body: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;\n /** Clear the slot; correctness-sensitive clears live in maintenance generation transactions. */\n readonly cancel: Effect.Effect<void, DurableAlarmError>;\n }\n>()(\"@effect-agent/platform-cloudflare/DurableAlarmService\") {\n static readonly layer: Layer.Layer<DurableAlarmService, never, DurableObjectContext> =\n Layer.effect(DurableAlarmService)(\n Effect.gen(function* () {\n const { ctx } = yield* DurableObjectContext;\n /**\n * In-memory pass bookkeeping — a pure CACHE, never state: a fresh incarnation has no\n * running pass, and a deferred wake lost to eviction was only ever a promptness hint\n * on top of the already-committed pre-armed alarm.\n */\n const runningPasses = yield* Ref.make(0);\n\n const scheduled = Effect.tryPromise({\n try: () => ctx.storage.getAlarm(),\n catch: alarmFailure(\"get alarm\"),\n }).pipe(\n Effect.map((deadline) =>\n deadline === null ? Option.none<number>() : Option.some(deadline),\n ),\n );\n\n const scheduleAt = (epochMillis: number) =>\n Effect.tryPromise({\n try: () => ctx.storage.setAlarm(epochMillis),\n catch: alarmFailure(\"set alarm\"),\n });\n\n const ensureScheduledBy = (epochMillis: number) =>\n scheduled.pipe(\n Effect.flatMap((existing) =>\n Option.isSome(existing) && existing.value <= epochMillis\n ? Effect.void\n : scheduleAt(epochMillis),\n ),\n );\n\n const armNow = Clock.currentTimeMillis.pipe(\n Effect.flatMap((now) => ensureScheduledBy(now)),\n );\n\n const scheduleNow = Ref.get(runningPasses).pipe(\n Effect.flatMap((passes) => (passes > 0 ? Effect.void : armNow)),\n );\n\n const withWakesDeferred = <A, E, R>(body: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>\n Ref.update(runningPasses, (passes) => passes + 1).pipe(\n Effect.andThen(body),\n Effect.ensuring(Ref.update(runningPasses, (passes) => passes - 1)),\n );\n\n const cancel = Effect.tryPromise({\n try: () => ctx.storage.deleteAlarm(),\n catch: alarmFailure(\"delete alarm\"),\n });\n\n return DurableAlarmService.of({\n scheduled,\n scheduleAt,\n ensureScheduledBy,\n scheduleNow,\n withWakesDeferred,\n cancel,\n });\n }),\n );\n}\n\n/** What one maintenance pass did — auditable evidence mirroring `NodeDurableHost`'s report. */\nexport class MaintenancePassReport extends Schema.Class<MaintenancePassReport>(\n \"@effect-agent/platform-cloudflare/MaintenancePassReport\",\n)({\n /** `caught-up` is generation-only; `actionable` ran recovery and at most one head Attempt. */\n phase: Schema.Literals([\"caught-up\", \"actionable\"]),\n /** Recovery decisions executed (or deferred) BEFORE any new claim in this pass. */\n recovered: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n /** Whether the head Attempt settled. Joined input may settle with that head. */\n settled: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n /** Submissions still nonterminal after the pass (suspended/unknown lanes stay honest). */\n nonterminal: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n /** `rearmed` for dirty/autonomous work, `cleared` for stable waits or settlement. */\n alarm: Schema.Literals([\"rearmed\", \"cleared\"]),\n}) {}\n\n/** Fault boundaries around every maintenance-owned durable mutation. */\nexport type ThreadMaintenanceFailpointLocation =\n | \"maintenance:dirty:before\"\n | \"maintenance:dirty:after\"\n | \"maintenance:mutation:armed\"\n | \"maintenance:mutation:finished\"\n | \"maintenance:ensure:before\"\n | \"maintenance:ensure:after\"\n | \"maintenance:begin:before\"\n | \"maintenance:begin:after\"\n | \"maintenance:finish:before\"\n | \"maintenance:finish:after\";\n\nexport type ThreadMaintenanceFailpointHandler = (\n location: ThreadMaintenanceFailpointLocation,\n) => Effect.Effect<void>;\n\n/** Test-only fault authority; production uses the inert layer. */\nexport class ThreadMaintenanceFailpoint extends Context.Service<\n ThreadMaintenanceFailpoint,\n {\n readonly hit: ThreadMaintenanceFailpointHandler;\n }\n>()(\"@effect-agent/platform-cloudflare/ThreadMaintenanceFailpoint\") {\n static readonly layer = Layer.succeed(this)({ hit: () => Effect.void });\n}\n\nconst MaintenanceGeneration = Schema.BigIntFromString.check(\n Schema.isGreaterThanOrEqualToBigInt(0n),\n);\n\n/** Versioned, platform-private maintenance state stored through Durable Object KV. */\nclass ThreadMaintenanceState extends Schema.Class<ThreadMaintenanceState>(\n \"@effect-agent/platform-cloudflare/ThreadMaintenanceState\",\n)({\n schemaVersion: Schema.Literal(1),\n dirty: MaintenanceGeneration,\n processed: MaintenanceGeneration,\n nonterminal: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),\n}) {}\n\nconst MAINTENANCE_STATE_KEY = \"effect-agent:thread-maintenance:v1\";\nconst decodeMaintenanceState = Schema.decodeUnknownSync(ThreadMaintenanceState);\nconst encodeMaintenanceState = Schema.encodeSync(ThreadMaintenanceState);\n\nconst initialMaintenanceState = (): ThreadMaintenanceState =>\n ThreadMaintenanceState.make({\n schemaVersion: 1,\n // Bootstrap Objects created by the pre-generation release without scanning the ledger in\n // the constructor. One useful pass classifies and acknowledges any existing obligation.\n dirty: 1n,\n processed: 0n,\n nonterminal: 0,\n });\n\nconst readMaintenanceState = async (\n transaction: DurableObjectTransaction,\n): Promise<{ readonly state: ThreadMaintenanceState; readonly initialized: boolean }> => {\n const encoded = await transaction.get(MAINTENANCE_STATE_KEY);\n\n return encoded === undefined\n ? { state: initialMaintenanceState(), initialized: false }\n : { state: decodeMaintenanceState(encoded), initialized: true };\n};\n\nconst ensureTransactionAlarmBy = async (\n transaction: DurableObjectTransaction,\n deadline: number,\n): Promise<void> => {\n const scheduled = await transaction.getAlarm();\n\n if (scheduled === null || scheduled > deadline) {\n await transaction.setAlarm(deadline);\n }\n};\n\nconst stableExternalWait = (\n snapshot: SubmissionSnapshot,\n reports: ReadonlyMap<string, RecoveryReport>,\n): boolean => {\n const decision = reports.get(snapshot.submissionId)?.decision._tag;\n\n // An accepted abort still owes cleanup/settlement even if its claim was deferred this pass.\n if (decision === \"SettleAborted\") return false;\n switch (snapshot.state) {\n case \"suspended\":\n case \"joined\":\n return true;\n case \"unknown\":\n return decision === \"AwaitUnknownResolution\" || decision === \"MarkUnknown\";\n case \"admitted\":\n return reports.get(snapshot.submissionId)?.decision._tag === \"AwaitParentEstablishment\";\n case \"input-applied\":\n case \"joining\":\n case \"ready\":\n case \"running\":\n case \"settled\":\n case \"terminalizing\":\n return false;\n }\n};\n\nexport type MaintenancePassFailure =\n | DurableWorkerFailure\n | DurableBindingFailure\n | DurableAlarmError;\n\n/**\n * Incremental, quiescent maintenance over a durable dirty/processed generation (issue #93).\n *\n * `pass` = generation snapshot/pre-arm → recovery → one head Attempt → generation acknowledgement:\n *\n * 1. One storage transaction reads dirty/processed and re-arms before work. A caught-up forced\n * alarm takes an O(1) path without recovery, ledger scans, or canonical-history reads.\n * 2. Recovery strictly precedes a new claim. One head Attempt advances the lane and requests\n * a safe yield after ten minutes. The whole event has a fourteen-minute cooperative timeout.\n * 3. The final transaction acknowledges only the generation observed at pass start. A racing\n * mutation therefore remains `dirty > processed` and retains its atomically-established alarm.\n * 4. Stable external waits acknowledge and clear. Autonomous retry, indeterminate, and lease\n * recovery states leave their generation dirty and retain bounded backoff rearming.\n */\nexport class ThreadMaintenance extends Context.Service<\n ThreadMaintenance,\n {\n /** One idempotent maintenance pass; failures propagate so workerd retries the alarm. */\n readonly pass: Effect.Effect<MaintenancePassReport, MaintenancePassFailure>;\n /**\n * Constructor gate: initialize/inspect only the O(1) maintenance record and ensure a dirty\n * generation has an alarm. It never scans the ledger or canonical history.\n */\n readonly ensureAlarm: Effect.Effect<void, MaintenancePassFailure>;\n /**\n * Serialize the pre-arm boundary with pass acknowledgement, advance the durable dirty\n * generation and arm the alarm in one transaction BEFORE running the caller's mutation.\n * A pass cannot acknowledge while that mutation remains in flight.\n */\n readonly withMutation: <A, E, R>(\n body: Effect.Effect<A, E, R>,\n ) => Effect.Effect<A, E | DurableAlarmError, R>;\n }\n>()(\"@effect-agent/platform-cloudflare/ThreadMaintenance\") {\n static readonly layer: Layer.Layer<\n ThreadMaintenance,\n never,\n | DurableAgentRuntime\n | SubmissionLedger\n | DurableAlarmService\n | ThreadMaintenanceFailpoint\n | CloudflareDurableRuntimeConfig\n | ThreadObjectIdentity\n | DurableObjectContext\n > = Layer.effect(ThreadMaintenance)(\n Effect.gen(function* () {\n const runtime = yield* DurableAgentRuntime;\n const ledger = yield* SubmissionLedger;\n const alarm = yield* DurableAlarmService;\n const config = yield* CloudflareDurableRuntimeConfig;\n const identity = yield* ThreadObjectIdentity;\n const { ctx } = yield* DurableObjectContext;\n const failpoint = yield* ThreadMaintenanceFailpoint;\n\n /**\n * Consecutive no-progress passes — an in-memory CACHE, not state: a fresh incarnation\n * restarts at zero and merely re-arms sooner than a long-lived one would have.\n */\n const stalls = yield* Ref.make(0);\n /**\n * Incarnation-local mutation count guarded with the generation transactions below. It is\n * deliberately not durable: after eviction every begun mutation has stopped, while its\n * pre-armed dirty generation remains durable for recovery. The short gate never spans the\n * caller's mutation or cross-Object I/O.\n */\n const activeMutations = yield* Ref.make(0);\n const generationGate = yield* Semaphore.make(1);\n // At-least-once deliveries are idempotent, but overlapping pass bodies could otherwise\n // acknowledge state while a sibling pass is still mutating it. Port/RPC mutations do not\n // take this permit, so cross-Object I/O cannot deadlock the maintenance serialization.\n const maintenancePassGate = yield* Semaphore.make(1);\n const minimumAlarmDelay = Math.max(1, Math.ceil(config.alarmBackoffBase / 2));\n\n const runTransaction = <A>(\n operation: string,\n transaction: () => Promise<A>,\n ): Effect.Effect<A, DurableAlarmError> =>\n Effect.tryPromise({\n try: transaction,\n catch: alarmFailure(operation),\n });\n\n const beginMutation = Effect.fn(\"ThreadMaintenance.beginMutation\")(function* () {\n yield* failpoint.hit(\"maintenance:dirty:before\");\n const now = yield* Clock.currentTimeMillis;\n\n yield* runTransaction(\"advance maintenance generation\", () =>\n ctx.storage.transaction(async (transaction) => {\n const { state } = await readMaintenanceState(transaction);\n\n const next = ThreadMaintenanceState.make({\n ...state,\n dirty: state.dirty + 1n,\n });\n\n await transaction.put(MAINTENANCE_STATE_KEY, encodeMaintenanceState(next));\n // The earliest configured retry bounds a newly actionable mutation without relying\n // on its best-effort immediate wake hint.\n await ensureTransactionAlarmBy(transaction, now + minimumAlarmDelay);\n }),\n );\n yield* failpoint.hit(\"maintenance:dirty:after\");\n yield* Ref.update(activeMutations, (active) => active + 1);\n });\n\n const endMutation = generationGate.withPermit(\n Ref.update(activeMutations, (active) => Math.max(0, active - 1)),\n );\n\n const withMutation = <A, E, R>(\n body: Effect.Effect<A, E, R>,\n ): Effect.Effect<A, E | DurableAlarmError, R> =>\n Effect.acquireUseRelease(\n generationGate.withPermit(beginMutation()),\n () =>\n failpoint.hit(\"maintenance:mutation:armed\").pipe(\n Effect.andThen(body),\n Effect.tap(() => failpoint.hit(\"maintenance:mutation:finished\")),\n ),\n () => endMutation,\n );\n\n const ensureAlarm = Effect.fn(\"ThreadMaintenance.ensureAlarm\")(function* () {\n yield* failpoint.hit(\"maintenance:ensure:before\");\n const now = yield* Clock.currentTimeMillis;\n\n yield* runTransaction(\"ensure maintenance alarm\", () =>\n ctx.storage.transaction(async (transaction) => {\n const { state, initialized } = await readMaintenanceState(transaction);\n\n if (!initialized) {\n await transaction.put(MAINTENANCE_STATE_KEY, encodeMaintenanceState(state));\n }\n if (state.dirty > state.processed) {\n await ensureTransactionAlarmBy(transaction, now + config.wakeScanInterval);\n }\n }),\n );\n yield* failpoint.hit(\"maintenance:ensure:after\");\n });\n\n const beginPass = Effect.fn(\"ThreadMaintenance.beginPass\")(function* () {\n yield* failpoint.hit(\"maintenance:begin:before\");\n const now = yield* Clock.currentTimeMillis;\n\n const result = yield* runTransaction(\"begin maintenance pass\", () =>\n ctx.storage.transaction(async (transaction) => {\n const { state, initialized } = await readMaintenanceState(transaction);\n\n if (!initialized) {\n await transaction.put(MAINTENANCE_STATE_KEY, encodeMaintenanceState(state));\n }\n if (state.processed >= state.dirty) {\n await transaction.deleteAlarm();\n\n return { _tag: \"CaughtUp\" as const, nonterminal: state.nonterminal };\n }\n // Pre-arm the earliest retry before recovery. A successful finish may move this slot\n // LATER to its bounded backoff, which does not cancel the running handler.\n await ensureTransactionAlarmBy(transaction, now + minimumAlarmDelay);\n\n return { _tag: \"Actionable\" as const, generation: state.dirty };\n }),\n );\n\n yield* failpoint.hit(\"maintenance:begin:after\");\n\n return result;\n });\n\n const rearmDelay = Effect.fn(\"ThreadMaintenance.rearmDelay\")(function* (progressed: boolean) {\n const priorStalls = yield* Ref.getAndUpdate(stalls, (count) =>\n progressed ? 0 : count + 1,\n );\n\n if (progressed) return config.alarmBackoffBase;\n const exponent = Math.min(priorStalls, 30);\n const backoff = Math.min(config.alarmBackoffCap, config.alarmBackoffBase * 2 ** exponent);\n const jitter = yield* Random.next;\n // Full jitter over [backoff/2, backoff]: desynchronizes retry storms without ever\n // waiting longer than the deterministic bound.\n const jittered = Math.ceil(backoff / 2 + (backoff / 2) * jitter);\n\n return Math.min(jittered, config.wakeScanInterval);\n });\n\n const pass = Effect.fn(\"ThreadMaintenance.pass\")(function* (\n yieldAfter: DateTime.Utc,\n ): Effect.fn.Return<MaintenancePassReport, MaintenancePassFailure> {\n const annotate = (report: MaintenancePassReport) =>\n Effect.annotateCurrentSpan({\n phase: report.phase,\n recovered: report.recovered,\n settled: report.settled,\n nonterminal: report.nonterminal,\n alarm: report.alarm,\n }).pipe(Effect.as(report));\n\n const started = yield* generationGate.withPermit(\n Effect.gen(function* () {\n const activeAtStart = yield* Ref.get(activeMutations);\n const generation = yield* beginPass();\n\n return { ...generation, activeAtStart };\n }),\n );\n\n if (started._tag === \"CaughtUp\") {\n return yield* annotate(\n MaintenancePassReport.make({\n phase: \"caught-up\",\n recovered: 0,\n settled: 0,\n nonterminal: started.nonterminal,\n alarm: \"cleared\",\n }),\n );\n }\n // Step 2 — reconciliation strictly precedes new work in this pass (exit gate).\n const recovered: ReadonlyArray<RecoveryReport> = yield* runtime.runRecovery;\n // One head Attempt per event. The runtime yields after a committed turn when the\n // soft deadline is reached; queued followers belong to a subsequent alarm.\n const settlement = yield* runtime.processThreadHead(identity.threadId, { yieldAfter });\n // Observe residual state before acknowledging this exact pass-start generation.\n const remaining = yield* Stream.runCollect(ledger.scanNonterminal);\n const reports = new Map(recovered.map((report) => [report.submissionId, report]));\n const head = remaining[0];\n const headWaiting = head !== undefined && stableExternalWait(head, reports);\n\n const autonomous = remaining.some((snapshot, index) => {\n // FIFO followers cannot execute through a stable external wait. Only plain queued\n // input is dormant here; admission repairs and accepted aborts still need a pass.\n if (\n index > 0 &&\n headWaiting &&\n snapshot.state === \"ready\" &&\n reports.get(snapshot.submissionId)?.decision._tag === \"ApplyInput\"\n )\n return false;\n\n return !stableExternalWait(snapshot, reports);\n });\n\n const progressed =\n Option.isSome(settlement) ||\n recovered.some((report) => report.disposition === \"repaired\");\n\n const delay = autonomous ? yield* rearmDelay(progressed) : 0;\n const now = yield* Clock.currentTimeMillis;\n\n yield* failpoint.hit(\"maintenance:finish:before\");\n\n const alarmDisposition = yield* generationGate.withPermit(\n Effect.gen(function* () {\n const active = yield* Ref.get(activeMutations);\n\n return yield* runTransaction(\"finish maintenance pass\", () =>\n ctx.storage.transaction(async (transaction) => {\n const { state } = await readMaintenanceState(transaction);\n\n // Autonomous work and in-flight mutations intentionally leave the observed\n // generation dirty. Otherwise acknowledge only the pass-start generation.\n const processed =\n autonomous || started.activeAtStart > 0 || active > 0\n ? state.processed\n : state.processed > started.generation\n ? state.processed\n : started.generation;\n\n const next = ThreadMaintenanceState.make({\n ...state,\n processed,\n nonterminal: remaining.length,\n });\n\n await transaction.put(MAINTENANCE_STATE_KEY, encodeMaintenanceState(next));\n if (autonomous) {\n // Replace the crash-fallback slot with this pass's bounded backoff. The target\n // is never earlier than the begin-pass fallback, so workerd does not cancel\n // this running alarm handler before its report/span can complete.\n await transaction.setAlarm(now + delay);\n\n return \"rearmed\" as const;\n }\n if (started.activeAtStart > 0 || active > 0 || next.dirty > next.processed) {\n // A mutation overlapped this pass's observation window or raced\n // acknowledgement. It stays dirty and its pre-armed bounded alarm survives;\n // unseen effects are never acknowledged. Do not accelerate that future alarm\n // from inside the current handler: workerd cancels a running handler when it\n // writes an earlier slot.\n await ensureTransactionAlarmBy(transaction, now + config.wakeScanInterval);\n\n return \"rearmed\" as const;\n }\n await transaction.deleteAlarm();\n\n return \"cleared\" as const;\n }),\n );\n }),\n );\n\n yield* failpoint.hit(\"maintenance:finish:after\");\n if (alarmDisposition === \"cleared\") {\n yield* Ref.set(stalls, 0);\n }\n\n return yield* annotate(\n MaintenancePassReport.make({\n phase: \"actionable\",\n recovered: recovered.length,\n settled: Option.isSome(settlement) ? 1 : 0,\n nonterminal: remaining.length,\n alarm: alarmDisposition,\n }),\n );\n });\n\n return ThreadMaintenance.of({\n // A mid-pass immediate hint is droppable; durable dirty state decides the final alarm.\n pass: Effect.gen(function* () {\n const yieldAfter = DateTime.makeUnsafe((yield* Clock.currentTimeMillis) + 10 * 60_000);\n\n return yield* alarm.withWakesDeferred(maintenancePassGate.withPermit(pass(yieldAfter)));\n }).pipe(\n // Include permit waiting, recovery and acknowledgement in the event deadline.\n // Interruption releases Attempt ownership, leaving the prearmed dirty generation\n // for recovery. It never changes the logical Run duration or settles a policy failure.\n // This cooperative timer cannot preempt synchronous CPU work or stuck finalizers.\n Effect.timeoutOrElse({\n duration: \"14 minutes\",\n orElse: () =>\n DurableAlarmError.make({\n operation: \"maintenance pass deadline\",\n message:\n \"The maintenance event exceeded its 14 minute deadline; durable recovery remains pending\",\n }),\n }),\n ),\n ensureAlarm: ensureAlarm(),\n withMutation,\n });\n }),\n );\n}\n"],"mappings":"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"}
@@ -1,11 +1,11 @@
1
1
  import { ThreadObjectNamespace } from "./CloudflareBindings.mjs";
2
- import { Context, Layer, Schema } from "effect";
2
+ import { Context, Effect, Layer, Schema } from "effect";
3
3
  import { DurableObject, DurableObjectAlarm, DurableObjectState as DurableObjectState$1, WorkerEnvironment } from "effect-cf";
4
4
  import { DoScheduleAlarmControl } from "@effect-agent/storage-cloudflare/DoScheduleStore";
5
- import { ScheduleAuthorizer, ScheduleOwner, SchedulingLimits } from "@effect-agent/thread/Schedule";
5
+ import { ScheduleAuthorizer, ScheduleFailpointError, ScheduleOwner, ScheduleStorageError, SchedulingLimits } from "@effect-agent/thread/Schedule";
6
6
  import { ScheduleDriver, Scheduling } from "@effect-agent/thread/Scheduling";
7
7
  declare namespace CloudflareScheduling_d_exports {
8
- export { CloudflareSchedulingClient, ScheduleAlarmProtocolError, ScheduleOwnerIdentity, ScheduleOwnerNamespace, ScheduleOwnerObjectClass, ScheduleOwnerObjectInstance, ScheduleOwnerObjectRpc, ScheduleOwnerProtocolError, makeScheduleOwnerObjectClass };
8
+ export { CloudflareSchedulingClient, ScheduleAlarmProtocolError, ScheduleOwnerIdentity, ScheduleOwnerNamespace, ScheduleOwnerObjectClass, ScheduleOwnerObjectInstance, ScheduleOwnerObjectRpc, ScheduleOwnerProtocolError, makeScheduleOwnerObjectClass, scheduleAlarmHandler };
9
9
  }
10
10
  declare const ScheduleAlarmProtocolError_base: Schema.Class<ScheduleAlarmProtocolError, Schema.TaggedStruct<"ScheduleAlarmProtocolError", {
11
11
  readonly message: Schema.String;
@@ -31,6 +31,8 @@ declare const ScheduleOwnerIdentity_base: Context.ServiceClass<ScheduleOwnerIden
31
31
  }>;
32
32
  declare class ScheduleOwnerIdentity extends ScheduleOwnerIdentity_base {}
33
33
  type ScheduleRuntimeServices = Scheduling | ScheduleDriver | DoScheduleAlarmControl | ScheduleOwnerIdentity | DurableObjectAlarm.DurableObjectAlarm;
34
+ /** @internal The complete native alarm operation, including its event deadline. */
35
+ declare const scheduleAlarmHandler: (limits: SchedulingLimits) => Effect.Effect<void, ScheduleAlarmProtocolError | ScheduleFailpointError | ScheduleStorageError | import("effect/Cause").TimeoutError | DurableObjectAlarm.DurableObjectAlarmError, DoScheduleAlarmControl | DurableObjectAlarm.DurableObjectAlarm | ScheduleDriver | ScheduleOwnerIdentity>;
34
36
  interface ScheduleOwnerObjectInstance extends InstanceType<DurableObject.DurableObjectClass<Record<never, never>, ScheduleRuntimeServices>> {
35
37
  schedule(encoded: unknown): Promise<unknown>;
36
38
  alarm(alarmInfo?: AlarmInvocationInfo): Promise<void> | void;
@@ -46,5 +48,5 @@ interface ScheduleOwnerObjectClass {
46
48
  */
47
49
  declare const makeScheduleOwnerObjectClass: <E>(host: Layer.Layer<ScheduleAuthorizer | ThreadObjectNamespace, E, DurableObjectState$1.DurableObjectState | WorkerEnvironment | ScheduleOwnerIdentity>, limits?: SchedulingLimits) => ScheduleOwnerObjectClass;
48
50
  //#endregion
49
- export { CloudflareSchedulingClient, ScheduleAlarmProtocolError, ScheduleOwnerIdentity, ScheduleOwnerNamespace, ScheduleOwnerObjectClass, ScheduleOwnerObjectInstance, ScheduleOwnerObjectRpc, ScheduleOwnerProtocolError, makeScheduleOwnerObjectClass, CloudflareScheduling_d_exports as t };
51
+ export { CloudflareSchedulingClient, ScheduleAlarmProtocolError, ScheduleOwnerIdentity, ScheduleOwnerNamespace, ScheduleOwnerObjectClass, ScheduleOwnerObjectInstance, ScheduleOwnerObjectRpc, ScheduleOwnerProtocolError, makeScheduleOwnerObjectClass, scheduleAlarmHandler, CloudflareScheduling_d_exports as t };
50
52
  //# sourceMappingURL=CloudflareScheduling.d.mts.map
@@ -19,7 +19,8 @@ var CloudflareScheduling_exports = /* @__PURE__ */ __exportAll({
19
19
  ScheduleOwnerIdentity: () => ScheduleOwnerIdentity,
20
20
  ScheduleOwnerNamespace: () => ScheduleOwnerNamespace,
21
21
  ScheduleOwnerProtocolError: () => ScheduleOwnerProtocolError,
22
- makeScheduleOwnerObjectClass: () => makeScheduleOwnerObjectClass
22
+ makeScheduleOwnerObjectClass: () => makeScheduleOwnerObjectClass,
23
+ scheduleAlarmHandler: () => scheduleAlarmHandler
23
24
  });
24
25
  const SCHEDULE_ALARM_TAG = "effect-agent/ScheduleOwnerWake";
25
26
  const SCHEDULE_ALARM_ID = "driver";
@@ -307,6 +308,7 @@ const handleScheduleRequest = Effect.fn("ScheduleOwner.handleRequest")(function*
307
308
  }) : Effect.succeed(scheduleProtocolFailure("The Schedule operation failed outside its public contract"))));
308
309
  return yield* encodeScheduleOwnerResponse(response).pipe(Effect.orDie);
309
310
  });
311
+ /** @internal The complete native alarm operation, including its event deadline. */
310
312
  const scheduleAlarmHandler = (limits) => DurableObjectAlarm.processDue((event) => Effect.gen(function* () {
311
313
  if (event.tag !== SCHEDULE_ALARM_TAG || event.id !== SCHEDULE_ALARM_ID) return yield* ScheduleAlarmProtocolError.make({ message: `Unsupported Schedule Owner alarm ${event.tag}/${event.id}` });
312
314
  yield* Schema.decodeUnknownEffect(ScheduleAlarmPayload)(event.payload).pipe(Effect.mapError(() => ScheduleAlarmProtocolError.make({ message: "Unsupported Schedule Owner alarm payload version" })));
@@ -317,7 +319,7 @@ const scheduleAlarmHandler = (limits) => DurableObjectAlarm.processDue((event) =
317
319
  yield* alarmControl.prearm(nowMillis + limits.recoveryPollMillis);
318
320
  if ((yield* scheduling.runDue(owner)).failed > 0) yield* alarmControl.prearm((yield* Clock.currentTimeMillis) + limits.recoveryPollMillis);
319
321
  else yield* alarmControl.reconcile;
320
- }), { mode: "ordered" }).pipe(Effect.asVoid);
322
+ }), { mode: "ordered" }).pipe(Effect.timeout("14 minutes"), Effect.asVoid);
321
323
  /**
322
324
  * The host Layer supplies authorization and routing and is cached for the object incarnation.
323
325
  * Cloudflare eviction does not guarantee its finalizers run. Do not acquire resources requiring
@@ -349,6 +351,6 @@ const makeScheduleOwnerObjectClass = (host, limits = defaultSchedulingLimits) =>
349
351
  return ScheduleOwnerObject;
350
352
  };
351
353
  //#endregion
352
- export { CloudflareSchedulingClient, ScheduleAlarmProtocolError, ScheduleOwnerIdentity, ScheduleOwnerNamespace, ScheduleOwnerProtocolError, makeScheduleOwnerObjectClass, CloudflareScheduling_exports as t };
354
+ export { CloudflareSchedulingClient, ScheduleAlarmProtocolError, ScheduleOwnerIdentity, ScheduleOwnerNamespace, ScheduleOwnerProtocolError, makeScheduleOwnerObjectClass, scheduleAlarmHandler, CloudflareScheduling_exports as t };
353
355
 
354
356
  //# sourceMappingURL=CloudflareScheduling.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"CloudflareScheduling.mjs","names":["ScheduleScopeSchema","ScheduleSnapshotPageSchema","EffectCfDurableObjectState","EffectCfDurableObject"],"sources":["../src/CloudflareScheduling.ts"],"sourcesContent":["import { AgentId } from \"@effect-agent/core/Identifiers\";\nimport {\n DoScheduleAlarmControl,\n DoScheduleTransaction,\n scheduleStoreLayer,\n} from \"@effect-agent/storage-cloudflare/DoScheduleStore\";\nimport { type DurableSubmitAgent } from \"@effect-agent/thread/DurableAgentRuntime\";\nimport { DefinitionDigests, PersistedJson } from \"@effect-agent/thread/Records\";\nimport {\n ScheduleAuthorizationError,\n type ScheduleAuthorizer,\n ScheduleCapacityError,\n ScheduleConflict,\n ScheduleDestination,\n ScheduleFailpointError,\n ScheduleId,\n type SchedulingLimits,\n ScheduleNotFound,\n ScheduleOwner,\n type ScheduleScope,\n ScheduleScope as ScheduleScopeSchema,\n ScheduleSnapshot,\n ScheduleSnapshotPage as ScheduleSnapshotPageSchema,\n ScheduleStorageError,\n ScheduleTimingRequest,\n ScheduleValidationError,\n defaultSchedulingLimits,\n} from \"@effect-agent/thread/Schedule\";\nimport { scheduleOwnerKey } from \"@effect-agent/thread/ScheduleTransition\";\nimport {\n Scheduling,\n ScheduleDriver,\n type ScheduleManagementFailure,\n ScheduleWakeNoop,\n} from \"@effect-agent/thread/Scheduling\";\nimport { BrowserCrypto } from \"@effect/platform-browser\";\nimport { SqliteClient } from \"@effect/sql-sqlite-do\";\nimport { Clock, Context, DateTime, Effect, Layer, Schema } from \"effect\";\nimport {\n DurableObject as EffectCfDurableObject,\n DurableObjectAlarm,\n DurableObjectState as EffectCfDurableObjectState,\n type WorkerEnvironment,\n} from \"effect-cf\";\n\nimport type { ThreadObjectNamespace } from \"./CloudflareBindings.ts\";\nimport { CloudflareThreadClient } from \"./CloudflareThreadClient.ts\";\nimport {\n cloudflarePreparedInputAdmissionLayer,\n cloudflareScheduledInputAdmissionLayer,\n} from \"./internal/prepared-admission.ts\";\n\nconst SCHEDULE_ALARM_TAG = \"effect-agent/ScheduleOwnerWake\";\nconst SCHEDULE_ALARM_ID = \"driver\";\n\nconst ScheduleAlarmPayload = Schema.Struct({\n schemaVersion: Schema.Literal(1),\n generation: Schema.Int.check(Schema.isGreaterThan(0)),\n});\n\nexport class ScheduleAlarmProtocolError extends Schema.TaggedError<ScheduleAlarmProtocolError>()(\n \"ScheduleAlarmProtocolError\",\n { message: Schema.String },\n) {}\n\nconst boundedProtocolMessage = (message: string): string =>\n message.length <= 4_096 ? message : `${message.slice(0, 4_093)}...`;\n\nexport class ScheduleOwnerProtocolError extends Schema.TaggedError<ScheduleOwnerProtocolError>()(\n \"ScheduleOwnerProtocolError\",\n { message: Schema.String.check(Schema.isMaxLength(4_096)) },\n) {}\n\nconst ScheduleMutationRequestFields = {\n schemaVersion: Schema.Literal(1),\n agentId: AgentId,\n input: PersistedJson,\n scope: ScheduleScopeSchema,\n scheduleId: ScheduleId,\n timing: ScheduleTimingRequest,\n destination: ScheduleDestination,\n deliveryPrincipal: ScheduleScopeSchema.fields.principal,\n definitions: DefinitionDigests,\n};\n\nconst ScheduleCreateRequest = Schema.TaggedStruct(\"Create\", ScheduleMutationRequestFields);\n\nconst ScheduleUpdateRequest = Schema.TaggedStruct(\"Update\", {\n ...ScheduleMutationRequestFields,\n expectedRevision: Schema.Int.check(Schema.isGreaterThan(0)),\n});\n\nconst ScheduleGetRequest = Schema.TaggedStruct(\"Get\", {\n schemaVersion: Schema.Literal(1),\n scope: ScheduleScopeSchema,\n scheduleId: ScheduleId,\n});\n\nconst ScheduleListRequest = Schema.TaggedStruct(\"List\", {\n schemaVersion: Schema.Literal(1),\n scope: ScheduleScopeSchema,\n after: Schema.optionalKey(ScheduleId),\n limit: Schema.optionalKey(\n Schema.Int.check(Schema.isGreaterThan(0), Schema.isLessThanOrEqualTo(100)),\n ),\n});\n\nconst ScheduleControlRequest = Schema.TaggedStruct(\"Control\", {\n schemaVersion: Schema.Literal(1),\n operation: Schema.Literals([\"pause\", \"resume\", \"cancel\"]),\n scope: ScheduleScopeSchema,\n scheduleId: ScheduleId,\n expectedRevision: Schema.Int.check(Schema.isGreaterThan(0)),\n});\n\nconst ScheduleOwnerRequest = Schema.Union([\n ScheduleCreateRequest,\n ScheduleUpdateRequest,\n ScheduleGetRequest,\n ScheduleListRequest,\n ScheduleControlRequest,\n]);\n\ntype ScheduleOwnerRequest = typeof ScheduleOwnerRequest.Type;\n\nconst ScheduleOwnerFailure = Schema.Union([\n ScheduleValidationError,\n ScheduleAuthorizationError,\n ScheduleConflict,\n ScheduleNotFound,\n ScheduleCapacityError,\n ScheduleStorageError,\n ScheduleFailpointError,\n ScheduleOwnerProtocolError,\n]);\n\ntype ScheduleOwnerFailure = typeof ScheduleOwnerFailure.Type;\n\nconst ScheduleOwnerResponse = Schema.Union([\n Schema.TaggedStruct(\"Snapshot\", { value: ScheduleSnapshot }),\n Schema.TaggedStruct(\"Page\", { value: ScheduleSnapshotPageSchema }),\n Schema.TaggedStruct(\"Failed\", { failure: ScheduleOwnerFailure }),\n]);\n\ntype ScheduleOwnerResponse = typeof ScheduleOwnerResponse.Type;\n\nconst decodeScheduleOwnerRequest = Schema.decodeUnknownEffect(ScheduleOwnerRequest);\nconst encodeScheduleOwnerRequest = Schema.encodeEffect(ScheduleOwnerRequest);\nconst decodeScheduleOwnerResponse = Schema.decodeUnknownEffect(ScheduleOwnerResponse);\nconst encodeScheduleOwnerResponse = Schema.encodeEffect(ScheduleOwnerResponse);\n\nconst scheduleProtocolFailure = (message: string): ScheduleOwnerResponse => ({\n _tag: \"Failed\",\n failure: ScheduleOwnerProtocolError.make({ message: boundedProtocolMessage(message) }),\n});\n\nexport interface ScheduleOwnerObjectRpc extends Rpc.DurableObjectBranded {\n schedule(encoded: unknown): Promise<unknown>;\n}\n\nexport class ScheduleOwnerNamespace extends Context.Service<\n ScheduleOwnerNamespace,\n { readonly namespace: DurableObjectNamespace<ScheduleOwnerObjectRpc> }\n>()(\"@effect-agent/platform-cloudflare/ScheduleOwnerNamespace\") {}\n\nconst passthroughAgent = (agentId: AgentId): DurableSubmitAgent<typeof PersistedJson> => ({\n definition: { id: agentId, input: PersistedJson },\n});\n\nconst requestOwner = (request: ScheduleOwnerRequest): ScheduleOwner => request.scope.owner;\n\n/** Provides the same authorized management service as NodeScheduling.layer. */\nexport class CloudflareSchedulingClient {\n static readonly layer: Layer.Layer<Scheduling, never, ScheduleOwnerNamespace> = Layer.effect(\n Scheduling,\n Effect.gen(function* () {\n const { namespace } = yield* ScheduleOwnerNamespace;\n\n const call = Effect.fn(\"CloudflareSchedulingClient.call\")(function* (\n owner: ScheduleOwner,\n request: ScheduleOwnerRequest,\n ): Effect.fn.Return<ScheduleOwnerResponse, ScheduleManagementFailure> {\n const encoded = yield* encodeScheduleOwnerRequest(request).pipe(\n Effect.mapError(() =>\n ScheduleStorageError.make({ operation: \"Schedule Owner protocol\", reason: \"corrupt\" }),\n ),\n );\n\n const raw = yield* Effect.tryPromise({\n try: () => namespace.get(namespace.idFromName(scheduleOwnerKey(owner))).schedule(encoded),\n catch: () =>\n ScheduleStorageError.make({\n operation: \"call Schedule Owner\",\n reason: \"unavailable\",\n }),\n });\n\n const response = yield* decodeScheduleOwnerResponse(raw).pipe(\n Effect.mapError(() =>\n ScheduleStorageError.make({ operation: \"Schedule Owner protocol\", reason: \"corrupt\" }),\n ),\n );\n\n if (response._tag !== \"Failed\") return response;\n\n return yield* response.failure._tag === \"ScheduleOwnerProtocolError\"\n ? ScheduleStorageError.make({ operation: \"Schedule Owner protocol\", reason: \"corrupt\" })\n : response.failure;\n });\n\n const encodeInput = Effect.fn(\"CloudflareSchedulingClient.encodeInput\")(function* <\n InputSchema extends Schema.Top,\n >(\n agent: DurableSubmitAgent<InputSchema>,\n input: InputSchema[\"Type\"],\n ): Effect.fn.Return<PersistedJson, ScheduleValidationError, InputSchema[\"EncodingServices\"]> {\n const encoded = yield* Schema.encodeEffect(agent.definition.input)(input).pipe(\n Effect.mapError(() =>\n ScheduleValidationError.make({\n message: \"Unable to encode Agent input\",\n }),\n ),\n );\n\n return yield* Schema.decodeUnknownEffect(PersistedJson)(encoded).pipe(\n Effect.mapError(() =>\n ScheduleValidationError.make({\n message: \"Agent input does not satisfy the canonical persistence bounds\",\n }),\n ),\n );\n });\n\n const create: Scheduling[\"Service\"][\"create\"] = (agent, input, options) =>\n Effect.gen(function* () {\n const payload = yield* encodeInput(agent, input);\n\n const response = yield* call(options.scope.owner, {\n _tag: \"Create\",\n schemaVersion: 1,\n agentId: agent.definition.id,\n input: payload,\n ...options,\n });\n\n return response._tag === \"Snapshot\"\n ? response.value\n : yield* ScheduleStorageError.make({\n operation: \"Schedule Owner protocol\",\n reason: \"corrupt\",\n });\n });\n\n const update: Scheduling[\"Service\"][\"update\"] = (agent, input, options) =>\n Effect.gen(function* () {\n const payload = yield* encodeInput(agent, input);\n\n const response = yield* call(options.scope.owner, {\n _tag: \"Update\",\n schemaVersion: 1,\n agentId: agent.definition.id,\n input: payload,\n ...options,\n });\n\n return response._tag === \"Snapshot\"\n ? response.value\n : yield* ScheduleStorageError.make({\n operation: \"Schedule Owner protocol\",\n reason: \"corrupt\",\n });\n });\n\n const get: Scheduling[\"Service\"][\"get\"] = (scope, scheduleId) =>\n Effect.gen(function* () {\n const response = yield* call(scope.owner, {\n _tag: \"Get\",\n schemaVersion: 1,\n scope,\n scheduleId,\n });\n\n return response._tag === \"Snapshot\"\n ? response.value\n : yield* ScheduleStorageError.make({\n operation: \"Schedule Owner protocol\",\n reason: \"corrupt\",\n });\n });\n\n const list: Scheduling[\"Service\"][\"list\"] = (scope, options = {}) =>\n Effect.gen(function* () {\n const response = yield* call(scope.owner, {\n _tag: \"List\",\n schemaVersion: 1,\n scope,\n ...(options.after === undefined ? {} : { after: options.after }),\n ...(options.limit === undefined ? {} : { limit: options.limit }),\n });\n\n return response._tag === \"Page\"\n ? response.value\n : yield* ScheduleStorageError.make({\n operation: \"Schedule Owner protocol\",\n reason: \"corrupt\",\n });\n });\n\n const control = (\n operation: \"pause\" | \"resume\" | \"cancel\",\n scope: ScheduleScope,\n scheduleId: ScheduleId,\n expectedRevision: number,\n ) =>\n Effect.gen(function* () {\n const response = yield* call(scope.owner, {\n _tag: \"Control\",\n schemaVersion: 1,\n operation,\n scope,\n scheduleId,\n expectedRevision,\n });\n\n return response._tag === \"Snapshot\"\n ? response.value\n : yield* ScheduleStorageError.make({\n operation: \"Schedule Owner protocol\",\n reason: \"corrupt\",\n });\n });\n\n return Scheduling.of({\n create,\n update,\n get,\n list,\n pause: (scope, id, revision) => control(\"pause\", scope, id, revision),\n resume: (scope, id, revision) => control(\"resume\", scope, id, revision),\n cancel: (scope, id, revision) => control(\"cancel\", scope, id, revision),\n });\n }),\n );\n}\n\nexport class ScheduleOwnerIdentity extends Context.Service<\n ScheduleOwnerIdentity,\n { readonly owner: ScheduleOwner }\n>()(\"@effect-agent/platform-cloudflare/ScheduleOwnerIdentity\") {}\n\nconst decodeOwnerName = Effect.fn(\"decodeScheduleOwnerName\")(function* (\n name: string | null | undefined,\n): Effect.fn.Return<ScheduleOwner, ScheduleOwnerProtocolError> {\n if (name === null || name === undefined) {\n return yield* ScheduleOwnerProtocolError.make({\n message: \"Schedule Owner objects require an idFromName identity\",\n });\n }\n\n const tuple = yield* Schema.decodeUnknownEffect(\n Schema.fromJsonString(Schema.Tuple([Schema.String, Schema.String])),\n )(name).pipe(\n Effect.mapError(() =>\n ScheduleOwnerProtocolError.make({ message: \"Schedule Owner object name is malformed\" }),\n ),\n );\n\n return yield* Schema.decodeUnknownEffect(ScheduleOwner)({\n tenantId: tuple[0],\n ownerId: tuple[1],\n }).pipe(\n Effect.mapError(() =>\n ScheduleOwnerProtocolError.make({ message: \"Schedule Owner object identity is invalid\" }),\n ),\n );\n});\n\nconst alarmStorageError = (operation: string) => (error: { readonly _tag: string }) =>\n ScheduleStorageError.make({\n operation,\n reason: error._tag === \"StorageOperationError\" ? \"unavailable\" : \"corrupt\",\n });\n\nconst transactionLayer: Layer.Layer<\n DoScheduleTransaction,\n never,\n DurableObjectAlarm.DurableObjectAlarm\n> = Layer.effect(\n DoScheduleTransaction,\n Effect.gen(function* () {\n const alarms = yield* DurableObjectAlarm.DurableObjectAlarm;\n\n return DoScheduleTransaction.of({\n run: (body) =>\n Effect.gen(function* () {\n const nowMillis = yield* Clock.currentTimeMillis;\n\n return yield* alarms\n .transaction((transaction) =>\n body((replacement) =>\n replacement.deadlineAtMillis === null\n ? transaction\n .cancelAlarm({ id: SCHEDULE_ALARM_ID, tag: SCHEDULE_ALARM_TAG })\n .pipe(Effect.mapError(alarmStorageError(\"cancel Schedule Owner alarm\")))\n : Effect.fromOption(\n DateTime.make(Math.max(replacement.deadlineAtMillis, nowMillis + 1)),\n ).pipe(\n Effect.mapError(() =>\n ScheduleStorageError.make({\n operation: \"validate Schedule Owner alarm deadline\",\n reason: \"corrupt\",\n }),\n ),\n Effect.flatMap((runAt) =>\n transaction\n .scheduleAlarm({\n id: SCHEDULE_ALARM_ID,\n tag: SCHEDULE_ALARM_TAG,\n runAt,\n payload: {\n schemaVersion: 1,\n generation: replacement.generation,\n },\n })\n .pipe(\n Effect.mapError(alarmStorageError(\"schedule Schedule Owner alarm\")),\n ),\n ),\n ),\n ),\n )\n .pipe(\n Effect.catchTag(\"StorageOperationError\", () =>\n ScheduleStorageError.make({\n operation: \"commit Schedule Owner transaction\",\n reason: \"unavailable\",\n }),\n ),\n );\n }),\n });\n }),\n);\n\ntype ScheduleRuntimeServices =\n | Scheduling\n | ScheduleDriver\n | DoScheduleAlarmControl\n | ScheduleOwnerIdentity\n | DurableObjectAlarm.DurableObjectAlarm;\n\nconst ensureOwner = (\n expected: ScheduleOwner,\n request: ScheduleOwnerRequest,\n): Effect.Effect<void, ScheduleOwnerProtocolError> => {\n const observed = requestOwner(request);\n\n return observed.tenantId === expected.tenantId && observed.ownerId === expected.ownerId\n ? Effect.void\n : Effect.fail(\n ScheduleOwnerProtocolError.make({\n message: \"The request owner does not match the addressed Schedule Owner object\",\n }),\n );\n};\n\nconst handleScheduleRequest = Effect.fn(\"ScheduleOwner.handleRequest\")(function* (\n encoded: unknown,\n): Effect.fn.Return<unknown, never, Scheduling | ScheduleOwnerIdentity> {\n const decoded = yield* decodeScheduleOwnerRequest(encoded).pipe(Effect.result);\n\n if (decoded._tag === \"Failure\") {\n return yield* encodeScheduleOwnerResponse(\n scheduleProtocolFailure(\"The Schedule request could not be decoded\"),\n ).pipe(Effect.orDie);\n }\n const request = decoded.success;\n const { owner } = yield* ScheduleOwnerIdentity;\n const scheduling = yield* Scheduling;\n\n const response = yield* Effect.gen(function* () {\n yield* ensureOwner(owner, request);\n switch (request._tag) {\n case \"Create\": {\n const value = yield* scheduling.create(passthroughAgent(request.agentId), request.input, {\n scope: request.scope,\n scheduleId: request.scheduleId,\n timing: request.timing,\n destination: request.destination,\n deliveryPrincipal: request.deliveryPrincipal,\n definitions: request.definitions,\n });\n\n return { _tag: \"Snapshot\" as const, value };\n }\n case \"Update\": {\n const value = yield* scheduling.update(passthroughAgent(request.agentId), request.input, {\n scope: request.scope,\n scheduleId: request.scheduleId,\n timing: request.timing,\n destination: request.destination,\n deliveryPrincipal: request.deliveryPrincipal,\n definitions: request.definitions,\n expectedRevision: request.expectedRevision,\n });\n\n return { _tag: \"Snapshot\" as const, value };\n }\n case \"Get\":\n return {\n _tag: \"Snapshot\" as const,\n value: yield* scheduling.get(request.scope, request.scheduleId),\n };\n case \"List\":\n return {\n _tag: \"Page\" as const,\n value: yield* scheduling.list(request.scope, {\n ...(request.after === undefined ? {} : { after: request.after }),\n ...(request.limit === undefined ? {} : { limit: request.limit }),\n }),\n };\n case \"Control\": {\n const value =\n request.operation === \"pause\"\n ? yield* scheduling.pause(request.scope, request.scheduleId, request.expectedRevision)\n : request.operation === \"resume\"\n ? yield* scheduling.resume(\n request.scope,\n request.scheduleId,\n request.expectedRevision,\n )\n : yield* scheduling.cancel(\n request.scope,\n request.scheduleId,\n request.expectedRevision,\n );\n\n return { _tag: \"Snapshot\" as const, value };\n }\n }\n }).pipe(\n Effect.map((value): ScheduleOwnerResponse => value),\n Effect.catch((failure) =>\n Schema.is(ScheduleOwnerFailure)(failure)\n ? Effect.succeed({ _tag: \"Failed\" as const, failure })\n : Effect.succeed(\n scheduleProtocolFailure(\"The Schedule operation failed outside its public contract\"),\n ),\n ),\n );\n\n return yield* encodeScheduleOwnerResponse(response).pipe(Effect.orDie);\n});\n\nconst scheduleAlarmHandler = (limits: SchedulingLimits) =>\n DurableObjectAlarm.processDue(\n (event) =>\n Effect.gen(function* () {\n if (event.tag !== SCHEDULE_ALARM_TAG || event.id !== SCHEDULE_ALARM_ID) {\n return yield* ScheduleAlarmProtocolError.make({\n message: `Unsupported Schedule Owner alarm ${event.tag}/${event.id}`,\n });\n }\n yield* Schema.decodeUnknownEffect(ScheduleAlarmPayload)(event.payload).pipe(\n Effect.mapError(() =>\n ScheduleAlarmProtocolError.make({\n message: \"Unsupported Schedule Owner alarm payload version\",\n }),\n ),\n );\n const scheduling = yield* ScheduleDriver;\n const alarmControl = yield* DoScheduleAlarmControl;\n const { owner } = yield* ScheduleOwnerIdentity;\n const nowMillis = yield* Clock.currentTimeMillis;\n\n yield* alarmControl.prearm(nowMillis + limits.recoveryPollMillis);\n const pass = yield* scheduling.runDue(owner);\n\n if (pass.failed > 0) {\n yield* alarmControl.prearm((yield* Clock.currentTimeMillis) + limits.recoveryPollMillis);\n } else {\n yield* alarmControl.reconcile;\n }\n }),\n { mode: \"ordered\" },\n ).pipe(Effect.asVoid);\n\nexport interface ScheduleOwnerObjectInstance extends InstanceType<\n EffectCfDurableObject.DurableObjectClass<Record<never, never>, ScheduleRuntimeServices>\n> {\n schedule(encoded: unknown): Promise<unknown>;\n alarm(alarmInfo?: AlarmInvocationInfo): Promise<void> | void;\n}\n\nexport interface ScheduleOwnerObjectClass {\n new (ctx: DurableObjectState, env: Cloudflare.Env): ScheduleOwnerObjectInstance;\n}\n\n/**\n * The host Layer supplies authorization and routing and is cached for the object incarnation.\n * Cloudflare eviction does not guarantee its finalizers run. Do not acquire resources requiring\n * cleanup in this Layer; acquire them inside scoped `manage` / `prepare` operations instead.\n * Native services belong to effect-cf; the database and alarm runtime remain instance-owned.\n */\nexport const makeScheduleOwnerObjectClass = <E>(\n host: Layer.Layer<\n ScheduleAuthorizer | ThreadObjectNamespace,\n E,\n EffectCfDurableObjectState.DurableObjectState | WorkerEnvironment | ScheduleOwnerIdentity\n >,\n limits: SchedulingLimits = defaultSchedulingLimits,\n): ScheduleOwnerObjectClass => {\n const ownerLayer = Layer.effect(\n ScheduleOwnerIdentity,\n Effect.gen(function* () {\n const state = yield* EffectCfDurableObjectState.DurableObjectState;\n\n return ScheduleOwnerIdentity.of({ owner: yield* decodeOwnerName(state.raw.id.name) });\n }),\n );\n\n const sqlLayer = Layer.unwrap(\n Effect.map(EffectCfDurableObjectState.DurableObjectState, (state) =>\n SqliteClient.layer({ storage: state.raw.storage }),\n ),\n );\n\n const application = Layer.merge(Scheduling.layer(limits), ScheduleDriver.layer(limits)).pipe(\n Layer.provideMerge(\n scheduleStoreLayer.pipe(Layer.provide(transactionLayer), Layer.provide(sqlLayer)),\n ),\n Layer.provide(\n cloudflareScheduledInputAdmissionLayer.pipe(\n Layer.provide(cloudflarePreparedInputAdmissionLayer),\n Layer.provide(CloudflareThreadClient.layer),\n ),\n ),\n Layer.provide(ScheduleWakeNoop),\n Layer.provide(BrowserCrypto.layer),\n Layer.provideMerge(DurableObjectAlarm.DurableObjectAlarm.layer),\n Layer.provide(host),\n Layer.provideMerge(ownerLayer),\n );\n\n const runtime: Layer.Layer<\n ScheduleRuntimeServices,\n E | ScheduleStorageError | ScheduleOwnerProtocolError | ScheduleValidationError,\n EffectCfDurableObjectState.DurableObjectState | WorkerEnvironment\n > = Layer.effectContext(\n Effect.gen(function* () {\n const state = yield* EffectCfDurableObjectState.DurableObjectState;\n const scope = yield* Effect.scope;\n\n return yield* state.blockConcurrencyWhile(Layer.buildWithScope(application, scope));\n }),\n );\n\n const rpc = {\n schedule: (encoded: unknown) => handleScheduleRequest(encoded),\n } satisfies EffectCfDurableObject.DurableObjectRpc<ScheduleRuntimeServices>;\n\n const Base = EffectCfDurableObject.make(runtime, {\n initialize: Effect.void,\n rpc,\n alarms: scheduleAlarmHandler(limits),\n });\n\n class ScheduleOwnerObject extends Base {\n override alarm(alarmInfo?: AlarmInvocationInfo): Promise<void> | void {\n return super.alarm?.(alarmInfo);\n }\n }\n\n return ScheduleOwnerObject;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"CloudflareScheduling.mjs","names":["ScheduleScopeSchema","ScheduleSnapshotPageSchema","EffectCfDurableObjectState","EffectCfDurableObject"],"sources":["../src/CloudflareScheduling.ts"],"sourcesContent":["import { AgentId } from \"@effect-agent/core/Identifiers\";\nimport {\n DoScheduleAlarmControl,\n DoScheduleTransaction,\n scheduleStoreLayer,\n} from \"@effect-agent/storage-cloudflare/DoScheduleStore\";\nimport { type DurableSubmitAgent } from \"@effect-agent/thread/DurableAgentRuntime\";\nimport { DefinitionDigests, PersistedJson } from \"@effect-agent/thread/Records\";\nimport {\n ScheduleAuthorizationError,\n type ScheduleAuthorizer,\n ScheduleCapacityError,\n ScheduleConflict,\n ScheduleDestination,\n ScheduleFailpointError,\n ScheduleId,\n type SchedulingLimits,\n ScheduleNotFound,\n ScheduleOwner,\n type ScheduleScope,\n ScheduleScope as ScheduleScopeSchema,\n ScheduleSnapshot,\n ScheduleSnapshotPage as ScheduleSnapshotPageSchema,\n ScheduleStorageError,\n ScheduleTimingRequest,\n ScheduleValidationError,\n defaultSchedulingLimits,\n} from \"@effect-agent/thread/Schedule\";\nimport { scheduleOwnerKey } from \"@effect-agent/thread/ScheduleTransition\";\nimport {\n Scheduling,\n ScheduleDriver,\n type ScheduleManagementFailure,\n ScheduleWakeNoop,\n} from \"@effect-agent/thread/Scheduling\";\nimport { BrowserCrypto } from \"@effect/platform-browser\";\nimport { SqliteClient } from \"@effect/sql-sqlite-do\";\nimport { Clock, Context, DateTime, Effect, Layer, Schema } from \"effect\";\nimport {\n DurableObject as EffectCfDurableObject,\n DurableObjectAlarm,\n DurableObjectState as EffectCfDurableObjectState,\n type WorkerEnvironment,\n} from \"effect-cf\";\n\nimport type { ThreadObjectNamespace } from \"./CloudflareBindings.ts\";\nimport { CloudflareThreadClient } from \"./CloudflareThreadClient.ts\";\nimport {\n cloudflarePreparedInputAdmissionLayer,\n cloudflareScheduledInputAdmissionLayer,\n} from \"./internal/prepared-admission.ts\";\n\nconst SCHEDULE_ALARM_TAG = \"effect-agent/ScheduleOwnerWake\";\nconst SCHEDULE_ALARM_ID = \"driver\";\n\nconst ScheduleAlarmPayload = Schema.Struct({\n schemaVersion: Schema.Literal(1),\n generation: Schema.Int.check(Schema.isGreaterThan(0)),\n});\n\nexport class ScheduleAlarmProtocolError extends Schema.TaggedError<ScheduleAlarmProtocolError>()(\n \"ScheduleAlarmProtocolError\",\n { message: Schema.String },\n) {}\n\nconst boundedProtocolMessage = (message: string): string =>\n message.length <= 4_096 ? message : `${message.slice(0, 4_093)}...`;\n\nexport class ScheduleOwnerProtocolError extends Schema.TaggedError<ScheduleOwnerProtocolError>()(\n \"ScheduleOwnerProtocolError\",\n { message: Schema.String.check(Schema.isMaxLength(4_096)) },\n) {}\n\nconst ScheduleMutationRequestFields = {\n schemaVersion: Schema.Literal(1),\n agentId: AgentId,\n input: PersistedJson,\n scope: ScheduleScopeSchema,\n scheduleId: ScheduleId,\n timing: ScheduleTimingRequest,\n destination: ScheduleDestination,\n deliveryPrincipal: ScheduleScopeSchema.fields.principal,\n definitions: DefinitionDigests,\n};\n\nconst ScheduleCreateRequest = Schema.TaggedStruct(\"Create\", ScheduleMutationRequestFields);\n\nconst ScheduleUpdateRequest = Schema.TaggedStruct(\"Update\", {\n ...ScheduleMutationRequestFields,\n expectedRevision: Schema.Int.check(Schema.isGreaterThan(0)),\n});\n\nconst ScheduleGetRequest = Schema.TaggedStruct(\"Get\", {\n schemaVersion: Schema.Literal(1),\n scope: ScheduleScopeSchema,\n scheduleId: ScheduleId,\n});\n\nconst ScheduleListRequest = Schema.TaggedStruct(\"List\", {\n schemaVersion: Schema.Literal(1),\n scope: ScheduleScopeSchema,\n after: Schema.optionalKey(ScheduleId),\n limit: Schema.optionalKey(\n Schema.Int.check(Schema.isGreaterThan(0), Schema.isLessThanOrEqualTo(100)),\n ),\n});\n\nconst ScheduleControlRequest = Schema.TaggedStruct(\"Control\", {\n schemaVersion: Schema.Literal(1),\n operation: Schema.Literals([\"pause\", \"resume\", \"cancel\"]),\n scope: ScheduleScopeSchema,\n scheduleId: ScheduleId,\n expectedRevision: Schema.Int.check(Schema.isGreaterThan(0)),\n});\n\nconst ScheduleOwnerRequest = Schema.Union([\n ScheduleCreateRequest,\n ScheduleUpdateRequest,\n ScheduleGetRequest,\n ScheduleListRequest,\n ScheduleControlRequest,\n]);\n\ntype ScheduleOwnerRequest = typeof ScheduleOwnerRequest.Type;\n\nconst ScheduleOwnerFailure = Schema.Union([\n ScheduleValidationError,\n ScheduleAuthorizationError,\n ScheduleConflict,\n ScheduleNotFound,\n ScheduleCapacityError,\n ScheduleStorageError,\n ScheduleFailpointError,\n ScheduleOwnerProtocolError,\n]);\n\ntype ScheduleOwnerFailure = typeof ScheduleOwnerFailure.Type;\n\nconst ScheduleOwnerResponse = Schema.Union([\n Schema.TaggedStruct(\"Snapshot\", { value: ScheduleSnapshot }),\n Schema.TaggedStruct(\"Page\", { value: ScheduleSnapshotPageSchema }),\n Schema.TaggedStruct(\"Failed\", { failure: ScheduleOwnerFailure }),\n]);\n\ntype ScheduleOwnerResponse = typeof ScheduleOwnerResponse.Type;\n\nconst decodeScheduleOwnerRequest = Schema.decodeUnknownEffect(ScheduleOwnerRequest);\nconst encodeScheduleOwnerRequest = Schema.encodeEffect(ScheduleOwnerRequest);\nconst decodeScheduleOwnerResponse = Schema.decodeUnknownEffect(ScheduleOwnerResponse);\nconst encodeScheduleOwnerResponse = Schema.encodeEffect(ScheduleOwnerResponse);\n\nconst scheduleProtocolFailure = (message: string): ScheduleOwnerResponse => ({\n _tag: \"Failed\",\n failure: ScheduleOwnerProtocolError.make({ message: boundedProtocolMessage(message) }),\n});\n\nexport interface ScheduleOwnerObjectRpc extends Rpc.DurableObjectBranded {\n schedule(encoded: unknown): Promise<unknown>;\n}\n\nexport class ScheduleOwnerNamespace extends Context.Service<\n ScheduleOwnerNamespace,\n { readonly namespace: DurableObjectNamespace<ScheduleOwnerObjectRpc> }\n>()(\"@effect-agent/platform-cloudflare/ScheduleOwnerNamespace\") {}\n\nconst passthroughAgent = (agentId: AgentId): DurableSubmitAgent<typeof PersistedJson> => ({\n definition: { id: agentId, input: PersistedJson },\n});\n\nconst requestOwner = (request: ScheduleOwnerRequest): ScheduleOwner => request.scope.owner;\n\n/** Provides the same authorized management service as NodeScheduling.layer. */\nexport class CloudflareSchedulingClient {\n static readonly layer: Layer.Layer<Scheduling, never, ScheduleOwnerNamespace> = Layer.effect(\n Scheduling,\n Effect.gen(function* () {\n const { namespace } = yield* ScheduleOwnerNamespace;\n\n const call = Effect.fn(\"CloudflareSchedulingClient.call\")(function* (\n owner: ScheduleOwner,\n request: ScheduleOwnerRequest,\n ): Effect.fn.Return<ScheduleOwnerResponse, ScheduleManagementFailure> {\n const encoded = yield* encodeScheduleOwnerRequest(request).pipe(\n Effect.mapError(() =>\n ScheduleStorageError.make({ operation: \"Schedule Owner protocol\", reason: \"corrupt\" }),\n ),\n );\n\n const raw = yield* Effect.tryPromise({\n try: () => namespace.get(namespace.idFromName(scheduleOwnerKey(owner))).schedule(encoded),\n catch: () =>\n ScheduleStorageError.make({\n operation: \"call Schedule Owner\",\n reason: \"unavailable\",\n }),\n });\n\n const response = yield* decodeScheduleOwnerResponse(raw).pipe(\n Effect.mapError(() =>\n ScheduleStorageError.make({ operation: \"Schedule Owner protocol\", reason: \"corrupt\" }),\n ),\n );\n\n if (response._tag !== \"Failed\") return response;\n\n return yield* response.failure._tag === \"ScheduleOwnerProtocolError\"\n ? ScheduleStorageError.make({ operation: \"Schedule Owner protocol\", reason: \"corrupt\" })\n : response.failure;\n });\n\n const encodeInput = Effect.fn(\"CloudflareSchedulingClient.encodeInput\")(function* <\n InputSchema extends Schema.Top,\n >(\n agent: DurableSubmitAgent<InputSchema>,\n input: InputSchema[\"Type\"],\n ): Effect.fn.Return<PersistedJson, ScheduleValidationError, InputSchema[\"EncodingServices\"]> {\n const encoded = yield* Schema.encodeEffect(agent.definition.input)(input).pipe(\n Effect.mapError(() =>\n ScheduleValidationError.make({\n message: \"Unable to encode Agent input\",\n }),\n ),\n );\n\n return yield* Schema.decodeUnknownEffect(PersistedJson)(encoded).pipe(\n Effect.mapError(() =>\n ScheduleValidationError.make({\n message: \"Agent input does not satisfy the canonical persistence bounds\",\n }),\n ),\n );\n });\n\n const create: Scheduling[\"Service\"][\"create\"] = (agent, input, options) =>\n Effect.gen(function* () {\n const payload = yield* encodeInput(agent, input);\n\n const response = yield* call(options.scope.owner, {\n _tag: \"Create\",\n schemaVersion: 1,\n agentId: agent.definition.id,\n input: payload,\n ...options,\n });\n\n return response._tag === \"Snapshot\"\n ? response.value\n : yield* ScheduleStorageError.make({\n operation: \"Schedule Owner protocol\",\n reason: \"corrupt\",\n });\n });\n\n const update: Scheduling[\"Service\"][\"update\"] = (agent, input, options) =>\n Effect.gen(function* () {\n const payload = yield* encodeInput(agent, input);\n\n const response = yield* call(options.scope.owner, {\n _tag: \"Update\",\n schemaVersion: 1,\n agentId: agent.definition.id,\n input: payload,\n ...options,\n });\n\n return response._tag === \"Snapshot\"\n ? response.value\n : yield* ScheduleStorageError.make({\n operation: \"Schedule Owner protocol\",\n reason: \"corrupt\",\n });\n });\n\n const get: Scheduling[\"Service\"][\"get\"] = (scope, scheduleId) =>\n Effect.gen(function* () {\n const response = yield* call(scope.owner, {\n _tag: \"Get\",\n schemaVersion: 1,\n scope,\n scheduleId,\n });\n\n return response._tag === \"Snapshot\"\n ? response.value\n : yield* ScheduleStorageError.make({\n operation: \"Schedule Owner protocol\",\n reason: \"corrupt\",\n });\n });\n\n const list: Scheduling[\"Service\"][\"list\"] = (scope, options = {}) =>\n Effect.gen(function* () {\n const response = yield* call(scope.owner, {\n _tag: \"List\",\n schemaVersion: 1,\n scope,\n ...(options.after === undefined ? {} : { after: options.after }),\n ...(options.limit === undefined ? {} : { limit: options.limit }),\n });\n\n return response._tag === \"Page\"\n ? response.value\n : yield* ScheduleStorageError.make({\n operation: \"Schedule Owner protocol\",\n reason: \"corrupt\",\n });\n });\n\n const control = (\n operation: \"pause\" | \"resume\" | \"cancel\",\n scope: ScheduleScope,\n scheduleId: ScheduleId,\n expectedRevision: number,\n ) =>\n Effect.gen(function* () {\n const response = yield* call(scope.owner, {\n _tag: \"Control\",\n schemaVersion: 1,\n operation,\n scope,\n scheduleId,\n expectedRevision,\n });\n\n return response._tag === \"Snapshot\"\n ? response.value\n : yield* ScheduleStorageError.make({\n operation: \"Schedule Owner protocol\",\n reason: \"corrupt\",\n });\n });\n\n return Scheduling.of({\n create,\n update,\n get,\n list,\n pause: (scope, id, revision) => control(\"pause\", scope, id, revision),\n resume: (scope, id, revision) => control(\"resume\", scope, id, revision),\n cancel: (scope, id, revision) => control(\"cancel\", scope, id, revision),\n });\n }),\n );\n}\n\nexport class ScheduleOwnerIdentity extends Context.Service<\n ScheduleOwnerIdentity,\n { readonly owner: ScheduleOwner }\n>()(\"@effect-agent/platform-cloudflare/ScheduleOwnerIdentity\") {}\n\nconst decodeOwnerName = Effect.fn(\"decodeScheduleOwnerName\")(function* (\n name: string | null | undefined,\n): Effect.fn.Return<ScheduleOwner, ScheduleOwnerProtocolError> {\n if (name === null || name === undefined) {\n return yield* ScheduleOwnerProtocolError.make({\n message: \"Schedule Owner objects require an idFromName identity\",\n });\n }\n\n const tuple = yield* Schema.decodeUnknownEffect(\n Schema.fromJsonString(Schema.Tuple([Schema.String, Schema.String])),\n )(name).pipe(\n Effect.mapError(() =>\n ScheduleOwnerProtocolError.make({ message: \"Schedule Owner object name is malformed\" }),\n ),\n );\n\n return yield* Schema.decodeUnknownEffect(ScheduleOwner)({\n tenantId: tuple[0],\n ownerId: tuple[1],\n }).pipe(\n Effect.mapError(() =>\n ScheduleOwnerProtocolError.make({ message: \"Schedule Owner object identity is invalid\" }),\n ),\n );\n});\n\nconst alarmStorageError = (operation: string) => (error: { readonly _tag: string }) =>\n ScheduleStorageError.make({\n operation,\n reason: error._tag === \"StorageOperationError\" ? \"unavailable\" : \"corrupt\",\n });\n\nconst transactionLayer: Layer.Layer<\n DoScheduleTransaction,\n never,\n DurableObjectAlarm.DurableObjectAlarm\n> = Layer.effect(\n DoScheduleTransaction,\n Effect.gen(function* () {\n const alarms = yield* DurableObjectAlarm.DurableObjectAlarm;\n\n return DoScheduleTransaction.of({\n run: (body) =>\n Effect.gen(function* () {\n const nowMillis = yield* Clock.currentTimeMillis;\n\n return yield* alarms\n .transaction((transaction) =>\n body((replacement) =>\n replacement.deadlineAtMillis === null\n ? transaction\n .cancelAlarm({ id: SCHEDULE_ALARM_ID, tag: SCHEDULE_ALARM_TAG })\n .pipe(Effect.mapError(alarmStorageError(\"cancel Schedule Owner alarm\")))\n : Effect.fromOption(\n DateTime.make(Math.max(replacement.deadlineAtMillis, nowMillis + 1)),\n ).pipe(\n Effect.mapError(() =>\n ScheduleStorageError.make({\n operation: \"validate Schedule Owner alarm deadline\",\n reason: \"corrupt\",\n }),\n ),\n Effect.flatMap((runAt) =>\n transaction\n .scheduleAlarm({\n id: SCHEDULE_ALARM_ID,\n tag: SCHEDULE_ALARM_TAG,\n runAt,\n payload: {\n schemaVersion: 1,\n generation: replacement.generation,\n },\n })\n .pipe(\n Effect.mapError(alarmStorageError(\"schedule Schedule Owner alarm\")),\n ),\n ),\n ),\n ),\n )\n .pipe(\n Effect.catchTag(\"StorageOperationError\", () =>\n ScheduleStorageError.make({\n operation: \"commit Schedule Owner transaction\",\n reason: \"unavailable\",\n }),\n ),\n );\n }),\n });\n }),\n);\n\ntype ScheduleRuntimeServices =\n | Scheduling\n | ScheduleDriver\n | DoScheduleAlarmControl\n | ScheduleOwnerIdentity\n | DurableObjectAlarm.DurableObjectAlarm;\n\nconst ensureOwner = (\n expected: ScheduleOwner,\n request: ScheduleOwnerRequest,\n): Effect.Effect<void, ScheduleOwnerProtocolError> => {\n const observed = requestOwner(request);\n\n return observed.tenantId === expected.tenantId && observed.ownerId === expected.ownerId\n ? Effect.void\n : Effect.fail(\n ScheduleOwnerProtocolError.make({\n message: \"The request owner does not match the addressed Schedule Owner object\",\n }),\n );\n};\n\nconst handleScheduleRequest = Effect.fn(\"ScheduleOwner.handleRequest\")(function* (\n encoded: unknown,\n): Effect.fn.Return<unknown, never, Scheduling | ScheduleOwnerIdentity> {\n const decoded = yield* decodeScheduleOwnerRequest(encoded).pipe(Effect.result);\n\n if (decoded._tag === \"Failure\") {\n return yield* encodeScheduleOwnerResponse(\n scheduleProtocolFailure(\"The Schedule request could not be decoded\"),\n ).pipe(Effect.orDie);\n }\n const request = decoded.success;\n const { owner } = yield* ScheduleOwnerIdentity;\n const scheduling = yield* Scheduling;\n\n const response = yield* Effect.gen(function* () {\n yield* ensureOwner(owner, request);\n switch (request._tag) {\n case \"Create\": {\n const value = yield* scheduling.create(passthroughAgent(request.agentId), request.input, {\n scope: request.scope,\n scheduleId: request.scheduleId,\n timing: request.timing,\n destination: request.destination,\n deliveryPrincipal: request.deliveryPrincipal,\n definitions: request.definitions,\n });\n\n return { _tag: \"Snapshot\" as const, value };\n }\n case \"Update\": {\n const value = yield* scheduling.update(passthroughAgent(request.agentId), request.input, {\n scope: request.scope,\n scheduleId: request.scheduleId,\n timing: request.timing,\n destination: request.destination,\n deliveryPrincipal: request.deliveryPrincipal,\n definitions: request.definitions,\n expectedRevision: request.expectedRevision,\n });\n\n return { _tag: \"Snapshot\" as const, value };\n }\n case \"Get\":\n return {\n _tag: \"Snapshot\" as const,\n value: yield* scheduling.get(request.scope, request.scheduleId),\n };\n case \"List\":\n return {\n _tag: \"Page\" as const,\n value: yield* scheduling.list(request.scope, {\n ...(request.after === undefined ? {} : { after: request.after }),\n ...(request.limit === undefined ? {} : { limit: request.limit }),\n }),\n };\n case \"Control\": {\n const value =\n request.operation === \"pause\"\n ? yield* scheduling.pause(request.scope, request.scheduleId, request.expectedRevision)\n : request.operation === \"resume\"\n ? yield* scheduling.resume(\n request.scope,\n request.scheduleId,\n request.expectedRevision,\n )\n : yield* scheduling.cancel(\n request.scope,\n request.scheduleId,\n request.expectedRevision,\n );\n\n return { _tag: \"Snapshot\" as const, value };\n }\n }\n }).pipe(\n Effect.map((value): ScheduleOwnerResponse => value),\n Effect.catch((failure) =>\n Schema.is(ScheduleOwnerFailure)(failure)\n ? Effect.succeed({ _tag: \"Failed\" as const, failure })\n : Effect.succeed(\n scheduleProtocolFailure(\"The Schedule operation failed outside its public contract\"),\n ),\n ),\n );\n\n return yield* encodeScheduleOwnerResponse(response).pipe(Effect.orDie);\n});\n\n/** @internal The complete native alarm operation, including its event deadline. */\nexport const scheduleAlarmHandler = (limits: SchedulingLimits) =>\n DurableObjectAlarm.processDue(\n (event) =>\n Effect.gen(function* () {\n if (event.tag !== SCHEDULE_ALARM_TAG || event.id !== SCHEDULE_ALARM_ID) {\n return yield* ScheduleAlarmProtocolError.make({\n message: `Unsupported Schedule Owner alarm ${event.tag}/${event.id}`,\n });\n }\n yield* Schema.decodeUnknownEffect(ScheduleAlarmPayload)(event.payload).pipe(\n Effect.mapError(() =>\n ScheduleAlarmProtocolError.make({\n message: \"Unsupported Schedule Owner alarm payload version\",\n }),\n ),\n );\n const scheduling = yield* ScheduleDriver;\n const alarmControl = yield* DoScheduleAlarmControl;\n const { owner } = yield* ScheduleOwnerIdentity;\n const nowMillis = yield* Clock.currentTimeMillis;\n\n yield* alarmControl.prearm(nowMillis + limits.recoveryPollMillis);\n const pass = yield* scheduling.runDue(owner);\n\n if (pass.failed > 0) {\n yield* alarmControl.prearm((yield* Clock.currentTimeMillis) + limits.recoveryPollMillis);\n } else {\n yield* alarmControl.reconcile;\n }\n }),\n { mode: \"ordered\" },\n ).pipe(\n // Bound due acquisition and acknowledgement as well as admission. Prepared occurrences\n // and their replacement alarm survive interruption and retain their idempotency keys.\n Effect.timeout(\"14 minutes\"),\n Effect.asVoid,\n );\n\nexport interface ScheduleOwnerObjectInstance extends InstanceType<\n EffectCfDurableObject.DurableObjectClass<Record<never, never>, ScheduleRuntimeServices>\n> {\n schedule(encoded: unknown): Promise<unknown>;\n alarm(alarmInfo?: AlarmInvocationInfo): Promise<void> | void;\n}\n\nexport interface ScheduleOwnerObjectClass {\n new (ctx: DurableObjectState, env: Cloudflare.Env): ScheduleOwnerObjectInstance;\n}\n\n/**\n * The host Layer supplies authorization and routing and is cached for the object incarnation.\n * Cloudflare eviction does not guarantee its finalizers run. Do not acquire resources requiring\n * cleanup in this Layer; acquire them inside scoped `manage` / `prepare` operations instead.\n * Native services belong to effect-cf; the database and alarm runtime remain instance-owned.\n */\nexport const makeScheduleOwnerObjectClass = <E>(\n host: Layer.Layer<\n ScheduleAuthorizer | ThreadObjectNamespace,\n E,\n EffectCfDurableObjectState.DurableObjectState | WorkerEnvironment | ScheduleOwnerIdentity\n >,\n limits: SchedulingLimits = defaultSchedulingLimits,\n): ScheduleOwnerObjectClass => {\n const ownerLayer = Layer.effect(\n ScheduleOwnerIdentity,\n Effect.gen(function* () {\n const state = yield* EffectCfDurableObjectState.DurableObjectState;\n\n return ScheduleOwnerIdentity.of({ owner: yield* decodeOwnerName(state.raw.id.name) });\n }),\n );\n\n const sqlLayer = Layer.unwrap(\n Effect.map(EffectCfDurableObjectState.DurableObjectState, (state) =>\n SqliteClient.layer({ storage: state.raw.storage }),\n ),\n );\n\n const application = Layer.merge(Scheduling.layer(limits), ScheduleDriver.layer(limits)).pipe(\n Layer.provideMerge(\n scheduleStoreLayer.pipe(Layer.provide(transactionLayer), Layer.provide(sqlLayer)),\n ),\n Layer.provide(\n cloudflareScheduledInputAdmissionLayer.pipe(\n Layer.provide(cloudflarePreparedInputAdmissionLayer),\n Layer.provide(CloudflareThreadClient.layer),\n ),\n ),\n Layer.provide(ScheduleWakeNoop),\n Layer.provide(BrowserCrypto.layer),\n Layer.provideMerge(DurableObjectAlarm.DurableObjectAlarm.layer),\n Layer.provide(host),\n Layer.provideMerge(ownerLayer),\n );\n\n const runtime: Layer.Layer<\n ScheduleRuntimeServices,\n E | ScheduleStorageError | ScheduleOwnerProtocolError | ScheduleValidationError,\n EffectCfDurableObjectState.DurableObjectState | WorkerEnvironment\n > = Layer.effectContext(\n Effect.gen(function* () {\n const state = yield* EffectCfDurableObjectState.DurableObjectState;\n const scope = yield* Effect.scope;\n\n return yield* state.blockConcurrencyWhile(Layer.buildWithScope(application, scope));\n }),\n );\n\n const rpc = {\n schedule: (encoded: unknown) => handleScheduleRequest(encoded),\n } satisfies EffectCfDurableObject.DurableObjectRpc<ScheduleRuntimeServices>;\n\n const Base = EffectCfDurableObject.make(runtime, {\n initialize: Effect.void,\n rpc,\n alarms: scheduleAlarmHandler(limits),\n });\n\n class ScheduleOwnerObject extends Base {\n override alarm(alarmInfo?: AlarmInvocationInfo): Promise<void> | void {\n return super.alarm?.(alarmInfo);\n }\n }\n\n return ScheduleOwnerObject;\n};\n"],"mappings":"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"}
@@ -1,5 +1,4 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import "./CloudflareBindings.mjs";
3
2
  import { CloudflareThreadClient } from "./CloudflareThreadClient.mjs";
4
3
  import { t as cloudflarePreparedInputAdmissionLayer } from "./prepared-admission-DRBhl2Sp.mjs";
5
4
  import { Principal } from "@effect-agent/thread/SubmissionLedger";