@effect-agent/platform-cloudflare 0.1.0-beta.6 → 0.1.0-beta.60

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.
Files changed (95) hide show
  1. package/dist/Alarm.d.mts +168 -0
  2. package/dist/Alarm.mjs +415 -0
  3. package/dist/Alarm.mjs.map +1 -0
  4. package/dist/BrowserRestCapture.d.mts +35 -0
  5. package/dist/BrowserRestCapture.mjs +238 -0
  6. package/dist/BrowserRestCapture.mjs.map +1 -0
  7. package/dist/BrowserRestCrawl.d.mts +17 -0
  8. package/dist/BrowserRestCrawl.mjs +244 -0
  9. package/dist/BrowserRestCrawl.mjs.map +1 -0
  10. package/dist/CloudflareBindings.d.mts +105 -0
  11. package/dist/CloudflareBindings.mjs +98 -0
  12. package/dist/CloudflareBindings.mjs.map +1 -0
  13. package/dist/CloudflareBrowser-Bj22nNUT.mjs +466 -0
  14. package/dist/CloudflareBrowser-Bj22nNUT.mjs.map +1 -0
  15. package/dist/CloudflareBrowser-DJq53niJ.d.mts +80 -0
  16. package/dist/CloudflareBrowser.d.mts +2 -0
  17. package/dist/CloudflareBrowser.mjs +2 -0
  18. package/dist/CloudflareCodeMode.d.mts +44 -0
  19. package/dist/CloudflareCodeMode.mjs +611 -0
  20. package/dist/CloudflareCodeMode.mjs.map +1 -0
  21. package/dist/CloudflareConfig-f3CqTel1.d.mts +101 -0
  22. package/dist/CloudflareConfig.d.mts +2 -0
  23. package/dist/CloudflareConfig.mjs +122 -0
  24. package/dist/CloudflareConfig.mjs.map +1 -0
  25. package/dist/CloudflareMemory.d.mts +140 -0
  26. package/dist/CloudflareMemory.mjs +168 -0
  27. package/dist/CloudflareMemory.mjs.map +1 -0
  28. package/dist/CloudflareScheduling.d.mts +52 -0
  29. package/dist/CloudflareScheduling.mjs +389 -0
  30. package/dist/CloudflareScheduling.mjs.map +1 -0
  31. package/dist/CloudflareSubscriptions.d.mts +87 -0
  32. package/dist/CloudflareSubscriptions.mjs +524 -0
  33. package/dist/CloudflareSubscriptions.mjs.map +1 -0
  34. package/dist/CloudflareThreadClient.d.mts +1214 -0
  35. package/dist/CloudflareThreadClient.mjs +386 -0
  36. package/dist/CloudflareThreadClient.mjs.map +1 -0
  37. package/dist/InteractiveBrowser.d.mts +144 -0
  38. package/dist/InteractiveBrowser.mjs +1090 -0
  39. package/dist/InteractiveBrowser.mjs.map +1 -0
  40. package/dist/ProtectedBrowser.d.mts +65 -0
  41. package/dist/ProtectedBrowser.mjs +859 -0
  42. package/dist/ProtectedBrowser.mjs.map +1 -0
  43. package/dist/ThreadObject-CvnEnVQH.d.mts +772 -0
  44. package/dist/ThreadObject-s5w3V_co.mjs +675 -0
  45. package/dist/ThreadObject-s5w3V_co.mjs.map +1 -0
  46. package/dist/ThreadObject.d.mts +2 -0
  47. package/dist/ThreadObject.mjs +3 -0
  48. package/dist/WakeScheduler.d.mts +23 -0
  49. package/dist/WakeScheduler.mjs +60 -0
  50. package/dist/WakeScheduler.mjs.map +1 -0
  51. package/dist/boundary-BguazVkh.mjs +42 -0
  52. package/dist/boundary-BguazVkh.mjs.map +1 -0
  53. package/dist/browser-session-lifecycle-CUbVfEgP.mjs +84 -0
  54. package/dist/browser-session-lifecycle-CUbVfEgP.mjs.map +1 -0
  55. package/dist/browser-session-lifecycle-DJpqLXy_.d.mts +21 -0
  56. package/dist/index.d.mts +12 -1543
  57. package/dist/index.mjs +12 -1636
  58. package/dist/prepared-admission-G7N4DDqS.mjs +73 -0
  59. package/dist/prepared-admission-G7N4DDqS.mjs.map +1 -0
  60. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  61. package/package.json +1 -53
  62. package/src/Alarm.ts +862 -0
  63. package/src/BrowserRestCapture.ts +477 -0
  64. package/src/BrowserRestCrawl.ts +540 -0
  65. package/src/CloudflareBindings.ts +171 -0
  66. package/src/CloudflareBrowser.ts +15 -0
  67. package/src/{code-mode-executor.ts → CloudflareCodeMode.ts} +367 -204
  68. package/src/{config.ts → CloudflareConfig.ts} +9 -8
  69. package/src/CloudflareMemory.ts +359 -0
  70. package/src/CloudflareScheduling.ts +733 -0
  71. package/src/CloudflareSubscriptions.ts +1045 -0
  72. package/src/CloudflareThreadClient.ts +807 -0
  73. package/src/InteractiveBrowser.ts +2357 -0
  74. package/src/ProtectedBrowser.ts +2 -0
  75. package/src/{conversation-object.ts → ThreadObject.ts} +423 -239
  76. package/src/{wake-scheduler.ts → WakeScheduler.ts} +23 -23
  77. package/src/index.ts +11 -23
  78. package/src/internal/boundary.ts +55 -0
  79. package/src/internal/browser-quick-action.ts +818 -0
  80. package/src/internal/browser-session-lifecycle.ts +160 -0
  81. package/src/internal/layers.ts +615 -0
  82. package/src/internal/message-delivery.ts +90 -0
  83. package/src/internal/prepared-admission.ts +116 -0
  84. package/src/internal/progress-wait.ts +121 -0
  85. package/src/internal/transport.ts +42 -0
  86. package/src/protected-browser/binding.ts +187 -0
  87. package/src/protected-browser/inspect-frame.ts +125 -0
  88. package/src/protected-browser/native.ts +429 -0
  89. package/src/protected-browser/policy.ts +719 -0
  90. package/dist/index.mjs.map +0 -1
  91. package/src/alarm.ts +0 -334
  92. package/src/bindings.ts +0 -145
  93. package/src/client.ts +0 -646
  94. package/src/layers.ts +0 -376
  95. package/src/transport.ts +0 -38
@@ -0,0 +1,675 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
+ import { DurableObjectContext, ThreadObjectIdentity, ThreadObjectNamespace, threadNamespaceFromEnv } from "./CloudflareBindings.mjs";
3
+ import { AdmissionLimitExceeded, CLOUDFLARE_RUNTIME_DEFAULTS, CloudflareDurableRuntimeConfig, CloudflareDurableRuntimeConfigValue, CloudflarePlatformConfigError } from "./CloudflareConfig.mjs";
4
+ import { DurableAlarmError, DurableAlarmService, ThreadMaintenance, ThreadMaintenanceFailpoint, ThreadMessageDelivery, ThreadMutationGate, ThreadPublication, publishCommitted } from "./Alarm.mjs";
5
+ import { AbortRecorded, ApprovalRecorded, CloudflareThreadClient, HostFailed, HostProtocolError, ObservedPage, ProgressCancelled, ProgressObserved, SettlementReached, SubmissionStatusResponse, SubmitSucceeded, UnknownResolutionRecorded, boundHostDiagnostic, decodeAbortCommand, decodeApprovalDecisionCommand, decodeAwaitProgressRequest, decodeCancelProgressRequest, decodeObservePageRequest, decodeReceipt, decodeSubmitRequest, decodeUnknownResolutionCommand, encodeHostResponse } from "./CloudflareThreadClient.mjs";
6
+ import { t as cloudflarePreparedInputAdmissionLayer } from "./prepared-admission-G7N4DDqS.mjs";
7
+ import { cloudflareWakeSchedulerLayer } from "./WakeScheduler.mjs";
8
+ import { compileRegistrations } from "@effect-agent/thread/AgentRegistration";
9
+ import { DurableAgentRuntime, DurableRuntimeConfig, RecoveryReport } from "@effect-agent/thread/DurableAgentRuntime";
10
+ import { AdmissionPolicyError, LedgerError, OwnershipLost, SettlementConflict, SubmissionLedger, SubmissionLookupByKey } from "@effect-agent/thread/SubmissionLedger";
11
+ import { ThreadProjectionMaintenance } from "@effect-agent/thread/ThreadProjectionMaintenance";
12
+ import { Cause, Clock, Context, Deferred, Duration, Effect, Layer, Option, Ref, Schema, Semaphore, Stream } from "effect";
13
+ import { SubmissionId, ThreadId } from "@effect-agent/core/Identifiers";
14
+ import { PersistedJson, ProducerId } from "@effect-agent/thread/Records";
15
+ import { DurableObject, DurableObjectState, WorkerEnvironment } from "effect-cf";
16
+ import { BrowserCrypto } from "@effect/platform-browser";
17
+ import { SqliteClient } from "@effect/sql-sqlite-do";
18
+ import { DigestError } from "@effect-agent/thread/Digest";
19
+ import { DurableRuntimeFailpoint, DurableRuntimeFailpointError } from "@effect-agent/thread/DurableFailpoint";
20
+ import { OperationAuthorizationRequest, OperationAuthorizer, OperationDenied, operationAuthorizerLayer } from "@effect-agent/thread/OperationAuthorizer";
21
+ import { AppendConflict, FenceRejected, ThreadNotMaterialized, ThreadRead, ThreadStore, ThreadStoreError } from "@effect-agent/thread/ThreadStore";
22
+ import { decodePortRequest, encodePortResponse } from "@effect-agent/storage-cloudflare/PortProtocol";
23
+ import { IntegrityReport, ObligationReport, ObligationThresholds, RecoveryExplanation, RetryCommand, RetryRefused } from "@effect-agent/thread/Admin";
24
+ import { RunJournalError } from "@effect-agent/thread/RunJournal";
25
+ import { WakeScheduler } from "@effect-agent/thread/WakeScheduler";
26
+ import { CurrentToolFailureObserver, RunContextPreparationPassthrough, RunToolAuthorization, toolFailureObserverLayer } from "@effect-agent/engine/RunOptions";
27
+ import { doMessageDeliveryStoreLayer } from "@effect-agent/storage-cloudflare/DoMessageDeliveryStore";
28
+ import "@effect-agent/storage-cloudflare/DoStorageFailpoint";
29
+ import { submissionLedgerLayer } from "@effect-agent/storage-cloudflare/DoSubmissionLedger";
30
+ import { storageConfigLayer, storageFailpointLayer, threadStoreLayer } from "@effect-agent/storage-cloudflare/DoThreadStore";
31
+ import { ThreadPortTransport, executePortRequest, portTransportFailure, routedSubmissionLedgerLayer, routedThreadStoreLayer } from "@effect-agent/storage-cloudflare/PortRouting";
32
+ import { MessageDeliveryDriver, MessageDeliveryError, MessageDeliveryStore } from "@effect-agent/thread/MessageDelivery";
33
+ import { ToolReconciler } from "@effect-agent/thread/ToolReconciler";
34
+ import { SqlClient } from "effect/unstable/sql/SqlClient";
35
+ //#region src/internal/message-delivery.ts
36
+ /** Every externally requested write prearms the owning Object's maintenance generation. */
37
+ const guardedMessageDeliveryStoreLayer = Layer.effect(MessageDeliveryStore, Effect.gen(function* () {
38
+ const store = yield* MessageDeliveryStore;
39
+ const mutations = yield* ThreadMutationGate;
40
+ const { threadId } = yield* ThreadObjectIdentity;
41
+ const deadline = yield* Ref.make(void 0);
42
+ const cacheGate = yield* Semaphore.make(1);
43
+ const local = (owner, body) => owner === threadId ? body : Effect.fail(MessageDeliveryError.make({
44
+ reason: "validation",
45
+ operation: "message owner"
46
+ }));
47
+ const mutate = (body) => mutations.withMutation(cacheGate.withPermit(Ref.set(deadline, void 0).pipe(Effect.andThen(body)))).pipe(Effect.catchTag("DurableAlarmError", () => MessageDeliveryError.make({
48
+ reason: "storage",
49
+ operation: "prearm message delivery"
50
+ })));
51
+ const nextDeadline = cacheGate.withPermit(Effect.gen(function* () {
52
+ const cached = yield* Ref.get(deadline);
53
+ if (cached !== void 0) return cached;
54
+ const current = yield* store.nextDeadline(threadId);
55
+ yield* Ref.set(deadline, current);
56
+ return current;
57
+ }));
58
+ return MessageDeliveryStore.of({
59
+ insert: (record) => local(record.key.ownerThreadId, mutate(store.insert(record))),
60
+ get: (key) => local(key.ownerThreadId, store.get(key)),
61
+ list: (request) => local(request.ownerThreadId, store.list(request)),
62
+ change: (key, change) => local(key.ownerThreadId, mutate(store.change(key, change))),
63
+ due: (nowMillis, limit, owner = threadId) => local(owner, store.due(nowMillis, limit, threadId)),
64
+ nextDeadline: (owner = threadId) => local(owner, nextDeadline)
65
+ });
66
+ }));
67
+ /** Message progress shares the native alarm slot without blocking source runtime work. */
68
+ const threadMessageDeliveryLayer = Layer.effectContext(Effect.gen(function* () {
69
+ const driver = yield* MessageDeliveryDriver;
70
+ const store = yield* MessageDeliveryStore;
71
+ const { threadId } = yield* ThreadObjectIdentity;
72
+ const failure = (operation) => () => DurableAlarmError.make({
73
+ operation,
74
+ message: "Durable message recovery remains pending"
75
+ });
76
+ return Context.make(ThreadMessageDelivery, {
77
+ drain: Effect.gen(function* () {
78
+ const deadline = yield* store.nextDeadline(threadId);
79
+ if (deadline !== null && deadline <= (yield* Clock.currentTimeMillis)) yield* driver.runDue(threadId);
80
+ }).pipe(Effect.mapError(failure("drain message delivery"))),
81
+ pendingDeadline: store.nextDeadline(threadId).pipe(Effect.map(Option.fromNullishOr), Effect.mapError(failure("read message deadline")))
82
+ });
83
+ }));
84
+ //#endregion
85
+ //#region src/internal/progress-wait.ts
86
+ /** Cancellation tombstones are bounded hints, never durable authority. */
87
+ const MAX_CANCELLATION_TOMBSTONES = 1024;
88
+ /**
89
+ * Per-incarnation cancellation registry for long-lived progress RPCs. The public runtime owns
90
+ * the actual wake registration; this host-only registry lets an interrupted Worker Effect ask
91
+ * the Object to interrupt its scoped wait before the Worker execution context itself ends.
92
+ */
93
+ var ProgressWaitRegistry = class ProgressWaitRegistry extends Context.Service()("@effect-agent/platform-cloudflare/ProgressWaitRegistry") {
94
+ static layer = Layer.effect(ProgressWaitRegistry, Effect.gen(function* () {
95
+ const registrations = yield* Ref.make(/* @__PURE__ */ new Map());
96
+ const remove = (waiterId, deferred) => Ref.update(registrations, (current) => {
97
+ const existing = current.get(waiterId);
98
+ if (existing === void 0 || existing === "cancelled" || !existing.has(deferred)) return current;
99
+ const next = new Map(current);
100
+ const active = new Set(existing);
101
+ active.delete(deferred);
102
+ if (active.size === 0) next.delete(waiterId);
103
+ else next.set(waiterId, active);
104
+ return next;
105
+ });
106
+ const subscribe = Effect.fn("ProgressWaitRegistry.subscribe")((waiterId) => Effect.gen(function* () {
107
+ const deferred = yield* Deferred.make();
108
+ yield* Effect.addFinalizer(() => remove(waiterId, deferred));
109
+ return {
110
+ cancelled: yield* Ref.modify(registrations, (current) => {
111
+ const existing = current.get(waiterId);
112
+ const next = new Map(current);
113
+ if (existing === "cancelled") return [true, current];
114
+ const active = new Set(existing ?? []);
115
+ active.add(deferred);
116
+ next.set(waiterId, active);
117
+ return [false, next];
118
+ }),
119
+ deferred
120
+ };
121
+ }).pipe(Effect.map(({ cancelled, deferred }) => cancelled ? Effect.void : Deferred.await(deferred))));
122
+ const cancel = Effect.fn("ProgressWaitRegistry.cancel")(function* (waiterId) {
123
+ const waiters = yield* Ref.modify(registrations, (current) => {
124
+ const existing = current.get(waiterId);
125
+ if (existing === "cancelled") return [[], current];
126
+ const next = new Map(current);
127
+ next.delete(waiterId);
128
+ next.set(waiterId, "cancelled");
129
+ let tombstones = 0;
130
+ for (const registration of next.values()) if (registration === "cancelled") tombstones += 1;
131
+ if (tombstones > MAX_CANCELLATION_TOMBSTONES) for (const [id, registration] of next) {
132
+ if (registration !== "cancelled") continue;
133
+ next.delete(id);
134
+ break;
135
+ }
136
+ return [existing === void 0 ? [] : [...existing], next];
137
+ });
138
+ yield* Effect.forEach(waiters, (waiter) => Deferred.succeed(waiter, void 0), { discard: true });
139
+ }, Effect.uninterruptible);
140
+ return ProgressWaitRegistry.of({
141
+ subscribe,
142
+ cancel
143
+ });
144
+ }));
145
+ };
146
+ //#endregion
147
+ //#region src/internal/transport.ts
148
+ /**
149
+ * `ThreadPortTransport` over native Durable Object JS RPC (decision D-P6-3): one
150
+ * `portCall(envelope)` on the stub of the Object that owns the addressed Thread
151
+ * (`namespace.idFromName(threadId)` — the identity rule, plan §1.2). The envelopes are
152
+ * already Schema-encoded JSON, so the RPC boundary carries only structured-cloneable values;
153
+ * the protocol module stays transport-agnostic and fetch-with-JSON remains the documented
154
+ * fallback carrier.
155
+ *
156
+ * Every delivery problem — stub construction, RPC rejection, overload, deploy-in-progress —
157
+ * surfaces as `PortTransportError` (preserving the platform stub's own `retryable` signal
158
+ * when present) and NEVER as a fabricated answer: on `resolveAdmission` the routing layer
159
+ * turns exactly this error into `AdmissionIndeterminate` (SUB-031).
160
+ */
161
+ const threadPortTransportLayer = Layer.effect(ThreadPortTransport)(Effect.gen(function* () {
162
+ const { namespace } = yield* ThreadObjectNamespace;
163
+ return ThreadPortTransport.of({ call: (threadId, request) => Effect.tryPromise({
164
+ try: () => namespace.get(namespace.idFromName(threadId)).portCall(request),
165
+ catch: (cause) => portTransportFailure(threadId, cause)
166
+ }).pipe(Effect.withSpan("CloudflarePortTransport.call", { attributes: { threadId } })) });
167
+ }));
168
+ //#endregion
169
+ //#region src/internal/layers.ts
170
+ /**
171
+ * Owner-side execution port for a `portCall` request the wire endpoint has already decoded.
172
+ * It executes against THIS Object's LOCAL port facets — never the routed decorators, so a
173
+ * request cannot bounce between Objects — and returns the typed response for the endpoint to
174
+ * encode.
175
+ */
176
+ var ThreadObjectPorts = class extends Context.Service()("@effect-agent/platform-cloudflare/ThreadObjectPorts") {};
177
+ const decodeConfigValue = Schema.decodeUnknownEffect(CloudflareDurableRuntimeConfigValue);
178
+ const decodeThreadId = Schema.decodeUnknownEffect(ThreadId);
179
+ const decodeProducerId = Schema.decodeUnknownEffect(ProducerId);
180
+ const configFromOptions = (options) => decodeConfigValue({
181
+ deploymentId: options.deploymentId,
182
+ producerPrefix: options.producerPrefix,
183
+ ownershipLeaseDuration: options.ownershipLeaseDuration ?? CLOUDFLARE_RUNTIME_DEFAULTS.ownershipLeaseDuration,
184
+ alarmBackoffBase: options.alarmBackoffBase ?? CLOUDFLARE_RUNTIME_DEFAULTS.alarmBackoffBase,
185
+ alarmBackoffCap: options.alarmBackoffCap ?? CLOUDFLARE_RUNTIME_DEFAULTS.alarmBackoffCap,
186
+ wakeScanInterval: options.wakeScanInterval ?? CLOUDFLARE_RUNTIME_DEFAULTS.wakeScanInterval,
187
+ settlementPollInterval: options.settlementPollInterval ?? CLOUDFLARE_RUNTIME_DEFAULTS.settlementPollInterval,
188
+ leaseRenewalInterval: options.leaseRenewalInterval ?? CLOUDFLARE_RUNTIME_DEFAULTS.leaseRenewalInterval,
189
+ abortPollInterval: options.abortPollInterval ?? CLOUDFLARE_RUNTIME_DEFAULTS.abortPollInterval,
190
+ observationPollInterval: options.observationPollInterval ?? CLOUDFLARE_RUNTIME_DEFAULTS.observationPollInterval,
191
+ maxStoredValueBytes: options.maxStoredValueBytes ?? CLOUDFLARE_RUNTIME_DEFAULTS.maxStoredValueBytes,
192
+ verifyOnOpen: options.verifyOnOpen ?? CLOUDFLARE_RUNTIME_DEFAULTS.verifyOnOpen,
193
+ limits: {
194
+ maxQueueDepthPerLane: options.maxQueueDepthPerLane ?? CLOUDFLARE_RUNTIME_DEFAULTS.maxQueueDepthPerLane,
195
+ maxInputBytes: Math.min(options.maxInputBytes ?? CLOUDFLARE_RUNTIME_DEFAULTS.maxInputBytes, options.maxStoredValueBytes ?? CLOUDFLARE_RUNTIME_DEFAULTS.maxStoredValueBytes),
196
+ maxDatabaseBytes: options.maxDatabaseBytes ?? CLOUDFLARE_RUNTIME_DEFAULTS.maxDatabaseBytes
197
+ }
198
+ }).pipe(Effect.mapError((error) => CloudflarePlatformConfigError.make({
199
+ message: `Invalid Cloudflare durable runtime configuration: ${error.message}`,
200
+ cause: error
201
+ })));
202
+ /**
203
+ * The Thread this Object owns, from the Object identity rule (plan §1.2): Thread
204
+ * Objects are addressed exclusively by `idFromName(threadId)`, so `ctx.id.name` IS the
205
+ * Thread ID. An unnamed Object (from `newUniqueId`) is a deployment error, not a lane.
206
+ */
207
+ const threadIdFromState = (ctx) => ctx.id.name === void 0 ? Effect.fail(CloudflarePlatformConfigError.make({ message: "This Durable Object was not created via idFromName(threadId); Thread Objects must be addressed by their Thread identity (plan §1.2)." })) : decodeThreadId(ctx.id.name).pipe(Effect.mapError((error) => CloudflarePlatformConfigError.make({
208
+ message: `The Durable Object name is not a valid ThreadId: ${error.message}`,
209
+ cause: error
210
+ })));
211
+ /**
212
+ * Validate deployment settings and derive services before building application dependencies.
213
+ * The native class factory builds this Layer inside its constructor gate. Custom Effect hosts
214
+ * can provide it around the complete application Layer with the native context already supplied.
215
+ */
216
+ const layerConfig = (options) => Layer.unwrap(Effect.gen(function* () {
217
+ const { ctx } = yield* DurableObjectContext;
218
+ const config = yield* configFromOptions(options);
219
+ const threadId = yield* threadIdFromState(ctx);
220
+ const producerId = yield* decodeProducerId(`${config.producerPrefix}:${threadId}`).pipe(Effect.mapError((error) => CloudflarePlatformConfigError.make({
221
+ message: `The minted producer identity is invalid: ${error.message}`,
222
+ cause: error
223
+ })));
224
+ return Layer.mergeAll(Layer.succeed(CloudflareDurableRuntimeConfig, config), Layer.succeed(ThreadObjectIdentity, {
225
+ threadId,
226
+ producerId
227
+ }), DurableRuntimeConfig.layer({
228
+ deploymentId: config.deploymentId,
229
+ producerId,
230
+ settlementPollInterval: Duration.millis(config.settlementPollInterval),
231
+ leaseRenewalInterval: Duration.millis(config.leaseRenewalInterval),
232
+ abortPollInterval: Duration.millis(config.abortPollInterval),
233
+ ...options.estimateCostMicrousd === void 0 ? {} : { estimateCostMicrousd: options.estimateCostMicrousd }
234
+ }), BrowserCrypto.layer, storageFailpointLayer({
235
+ storage: ctx.storage,
236
+ failpoint: options.storageFailpoint?.(ctx)
237
+ }), options.runtimeFailpoint === void 0 ? DurableRuntimeFailpoint.layer : Layer.succeed(DurableRuntimeFailpoint, { hit: options.runtimeFailpoint(ctx) }), options.maintenanceFailpoint === void 0 ? ThreadMaintenanceFailpoint.layer : Layer.succeed(ThreadMaintenanceFailpoint, { hit: options.maintenanceFailpoint(ctx) }), options.toolReconciler ?? ToolReconciler.uncertain, options.operationAuthorizer === void 0 ? Layer.empty : operationAuthorizerLayer(options.operationAuthorizer), options.toolFailureObserver === void 0 ? Layer.succeed(CurrentToolFailureObserver, void 0) : toolFailureObserverLayer(options.toolFailureObserver), RunContextPreparationPassthrough, RunToolAuthorization.allowAll);
238
+ }));
239
+ /**
240
+ * Register typed Agents and version declarations. Hashing and dependency capture happen in
241
+ * this Layer's Scope, after application Layers have been provided. Every Agent's instruction,
242
+ * Tool, Schema, and model requirements remain visible until satisfied by Layer composition.
243
+ * Use Layer.unwrap for registration values that need effectful application setup.
244
+ */
245
+ const registeredLayer = (registrations, options = {}) => Layer.unwrap(Effect.map(compileRegistrations(registrations), (bindings) => boundLayer(bindings, options)));
246
+ function layer(registrations, options = {}) {
247
+ return registeredLayer(registrations, options);
248
+ }
249
+ /**
250
+ * Assemble the durable runtime from already-resolved Agent Bindings.
251
+ * Use `ThreadObject.layer` to compile typed Agent registrations instead.
252
+ * Supply host services through `ThreadObject.make` or `ThreadObject.layerConfig` and
253
+ * the Durable Object context and namespace Layers when composing a custom host.
254
+ */
255
+ const boundLayer = (bindings, options = {}) => Layer.unwrap(Effect.gen(function* () {
256
+ const { ctx } = yield* DurableObjectContext;
257
+ const config = yield* CloudflareDurableRuntimeConfig;
258
+ const { threadId } = yield* ThreadObjectIdentity;
259
+ const storageOptions = {
260
+ storage: ctx.storage,
261
+ observationPollInterval: config.observationPollInterval,
262
+ ownershipLeaseDuration: config.ownershipLeaseDuration,
263
+ maxStoredValueBytes: config.maxStoredValueBytes,
264
+ verifyOnOpen: config.verifyOnOpen
265
+ };
266
+ const infrastructure = Layer.mergeAll(storageConfigLayer(storageOptions), SqliteClient.layer({ storage: ctx.storage }));
267
+ const rawLocalPorts = Layer.mergeAll(threadStoreLayer, submissionLedgerLayer).pipe(Layer.provide(infrastructure));
268
+ const messageStore = guardedMessageDeliveryStoreLayer.pipe(Layer.provide(doMessageDeliveryStoreLayer().pipe(Layer.provide(infrastructure))));
269
+ const messageRecovery = threadMessageDeliveryLayer.pipe(Layer.provide(MessageDeliveryDriver.layer({
270
+ batchSize: 4,
271
+ concurrency: 4
272
+ })), Layer.provide(cloudflarePreparedInputAdmissionLayer), Layer.provide(CloudflareThreadClient.layer), Layer.provide(messageStore));
273
+ const publication = (options.publication ?? ThreadPublication.layer).pipe(Layer.provide(Layer.mergeAll(rawLocalPorts, Layer.effect(SqlClient)(SqlClient))));
274
+ const projection = (options.projection ?? ThreadProjectionMaintenance.layer).pipe(Layer.provide(Layer.mergeAll(rawLocalPorts, Layer.effect(SqlClient)(SqlClient))));
275
+ const localPorts = options.publication === void 0 && options.projection === void 0 ? rawLocalPorts : Layer.effectContext(Effect.gen(function* () {
276
+ const store = yield* ThreadStore;
277
+ const ledger = yield* SubmissionLedger;
278
+ const mutations = yield* ThreadMutationGate;
279
+ const index = yield* ThreadProjectionMaintenance;
280
+ const publish = yield* Effect.context();
281
+ const afterCommit = publishCommitted.pipe(Effect.provide(publish));
282
+ const sourceCommits = yield* Semaphore.make(1);
283
+ const observedStore = ThreadStore.of({
284
+ ...store,
285
+ append: (request) => mutations.withMutation(sourceCommits.withPermit(store.append(request).pipe(Effect.tap((result) => index.applyCommitted(request, result).pipe(Effect.catchCause((cause) => Cause.hasInterrupts(cause) ? Effect.interrupt : Effect.logError("Thread projection deferred after source commit", cause)))))).pipe(Effect.tap(() => afterCommit))).pipe(Effect.catchTag("DurableAlarmError", (cause) => ThreadStoreError.make({
286
+ operation: "prearm publication append",
287
+ message: cause.message,
288
+ cause
289
+ })))
290
+ });
291
+ const observeIntent = (body) => mutations.withMutation(body.pipe(Effect.tap(() => afterCommit))).pipe(Effect.catchTag("DurableAlarmError", (cause) => LedgerError.make({
292
+ operation: "prearm publication intent",
293
+ message: "The publication generation could not be armed",
294
+ cause
295
+ })));
296
+ return Context.make(ThreadStore, observedStore).pipe(Context.add(SubmissionLedger, {
297
+ ...ledger,
298
+ recordApprovalDecision: (request) => observeIntent(ledger.recordApprovalDecision(request)),
299
+ requestAbort: (request) => observeIntent(ledger.requestAbort(request)),
300
+ recordUnknownResolution: (request) => observeIntent(ledger.recordUnknownResolution(request))
301
+ }));
302
+ })).pipe(Layer.provide(rawLocalPorts));
303
+ const portsEndpointLayer = Layer.effect(ThreadObjectPorts)(Effect.gen(function* () {
304
+ const local = yield* Effect.context();
305
+ return ThreadObjectPorts.of({ handle: (request) => executePortRequest(request).pipe(Effect.provide(local)) });
306
+ })).pipe(Layer.provide(localPorts));
307
+ const routedPorts = Layer.mergeAll(routedSubmissionLedgerLayer({ localThreadId: threadId }), routedThreadStoreLayer({ localThreadId: threadId })).pipe(Layer.provide(localPorts), Layer.provide(threadPortTransportLayer));
308
+ const base = Layer.mergeAll(DurableAlarmService.layer, ProgressWaitRegistry.layer);
309
+ const runtimeStack = DurableAgentRuntime.layerWithBindings(bindings).pipe(Layer.provide(cloudflarePreparedInputAdmissionLayer.pipe(Layer.provide(CloudflareThreadClient.layer))), Layer.provideMerge(messageStore), Layer.provideMerge(routedPorts), Layer.provideMerge(cloudflareWakeSchedulerLayer), Layer.provideMerge(base));
310
+ return Layer.mergeAll(runtimeStack, ThreadMaintenance.layer.pipe(Layer.provide(runtimeStack), Layer.provide(messageRecovery)), portsEndpointLayer, messageStore).pipe(Layer.provideMerge(publication), Layer.provideMerge(projection), Layer.provideMerge(ThreadMutationGate.layer), Layer.provideMerge(infrastructure));
311
+ }));
312
+ //#endregion
313
+ //#region src/ThreadObject.ts
314
+ var ThreadObject_exports = /* @__PURE__ */ __exportAll({
315
+ AdminExplainRequest: () => AdminExplainRequest,
316
+ AdminFailed: () => AdminFailed,
317
+ AdminFailure: () => AdminFailure,
318
+ AdminResponse: () => AdminResponse,
319
+ AdminVerifyRequest: () => AdminVerifyRequest,
320
+ ExplainedRecovery: () => ExplainedRecovery,
321
+ ObligationsScanned: () => ObligationsScanned,
322
+ RetryExecuted: () => RetryExecuted,
323
+ VerifiedIntegrity: () => VerifiedIntegrity,
324
+ decodeAdminExplainRequest: () => decodeAdminExplainRequest,
325
+ decodeAdminResponse: () => decodeAdminResponse,
326
+ decodeAdminVerifyRequest: () => decodeAdminVerifyRequest,
327
+ decodeObligationThresholds: () => decodeObligationThresholds,
328
+ decodeRetryCommand: () => decodeRetryCommand,
329
+ encodeAdminResponse: () => encodeAdminResponse,
330
+ layer: () => layer,
331
+ layerConfig: () => layerConfig,
332
+ make: () => make
333
+ });
334
+ /** Classify only a decoded port request so new protocol members cannot bypass pre-arming. */
335
+ const isMutatingPortRequest = (request) => {
336
+ switch (request._tag) {
337
+ case "LedgerAdmit":
338
+ case "LedgerMarkReady":
339
+ case "LedgerRequestAbort":
340
+ case "LedgerRecordChildSettled":
341
+ case "StoreMaterialize":
342
+ case "StoreAppend": return true;
343
+ case "LedgerLookup":
344
+ case "LedgerResolveAdmission":
345
+ case "StoreReadPage":
346
+ case "StoreInspectTail":
347
+ case "StoreExport": return false;
348
+ }
349
+ return false;
350
+ };
351
+ /** The literal encoded `PortFailed(PortProtocolError)` fallback (same shape as WP2's). */
352
+ const encodedPortProtocolFailure = (message) => ({
353
+ _tag: "PortFailed",
354
+ failure: {
355
+ _tag: "PortProtocolError",
356
+ message: boundHostDiagnostic(message)
357
+ }
358
+ });
359
+ const protocolFailure = (context) => (error) => HostProtocolError.make({ message: boundHostDiagnostic(`${context}: ${error.message}`) });
360
+ /** Fold one endpoint's typed failures into the uniform `HostResponse` envelope. */
361
+ const respond = (effect) => effect.pipe(Effect.map((result) => result), Effect.catch((failure) => Effect.succeed(HostFailed.make({ failure }))));
362
+ /** Encode the response envelope; an unencodable response degrades to a protocol failure. */
363
+ const encodeResponse = (response) => encodeHostResponse(response).pipe(Effect.catch((error) => Effect.succeed({
364
+ _tag: "HostFailed",
365
+ failure: {
366
+ _tag: "HostProtocolError",
367
+ message: boundHostDiagnostic(`The host response could not be encoded: ${error.message}`)
368
+ }
369
+ })));
370
+ const utf8Bytes = (value) => new TextEncoder().encode(JSON.stringify(value)).length;
371
+ /**
372
+ * The admission-limits gate, BEFORE `runtime.submit` touches the ledger (exit gate
373
+ * "resource limits are checked before admission"; DEPLOY-007). A replayed idempotency key is
374
+ * exempt: its accepted-work obligation already exists, and returning the original Receipt
375
+ * consumes no new quota. Refusals are typed `AdmissionLimitExceeded` and nothing is written.
376
+ */
377
+ const gateAdmissionLimits = Effect.fn("ThreadObject.gateAdmissionLimits")(function* (request) {
378
+ const identity = yield* ThreadObjectIdentity;
379
+ const config = yield* CloudflareDurableRuntimeConfig;
380
+ const ledger = yield* SubmissionLedger;
381
+ const { ctx } = yield* DurableObjectContext;
382
+ const existing = yield* ledger.lookup(SubmissionLookupByKey.make({
383
+ threadId: identity.threadId,
384
+ principal: request.principal,
385
+ idempotencyKey: request.idempotencyKey
386
+ }));
387
+ if (Option.isSome(existing)) return;
388
+ const inputBytes = utf8Bytes(request.inputPayload);
389
+ if (inputBytes > config.limits.maxInputBytes) return yield* AdmissionLimitExceeded.make({
390
+ limit: "input-bytes",
391
+ actual: inputBytes,
392
+ maximum: config.limits.maxInputBytes
393
+ });
394
+ const nonterminal = yield* Stream.runCollect(ledger.scanNonterminal);
395
+ if (nonterminal.length >= config.limits.maxQueueDepthPerLane) return yield* AdmissionLimitExceeded.make({
396
+ limit: "queue-depth",
397
+ actual: nonterminal.length,
398
+ maximum: config.limits.maxQueueDepthPerLane
399
+ });
400
+ const databaseBytes = yield* Effect.sync(() => ctx.storage.sql.databaseSize);
401
+ if (databaseBytes > config.limits.maxDatabaseBytes) return yield* AdmissionLimitExceeded.make({
402
+ limit: "database-bytes",
403
+ actual: databaseBytes,
404
+ maximum: config.limits.maxDatabaseBytes
405
+ });
406
+ });
407
+ /**
408
+ * The submit-capable projection of an Agent Binding on the OBJECT side: the input arrived
409
+ * already encoded through the real input schema on the Worker side (`client.ts`), so the
410
+ * Object admits the canonical `PersistedJson` payload as-is; the resolved Binding re-derives
411
+ * everything else from the stored `(agentId, agentDigests)` at claim time (SUB-023).
412
+ */
413
+ const passthroughSubmitAgent = (agentId) => ({ definition: {
414
+ id: agentId,
415
+ input: PersistedJson
416
+ } });
417
+ const submitEndpoint = (encoded) => decodeSubmitRequest(encoded).pipe(Effect.mapError(protocolFailure("The submit request could not be decoded")), Effect.flatMap((request) => Effect.gen(function* () {
418
+ const identity = yield* ThreadObjectIdentity;
419
+ const maintenance = yield* ThreadMaintenance;
420
+ const runtime = yield* DurableAgentRuntime;
421
+ yield* gateAdmissionLimits(request);
422
+ const receipt = yield* maintenance.withMutation(runtime.submit(passthroughSubmitAgent(request.agentId), request.inputPayload, {
423
+ threadId: identity.threadId,
424
+ principal: request.principal,
425
+ idempotencyKey: request.idempotencyKey,
426
+ ...request.admissionGroup === void 0 ? {} : { admissionGroup: request.admissionGroup },
427
+ ...request.admissionFence === void 0 ? {} : { admissionFence: request.admissionFence },
428
+ ...request.workerAdmission === void 0 ? {} : { workerAdmission: request.workerAdmission },
429
+ ...request.messageAdmission === void 0 ? {} : { messageAdmission: request.messageAdmission },
430
+ definitions: request.definitions
431
+ }));
432
+ return SubmitSucceeded.make({ receipt });
433
+ })), respond, Effect.flatMap(encodeResponse));
434
+ const submissionStatusEndpoint = (encoded) => decodeReceipt(encoded).pipe(Effect.mapError(protocolFailure("The receipt could not be decoded")), Effect.flatMap((receipt) => Effect.gen(function* () {
435
+ const runtime = yield* DurableAgentRuntime;
436
+ return SubmissionStatusResponse.make({ status: yield* runtime.submissionStatus(receipt) });
437
+ })), respond, Effect.flatMap(encodeResponse));
438
+ const awaitSettlementEndpoint = (encoded) => decodeReceipt(encoded).pipe(Effect.mapError(protocolFailure("The receipt could not be decoded")), Effect.flatMap((receipt) => Effect.gen(function* () {
439
+ const settlement = yield* (yield* DurableAgentRuntime).awaitSettlement(receipt);
440
+ return SettlementReached.make({ settlement });
441
+ })), respond, Effect.flatMap(encodeResponse));
442
+ const awaitProgressEndpoint = (encoded) => decodeAwaitProgressRequest(encoded).pipe(Effect.mapError(protocolFailure("The progress request could not be decoded")), Effect.flatMap((request) => Effect.gen(function* () {
443
+ const identity = yield* ThreadObjectIdentity;
444
+ const runtime = yield* DurableAgentRuntime;
445
+ const registry = yield* ProgressWaitRegistry;
446
+ yield* Effect.scoped(Effect.gen(function* () {
447
+ const cancelled = yield* registry.subscribe(request.waiterId);
448
+ yield* Effect.raceFirst(runtime.awaitProgress(identity.threadId, request.afterSequence), cancelled);
449
+ }));
450
+ return ProgressObserved.make();
451
+ })), respond, Effect.flatMap(encodeResponse));
452
+ const cancelProgressEndpoint = (encoded) => decodeCancelProgressRequest(encoded).pipe(Effect.mapError(protocolFailure("The progress cancellation could not be decoded")), Effect.flatMap((request) => Effect.gen(function* () {
453
+ yield* (yield* ProgressWaitRegistry).cancel(request.waiterId);
454
+ return ProgressCancelled.make();
455
+ })), respond, Effect.flatMap(encodeResponse));
456
+ const observePageEndpoint = (encoded) => decodeObservePageRequest(encoded).pipe(Effect.mapError(protocolFailure("The observe request could not be decoded")), Effect.flatMap((request) => Effect.gen(function* () {
457
+ const identity = yield* ThreadObjectIdentity;
458
+ const store = yield* ThreadStore;
459
+ yield* (yield* OperationAuthorizer).authorize(OperationAuthorizationRequest.make({
460
+ operation: "observe",
461
+ threadId: identity.threadId
462
+ }));
463
+ const records = yield* Stream.runCollect(store.read(ThreadRead.make({
464
+ threadId: identity.threadId,
465
+ ...request.afterSequence === void 0 ? {} : { afterSequence: request.afterSequence },
466
+ limit: request.limit
467
+ })));
468
+ return ObservedPage.make({ records: [...records] });
469
+ })), respond, Effect.flatMap(encodeResponse));
470
+ const abortEndpoint = (encoded) => decodeAbortCommand(encoded).pipe(Effect.mapError(protocolFailure("The abort command could not be decoded")), Effect.flatMap((command) => Effect.gen(function* () {
471
+ const maintenance = yield* ThreadMaintenance;
472
+ const runtime = yield* DurableAgentRuntime;
473
+ const intent = yield* maintenance.withMutation(runtime.abort(command));
474
+ return AbortRecorded.make({ intent });
475
+ })), respond, Effect.flatMap(encodeResponse));
476
+ const resolveApprovalEndpoint = (encoded) => decodeApprovalDecisionCommand(encoded).pipe(Effect.mapError(protocolFailure("The approval command could not be decoded")), Effect.flatMap((command) => Effect.gen(function* () {
477
+ const maintenance = yield* ThreadMaintenance;
478
+ const runtime = yield* DurableAgentRuntime;
479
+ const intent = yield* maintenance.withMutation(runtime.resolveApproval(command));
480
+ return ApprovalRecorded.make({ intent });
481
+ })), respond, Effect.flatMap(encodeResponse));
482
+ const resolveUnknownEndpoint = (encoded) => decodeUnknownResolutionCommand(encoded).pipe(Effect.mapError(protocolFailure("The resolution command could not be decoded")), Effect.flatMap((command) => Effect.gen(function* () {
483
+ const maintenance = yield* ThreadMaintenance;
484
+ const runtime = yield* DurableAgentRuntime;
485
+ const intent = yield* maintenance.withMutation(runtime.resolveUnknown(command));
486
+ return UnknownResolutionRecorded.make({ intent });
487
+ })), respond, Effect.flatMap(encodeResponse));
488
+ /** Explain one Submission (`submissionId` present) or every nonterminal lane member. */
489
+ var AdminExplainRequest = class extends Schema.Class("@effect-agent/platform-cloudflare/AdminExplainRequest")({ submissionId: Schema.optionalKey(SubmissionId) }) {};
490
+ /** Verify carries no parameters — the addressed Object IS the lane. */
491
+ var AdminVerifyRequest = class extends Schema.Class("@effect-agent/platform-cloudflare/AdminVerifyRequest")({}) {};
492
+ /** Every typed failure of the four admin entry points, plus the protocol's own errors. */
493
+ const AdminFailure = Schema.Union([
494
+ AdmissionPolicyError,
495
+ OperationDenied,
496
+ RetryRefused,
497
+ LedgerError,
498
+ RunJournalError,
499
+ DigestError,
500
+ OwnershipLost,
501
+ SettlementConflict,
502
+ ThreadStoreError,
503
+ ThreadNotMaterialized,
504
+ AppendConflict,
505
+ FenceRejected,
506
+ DurableRuntimeFailpointError,
507
+ DurableAlarmError,
508
+ HostProtocolError
509
+ ]);
510
+ var ExplainedRecovery = class extends Schema.TaggedClass("@effect-agent/platform-cloudflare/ExplainedRecovery")("ExplainedRecovery", { explanations: Schema.Array(RecoveryExplanation).check(Schema.isMaxLength(1024)) }) {};
511
+ var VerifiedIntegrity = class extends Schema.TaggedClass("@effect-agent/platform-cloudflare/VerifiedIntegrity")("VerifiedIntegrity", { report: IntegrityReport }) {};
512
+ var RetryExecuted = class extends Schema.TaggedClass("@effect-agent/platform-cloudflare/RetryExecuted")("RetryExecuted", { report: RecoveryReport }) {};
513
+ var ObligationsScanned = class extends Schema.TaggedClass("@effect-agent/platform-cloudflare/ObligationsScanned")("ObligationsScanned", { report: ObligationReport }) {};
514
+ /** The admin entry point failed TYPED on the Object; the failure re-decodes verbatim. */
515
+ var AdminFailed = class extends Schema.TaggedClass("@effect-agent/platform-cloudflare/AdminFailed")("AdminFailed", { failure: AdminFailure }) {};
516
+ /** The uniform answer of one admin entry point. Callers narrow by the tag their call implies. */
517
+ const AdminResponse = Schema.Union([
518
+ ExplainedRecovery,
519
+ VerifiedIntegrity,
520
+ RetryExecuted,
521
+ ObligationsScanned,
522
+ AdminFailed
523
+ ]);
524
+ const decodeAdminExplainRequest = Schema.decodeUnknownEffect(AdminExplainRequest);
525
+ const decodeAdminVerifyRequest = Schema.decodeUnknownEffect(AdminVerifyRequest);
526
+ const decodeRetryCommand = Schema.decodeUnknownEffect(RetryCommand);
527
+ const decodeObligationThresholds = Schema.decodeUnknownEffect(ObligationThresholds);
528
+ const encodeAdminResponse = Schema.encodeEffect(AdminResponse);
529
+ const decodeAdminResponse = Schema.decodeUnknownEffect(AdminResponse);
530
+ /** Fold one admin endpoint's typed failures into the uniform `AdminResponse` envelope. */
531
+ const respondAdmin = (effect) => effect.pipe(Effect.map((result) => result), Effect.catch((failure) => Effect.succeed(AdminFailed.make({ failure }))));
532
+ /** Encode the admin response envelope; an unencodable response degrades to a protocol failure. */
533
+ const encodeAdminResponseTotal = (response) => encodeAdminResponse(response).pipe(Effect.catch((error) => Effect.succeed({
534
+ _tag: "AdminFailed",
535
+ failure: {
536
+ _tag: "HostProtocolError",
537
+ message: boundHostDiagnostic(`The admin response could not be encoded: ${error.message}`)
538
+ }
539
+ })));
540
+ const explainEndpoint = (encoded) => decodeAdminExplainRequest(encoded).pipe(Effect.mapError(protocolFailure("The explain request could not be decoded")), Effect.flatMap((request) => Effect.gen(function* () {
541
+ const identity = yield* ThreadObjectIdentity;
542
+ const runtime = yield* DurableAgentRuntime;
543
+ const explanations = request.submissionId === void 0 ? yield* runtime.explainThread(identity.threadId) : [yield* runtime.explain(request.submissionId)];
544
+ return ExplainedRecovery.make({ explanations });
545
+ })), respondAdmin, Effect.flatMap(encodeAdminResponseTotal));
546
+ const verifyEndpoint = (encoded) => decodeAdminVerifyRequest(encoded).pipe(Effect.mapError(protocolFailure("The verify request could not be decoded")), Effect.flatMap(() => Effect.gen(function* () {
547
+ const identity = yield* ThreadObjectIdentity;
548
+ const report = yield* (yield* DurableAgentRuntime).verify(identity.threadId);
549
+ return VerifiedIntegrity.make({ report });
550
+ })), respondAdmin, Effect.flatMap(encodeAdminResponseTotal));
551
+ const retryEndpoint = (encoded) => decodeRetryCommand(encoded).pipe(Effect.mapError(protocolFailure("The retry command could not be decoded")), Effect.flatMap((command) => Effect.gen(function* () {
552
+ const maintenance = yield* ThreadMaintenance;
553
+ const runtime = yield* DurableAgentRuntime;
554
+ const report = yield* maintenance.withMutation(runtime.retry(command));
555
+ return RetryExecuted.make({ report });
556
+ })), respondAdmin, Effect.flatMap(encodeAdminResponseTotal));
557
+ const obligationsEndpoint = (encoded) => decodeObligationThresholds(encoded).pipe(Effect.mapError(protocolFailure("The obligation thresholds could not be decoded")), Effect.flatMap((thresholds) => Effect.gen(function* () {
558
+ const report = yield* (yield* DurableAgentRuntime).scanObligations(thresholds);
559
+ return ObligationsScanned.make({ report });
560
+ })), respondAdmin, Effect.flatMap(encodeAdminResponseTotal));
561
+ /**
562
+ * Owner-side `portCall`: wrap a mutating envelope in the same pre-armed generation protocol as
563
+ * public RPC (a routed mutation committed by THIS Object must already carry the alarm that will
564
+ * finish it), execute on the LOCAL facets (never the routed decorators), then arm an immediate
565
+ * alarm so the mutated lane is processed promptly. Protocol anomalies answer
566
+ * `PortFailed(PortProtocolError)`.
567
+ */
568
+ const portCallEndpoint = (encoded) => Effect.gen(function* () {
569
+ const ports = yield* ThreadObjectPorts;
570
+ const maintenance = yield* ThreadMaintenance;
571
+ const alarm = yield* DurableAlarmService;
572
+ const decoded = yield* decodePortRequest(encoded).pipe(Effect.map((request) => ({
573
+ _tag: "success",
574
+ request
575
+ })), Effect.catch((error) => Effect.succeed({
576
+ _tag: "failure",
577
+ message: error.message
578
+ })));
579
+ if (decoded._tag === "failure") return encodedPortProtocolFailure(`The port request could not be decoded: ${decoded.message}`);
580
+ const mutating = isMutatingPortRequest(decoded.request);
581
+ const handled = yield* (mutating ? maintenance.withMutation(ports.handle(decoded.request)) : ports.handle(decoded.request)).pipe(Effect.exit);
582
+ if (handled._tag === "Failure") return encodedPortProtocolFailure("The owner Object could not arm its maintenance alarm before the mutation.");
583
+ const response = yield* encodePortResponse(handled.value).pipe(Effect.catch((error) => Effect.succeed(encodedPortProtocolFailure(`The port response could not be encoded: ${error.message}`))));
584
+ if (mutating) yield* alarm.scheduleNow.pipe(Effect.catch((error) => Effect.logWarning("ThreadObject.portCall: immediate re-arm failed", error)));
585
+ return response;
586
+ });
587
+ const wakeEndpoint = Effect.gen(function* () {
588
+ const identity = yield* ThreadObjectIdentity;
589
+ yield* (yield* WakeScheduler).notify(identity.threadId);
590
+ });
591
+ const alarmEndpoint = Effect.gen(function* () {
592
+ yield* (yield* ThreadMaintenance).pass;
593
+ });
594
+ const gateEndpoint = Effect.gen(function* () {
595
+ yield* (yield* ThreadMaintenance).ensureAlarm;
596
+ });
597
+ /**
598
+ * Adapter from effect-cf's native Durable Object services to Effect Agent's existing platform
599
+ * ports. effect-cf owns the cached ManagedRuntime and supplies these values once per Object
600
+ * incarnation; the durable runtime continues to depend only on the narrow services below.
601
+ */
602
+ const effectCfPlatformLayer = (namespaceBinding, rpcTracing = false) => {
603
+ const context = Layer.effect(DurableObjectContext)(Effect.gen(function* () {
604
+ const state = yield* DurableObjectState.DurableObjectState;
605
+ const env = yield* WorkerEnvironment;
606
+ return DurableObjectContext.of({
607
+ ctx: state.raw,
608
+ env
609
+ });
610
+ }));
611
+ const namespace = Layer.effect(ThreadObjectNamespace)(Effect.gen(function* () {
612
+ const env = yield* WorkerEnvironment;
613
+ const binding = yield* threadNamespaceFromEnv(env, namespaceBinding);
614
+ return ThreadObjectNamespace.of({
615
+ namespace: binding,
616
+ ...rpcTracing === true ? { rpcTracing: namespaceBinding } : {}
617
+ });
618
+ }));
619
+ return Layer.merge(context, namespace);
620
+ };
621
+ /**
622
+ * Export a composed application Layer as a native Durable Object class.
623
+ * Bootstrap services are provided to the whole graph before it acquires, so application Layers
624
+ * can yield effect-cf's WorkerEnvironment and DurableObjectState, derived identity, and Crypto.
625
+ * Application dependencies remain visible until Layer.provide satisfies them. effect-cf owns the
626
+ * cached ManagedRuntime, native RPC methods, event scopes, and telemetry flushing.
627
+ * Initialization is local and bounded inside the constructor gate. Cloudflare eviction does not
628
+ * guarantee finalizers; put resources requiring timely release in scoped operations or eventLayer.
629
+ */
630
+ const make = (applicationLayer, options) => {
631
+ const application = applicationLayer.pipe(Layer.provideMerge(layerConfig(options)), Layer.provideMerge(effectCfPlatformLayer(options.namespaceBinding, options.rpcTracing)));
632
+ const runtime = Layer.effectContext(Effect.gen(function* () {
633
+ const state = yield* DurableObjectState.DurableObjectState;
634
+ const scope = yield* Effect.scope;
635
+ return yield* state.blockConcurrencyWhile(Effect.gen(function* () {
636
+ const services = yield* Layer.buildWithScope(application, scope);
637
+ yield* gateEndpoint.pipe(Effect.provide(services));
638
+ return services;
639
+ }));
640
+ }));
641
+ const rpc = {
642
+ submitEncoded: (encoded) => submitEndpoint(encoded),
643
+ submissionStatusEncoded: (encoded) => submissionStatusEndpoint(encoded),
644
+ awaitSettlementEncoded: (encoded) => awaitSettlementEndpoint(encoded),
645
+ awaitProgressEncoded: (encoded) => awaitProgressEndpoint(encoded),
646
+ cancelProgressEncoded: (encoded) => cancelProgressEndpoint(encoded),
647
+ observePage: (encoded) => observePageEndpoint(encoded),
648
+ abortEncoded: (encoded) => abortEndpoint(encoded),
649
+ resolveApprovalEncoded: (encoded) => resolveApprovalEndpoint(encoded),
650
+ resolveUnknownEncoded: (encoded) => resolveUnknownEndpoint(encoded),
651
+ explainEncoded: (encoded) => explainEndpoint(encoded),
652
+ verifyEncoded: (encoded) => verifyEndpoint(encoded),
653
+ retryEncoded: (encoded) => retryEndpoint(encoded),
654
+ obligationsEncoded: (encoded) => obligationsEndpoint(encoded),
655
+ portCall: (encoded) => portCallEndpoint(encoded),
656
+ wake: () => wakeEndpoint
657
+ };
658
+ const EffectCfThreadObject = DurableObject.make(runtime, {
659
+ ...options.rpcTracing === true ? { rpcTracing: { service: options.namespaceBinding } } : {},
660
+ ...options.eventLayer === void 0 ? {} : { eventLayer: options.eventLayer },
661
+ initialize: Effect.void,
662
+ rpc,
663
+ alarm: () => alarmEndpoint
664
+ });
665
+ class ThreadObject extends EffectCfThreadObject {
666
+ alarm(alarmInfo) {
667
+ return super.alarm?.(alarmInfo);
668
+ }
669
+ }
670
+ return ThreadObject;
671
+ };
672
+ //#endregion
673
+ export { make as _, AdminVerifyRequest as a, RetryExecuted as c, decodeAdminExplainRequest as d, decodeAdminResponse as f, encodeAdminResponse as g, decodeRetryCommand as h, AdminResponse as i, ThreadObject_exports as l, decodeObligationThresholds as m, AdminFailed as n, ExplainedRecovery as o, decodeAdminVerifyRequest as p, AdminFailure as r, ObligationsScanned as s, AdminExplainRequest as t, VerifiedIntegrity as u, layer as v, layerConfig as y };
674
+
675
+ //# sourceMappingURL=ThreadObject-s5w3V_co.mjs.map