@effect-agent/platform-cloudflare 0.1.0-beta.9 → 0.1.0-beta.90

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 (100) hide show
  1. package/dist/Alarm.d.mts +188 -0
  2. package/dist/Alarm.mjs +451 -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/CloudflareAiGateway.d.mts +64 -0
  11. package/dist/CloudflareAiGateway.mjs +70 -0
  12. package/dist/CloudflareAiGateway.mjs.map +1 -0
  13. package/dist/CloudflareBindings.d.mts +115 -0
  14. package/dist/CloudflareBindings.mjs +113 -0
  15. package/dist/CloudflareBindings.mjs.map +1 -0
  16. package/dist/CloudflareBrowser-DV6kya1H.mjs +495 -0
  17. package/dist/CloudflareBrowser-DV6kya1H.mjs.map +1 -0
  18. package/dist/CloudflareBrowser-Doe1M7R5.d.mts +80 -0
  19. package/dist/CloudflareBrowser.d.mts +2 -0
  20. package/dist/CloudflareBrowser.mjs +2 -0
  21. package/dist/CloudflareCodeMode.d.mts +44 -0
  22. package/dist/CloudflareCodeMode.mjs +616 -0
  23. package/dist/CloudflareCodeMode.mjs.map +1 -0
  24. package/dist/CloudflareConfig-f3CqTel1.d.mts +101 -0
  25. package/dist/CloudflareConfig.d.mts +2 -0
  26. package/dist/CloudflareConfig.mjs +122 -0
  27. package/dist/CloudflareConfig.mjs.map +1 -0
  28. package/dist/CloudflareMemory.d.mts +142 -0
  29. package/dist/CloudflareMemory.mjs +202 -0
  30. package/dist/CloudflareMemory.mjs.map +1 -0
  31. package/dist/CloudflareScheduling.d.mts +52 -0
  32. package/dist/CloudflareScheduling.mjs +396 -0
  33. package/dist/CloudflareScheduling.mjs.map +1 -0
  34. package/dist/CloudflareSubscriptions.d.mts +87 -0
  35. package/dist/CloudflareSubscriptions.mjs +530 -0
  36. package/dist/CloudflareSubscriptions.mjs.map +1 -0
  37. package/dist/CloudflareThreadClient.d.mts +1496 -0
  38. package/dist/CloudflareThreadClient.mjs +382 -0
  39. package/dist/CloudflareThreadClient.mjs.map +1 -0
  40. package/dist/InteractiveBrowser-DUE_m12-.d.mts +161 -0
  41. package/dist/InteractiveBrowser-DupDtfw2.mjs +1169 -0
  42. package/dist/InteractiveBrowser-DupDtfw2.mjs.map +1 -0
  43. package/dist/InteractiveBrowser.d.mts +2 -0
  44. package/dist/InteractiveBrowser.mjs +2 -0
  45. package/dist/ProtectedBrowser.d.mts +123 -0
  46. package/dist/ProtectedBrowser.mjs +1135 -0
  47. package/dist/ProtectedBrowser.mjs.map +1 -0
  48. package/dist/ThreadObject-CIbmXZCY.d.mts +812 -0
  49. package/dist/ThreadObject-DvRG0dDz.mjs +835 -0
  50. package/dist/ThreadObject-DvRG0dDz.mjs.map +1 -0
  51. package/dist/ThreadObject.d.mts +2 -0
  52. package/dist/ThreadObject.mjs +3 -0
  53. package/dist/WakeScheduler.d.mts +23 -0
  54. package/dist/WakeScheduler.mjs +57 -0
  55. package/dist/WakeScheduler.mjs.map +1 -0
  56. package/dist/boundary-BguazVkh.mjs +42 -0
  57. package/dist/boundary-BguazVkh.mjs.map +1 -0
  58. package/dist/index.d.mts +13 -1548
  59. package/dist/index.mjs +13 -1636
  60. package/dist/prepared-admission-DU0_T-ev.mjs +73 -0
  61. package/dist/prepared-admission-DU0_T-ev.mjs.map +1 -0
  62. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  63. package/package.json +1 -53
  64. package/src/Alarm.ts +973 -0
  65. package/src/BrowserRestCapture.ts +477 -0
  66. package/src/BrowserRestCrawl.ts +540 -0
  67. package/src/CloudflareAiGateway.ts +170 -0
  68. package/src/CloudflareBindings.ts +199 -0
  69. package/src/CloudflareBrowser.ts +15 -0
  70. package/src/{code-mode-executor.ts → CloudflareCodeMode.ts} +372 -204
  71. package/src/{config.ts → CloudflareConfig.ts} +9 -8
  72. package/src/CloudflareMemory.ts +420 -0
  73. package/src/CloudflareScheduling.ts +747 -0
  74. package/src/CloudflareSubscriptions.ts +1041 -0
  75. package/src/CloudflareThreadClient.ts +809 -0
  76. package/src/InteractiveBrowser.ts +2354 -0
  77. package/src/ProtectedBrowser.ts +9 -0
  78. package/src/ThreadObject.ts +1179 -0
  79. package/src/{wake-scheduler.ts → WakeScheduler.ts} +32 -26
  80. package/src/index.ts +12 -23
  81. package/src/internal/boundary.ts +55 -0
  82. package/src/internal/browser-quick-action.ts +857 -0
  83. package/src/internal/browser-session-lifecycle.ts +160 -0
  84. package/src/internal/layers.ts +751 -0
  85. package/src/internal/message-delivery.ts +152 -0
  86. package/src/internal/prepared-admission.ts +116 -0
  87. package/src/internal/progress-wait.ts +121 -0
  88. package/src/internal/transport.ts +44 -0
  89. package/src/protected-browser/binding.ts +313 -0
  90. package/src/protected-browser/host.ts +344 -0
  91. package/src/protected-browser/inspect-frame.ts +125 -0
  92. package/src/protected-browser/native.ts +445 -0
  93. package/src/protected-browser/policy.ts +821 -0
  94. package/dist/index.mjs.map +0 -1
  95. package/src/alarm.ts +0 -334
  96. package/src/bindings.ts +0 -145
  97. package/src/client.ts +0 -646
  98. package/src/conversation-object.ts +0 -768
  99. package/src/layers.ts +0 -376
  100. package/src/transport.ts +0 -38
@@ -0,0 +1,530 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
+ import { CloudflareThreadClient } from "./CloudflareThreadClient.mjs";
3
+ import { t as cloudflarePreparedInputAdmissionLayer } from "./prepared-admission-DU0_T-ev.mjs";
4
+ import { Cause, Clock, Context, DateTime, Effect, Layer, Schema } from "effect";
5
+ import { Principal } from "effect-agent/submission-ledger";
6
+ import { PersistedJson } from "effect-agent/records";
7
+ import { DurableObject, DurableObjectAlarm, DurableObjectState } from "effect-cf";
8
+ import { BrowserCrypto } from "@effect/platform-browser";
9
+ import { SqliteClient } from "@effect/sql-sqlite-do";
10
+ import { EventAcknowledgement, EventSourceVersion, SourcePartition, SubscriptionConfiguration, SubscriptionDeliveryKey, SubscriptionDeliverySnapshot, SubscriptionError, SubscriptionFailpointError, SubscriptionKey, SubscriptionScope, SubscriptionSnapshot, SubscriptionSourceError, defaultSubscriptionLimits } from "effect-agent/subscription";
11
+ import { DoSubscriptionAlarmControl, DoSubscriptionTransaction, doSubscriptionStoreLayer } from "@effect-agent/storage-cloudflare/do-subscription-store";
12
+ import "effect-agent/event-source";
13
+ import "effect-agent/subscription-input";
14
+ import { SubscriptionDriver, SubscriptionIntake, Subscriptions } from "effect-agent/subscriptions";
15
+ //#region src/CloudflareSubscriptions.ts
16
+ var CloudflareSubscriptions_exports = /* @__PURE__ */ __exportAll({
17
+ CloudflareSubscriptionConfigError: () => CloudflareSubscriptionConfigError,
18
+ CloudflareSubscriptionsClient: () => CloudflareSubscriptionsClient,
19
+ SubscriptionAlarmExtensionError: () => SubscriptionAlarmExtensionError,
20
+ SubscriptionAlarmProtocolError: () => SubscriptionAlarmProtocolError,
21
+ SubscriptionPartitionAlarmExtension: () => SubscriptionPartitionAlarmExtension,
22
+ SubscriptionPartitionIdentity: () => SubscriptionPartitionIdentity,
23
+ SubscriptionPartitionNamespace: () => SubscriptionPartitionNamespace,
24
+ SubscriptionPartitionProtocolError: () => SubscriptionPartitionProtocolError,
25
+ makeSubscriptionPartitionAlarmHandler: () => makeSubscriptionPartitionAlarmHandler,
26
+ makeSubscriptionPartitionObjectClass: () => makeSubscriptionPartitionObjectClass,
27
+ sourcePartitionName: () => sourcePartitionName,
28
+ validateCloudflareSubscriptionLimits: () => validateCloudflareSubscriptionLimits
29
+ });
30
+ const SUBSCRIPTION_ALARM_TAG = "effect-agent/SubscriptionPartitionWake";
31
+ const SUBSCRIPTION_ALARM_ID = "driver";
32
+ const MAX_ALARM_WALL_MILLIS = 72e4;
33
+ const MAX_ALARMS_PER_INVOCATION = 16;
34
+ const MAX_ANCILLARY_ALARM_MILLIS = 3e4;
35
+ const SubscriptionAlarmPayload = Schema.Struct({
36
+ schemaVersion: Schema.Literal(1),
37
+ generation: Schema.Int.check(Schema.isGreaterThan(0))
38
+ });
39
+ var SubscriptionAlarmProtocolError = class extends Schema.TaggedError()("SubscriptionAlarmProtocolError", { message: Schema.String }) {};
40
+ /** Bounded host diagnostic; credentials and provider responses do not belong in alarm failures. */
41
+ var SubscriptionAlarmExtensionError = class extends Schema.TaggedError()("SubscriptionAlarmExtensionError", { code: Schema.NonEmptyString.check(Schema.isMaxLength(128)) }) {};
42
+ /** Host-only handlers; the framework reserves its namespace and rejects every unknown tag. */
43
+ const SubscriptionPartitionAlarmExtension = Context.Reference("@effect-agent/platform-cloudflare/SubscriptionPartitionAlarmExtension", { defaultValue: () => ({ handlers: [] }) });
44
+ /** Capture host services once, deferring native partition services to invocation.
45
+ * Each invocation owns its codec/handler Scope and timeout.
46
+ * Callback failures stay typed. Defects and interruption reach the native alarm multiplexer.
47
+ * The host owns durable idempotency, prearming and external-effect uncertainty.
48
+ */
49
+ const makeSubscriptionPartitionAlarmHandler = Effect.fn("makeSubscriptionPartitionAlarmHandler")(function* (options) {
50
+ if (options.tag.length === 0 || options.tag.length > 128 || options.tag.startsWith("effect-agent/") || !Number.isSafeInteger(options.timeoutMillis) || options.timeoutMillis < 1 || options.timeoutMillis > MAX_ANCILLARY_ALARM_MILLIS) return yield* SubscriptionAlarmProtocolError.make({ message: "Invalid ancillary alarm tag or timeout" });
51
+ const services = (yield* Effect.context()).pipe(Context.omit(Subscriptions, SubscriptionIntake, SubscriptionDriver));
52
+ return {
53
+ tag: options.tag,
54
+ handle: (event) => Effect.gen(function* () {
55
+ if (event.tag !== options.tag) return yield* SubscriptionAlarmProtocolError.make({ message: "Ancillary alarm tag mismatch" });
56
+ const payload = yield* Schema.decodeEffect(options.payload)(event.payload).pipe(Effect.mapError(() => SubscriptionAlarmProtocolError.make({ message: "Invalid ancillary alarm payload" })));
57
+ yield* options.handle({
58
+ ...event,
59
+ payload
60
+ });
61
+ }).pipe(Effect.scoped, Effect.timeoutOrElse({
62
+ duration: options.timeoutMillis,
63
+ orElse: () => SubscriptionAlarmExtensionError.make({ code: "timeout" })
64
+ }), Effect.provideContext(services))
65
+ };
66
+ });
67
+ var SubscriptionPartitionProtocolError = class extends Schema.TaggedError()("SubscriptionPartitionProtocolError", { message: Schema.String.check(Schema.isMaxLength(4096)) }) {};
68
+ var CloudflareSubscriptionConfigError = class extends Schema.TaggedError()("CloudflareSubscriptionConfigError", { message: Schema.String }) {};
69
+ /** Reject limits whose four bounded phases could exceed the safe Durable Object alarm budget. */
70
+ const validateCloudflareSubscriptionLimits = (limits, options = {}) => {
71
+ return 4 * Math.ceil(limits.batchSize / limits.concurrency) * limits.operationTimeoutMillis + (options.ancillaryAlarms === true ? MAX_ALARMS_PER_INVOCATION * MAX_ANCILLARY_ALARM_MILLIS : 0) <= MAX_ALARM_WALL_MILLIS ? Effect.void : Effect.fail(CloudflareSubscriptionConfigError.make({ message: "Subscription limits can exceed the bounded Durable Object alarm wall budget" }));
72
+ };
73
+ const protocolMessage = (message) => message.length <= 4096 ? message : `${message.slice(0, 4093)}...`;
74
+ const SubscribeRequest = Schema.TaggedStruct("Subscribe", {
75
+ schemaVersion: Schema.Literal(1),
76
+ scope: Schema.Struct({ ...SubscriptionScope.fields }),
77
+ options: Schema.Struct({
78
+ subscriptionId: SubscriptionKey.fields.subscriptionId,
79
+ source: EventSourceVersion,
80
+ parameters: PersistedJson,
81
+ context: PersistedJson,
82
+ mode: Schema.Literals(["once", "continuous"]),
83
+ expiresAtMillis: Schema.NullOr(Schema.Number),
84
+ destination: SubscriptionConfiguration.fields.destination,
85
+ deliveryPrincipal: SubscriptionConfiguration.fields.deliveryPrincipal,
86
+ admissionGroup: SubscriptionConfiguration.fields.admissionGroup,
87
+ admissionFence: SubscriptionConfiguration.fields.admissionFence,
88
+ agentId: SubscriptionConfiguration.fields.agentId,
89
+ definitions: SubscriptionConfiguration.fields.definitions
90
+ })
91
+ });
92
+ const UpdateSubscriptionRequest = Schema.TaggedStruct("UpdateSubscription", {
93
+ schemaVersion: Schema.Literal(1),
94
+ scope: SubscribeRequest.fields.scope,
95
+ key: SubscriptionKey,
96
+ expectedRevision: Schema.Int.check(Schema.isGreaterThan(0)),
97
+ options: SubscribeRequest.fields.options.mapFields(({ subscriptionId: _, ...fields }) => fields)
98
+ });
99
+ const SubscriptionStateRequest = Schema.Struct({
100
+ _tag: Schema.Literals([
101
+ "PauseSubscription",
102
+ "ResumeSubscription",
103
+ "RecoverSubscription"
104
+ ]),
105
+ schemaVersion: Schema.Literal(1),
106
+ scope: SubscribeRequest.fields.scope,
107
+ key: SubscriptionKey,
108
+ expectedRevision: Schema.Int.check(Schema.isGreaterThan(0))
109
+ });
110
+ const ListSubscriptionsRequest = Schema.TaggedStruct("ListSubscriptions", {
111
+ schemaVersion: Schema.Literal(1),
112
+ scope: SubscribeRequest.fields.scope,
113
+ after: Schema.optionalKey(Schema.Natural),
114
+ limit: Schema.optionalKey(Schema.Int.check(Schema.isGreaterThan(0)))
115
+ });
116
+ const CancelSubscriptionRequest = Schema.TaggedStruct("CancelSubscription", {
117
+ expectedRevision: Schema.optionalKey(Schema.Int.check(Schema.isGreaterThan(0))),
118
+ schemaVersion: Schema.Literal(1),
119
+ scope: SubscribeRequest.fields.scope,
120
+ key: SubscriptionKey
121
+ });
122
+ const GetSubscriptionRequest = Schema.TaggedStruct("GetSubscription", {
123
+ schemaVersion: Schema.Literal(1),
124
+ scope: SubscriptionScope,
125
+ key: SubscriptionKey
126
+ });
127
+ const RecoverDeliveryRequest = Schema.TaggedStruct("RecoverDelivery", {
128
+ expectedGeneration: Schema.Natural,
129
+ schemaVersion: Schema.Literal(1),
130
+ scope: SubscribeRequest.fields.scope,
131
+ key: SubscriptionDeliveryKey
132
+ });
133
+ const ListDeliveriesRequest = Schema.TaggedStruct("ListDeliveries", {
134
+ schemaVersion: Schema.Literal(1),
135
+ scope: SubscribeRequest.fields.scope,
136
+ key: SubscriptionKey,
137
+ after: Schema.optionalKey(Schema.String),
138
+ limit: Schema.optionalKey(Schema.Int.check(Schema.isGreaterThan(0)))
139
+ });
140
+ const AcceptRequest = Schema.TaggedStruct("Accept", {
141
+ schemaVersion: Schema.Literal(1),
142
+ partition: SourcePartition,
143
+ principal: Principal,
144
+ source: EventSourceVersion,
145
+ payload: PersistedJson
146
+ });
147
+ const StatusRequest = Schema.TaggedStruct("Status", {
148
+ schemaVersion: Schema.Literal(1),
149
+ partition: SourcePartition,
150
+ principal: Principal,
151
+ source: EventSourceVersion,
152
+ eventId: Schema.String
153
+ });
154
+ const SubscriptionPartitionRequest = Schema.Union([
155
+ SubscribeRequest,
156
+ GetSubscriptionRequest,
157
+ UpdateSubscriptionRequest,
158
+ SubscriptionStateRequest,
159
+ ListSubscriptionsRequest,
160
+ CancelSubscriptionRequest,
161
+ ListDeliveriesRequest,
162
+ RecoverDeliveryRequest,
163
+ AcceptRequest,
164
+ StatusRequest
165
+ ]);
166
+ const SubscriptionPage = Schema.Struct({
167
+ items: Schema.Array(SubscriptionSnapshot),
168
+ next: Schema.NullOr(Schema.Natural)
169
+ });
170
+ const DeliveryPage = Schema.Struct({
171
+ items: Schema.Array(SubscriptionDeliverySnapshot),
172
+ next: Schema.NullOr(Schema.String)
173
+ });
174
+ const IntakeStatus = Schema.Struct({
175
+ ...EventAcknowledgement.fields,
176
+ routingComplete: Schema.Boolean,
177
+ routingFailure: Schema.NullOr(Schema.String),
178
+ nextAttemptAtMillis: Schema.Number
179
+ });
180
+ const SubscriptionPartitionFailure = Schema.Union([
181
+ SubscriptionError,
182
+ SubscriptionSourceError,
183
+ SubscriptionFailpointError,
184
+ SubscriptionPartitionProtocolError
185
+ ]);
186
+ const SubscriptionPartitionResponse = Schema.Union([
187
+ Schema.TaggedStruct("Snapshot", { value: SubscriptionSnapshot }),
188
+ Schema.TaggedStruct("SubscriptionPage", { value: SubscriptionPage }),
189
+ Schema.TaggedStruct("DeliveryPage", { value: DeliveryPage }),
190
+ Schema.TaggedStruct("DeliverySnapshot", { value: SubscriptionDeliverySnapshot }),
191
+ Schema.TaggedStruct("Acknowledgement", { value: EventAcknowledgement }),
192
+ Schema.TaggedStruct("Status", { value: IntakeStatus }),
193
+ Schema.TaggedStruct("Failed", { failure: SubscriptionPartitionFailure })
194
+ ]);
195
+ const decodeRequest = Schema.decodeUnknownEffect(SubscriptionPartitionRequest);
196
+ const encodeRequest = Schema.encodeEffect(SubscriptionPartitionRequest);
197
+ const decodeResponse = Schema.decodeUnknownEffect(SubscriptionPartitionResponse);
198
+ const encodeResponse = Schema.encodeEffect(SubscriptionPartitionResponse);
199
+ const protocolFailure = (message) => ({
200
+ _tag: "Failed",
201
+ failure: SubscriptionPartitionProtocolError.make({ message: protocolMessage(message) })
202
+ });
203
+ const sourcePartitionName = (partition) => JSON.stringify([partition.tenantId, partition.address]);
204
+ var SubscriptionPartitionNamespace = class extends Context.Service()("@effect-agent/platform-cloudflare/SubscriptionPartitionNamespace") {};
205
+ const storageFailure = (code) => SubscriptionError.make({
206
+ reason: "storage",
207
+ code
208
+ });
209
+ const corruptFailure = (code) => SubscriptionError.make({
210
+ reason: "corrupt",
211
+ code
212
+ });
213
+ /** Worker-side management and trusted intake, routed to one fresh partition stub per call. */
214
+ var CloudflareSubscriptionsClient = class {
215
+ static layer(partition) {
216
+ return Layer.effectContext(Effect.gen(function* () {
217
+ const { namespace } = yield* SubscriptionPartitionNamespace;
218
+ const call = Effect.fn("CloudflareSubscriptionsClient.call")(function* (addressedPartition, request) {
219
+ if (!samePartition(partition, addressedPartition)) return yield* SubscriptionError.make({
220
+ reason: "unauthorized",
221
+ code: "partition"
222
+ });
223
+ const encoded = yield* encodeRequest(request).pipe(Effect.mapError(() => corruptFailure("subscription-partition-protocol")));
224
+ const raw = yield* Effect.tryPromise({
225
+ try: () => namespace.get(namespace.idFromName(sourcePartitionName(partition))).subscription(encoded),
226
+ catch: () => storageFailure("call-subscription-partition")
227
+ });
228
+ return yield* decodeResponse(raw).pipe(Effect.mapError(() => corruptFailure("subscription-partition-protocol")));
229
+ });
230
+ const failed = (response) => response._tag === "Failed" ? response.failure : SubscriptionPartitionProtocolError.make({ message: "Unexpected subscription response" });
231
+ const asProtocolError = () => corruptFailure("subscription-partition-protocol");
232
+ const changeState = Effect.fn("CloudflareSubscriptions.changeState")(function* (scope, key, expectedRevision, _tag) {
233
+ const response = yield* call(scope.partition, {
234
+ _tag,
235
+ schemaVersion: 1,
236
+ scope,
237
+ key,
238
+ expectedRevision
239
+ });
240
+ if (response._tag === "Snapshot") return response.value;
241
+ const failure = failed(response);
242
+ return yield* failure._tag === "SubscriptionError" || failure._tag === "SubscriptionFailpointError" ? failure : asProtocolError();
243
+ });
244
+ const subscriptions = Subscriptions.of({
245
+ recoverSubscription: (scope, key, revision) => changeState(scope, key, revision, "RecoverSubscription"),
246
+ getSubscription: (scope, key) => Effect.gen(function* () {
247
+ const response = yield* call(scope.partition, {
248
+ _tag: "GetSubscription",
249
+ schemaVersion: 1,
250
+ scope,
251
+ key
252
+ });
253
+ if (response._tag === "Snapshot") return response.value;
254
+ const failure = failed(response);
255
+ return yield* failure._tag === "SubscriptionError" ? failure : asProtocolError();
256
+ }),
257
+ recoverDelivery: (scope, key, expectedGeneration) => Effect.gen(function* () {
258
+ const response = yield* call(scope.partition, {
259
+ _tag: "RecoverDelivery",
260
+ expectedGeneration,
261
+ schemaVersion: 1,
262
+ scope,
263
+ key
264
+ });
265
+ if (response._tag === "DeliverySnapshot") return response.value;
266
+ const failure = failed(response);
267
+ return yield* failure._tag === "SubscriptionError" || failure._tag === "SubscriptionFailpointError" ? failure : asProtocolError();
268
+ }),
269
+ updateSubscription: (scope, key, expectedRevision, options) => Effect.gen(function* () {
270
+ const response = yield* call(scope.partition, {
271
+ _tag: "UpdateSubscription",
272
+ schemaVersion: 1,
273
+ scope,
274
+ key,
275
+ expectedRevision,
276
+ options
277
+ });
278
+ if (response._tag === "Snapshot") return response.value;
279
+ const failure = failed(response);
280
+ return yield* failure._tag === "SubscriptionError" || failure._tag === "SubscriptionFailpointError" || failure._tag === "SubscriptionSourceError" ? failure : asProtocolError();
281
+ }),
282
+ pauseSubscription: (scope, key, revision) => changeState(scope, key, revision, "PauseSubscription"),
283
+ resumeSubscription: (scope, key, revision) => changeState(scope, key, revision, "ResumeSubscription"),
284
+ subscribe: (scope, options) => Effect.gen(function* () {
285
+ const response = yield* call(scope.partition, {
286
+ _tag: "Subscribe",
287
+ schemaVersion: 1,
288
+ scope,
289
+ options
290
+ });
291
+ if (response._tag === "Snapshot") return response.value;
292
+ const failure = failed(response);
293
+ if (failure._tag === "SubscriptionError" || failure._tag === "SubscriptionSourceError" || failure._tag === "SubscriptionFailpointError") return yield* failure;
294
+ return yield* asProtocolError();
295
+ }),
296
+ listSubscriptions: (scope, after, limit) => Effect.gen(function* () {
297
+ const response = yield* call(scope.partition, {
298
+ _tag: "ListSubscriptions",
299
+ schemaVersion: 1,
300
+ scope,
301
+ ...after === void 0 ? {} : { after },
302
+ ...limit === void 0 ? {} : { limit }
303
+ });
304
+ if (response._tag === "SubscriptionPage") return response.value;
305
+ const failure = failed(response);
306
+ return yield* failure._tag === "SubscriptionError" ? failure : asProtocolError();
307
+ }),
308
+ cancelSubscription: (scope, key, expectedRevision) => Effect.gen(function* () {
309
+ const response = yield* call(scope.partition, {
310
+ _tag: "CancelSubscription",
311
+ ...expectedRevision === void 0 ? {} : { expectedRevision },
312
+ schemaVersion: 1,
313
+ scope,
314
+ key
315
+ });
316
+ if (response._tag === "Snapshot") return response.value;
317
+ const failure = failed(response);
318
+ if (failure._tag === "SubscriptionError" || failure._tag === "SubscriptionFailpointError") return yield* failure;
319
+ return yield* asProtocolError();
320
+ }),
321
+ listDeliveries: (scope, key, after, limit) => Effect.gen(function* () {
322
+ const response = yield* call(scope.partition, {
323
+ _tag: "ListDeliveries",
324
+ schemaVersion: 1,
325
+ scope,
326
+ key,
327
+ ...after === void 0 ? {} : { after },
328
+ ...limit === void 0 ? {} : { limit }
329
+ });
330
+ if (response._tag === "DeliveryPage") return response.value;
331
+ const failure = failed(response);
332
+ return yield* failure._tag === "SubscriptionError" ? failure : asProtocolError();
333
+ })
334
+ });
335
+ const intake = SubscriptionIntake.of({
336
+ accept: (principal, source, payload) => Effect.gen(function* () {
337
+ const request = yield* Schema.decodeUnknownEffect(AcceptRequest)({
338
+ _tag: "Accept",
339
+ schemaVersion: 1,
340
+ partition,
341
+ principal,
342
+ source,
343
+ payload
344
+ }).pipe(Effect.mapError(() => SubscriptionError.make({
345
+ reason: "validation",
346
+ code: "event-payload"
347
+ })));
348
+ const response = yield* call(request.partition, request);
349
+ if (response._tag === "Acknowledgement") return response.value;
350
+ const failure = failed(response);
351
+ if (failure._tag === "SubscriptionError" || failure._tag === "SubscriptionSourceError" || failure._tag === "SubscriptionFailpointError") return yield* failure;
352
+ return yield* asProtocolError();
353
+ }),
354
+ status: (principal, source, eventId) => Effect.gen(function* () {
355
+ const response = yield* call(partition, {
356
+ _tag: "Status",
357
+ schemaVersion: 1,
358
+ partition,
359
+ principal,
360
+ source,
361
+ eventId
362
+ });
363
+ if (response._tag === "Status") return response.value;
364
+ const failure = failed(response);
365
+ return yield* failure._tag === "SubscriptionError" ? failure : asProtocolError();
366
+ })
367
+ });
368
+ return Context.make(Subscriptions, subscriptions).pipe(Context.add(SubscriptionIntake, intake));
369
+ }));
370
+ }
371
+ };
372
+ var SubscriptionPartitionIdentity = class extends Context.Service()("@effect-agent/platform-cloudflare/SubscriptionPartitionIdentity") {};
373
+ const decodePartitionName = Effect.fn("decodeSubscriptionPartitionName")(function* (name) {
374
+ if (name === null || name === void 0) return yield* SubscriptionPartitionProtocolError.make({ message: "Subscription Partition objects require an idFromName identity" });
375
+ const tuple = yield* Schema.decodeEffect(Schema.fromJsonString(Schema.Tuple([Schema.String, Schema.String])))(name).pipe(Effect.mapError(() => SubscriptionPartitionProtocolError.make({ message: "Subscription Partition name is malformed" })));
376
+ return yield* Schema.decodeEffect(SourcePartition)({
377
+ tenantId: tuple[0],
378
+ address: tuple[1]
379
+ }).pipe(Effect.mapError(() => SubscriptionPartitionProtocolError.make({ message: "Subscription Partition identity is invalid" })));
380
+ });
381
+ const samePartition = Schema.toEquivalence(SourcePartition);
382
+ const requestPartition = (request) => request._tag === "Accept" || request._tag === "Status" ? request.partition : request.scope.partition;
383
+ const handleRequest = Effect.fn("SubscriptionPartition.handleRequest")(function* (encoded) {
384
+ const decoded = yield* decodeRequest(encoded).pipe(Effect.result);
385
+ if (decoded._tag === "Failure") return yield* encodeResponse(protocolFailure("The subscription request could not be decoded")).pipe(Effect.orDie);
386
+ const request = decoded.success;
387
+ const { partition } = yield* SubscriptionPartitionIdentity;
388
+ if (!samePartition(partition, requestPartition(request))) return yield* encodeResponse(protocolFailure("The request partition does not match the addressed object")).pipe(Effect.orDie);
389
+ const subscriptions = yield* Subscriptions;
390
+ const intake = yield* SubscriptionIntake;
391
+ const response = yield* Effect.gen(function* () {
392
+ switch (request._tag) {
393
+ case "GetSubscription": return {
394
+ _tag: "Snapshot",
395
+ value: yield* subscriptions.getSubscription(request.scope, request.key)
396
+ };
397
+ case "Subscribe": return {
398
+ _tag: "Snapshot",
399
+ value: yield* subscriptions.subscribe(request.scope, request.options)
400
+ };
401
+ case "UpdateSubscription": return {
402
+ _tag: "Snapshot",
403
+ value: yield* subscriptions.updateSubscription(request.scope, request.key, request.expectedRevision, request.options)
404
+ };
405
+ case "RecoverSubscription": return {
406
+ _tag: "Snapshot",
407
+ value: yield* subscriptions.recoverSubscription(request.scope, request.key, request.expectedRevision)
408
+ };
409
+ case "PauseSubscription": return {
410
+ _tag: "Snapshot",
411
+ value: yield* subscriptions.pauseSubscription(request.scope, request.key, request.expectedRevision)
412
+ };
413
+ case "ResumeSubscription": return {
414
+ _tag: "Snapshot",
415
+ value: yield* subscriptions.resumeSubscription(request.scope, request.key, request.expectedRevision)
416
+ };
417
+ case "ListSubscriptions": return {
418
+ _tag: "SubscriptionPage",
419
+ value: yield* subscriptions.listSubscriptions(request.scope, request.after, request.limit)
420
+ };
421
+ case "CancelSubscription": return {
422
+ _tag: "Snapshot",
423
+ value: yield* subscriptions.cancelSubscription(request.scope, request.key, request.expectedRevision)
424
+ };
425
+ case "RecoverDelivery": return {
426
+ _tag: "DeliverySnapshot",
427
+ value: yield* subscriptions.recoverDelivery(request.scope, request.key, request.expectedGeneration)
428
+ };
429
+ case "ListDeliveries": return {
430
+ _tag: "DeliveryPage",
431
+ value: yield* subscriptions.listDeliveries(request.scope, request.key, request.after, request.limit)
432
+ };
433
+ case "Accept": return {
434
+ _tag: "Acknowledgement",
435
+ value: yield* intake.accept(request.principal, request.source, request.payload)
436
+ };
437
+ case "Status": return {
438
+ _tag: "Status",
439
+ value: yield* intake.status(request.principal, request.source, request.eventId)
440
+ };
441
+ }
442
+ }).pipe(Effect.catch((failure) => Schema.is(SubscriptionPartitionFailure)(failure) ? Effect.succeed({
443
+ _tag: "Failed",
444
+ failure
445
+ }) : Effect.succeed(protocolFailure("The subscription operation failed outside its contract"))));
446
+ return yield* encodeResponse(response).pipe(Effect.orDie);
447
+ });
448
+ const alarmStorageError = (code) => () => storageFailure(code);
449
+ const transactionLayer = Layer.effect(DoSubscriptionTransaction, Effect.gen(function* () {
450
+ const alarms = yield* DurableObjectAlarm.DurableObjectAlarm;
451
+ return DoSubscriptionTransaction.of({ run: (body) => Effect.gen(function* () {
452
+ const nowMillis = yield* Clock.currentTimeMillis;
453
+ return yield* alarms.transaction((transaction) => body((replacement) => replacement.deadlineAtMillis === null ? transaction.cancelAlarm({
454
+ id: SUBSCRIPTION_ALARM_ID,
455
+ tag: SUBSCRIPTION_ALARM_TAG
456
+ }).pipe(Effect.mapError(alarmStorageError("cancel-subscription-alarm"))) : Effect.fromOption(DateTime.make(Math.max(replacement.deadlineAtMillis, nowMillis + 1))).pipe(Effect.mapError(() => corruptFailure("subscription-alarm-deadline")), Effect.flatMap((runAt) => transaction.scheduleAlarm({
457
+ id: SUBSCRIPTION_ALARM_ID,
458
+ tag: SUBSCRIPTION_ALARM_TAG,
459
+ runAt,
460
+ payload: {
461
+ schemaVersion: 1,
462
+ generation: replacement.generation
463
+ }
464
+ }).pipe(Effect.mapError(alarmStorageError("schedule-subscription-alarm"))))))).pipe(Effect.catchTag("StorageOperationError", () => storageFailure("commit-subscription-transaction")));
465
+ }) });
466
+ }));
467
+ const alarmHandler = (limits) => DurableObjectAlarm.processDue((event) => Effect.gen(function* () {
468
+ if (event.tag !== SUBSCRIPTION_ALARM_TAG) {
469
+ const { handlers } = yield* SubscriptionPartitionAlarmExtension;
470
+ const matches = handlers.filter((handler) => handler.tag === event.tag);
471
+ const handler = matches[0];
472
+ if (event.tag.startsWith("effect-agent/") || matches.length !== 1 || handler === void 0) return yield* SubscriptionAlarmProtocolError.make({ message: "Unknown or ambiguous ancillary alarm tag" });
473
+ return yield* handler.handle(event).pipe(Effect.scoped, Effect.timeoutOrElse({
474
+ duration: MAX_ANCILLARY_ALARM_MILLIS,
475
+ orElse: () => SubscriptionAlarmExtensionError.make({ code: "timeout" })
476
+ }));
477
+ }
478
+ if (event.id !== SUBSCRIPTION_ALARM_ID) return yield* SubscriptionAlarmProtocolError.make({ message: `Unsupported Subscription Partition alarm ${event.tag}/${event.id}` });
479
+ yield* Schema.decodeUnknownEffect(SubscriptionAlarmPayload)(event.payload).pipe(Effect.mapError(() => SubscriptionAlarmProtocolError.make({ message: "Unsupported subscription alarm payload" })));
480
+ const driver = yield* SubscriptionDriver;
481
+ const alarmControl = yield* DoSubscriptionAlarmControl;
482
+ yield* alarmControl.prearm((yield* Clock.currentTimeMillis) + limits.retryMillis);
483
+ if ((yield* driver.runDue.pipe(Effect.catchCauseIf((cause) => !Cause.hasInterrupts(cause), (cause) => Clock.currentTimeMillis.pipe(Effect.flatMap((time) => alarmControl.prearm(time + limits.retryMillis)), Effect.andThen(Effect.failCause(cause)))))).failed > 0) yield* alarmControl.prearm((yield* Clock.currentTimeMillis) + limits.retryMillis);
484
+ else yield* alarmControl.reconcile;
485
+ }), {
486
+ mode: "isolated",
487
+ limit: MAX_ALARMS_PER_INVOCATION,
488
+ retryFailedAfter: limits.retryMillis,
489
+ onFailure: () => Effect.logWarning("Subscription partition alarm retained for retry")
490
+ }).pipe(Effect.asVoid);
491
+ /**
492
+ * Build one source-addressed SQLite Durable Object. The host Layer binds the permitted source
493
+ * catalog and authority. It must not retain cleanup-scoped resources across RPC events.
494
+ */
495
+ const makeSubscriptionPartitionObjectClass = (host, limits = defaultSubscriptionLimits) => {
496
+ const cloudflareLimitsLayer = Layer.effectDiscard(validateCloudflareSubscriptionLimits(limits));
497
+ const identityLayer = Layer.effect(SubscriptionPartitionIdentity, Effect.gen(function* () {
498
+ const state = yield* DurableObjectState.DurableObjectState;
499
+ return SubscriptionPartitionIdentity.of({ partition: yield* decodePartitionName(state.raw.id.name) });
500
+ }));
501
+ const sqlLayer = Layer.unwrap(Effect.map(DurableObjectState.DurableObjectState, (state) => SqliteClient.layer({ storage: state.raw.storage })));
502
+ const partitionStore = Layer.unwrap(Effect.map(SubscriptionPartitionIdentity, ({ partition }) => doSubscriptionStoreLayer(partition).pipe(Layer.provide(transactionLayer), Layer.provide(sqlLayer))));
503
+ const application = Layer.mergeAll(Subscriptions.layer(limits), SubscriptionIntake.layer(limits), SubscriptionDriver.layer(limits), cloudflareLimitsLayer, Layer.effect(SubscriptionPartitionAlarmExtension, Effect.gen(function* () {
504
+ const extension = yield* SubscriptionPartitionAlarmExtension;
505
+ const tags = extension.handlers.map((handler) => handler.tag);
506
+ if (tags.length > MAX_ALARMS_PER_INVOCATION || new Set(tags).size !== tags.length || tags.some((tag) => tag.length === 0 || tag.length > 128 || tag.startsWith("effect-agent/"))) return yield* SubscriptionAlarmProtocolError.make({ message: "Invalid ancillary alarm handler registry" });
507
+ yield* validateCloudflareSubscriptionLimits(limits, { ancillaryAlarms: tags.length > 0 });
508
+ return extension;
509
+ }))).pipe(Layer.provideMerge(partitionStore), Layer.provide(cloudflarePreparedInputAdmissionLayer.pipe(Layer.provide(CloudflareThreadClient.layer))), Layer.provide(BrowserCrypto.layer), Layer.provideMerge(DurableObjectAlarm.DurableObjectAlarm.layer), Layer.provide(host), Layer.provideMerge(identityLayer));
510
+ const runtime = Layer.effectContext(Effect.gen(function* () {
511
+ const state = yield* DurableObjectState.DurableObjectState;
512
+ const scope = yield* Effect.scope;
513
+ return yield* state.blockConcurrencyWhile(Layer.buildWithScope(application, scope));
514
+ }));
515
+ const Base = DurableObject.make(runtime, {
516
+ initialize: Effect.void,
517
+ rpc: { subscription: (encoded) => handleRequest(encoded) },
518
+ alarms: alarmHandler(limits)
519
+ });
520
+ class SubscriptionPartitionObject extends Base {
521
+ alarm(alarmInfo) {
522
+ return super.alarm?.(alarmInfo);
523
+ }
524
+ }
525
+ return SubscriptionPartitionObject;
526
+ };
527
+ //#endregion
528
+ export { CloudflareSubscriptionConfigError, CloudflareSubscriptionsClient, SubscriptionAlarmExtensionError, SubscriptionAlarmProtocolError, SubscriptionPartitionAlarmExtension, SubscriptionPartitionIdentity, SubscriptionPartitionNamespace, SubscriptionPartitionProtocolError, makeSubscriptionPartitionAlarmHandler, makeSubscriptionPartitionObjectClass, sourcePartitionName, CloudflareSubscriptions_exports as t, validateCloudflareSubscriptionLimits };
529
+
530
+ //# sourceMappingURL=CloudflareSubscriptions.mjs.map