@effect-agent/platform-cloudflare 0.1.0-beta.42 → 0.1.0-beta.45
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/browser-quick-action.mjs.map +1 -1
- package/dist/browser-rest-capture.mjs.map +1 -1
- package/dist/browser-rest-crawl.mjs.map +1 -1
- package/dist/browser-session-lifecycle-DqntvG-Y.d.mts +21 -0
- package/dist/browser-session-lifecycle-ZGgb3pnK.mjs +84 -0
- package/dist/browser-session-lifecycle-ZGgb3pnK.mjs.map +1 -0
- package/dist/index.d.mts +47 -34
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +1 -1
- package/dist/interactive-browser.d.mts +1 -18
- package/dist/interactive-browser.mjs +2 -81
- package/dist/interactive-browser.mjs.map +1 -1
- package/dist/{prepared-admission-BKp_Upw2.mjs → prepared-admission-BhW2eT_a.mjs} +3 -3
- package/dist/prepared-admission-BhW2eT_a.mjs.map +1 -0
- package/dist/protected-browser.d.mts +62 -0
- package/dist/protected-browser.mjs +714 -0
- package/dist/protected-browser.mjs.map +1 -0
- package/dist/scheduling.mjs +1 -1
- package/dist/scheduling.mjs.map +1 -1
- package/dist/subscriptions.mjs +1 -1
- package/dist/subscriptions.mjs.map +1 -1
- package/package.json +1 -81
- package/src/alarm.ts +277 -242
- package/src/bindings.ts +5 -0
- package/src/boundary.ts +4 -0
- package/src/browser-quick-action.ts +52 -0
- package/src/browser-rest-capture.ts +30 -0
- package/src/browser-rest-crawl.ts +43 -0
- package/src/browser-session-lifecycle.ts +18 -0
- package/src/client.ts +40 -0
- package/src/code-mode-executor.ts +50 -0
- package/src/interactive-browser.ts +176 -0
- package/src/layers.ts +13 -3
- package/src/memory.ts +42 -3
- package/src/prepared-admission.ts +1 -0
- package/src/progress-wait.ts +14 -0
- package/src/protected-browser/binding.ts +185 -0
- package/src/protected-browser/inspect-frame.ts +82 -0
- package/src/protected-browser/native.ts +384 -0
- package/src/protected-browser/policy.ts +594 -0
- package/src/protected-browser.ts +2 -0
- package/src/scheduling.ts +34 -0
- package/src/subscriptions.ts +50 -0
- package/src/thread-object.ts +55 -1
- package/src/transport.ts +1 -0
- package/src/wake-scheduler.ts +1 -0
- package/dist/prepared-admission-BKp_Upw2.mjs.map +0 -1
package/src/scheduling.ts
CHANGED
|
@@ -119,6 +119,7 @@ const ScheduleOwnerRequest = Schema.Union([
|
|
|
119
119
|
ScheduleListRequest,
|
|
120
120
|
ScheduleControlRequest,
|
|
121
121
|
]);
|
|
122
|
+
|
|
122
123
|
type ScheduleOwnerRequest = typeof ScheduleOwnerRequest.Type;
|
|
123
124
|
|
|
124
125
|
const ScheduleOwnerFailure = Schema.Union([
|
|
@@ -131,6 +132,7 @@ const ScheduleOwnerFailure = Schema.Union([
|
|
|
131
132
|
ScheduleFailpointError,
|
|
132
133
|
ScheduleOwnerProtocolError,
|
|
133
134
|
]);
|
|
135
|
+
|
|
134
136
|
type ScheduleOwnerFailure = typeof ScheduleOwnerFailure.Type;
|
|
135
137
|
|
|
136
138
|
const ScheduleOwnerResponse = Schema.Union([
|
|
@@ -138,6 +140,7 @@ const ScheduleOwnerResponse = Schema.Union([
|
|
|
138
140
|
Schema.TaggedStruct("Page", { value: ScheduleSnapshotPageSchema }),
|
|
139
141
|
Schema.TaggedStruct("Failed", { failure: ScheduleOwnerFailure }),
|
|
140
142
|
]);
|
|
143
|
+
|
|
141
144
|
type ScheduleOwnerResponse = typeof ScheduleOwnerResponse.Type;
|
|
142
145
|
|
|
143
146
|
const decodeScheduleOwnerRequest = Schema.decodeUnknownEffect(ScheduleOwnerRequest);
|
|
@@ -181,6 +184,7 @@ export class CloudflareSchedulingClient {
|
|
|
181
184
|
ScheduleStorageError.make({ operation: "Schedule Owner protocol", reason: "corrupt" }),
|
|
182
185
|
),
|
|
183
186
|
);
|
|
187
|
+
|
|
184
188
|
const raw = yield* Effect.tryPromise({
|
|
185
189
|
try: () => namespace.get(namespace.idFromName(scheduleOwnerKey(owner))).schedule(encoded),
|
|
186
190
|
catch: () =>
|
|
@@ -189,12 +193,15 @@ export class CloudflareSchedulingClient {
|
|
|
189
193
|
reason: "unavailable",
|
|
190
194
|
}),
|
|
191
195
|
});
|
|
196
|
+
|
|
192
197
|
const response = yield* decodeScheduleOwnerResponse(raw).pipe(
|
|
193
198
|
Effect.mapError(() =>
|
|
194
199
|
ScheduleStorageError.make({ operation: "Schedule Owner protocol", reason: "corrupt" }),
|
|
195
200
|
),
|
|
196
201
|
);
|
|
202
|
+
|
|
197
203
|
if (response._tag !== "Failed") return response;
|
|
204
|
+
|
|
198
205
|
return yield* response.failure._tag === "ScheduleOwnerProtocolError"
|
|
199
206
|
? ScheduleStorageError.make({ operation: "Schedule Owner protocol", reason: "corrupt" })
|
|
200
207
|
: response.failure;
|
|
@@ -213,6 +220,7 @@ export class CloudflareSchedulingClient {
|
|
|
213
220
|
}),
|
|
214
221
|
),
|
|
215
222
|
);
|
|
223
|
+
|
|
216
224
|
return yield* Schema.decodeUnknownEffect(PersistedJson)(encoded).pipe(
|
|
217
225
|
Effect.mapError(() =>
|
|
218
226
|
ScheduleValidationError.make({
|
|
@@ -225,6 +233,7 @@ export class CloudflareSchedulingClient {
|
|
|
225
233
|
const create: Scheduling["Service"]["create"] = (agent, input, options) =>
|
|
226
234
|
Effect.gen(function* () {
|
|
227
235
|
const payload = yield* encodeInput(agent, input);
|
|
236
|
+
|
|
228
237
|
const response = yield* call(options.scope.owner, {
|
|
229
238
|
_tag: "Create",
|
|
230
239
|
schemaVersion: 1,
|
|
@@ -232,6 +241,7 @@ export class CloudflareSchedulingClient {
|
|
|
232
241
|
input: payload,
|
|
233
242
|
...options,
|
|
234
243
|
});
|
|
244
|
+
|
|
235
245
|
return response._tag === "Snapshot"
|
|
236
246
|
? response.value
|
|
237
247
|
: yield* ScheduleStorageError.make({
|
|
@@ -243,6 +253,7 @@ export class CloudflareSchedulingClient {
|
|
|
243
253
|
const update: Scheduling["Service"]["update"] = (agent, input, options) =>
|
|
244
254
|
Effect.gen(function* () {
|
|
245
255
|
const payload = yield* encodeInput(agent, input);
|
|
256
|
+
|
|
246
257
|
const response = yield* call(options.scope.owner, {
|
|
247
258
|
_tag: "Update",
|
|
248
259
|
schemaVersion: 1,
|
|
@@ -250,6 +261,7 @@ export class CloudflareSchedulingClient {
|
|
|
250
261
|
input: payload,
|
|
251
262
|
...options,
|
|
252
263
|
});
|
|
264
|
+
|
|
253
265
|
return response._tag === "Snapshot"
|
|
254
266
|
? response.value
|
|
255
267
|
: yield* ScheduleStorageError.make({
|
|
@@ -266,6 +278,7 @@ export class CloudflareSchedulingClient {
|
|
|
266
278
|
scope,
|
|
267
279
|
scheduleId,
|
|
268
280
|
});
|
|
281
|
+
|
|
269
282
|
return response._tag === "Snapshot"
|
|
270
283
|
? response.value
|
|
271
284
|
: yield* ScheduleStorageError.make({
|
|
@@ -283,6 +296,7 @@ export class CloudflareSchedulingClient {
|
|
|
283
296
|
...(options.after === undefined ? {} : { after: options.after }),
|
|
284
297
|
...(options.limit === undefined ? {} : { limit: options.limit }),
|
|
285
298
|
});
|
|
299
|
+
|
|
286
300
|
return response._tag === "Page"
|
|
287
301
|
? response.value
|
|
288
302
|
: yield* ScheduleStorageError.make({
|
|
@@ -306,6 +320,7 @@ export class CloudflareSchedulingClient {
|
|
|
306
320
|
scheduleId,
|
|
307
321
|
expectedRevision,
|
|
308
322
|
});
|
|
323
|
+
|
|
309
324
|
return response._tag === "Snapshot"
|
|
310
325
|
? response.value
|
|
311
326
|
: yield* ScheduleStorageError.make({
|
|
@@ -340,6 +355,7 @@ const decodeOwnerName = Effect.fn("decodeScheduleOwnerName")(function* (
|
|
|
340
355
|
message: "Schedule Owner objects require an idFromName identity",
|
|
341
356
|
});
|
|
342
357
|
}
|
|
358
|
+
|
|
343
359
|
const tuple = yield* Schema.decodeUnknownEffect(
|
|
344
360
|
Schema.fromJsonString(Schema.Tuple([Schema.String, Schema.String])),
|
|
345
361
|
)(name).pipe(
|
|
@@ -347,6 +363,7 @@ const decodeOwnerName = Effect.fn("decodeScheduleOwnerName")(function* (
|
|
|
347
363
|
ScheduleOwnerProtocolError.make({ message: "Schedule Owner object name is malformed" }),
|
|
348
364
|
),
|
|
349
365
|
);
|
|
366
|
+
|
|
350
367
|
return yield* Schema.decodeUnknownEffect(ScheduleOwner)({
|
|
351
368
|
tenantId: tuple[0],
|
|
352
369
|
ownerId: tuple[1],
|
|
@@ -371,10 +388,12 @@ const transactionLayer: Layer.Layer<
|
|
|
371
388
|
DoScheduleTransaction,
|
|
372
389
|
Effect.gen(function* () {
|
|
373
390
|
const alarms = yield* DurableObjectAlarm.DurableObjectAlarm;
|
|
391
|
+
|
|
374
392
|
return DoScheduleTransaction.of({
|
|
375
393
|
run: (body) =>
|
|
376
394
|
Effect.gen(function* () {
|
|
377
395
|
const nowMillis = yield* Clock.currentTimeMillis;
|
|
396
|
+
|
|
378
397
|
return yield* alarms
|
|
379
398
|
.transaction((transaction) =>
|
|
380
399
|
body((replacement) =>
|
|
@@ -434,6 +453,7 @@ const ensureOwner = (
|
|
|
434
453
|
request: ScheduleOwnerRequest,
|
|
435
454
|
): Effect.Effect<void, ScheduleOwnerProtocolError> => {
|
|
436
455
|
const observed = requestOwner(request);
|
|
456
|
+
|
|
437
457
|
return observed.tenantId === expected.tenantId && observed.ownerId === expected.ownerId
|
|
438
458
|
? Effect.void
|
|
439
459
|
: Effect.fail(
|
|
@@ -447,6 +467,7 @@ const handleScheduleRequest = Effect.fn("ScheduleOwner.handleRequest")(function*
|
|
|
447
467
|
encoded: unknown,
|
|
448
468
|
): Effect.fn.Return<unknown, never, Scheduling | ScheduleOwnerIdentity> {
|
|
449
469
|
const decoded = yield* decodeScheduleOwnerRequest(encoded).pipe(Effect.result);
|
|
470
|
+
|
|
450
471
|
if (decoded._tag === "Failure") {
|
|
451
472
|
return yield* encodeScheduleOwnerResponse(
|
|
452
473
|
scheduleProtocolFailure("The Schedule request could not be decoded"),
|
|
@@ -455,6 +476,7 @@ const handleScheduleRequest = Effect.fn("ScheduleOwner.handleRequest")(function*
|
|
|
455
476
|
const request = decoded.success;
|
|
456
477
|
const { owner } = yield* ScheduleOwnerIdentity;
|
|
457
478
|
const scheduling = yield* Scheduling;
|
|
479
|
+
|
|
458
480
|
const response = yield* Effect.gen(function* () {
|
|
459
481
|
yield* ensureOwner(owner, request);
|
|
460
482
|
switch (request._tag) {
|
|
@@ -467,6 +489,7 @@ const handleScheduleRequest = Effect.fn("ScheduleOwner.handleRequest")(function*
|
|
|
467
489
|
deliveryPrincipal: request.deliveryPrincipal,
|
|
468
490
|
definitions: request.definitions,
|
|
469
491
|
});
|
|
492
|
+
|
|
470
493
|
return { _tag: "Snapshot" as const, value };
|
|
471
494
|
}
|
|
472
495
|
case "Update": {
|
|
@@ -479,6 +502,7 @@ const handleScheduleRequest = Effect.fn("ScheduleOwner.handleRequest")(function*
|
|
|
479
502
|
definitions: request.definitions,
|
|
480
503
|
expectedRevision: request.expectedRevision,
|
|
481
504
|
});
|
|
505
|
+
|
|
482
506
|
return { _tag: "Snapshot" as const, value };
|
|
483
507
|
}
|
|
484
508
|
case "Get":
|
|
@@ -509,6 +533,7 @@ const handleScheduleRequest = Effect.fn("ScheduleOwner.handleRequest")(function*
|
|
|
509
533
|
request.scheduleId,
|
|
510
534
|
request.expectedRevision,
|
|
511
535
|
);
|
|
536
|
+
|
|
512
537
|
return { _tag: "Snapshot" as const, value };
|
|
513
538
|
}
|
|
514
539
|
}
|
|
@@ -522,6 +547,7 @@ const handleScheduleRequest = Effect.fn("ScheduleOwner.handleRequest")(function*
|
|
|
522
547
|
),
|
|
523
548
|
),
|
|
524
549
|
);
|
|
550
|
+
|
|
525
551
|
return yield* encodeScheduleOwnerResponse(response).pipe(Effect.orDie);
|
|
526
552
|
});
|
|
527
553
|
|
|
@@ -545,8 +571,10 @@ const scheduleAlarmHandler = (limits: SchedulingLimits) =>
|
|
|
545
571
|
const alarmControl = yield* DoScheduleAlarmControl;
|
|
546
572
|
const { owner } = yield* ScheduleOwnerIdentity;
|
|
547
573
|
const nowMillis = yield* Clock.currentTimeMillis;
|
|
574
|
+
|
|
548
575
|
yield* alarmControl.prearm(nowMillis + limits.recoveryPollMillis);
|
|
549
576
|
const pass = yield* scheduling.runDue(owner);
|
|
577
|
+
|
|
550
578
|
if (pass.failed > 0) {
|
|
551
579
|
yield* alarmControl.prearm((yield* Clock.currentTimeMillis) + limits.recoveryPollMillis);
|
|
552
580
|
} else {
|
|
@@ -585,14 +613,17 @@ export const makeScheduleOwnerObjectClass = <E>(
|
|
|
585
613
|
ScheduleOwnerIdentity,
|
|
586
614
|
Effect.gen(function* () {
|
|
587
615
|
const state = yield* EffectCfDurableObjectState.DurableObjectState;
|
|
616
|
+
|
|
588
617
|
return ScheduleOwnerIdentity.of({ owner: yield* decodeOwnerName(state.raw.id.name) });
|
|
589
618
|
}),
|
|
590
619
|
);
|
|
620
|
+
|
|
591
621
|
const sqlLayer = Layer.unwrap(
|
|
592
622
|
Effect.map(EffectCfDurableObjectState.DurableObjectState, (state) =>
|
|
593
623
|
SqliteClient.layer({ storage: state.raw.storage }),
|
|
594
624
|
),
|
|
595
625
|
);
|
|
626
|
+
|
|
596
627
|
const application = Layer.merge(Scheduling.layer(limits), ScheduleDriver.layer(limits)).pipe(
|
|
597
628
|
Layer.provideMerge(
|
|
598
629
|
scheduleStoreLayer.pipe(Layer.provide(transactionLayer), Layer.provide(sqlLayer)),
|
|
@@ -609,6 +640,7 @@ export const makeScheduleOwnerObjectClass = <E>(
|
|
|
609
640
|
Layer.provide(host),
|
|
610
641
|
Layer.provideMerge(ownerLayer),
|
|
611
642
|
);
|
|
643
|
+
|
|
612
644
|
const runtime: Layer.Layer<
|
|
613
645
|
ScheduleRuntimeServices,
|
|
614
646
|
E | ScheduleStorageError | ScheduleOwnerProtocolError | ScheduleValidationError,
|
|
@@ -617,6 +649,7 @@ export const makeScheduleOwnerObjectClass = <E>(
|
|
|
617
649
|
Effect.gen(function* () {
|
|
618
650
|
const state = yield* EffectCfDurableObjectState.DurableObjectState;
|
|
619
651
|
const scope = yield* Effect.scope;
|
|
652
|
+
|
|
620
653
|
return yield* state.blockConcurrencyWhile(Layer.buildWithScope(application, scope));
|
|
621
654
|
}),
|
|
622
655
|
);
|
|
@@ -636,5 +669,6 @@ export const makeScheduleOwnerObjectClass = <E>(
|
|
|
636
669
|
return super.alarm?.(alarmInfo);
|
|
637
670
|
}
|
|
638
671
|
}
|
|
672
|
+
|
|
639
673
|
return ScheduleOwnerObject;
|
|
640
674
|
};
|
package/src/subscriptions.ts
CHANGED
|
@@ -70,6 +70,7 @@ export const validateCloudflareSubscriptionLimits = (
|
|
|
70
70
|
): Effect.Effect<void, CloudflareSubscriptionConfigError> => {
|
|
71
71
|
const worstCaseMillis =
|
|
72
72
|
4 * Math.ceil(limits.batchSize / limits.concurrency) * limits.operationTimeoutMillis;
|
|
73
|
+
|
|
73
74
|
return worstCaseMillis <= MAX_ALARM_WALL_MILLIS
|
|
74
75
|
? Effect.void
|
|
75
76
|
: Effect.fail(
|
|
@@ -146,16 +147,19 @@ const SubscriptionPartitionRequest = Schema.Union([
|
|
|
146
147
|
AcceptRequest,
|
|
147
148
|
StatusRequest,
|
|
148
149
|
]);
|
|
150
|
+
|
|
149
151
|
type SubscriptionPartitionRequest = typeof SubscriptionPartitionRequest.Type;
|
|
150
152
|
|
|
151
153
|
const SubscriptionPage = Schema.Struct({
|
|
152
154
|
items: Schema.Array(SubscriptionSnapshot),
|
|
153
155
|
next: Schema.NullOr(Schema.Natural),
|
|
154
156
|
});
|
|
157
|
+
|
|
155
158
|
const DeliveryPage = Schema.Struct({
|
|
156
159
|
items: Schema.Array(SubscriptionDeliverySnapshot),
|
|
157
160
|
next: Schema.NullOr(Schema.String),
|
|
158
161
|
});
|
|
162
|
+
|
|
159
163
|
const IntakeStatus = Schema.Struct({
|
|
160
164
|
...EventAcknowledgement.fields,
|
|
161
165
|
routingComplete: Schema.Boolean,
|
|
@@ -169,6 +173,7 @@ const SubscriptionPartitionFailure = Schema.Union([
|
|
|
169
173
|
SubscriptionFailpointError,
|
|
170
174
|
SubscriptionPartitionProtocolError,
|
|
171
175
|
]);
|
|
176
|
+
|
|
172
177
|
type SubscriptionPartitionFailure = typeof SubscriptionPartitionFailure.Type;
|
|
173
178
|
|
|
174
179
|
const SubscriptionPartitionResponse = Schema.Union([
|
|
@@ -179,6 +184,7 @@ const SubscriptionPartitionResponse = Schema.Union([
|
|
|
179
184
|
Schema.TaggedStruct("Status", { value: IntakeStatus }),
|
|
180
185
|
Schema.TaggedStruct("Failed", { failure: SubscriptionPartitionFailure }),
|
|
181
186
|
]);
|
|
187
|
+
|
|
182
188
|
type SubscriptionPartitionResponse = typeof SubscriptionPartitionResponse.Type;
|
|
183
189
|
|
|
184
190
|
const decodeRequest = Schema.decodeUnknownEffect(SubscriptionPartitionRequest);
|
|
@@ -205,6 +211,7 @@ export class SubscriptionPartitionNamespace extends Context.Service<
|
|
|
205
211
|
|
|
206
212
|
const storageFailure = (code: string): SubscriptionError =>
|
|
207
213
|
SubscriptionError.make({ reason: "storage", code });
|
|
214
|
+
|
|
208
215
|
const corruptFailure = (code: string): SubscriptionError =>
|
|
209
216
|
SubscriptionError.make({ reason: "corrupt", code });
|
|
210
217
|
|
|
@@ -224,9 +231,11 @@ export class CloudflareSubscriptionsClient {
|
|
|
224
231
|
if (!samePartition(partition, addressedPartition)) {
|
|
225
232
|
return yield* SubscriptionError.make({ reason: "unauthorized", code: "partition" });
|
|
226
233
|
}
|
|
234
|
+
|
|
227
235
|
const encoded = yield* encodeRequest(request).pipe(
|
|
228
236
|
Effect.mapError(() => corruptFailure("subscription-partition-protocol")),
|
|
229
237
|
);
|
|
238
|
+
|
|
230
239
|
const raw = yield* Effect.tryPromise({
|
|
231
240
|
try: () =>
|
|
232
241
|
namespace
|
|
@@ -234,6 +243,7 @@ export class CloudflareSubscriptionsClient {
|
|
|
234
243
|
.subscription(encoded),
|
|
235
244
|
catch: () => storageFailure("call-subscription-partition"),
|
|
236
245
|
});
|
|
246
|
+
|
|
237
247
|
return yield* decodeResponse(raw).pipe(
|
|
238
248
|
Effect.mapError(() => corruptFailure("subscription-partition-protocol")),
|
|
239
249
|
);
|
|
@@ -245,6 +255,7 @@ export class CloudflareSubscriptionsClient {
|
|
|
245
255
|
: SubscriptionPartitionProtocolError.make({
|
|
246
256
|
message: "Unexpected subscription response",
|
|
247
257
|
});
|
|
258
|
+
|
|
248
259
|
const asProtocolError = (): SubscriptionError =>
|
|
249
260
|
corruptFailure("subscription-partition-protocol");
|
|
250
261
|
|
|
@@ -257,14 +268,17 @@ export class CloudflareSubscriptionsClient {
|
|
|
257
268
|
scope,
|
|
258
269
|
options,
|
|
259
270
|
});
|
|
271
|
+
|
|
260
272
|
if (response._tag === "Snapshot") return response.value;
|
|
261
273
|
const failure = failed(response);
|
|
274
|
+
|
|
262
275
|
if (
|
|
263
276
|
failure._tag === "SubscriptionError" ||
|
|
264
277
|
failure._tag === "SubscriptionSourceError" ||
|
|
265
278
|
failure._tag === "SubscriptionFailpointError"
|
|
266
279
|
)
|
|
267
280
|
return yield* failure;
|
|
281
|
+
|
|
268
282
|
return yield* asProtocolError();
|
|
269
283
|
}),
|
|
270
284
|
listSubscriptions: (scope, after, limit) =>
|
|
@@ -276,8 +290,10 @@ export class CloudflareSubscriptionsClient {
|
|
|
276
290
|
...(after === undefined ? {} : { after }),
|
|
277
291
|
...(limit === undefined ? {} : { limit }),
|
|
278
292
|
});
|
|
293
|
+
|
|
279
294
|
if (response._tag === "SubscriptionPage") return response.value;
|
|
280
295
|
const failure = failed(response);
|
|
296
|
+
|
|
281
297
|
return yield* failure._tag === "SubscriptionError" ? failure : asProtocolError();
|
|
282
298
|
}),
|
|
283
299
|
cancelSubscription: (scope, key) =>
|
|
@@ -288,13 +304,16 @@ export class CloudflareSubscriptionsClient {
|
|
|
288
304
|
scope,
|
|
289
305
|
key,
|
|
290
306
|
});
|
|
307
|
+
|
|
291
308
|
if (response._tag === "Snapshot") return response.value;
|
|
292
309
|
const failure = failed(response);
|
|
310
|
+
|
|
293
311
|
if (
|
|
294
312
|
failure._tag === "SubscriptionError" ||
|
|
295
313
|
failure._tag === "SubscriptionFailpointError"
|
|
296
314
|
)
|
|
297
315
|
return yield* failure;
|
|
316
|
+
|
|
298
317
|
return yield* asProtocolError();
|
|
299
318
|
}),
|
|
300
319
|
listDeliveries: (scope, key, after, limit) =>
|
|
@@ -307,8 +326,10 @@ export class CloudflareSubscriptionsClient {
|
|
|
307
326
|
...(after === undefined ? {} : { after }),
|
|
308
327
|
...(limit === undefined ? {} : { limit }),
|
|
309
328
|
});
|
|
329
|
+
|
|
310
330
|
if (response._tag === "DeliveryPage") return response.value;
|
|
311
331
|
const failure = failed(response);
|
|
332
|
+
|
|
312
333
|
return yield* failure._tag === "SubscriptionError" ? failure : asProtocolError();
|
|
313
334
|
}),
|
|
314
335
|
});
|
|
@@ -328,15 +349,19 @@ export class CloudflareSubscriptionsClient {
|
|
|
328
349
|
SubscriptionError.make({ reason: "validation", code: "event-payload" }),
|
|
329
350
|
),
|
|
330
351
|
);
|
|
352
|
+
|
|
331
353
|
const response = yield* call(request.partition, request);
|
|
354
|
+
|
|
332
355
|
if (response._tag === "Acknowledgement") return response.value;
|
|
333
356
|
const failure = failed(response);
|
|
357
|
+
|
|
334
358
|
if (
|
|
335
359
|
failure._tag === "SubscriptionError" ||
|
|
336
360
|
failure._tag === "SubscriptionSourceError" ||
|
|
337
361
|
failure._tag === "SubscriptionFailpointError"
|
|
338
362
|
)
|
|
339
363
|
return yield* failure;
|
|
364
|
+
|
|
340
365
|
return yield* asProtocolError();
|
|
341
366
|
}),
|
|
342
367
|
status: (principal, source, eventId) =>
|
|
@@ -349,8 +374,10 @@ export class CloudflareSubscriptionsClient {
|
|
|
349
374
|
source,
|
|
350
375
|
eventId,
|
|
351
376
|
});
|
|
377
|
+
|
|
352
378
|
if (response._tag === "Status") return response.value;
|
|
353
379
|
const failure = failed(response);
|
|
380
|
+
|
|
354
381
|
return yield* failure._tag === "SubscriptionError" ? failure : asProtocolError();
|
|
355
382
|
}),
|
|
356
383
|
});
|
|
@@ -376,6 +403,7 @@ const decodePartitionName = Effect.fn("decodeSubscriptionPartitionName")(functio
|
|
|
376
403
|
message: "Subscription Partition objects require an idFromName identity",
|
|
377
404
|
});
|
|
378
405
|
}
|
|
406
|
+
|
|
379
407
|
const tuple = yield* Schema.decodeUnknownEffect(
|
|
380
408
|
Schema.fromJsonString(Schema.Tuple([Schema.String, Schema.String])),
|
|
381
409
|
)(name).pipe(
|
|
@@ -385,6 +413,7 @@ const decodePartitionName = Effect.fn("decodeSubscriptionPartitionName")(functio
|
|
|
385
413
|
}),
|
|
386
414
|
),
|
|
387
415
|
);
|
|
416
|
+
|
|
388
417
|
return yield* Schema.decodeUnknownEffect(SourcePartition)({
|
|
389
418
|
tenantId: tuple[0],
|
|
390
419
|
address: tuple[1],
|
|
@@ -398,6 +427,7 @@ const decodePartitionName = Effect.fn("decodeSubscriptionPartitionName")(functio
|
|
|
398
427
|
});
|
|
399
428
|
|
|
400
429
|
const samePartition = Schema.toEquivalence(SourcePartition);
|
|
430
|
+
|
|
401
431
|
const requestPartition = (request: SubscriptionPartitionRequest): SourcePartition =>
|
|
402
432
|
request._tag === "Accept" || request._tag === "Status"
|
|
403
433
|
? request.partition
|
|
@@ -407,6 +437,7 @@ const handleRequest = Effect.fn("SubscriptionPartition.handleRequest")(function*
|
|
|
407
437
|
encoded: unknown,
|
|
408
438
|
) {
|
|
409
439
|
const decoded = yield* decodeRequest(encoded).pipe(Effect.result);
|
|
440
|
+
|
|
410
441
|
if (decoded._tag === "Failure") {
|
|
411
442
|
return yield* encodeResponse(
|
|
412
443
|
protocolFailure("The subscription request could not be decoded"),
|
|
@@ -414,6 +445,7 @@ const handleRequest = Effect.fn("SubscriptionPartition.handleRequest")(function*
|
|
|
414
445
|
}
|
|
415
446
|
const request = decoded.success;
|
|
416
447
|
const { partition } = yield* SubscriptionPartitionIdentity;
|
|
448
|
+
|
|
417
449
|
if (!samePartition(partition, requestPartition(request))) {
|
|
418
450
|
return yield* encodeResponse(
|
|
419
451
|
protocolFailure("The request partition does not match the addressed object"),
|
|
@@ -421,6 +453,7 @@ const handleRequest = Effect.fn("SubscriptionPartition.handleRequest")(function*
|
|
|
421
453
|
}
|
|
422
454
|
const subscriptions = yield* Subscriptions;
|
|
423
455
|
const intake = yield* SubscriptionIntake;
|
|
456
|
+
|
|
424
457
|
const response = yield* Effect.gen(function* (): Effect.fn.Return<
|
|
425
458
|
SubscriptionPartitionResponse,
|
|
426
459
|
SubscriptionPartitionFailure
|
|
@@ -473,6 +506,7 @@ const handleRequest = Effect.fn("SubscriptionPartition.handleRequest")(function*
|
|
|
473
506
|
: Effect.succeed(protocolFailure("The subscription operation failed outside its contract")),
|
|
474
507
|
),
|
|
475
508
|
);
|
|
509
|
+
|
|
476
510
|
return yield* encodeResponse(response).pipe(Effect.orDie);
|
|
477
511
|
});
|
|
478
512
|
|
|
@@ -486,10 +520,12 @@ const transactionLayer: Layer.Layer<
|
|
|
486
520
|
DoSubscriptionTransaction,
|
|
487
521
|
Effect.gen(function* () {
|
|
488
522
|
const alarms = yield* DurableObjectAlarm.DurableObjectAlarm;
|
|
523
|
+
|
|
489
524
|
return DoSubscriptionTransaction.of({
|
|
490
525
|
run: (body) =>
|
|
491
526
|
Effect.gen(function* () {
|
|
492
527
|
const nowMillis = yield* Clock.currentTimeMillis;
|
|
528
|
+
|
|
493
529
|
return yield* alarms
|
|
494
530
|
.transaction((transaction) =>
|
|
495
531
|
body((replacement) =>
|
|
@@ -542,7 +578,9 @@ const alarmHandler = (limits: SubscriptionLimits) =>
|
|
|
542
578
|
);
|
|
543
579
|
const driver = yield* SubscriptionDriver;
|
|
544
580
|
const alarmControl = yield* DoSubscriptionAlarmControl;
|
|
581
|
+
|
|
545
582
|
yield* alarmControl.prearm((yield* Clock.currentTimeMillis) + limits.retryMillis);
|
|
583
|
+
|
|
546
584
|
const pass = yield* driver.runDue.pipe(
|
|
547
585
|
Effect.catchCause((cause) =>
|
|
548
586
|
Cause.hasInterrupts(cause)
|
|
@@ -553,6 +591,7 @@ const alarmHandler = (limits: SubscriptionLimits) =>
|
|
|
553
591
|
),
|
|
554
592
|
),
|
|
555
593
|
);
|
|
594
|
+
|
|
556
595
|
if (pass.failed > 0) {
|
|
557
596
|
yield* alarmControl.prearm((yield* Clock.currentTimeMillis) + limits.retryMillis);
|
|
558
597
|
} else {
|
|
@@ -596,20 +635,24 @@ export const makeSubscriptionPartitionObjectClass = <E>(
|
|
|
596
635
|
limits: SubscriptionLimits = defaultSubscriptionLimits,
|
|
597
636
|
): SubscriptionPartitionObjectClass => {
|
|
598
637
|
const cloudflareLimitsLayer = Layer.effectDiscard(validateCloudflareSubscriptionLimits(limits));
|
|
638
|
+
|
|
599
639
|
const identityLayer = Layer.effect(
|
|
600
640
|
SubscriptionPartitionIdentity,
|
|
601
641
|
Effect.gen(function* () {
|
|
602
642
|
const state = yield* EffectCfDurableObjectState.DurableObjectState;
|
|
643
|
+
|
|
603
644
|
return SubscriptionPartitionIdentity.of({
|
|
604
645
|
partition: yield* decodePartitionName(state.raw.id.name),
|
|
605
646
|
});
|
|
606
647
|
}),
|
|
607
648
|
);
|
|
649
|
+
|
|
608
650
|
const sqlLayer = Layer.unwrap(
|
|
609
651
|
Effect.map(EffectCfDurableObjectState.DurableObjectState, (state) =>
|
|
610
652
|
SqliteClient.layer({ storage: state.raw.storage }),
|
|
611
653
|
),
|
|
612
654
|
);
|
|
655
|
+
|
|
613
656
|
const partitionStore = Layer.unwrap(
|
|
614
657
|
Effect.map(SubscriptionPartitionIdentity, ({ partition }) =>
|
|
615
658
|
doSubscriptionStoreLayer(partition).pipe(
|
|
@@ -618,6 +661,7 @@ export const makeSubscriptionPartitionObjectClass = <E>(
|
|
|
618
661
|
),
|
|
619
662
|
),
|
|
620
663
|
);
|
|
664
|
+
|
|
621
665
|
const application = Layer.mergeAll(
|
|
622
666
|
Subscriptions.layer(limits),
|
|
623
667
|
SubscriptionIntake.layer(limits),
|
|
@@ -633,6 +677,7 @@ export const makeSubscriptionPartitionObjectClass = <E>(
|
|
|
633
677
|
Layer.provide(host),
|
|
634
678
|
Layer.provideMerge(identityLayer),
|
|
635
679
|
);
|
|
680
|
+
|
|
636
681
|
const runtime: Layer.Layer<
|
|
637
682
|
SubscriptionRuntimeServices,
|
|
638
683
|
E | SubscriptionError | SubscriptionPartitionProtocolError | CloudflareSubscriptionConfigError,
|
|
@@ -641,21 +686,26 @@ export const makeSubscriptionPartitionObjectClass = <E>(
|
|
|
641
686
|
Effect.gen(function* () {
|
|
642
687
|
const state = yield* EffectCfDurableObjectState.DurableObjectState;
|
|
643
688
|
const scope = yield* Effect.scope;
|
|
689
|
+
|
|
644
690
|
return yield* state.blockConcurrencyWhile(Layer.buildWithScope(application, scope));
|
|
645
691
|
}),
|
|
646
692
|
);
|
|
693
|
+
|
|
647
694
|
const rpc = {
|
|
648
695
|
subscription: (encoded: unknown) => handleRequest(encoded),
|
|
649
696
|
} satisfies EffectCfDurableObject.DurableObjectRpc<SubscriptionRuntimeServices>;
|
|
697
|
+
|
|
650
698
|
const Base = EffectCfDurableObject.make(runtime, {
|
|
651
699
|
initialize: Effect.void,
|
|
652
700
|
rpc,
|
|
653
701
|
alarms: alarmHandler(limits),
|
|
654
702
|
});
|
|
703
|
+
|
|
655
704
|
class SubscriptionPartitionObject extends Base {
|
|
656
705
|
override alarm(alarmInfo?: AlarmInvocationInfo): Promise<void> | void {
|
|
657
706
|
return super.alarm?.(alarmInfo);
|
|
658
707
|
}
|
|
659
708
|
}
|
|
709
|
+
|
|
660
710
|
return SubscriptionPartitionObject;
|
|
661
711
|
};
|