@effect-agent/platform-cloudflare 0.1.0-beta.42 → 0.1.0-beta.44
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 +69 -56
- 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.map +1 -1
- 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.map +1 -1
- package/dist/subscriptions.mjs.map +1 -1
- package/package.json +1 -81
- package/src/alarm.ts +41 -0
- 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 +10 -0
- 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/src/thread-object.ts
CHANGED
|
@@ -170,6 +170,7 @@ const isMutatingPortRequest = (request: PortRequest): boolean => {
|
|
|
170
170
|
return false;
|
|
171
171
|
}
|
|
172
172
|
request satisfies never;
|
|
173
|
+
|
|
173
174
|
return false;
|
|
174
175
|
};
|
|
175
176
|
|
|
@@ -233,9 +234,11 @@ const gateAdmissionLimits = Effect.fn("ThreadObject.gateAdmissionLimits")(functi
|
|
|
233
234
|
idempotencyKey: request.idempotencyKey,
|
|
234
235
|
}),
|
|
235
236
|
);
|
|
237
|
+
|
|
236
238
|
if (Option.isSome(existing)) return;
|
|
237
239
|
|
|
238
240
|
const inputBytes = utf8Bytes(request.inputPayload);
|
|
241
|
+
|
|
239
242
|
if (inputBytes > config.limits.maxInputBytes) {
|
|
240
243
|
return yield* AdmissionLimitExceeded.make({
|
|
241
244
|
limit: "input-bytes",
|
|
@@ -246,6 +249,7 @@ const gateAdmissionLimits = Effect.fn("ThreadObject.gateAdmissionLimits")(functi
|
|
|
246
249
|
|
|
247
250
|
// One Thread per Object (durability §5): the local scan IS this lane's queue.
|
|
248
251
|
const nonterminal = yield* Stream.runCollect(ledger.scanNonterminal);
|
|
252
|
+
|
|
249
253
|
if (nonterminal.length >= config.limits.maxQueueDepthPerLane) {
|
|
250
254
|
return yield* AdmissionLimitExceeded.make({
|
|
251
255
|
limit: "queue-depth",
|
|
@@ -255,6 +259,7 @@ const gateAdmissionLimits = Effect.fn("ThreadObject.gateAdmissionLimits")(functi
|
|
|
255
259
|
}
|
|
256
260
|
|
|
257
261
|
const databaseBytes = yield* Effect.sync(() => ctx.storage.sql.databaseSize);
|
|
262
|
+
|
|
258
263
|
if (databaseBytes > config.limits.maxDatabaseBytes) {
|
|
259
264
|
return yield* AdmissionLimitExceeded.make({
|
|
260
265
|
limit: "database-bytes",
|
|
@@ -285,7 +290,9 @@ const submitEndpoint = (encoded: unknown): Effect.Effect<unknown, never, Endpoin
|
|
|
285
290
|
const identity = yield* ThreadObjectIdentity;
|
|
286
291
|
const maintenance = yield* ThreadMaintenance;
|
|
287
292
|
const runtime = yield* DurableAgentRuntime;
|
|
293
|
+
|
|
288
294
|
yield* gateAdmissionLimits(request);
|
|
295
|
+
|
|
289
296
|
// Alarm invariant: the generation + alarm commit BEFORE the admission, and maintenance
|
|
290
297
|
// cannot acknowledge that generation until this mutation leaves its public RPC seam.
|
|
291
298
|
const receipt = yield* maintenance.withMutation(
|
|
@@ -296,6 +303,7 @@ const submitEndpoint = (encoded: unknown): Effect.Effect<unknown, never, Endpoin
|
|
|
296
303
|
definitions: request.definitions,
|
|
297
304
|
}),
|
|
298
305
|
);
|
|
306
|
+
|
|
299
307
|
return SubmitSucceeded.make({ receipt });
|
|
300
308
|
}),
|
|
301
309
|
),
|
|
@@ -312,6 +320,7 @@ const awaitSettlementEndpoint = (
|
|
|
312
320
|
Effect.gen(function* () {
|
|
313
321
|
const runtime = yield* DurableAgentRuntime;
|
|
314
322
|
const settlement = yield* runtime.awaitSettlement(receipt);
|
|
323
|
+
|
|
315
324
|
return SettlementReached.make({ settlement });
|
|
316
325
|
}),
|
|
317
326
|
),
|
|
@@ -327,15 +336,18 @@ const awaitProgressEndpoint = (encoded: unknown): Effect.Effect<unknown, never,
|
|
|
327
336
|
const identity = yield* ThreadObjectIdentity;
|
|
328
337
|
const runtime = yield* DurableAgentRuntime;
|
|
329
338
|
const registry = yield* ProgressWaitRegistry;
|
|
339
|
+
|
|
330
340
|
yield* Effect.scoped(
|
|
331
341
|
Effect.gen(function* () {
|
|
332
342
|
const cancelled = yield* registry.subscribe(request.waiterId);
|
|
343
|
+
|
|
333
344
|
yield* Effect.raceFirst(
|
|
334
345
|
runtime.awaitProgress(identity.threadId, request.afterSequence),
|
|
335
346
|
cancelled,
|
|
336
347
|
);
|
|
337
348
|
}),
|
|
338
349
|
);
|
|
350
|
+
|
|
339
351
|
return ProgressObserved.make();
|
|
340
352
|
}),
|
|
341
353
|
),
|
|
@@ -351,7 +363,9 @@ const cancelProgressEndpoint = (
|
|
|
351
363
|
Effect.flatMap((request) =>
|
|
352
364
|
Effect.gen(function* () {
|
|
353
365
|
const registry = yield* ProgressWaitRegistry;
|
|
366
|
+
|
|
354
367
|
yield* registry.cancel(request.waiterId);
|
|
368
|
+
|
|
355
369
|
return ProgressCancelled.make();
|
|
356
370
|
}),
|
|
357
371
|
),
|
|
@@ -369,12 +383,14 @@ const observePageEndpoint = (encoded: unknown): Effect.Effect<unknown, never, En
|
|
|
369
383
|
// The same fail-closed authorization seam the runtime's `observe` consults (P7 WP1);
|
|
370
384
|
// the default reference preserves the possession behavior.
|
|
371
385
|
const authorizer = yield* OperationAuthorizer;
|
|
386
|
+
|
|
372
387
|
yield* authorizer.authorize(
|
|
373
388
|
OperationAuthorizationRequest.make({
|
|
374
389
|
operation: "observe",
|
|
375
390
|
threadId: identity.threadId,
|
|
376
391
|
}),
|
|
377
392
|
);
|
|
393
|
+
|
|
378
394
|
const records = yield* Stream.runCollect(
|
|
379
395
|
store.read(
|
|
380
396
|
ThreadRead.make({
|
|
@@ -386,6 +402,7 @@ const observePageEndpoint = (encoded: unknown): Effect.Effect<unknown, never, En
|
|
|
386
402
|
}),
|
|
387
403
|
),
|
|
388
404
|
);
|
|
405
|
+
|
|
389
406
|
return ObservedPage.make({ records: [...records] });
|
|
390
407
|
}),
|
|
391
408
|
),
|
|
@@ -401,6 +418,7 @@ const abortEndpoint = (encoded: unknown): Effect.Effect<unknown, never, Endpoint
|
|
|
401
418
|
const maintenance = yield* ThreadMaintenance;
|
|
402
419
|
const runtime = yield* DurableAgentRuntime;
|
|
403
420
|
const intent = yield* maintenance.withMutation(runtime.abort(command));
|
|
421
|
+
|
|
404
422
|
return AbortRecorded.make({ intent });
|
|
405
423
|
}),
|
|
406
424
|
),
|
|
@@ -418,6 +436,7 @@ const resolveApprovalEndpoint = (
|
|
|
418
436
|
const maintenance = yield* ThreadMaintenance;
|
|
419
437
|
const runtime = yield* DurableAgentRuntime;
|
|
420
438
|
const intent = yield* maintenance.withMutation(runtime.resolveApproval(command));
|
|
439
|
+
|
|
421
440
|
return ApprovalRecorded.make({ intent });
|
|
422
441
|
}),
|
|
423
442
|
),
|
|
@@ -435,6 +454,7 @@ const resolveUnknownEndpoint = (
|
|
|
435
454
|
const maintenance = yield* ThreadMaintenance;
|
|
436
455
|
const runtime = yield* DurableAgentRuntime;
|
|
437
456
|
const intent = yield* maintenance.withMutation(runtime.resolveUnknown(command));
|
|
457
|
+
|
|
438
458
|
return UnknownResolutionRecorded.make({ intent });
|
|
439
459
|
}),
|
|
440
460
|
),
|
|
@@ -479,6 +499,7 @@ export const AdminFailure = Schema.Union([
|
|
|
479
499
|
DurableAlarmError,
|
|
480
500
|
HostProtocolError,
|
|
481
501
|
]);
|
|
502
|
+
|
|
482
503
|
export type AdminFailure = typeof AdminFailure.Type;
|
|
483
504
|
|
|
484
505
|
export class ExplainedRecovery extends Schema.TaggedClass<ExplainedRecovery>(
|
|
@@ -520,6 +541,7 @@ export const AdminResponse = Schema.Union([
|
|
|
520
541
|
ObligationsScanned,
|
|
521
542
|
AdminFailed,
|
|
522
543
|
]);
|
|
544
|
+
|
|
523
545
|
export type AdminResponse = typeof AdminResponse.Type;
|
|
524
546
|
|
|
525
547
|
export const decodeAdminExplainRequest = Schema.decodeUnknownEffect(AdminExplainRequest);
|
|
@@ -559,10 +581,12 @@ const explainEndpoint = (encoded: unknown): Effect.Effect<unknown, never, Endpoi
|
|
|
559
581
|
Effect.gen(function* () {
|
|
560
582
|
const identity = yield* ThreadObjectIdentity;
|
|
561
583
|
const runtime = yield* DurableAgentRuntime;
|
|
584
|
+
|
|
562
585
|
const explanations =
|
|
563
586
|
request.submissionId === undefined
|
|
564
587
|
? yield* runtime.explainThread(identity.threadId)
|
|
565
588
|
: [yield* runtime.explain(request.submissionId)];
|
|
589
|
+
|
|
566
590
|
return ExplainedRecovery.make({ explanations });
|
|
567
591
|
}),
|
|
568
592
|
),
|
|
@@ -578,6 +602,7 @@ const verifyEndpoint = (encoded: unknown): Effect.Effect<unknown, never, Endpoin
|
|
|
578
602
|
const identity = yield* ThreadObjectIdentity;
|
|
579
603
|
const runtime = yield* DurableAgentRuntime;
|
|
580
604
|
const report = yield* runtime.verify(identity.threadId);
|
|
605
|
+
|
|
581
606
|
return VerifiedIntegrity.make({ report });
|
|
582
607
|
}),
|
|
583
608
|
),
|
|
@@ -594,6 +619,7 @@ const retryEndpoint = (encoded: unknown): Effect.Effect<unknown, never, Endpoint
|
|
|
594
619
|
const runtime = yield* DurableAgentRuntime;
|
|
595
620
|
// Retry may repair durable state, so its generation + alarm commit before the mutation.
|
|
596
621
|
const report = yield* maintenance.withMutation(runtime.retry(command));
|
|
622
|
+
|
|
597
623
|
return RetryExecuted.make({ report });
|
|
598
624
|
}),
|
|
599
625
|
),
|
|
@@ -608,6 +634,7 @@ const obligationsEndpoint = (encoded: unknown): Effect.Effect<unknown, never, En
|
|
|
608
634
|
Effect.gen(function* () {
|
|
609
635
|
const runtime = yield* DurableAgentRuntime;
|
|
610
636
|
const report = yield* runtime.scanObligations(thresholds);
|
|
637
|
+
|
|
611
638
|
return ObligationsScanned.make({ report });
|
|
612
639
|
}),
|
|
613
640
|
),
|
|
@@ -627,21 +654,25 @@ const portCallEndpoint = (encoded: unknown): Effect.Effect<unknown, never, Endpo
|
|
|
627
654
|
const ports = yield* ThreadObjectPorts;
|
|
628
655
|
const maintenance = yield* ThreadMaintenance;
|
|
629
656
|
const alarm = yield* DurableAlarmService;
|
|
657
|
+
|
|
630
658
|
const decoded = yield* decodePortRequest(encoded).pipe(
|
|
631
659
|
Effect.map((request) => ({ _tag: "success" as const, request })),
|
|
632
660
|
Effect.catch((error) => Effect.succeed({ _tag: "failure" as const, message: error.message })),
|
|
633
661
|
);
|
|
662
|
+
|
|
634
663
|
if (decoded._tag === "failure") {
|
|
635
664
|
return encodedPortProtocolFailure(
|
|
636
665
|
`The port request could not be decoded: ${decoded.message}`,
|
|
637
666
|
);
|
|
638
667
|
}
|
|
639
668
|
const mutating = isMutatingPortRequest(decoded.request);
|
|
669
|
+
|
|
640
670
|
const handled = yield* (
|
|
641
671
|
mutating
|
|
642
672
|
? maintenance.withMutation(ports.handle(decoded.request))
|
|
643
673
|
: ports.handle(decoded.request)
|
|
644
674
|
).pipe(Effect.exit);
|
|
675
|
+
|
|
645
676
|
if (handled._tag === "Failure") {
|
|
646
677
|
// Without the committed generation/alarm the invariant cannot be promised; refuse before
|
|
647
678
|
// the port mutation runs. `ports.handle` itself is total, so this is the maintenance error.
|
|
@@ -649,6 +680,7 @@ const portCallEndpoint = (encoded: unknown): Effect.Effect<unknown, never, Endpo
|
|
|
649
680
|
"The owner Object could not arm its maintenance alarm before the mutation.",
|
|
650
681
|
);
|
|
651
682
|
}
|
|
683
|
+
|
|
652
684
|
const response = yield* encodePortResponse(handled.value).pipe(
|
|
653
685
|
Effect.catch((error) =>
|
|
654
686
|
Effect.succeed(
|
|
@@ -656,6 +688,7 @@ const portCallEndpoint = (encoded: unknown): Effect.Effect<unknown, never, Endpo
|
|
|
656
688
|
),
|
|
657
689
|
),
|
|
658
690
|
);
|
|
691
|
+
|
|
659
692
|
if (mutating) {
|
|
660
693
|
// Prompt processing hint; the pre-armed alarm already guarantees convergence.
|
|
661
694
|
yield* alarm.scheduleNow.pipe(
|
|
@@ -664,12 +697,14 @@ const portCallEndpoint = (encoded: unknown): Effect.Effect<unknown, never, Endpo
|
|
|
664
697
|
),
|
|
665
698
|
);
|
|
666
699
|
}
|
|
700
|
+
|
|
667
701
|
return response;
|
|
668
702
|
});
|
|
669
703
|
|
|
670
704
|
const wakeEndpoint: Effect.Effect<void, never, EndpointServices> = Effect.gen(function* () {
|
|
671
705
|
const identity = yield* ThreadObjectIdentity;
|
|
672
706
|
const wake = yield* WakeScheduler;
|
|
707
|
+
|
|
673
708
|
// Route the remote hint through this incarnation's scheduler so scoped progress waiters and
|
|
674
709
|
// the alarm receive the same hint. Delivery remains droppable; canonical storage is authority.
|
|
675
710
|
yield* wake.notify(identity.threadId);
|
|
@@ -678,6 +713,7 @@ const wakeEndpoint: Effect.Effect<void, never, EndpointServices> = Effect.gen(fu
|
|
|
678
713
|
const alarmEndpoint: Effect.Effect<void, MaintenancePassFailure, EndpointServices> = Effect.gen(
|
|
679
714
|
function* () {
|
|
680
715
|
const maintenance = yield* ThreadMaintenance;
|
|
716
|
+
|
|
681
717
|
// Typed pass failures propagate: the rejected promise makes workerd retry the alarm
|
|
682
718
|
// (at-least-once delivery), and the dirty generation retains a committed slot meanwhile.
|
|
683
719
|
yield* maintenance.pass;
|
|
@@ -690,6 +726,7 @@ const gateEndpoint: Effect.Effect<void, MaintenancePassFailure, EndpointServices
|
|
|
690
726
|
// check + configuration decode (DEPLOY-008 fails typed here, before any mutation), then
|
|
691
727
|
// the defensive local ensure-alarm half of the invariant. LOCAL-ONLY by construction.
|
|
692
728
|
const maintenance = yield* ThreadMaintenance;
|
|
729
|
+
|
|
693
730
|
yield* maintenance.ensureAlarm;
|
|
694
731
|
},
|
|
695
732
|
);
|
|
@@ -711,19 +748,23 @@ const effectCfPlatformLayer = (
|
|
|
711
748
|
Effect.gen(function* () {
|
|
712
749
|
const state = yield* EffectCfDurableObjectState.DurableObjectState;
|
|
713
750
|
const env = yield* WorkerEnvironment;
|
|
751
|
+
|
|
714
752
|
return DurableObjectContext.of({ ctx: state.raw, env });
|
|
715
753
|
}),
|
|
716
754
|
);
|
|
755
|
+
|
|
717
756
|
const namespace = Layer.effect(ThreadObjectNamespace)(
|
|
718
757
|
Effect.gen(function* () {
|
|
719
758
|
const env = yield* WorkerEnvironment;
|
|
720
759
|
const binding = yield* threadNamespaceFromEnv(env, namespaceBinding);
|
|
760
|
+
|
|
721
761
|
return ThreadObjectNamespace.of({
|
|
722
762
|
namespace: binding,
|
|
723
763
|
...(rpcTracing === true ? { rpcTracing: namespaceBinding } : {}),
|
|
724
764
|
});
|
|
725
765
|
}),
|
|
726
766
|
);
|
|
767
|
+
|
|
727
768
|
return Layer.merge(context, namespace);
|
|
728
769
|
};
|
|
729
770
|
|
|
@@ -795,10 +836,13 @@ export const make = <
|
|
|
795
836
|
Effect.gen(function* () {
|
|
796
837
|
const state = yield* EffectCfDurableObjectState.DurableObjectState;
|
|
797
838
|
const scope = yield* Effect.scope;
|
|
839
|
+
|
|
798
840
|
return yield* state.blockConcurrencyWhile(
|
|
799
841
|
Effect.gen(function* () {
|
|
800
842
|
const services = yield* Layer.buildWithScope(application, scope);
|
|
843
|
+
|
|
801
844
|
yield* gateEndpoint.pipe(Effect.provide(services));
|
|
845
|
+
|
|
802
846
|
return services;
|
|
803
847
|
}),
|
|
804
848
|
);
|
|
@@ -824,6 +868,13 @@ export const make = <
|
|
|
824
868
|
RuntimeServices | ApplicationServices | EventServices
|
|
825
869
|
>;
|
|
826
870
|
|
|
871
|
+
type NativeOptions = EffectCfDurableObject.DurableObjectOptions<
|
|
872
|
+
RuntimeServices | ApplicationServices,
|
|
873
|
+
EventServices,
|
|
874
|
+
EventLayerError,
|
|
875
|
+
typeof rpc
|
|
876
|
+
>;
|
|
877
|
+
|
|
827
878
|
const EffectCfThreadObject = EffectCfDurableObject.make<
|
|
828
879
|
RuntimeServices | ApplicationServices,
|
|
829
880
|
ThreadObjectInitializationError | ApplicationError,
|
|
@@ -838,7 +889,10 @@ export const make = <
|
|
|
838
889
|
initialize: Effect.void,
|
|
839
890
|
rpc,
|
|
840
891
|
alarm: () => alarmEndpoint,
|
|
841
|
-
|
|
892
|
+
// This host owns the raw alarm and supplies event services through options.eventLayer.
|
|
893
|
+
// Upstream's conditional alarm-registration check cannot reduce over generic application
|
|
894
|
+
// services. Options and the rpc satisfies check above retain their Effect requirements.
|
|
895
|
+
} as NativeOptions);
|
|
842
896
|
|
|
843
897
|
// effect-cf's class type keeps `alarm` optional even when the handler option is present. This
|
|
844
898
|
// concrete override reflects this factory's stronger contract while delegating execution to
|
package/src/transport.ts
CHANGED
|
@@ -23,6 +23,7 @@ export const threadPortTransportLayer: Layer.Layer<
|
|
|
23
23
|
> = Layer.effect(ThreadPortTransport)(
|
|
24
24
|
Effect.gen(function* () {
|
|
25
25
|
const { namespace } = yield* ThreadObjectNamespace;
|
|
26
|
+
|
|
26
27
|
return ThreadPortTransport.of({
|
|
27
28
|
call: (threadId, request) =>
|
|
28
29
|
Effect.tryPromise({
|
package/src/wake-scheduler.ts
CHANGED
|
@@ -44,6 +44,7 @@ export const cloudflareWakeSchedulerLayer: Layer.Layer<
|
|
|
44
44
|
const { namespace } = yield* ThreadObjectNamespace;
|
|
45
45
|
const hints = yield* PubSub.sliding<ThreadId>(WAKE_BUFFER_CAPACITY);
|
|
46
46
|
const progress = yield* makeWakeSubscriptionHub;
|
|
47
|
+
|
|
47
48
|
yield* Effect.addFinalizer(() => PubSub.shutdown(hints));
|
|
48
49
|
|
|
49
50
|
const notifyLocal = (threadId: ThreadId) =>
|