@effect-agent/platform-cloudflare 0.1.0-beta.41 → 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.
Files changed (44) hide show
  1. package/dist/browser-quick-action.mjs.map +1 -1
  2. package/dist/browser-rest-capture.mjs.map +1 -1
  3. package/dist/browser-rest-crawl.mjs.map +1 -1
  4. package/dist/browser-session-lifecycle-DqntvG-Y.d.mts +21 -0
  5. package/dist/browser-session-lifecycle-ZGgb3pnK.mjs +84 -0
  6. package/dist/browser-session-lifecycle-ZGgb3pnK.mjs.map +1 -0
  7. package/dist/index.d.mts +85 -65
  8. package/dist/index.mjs +7 -2
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/interactive-browser.d.mts +1 -18
  11. package/dist/interactive-browser.mjs +2 -81
  12. package/dist/interactive-browser.mjs.map +1 -1
  13. package/dist/prepared-admission-BKp_Upw2.mjs.map +1 -1
  14. package/dist/protected-browser.d.mts +62 -0
  15. package/dist/protected-browser.mjs +714 -0
  16. package/dist/protected-browser.mjs.map +1 -0
  17. package/dist/scheduling.mjs.map +1 -1
  18. package/dist/subscriptions.mjs.map +1 -1
  19. package/package.json +1 -81
  20. package/src/alarm.ts +41 -0
  21. package/src/bindings.ts +5 -0
  22. package/src/boundary.ts +4 -0
  23. package/src/browser-quick-action.ts +52 -0
  24. package/src/browser-rest-capture.ts +30 -0
  25. package/src/browser-rest-crawl.ts +43 -0
  26. package/src/browser-session-lifecycle.ts +18 -0
  27. package/src/client.ts +40 -0
  28. package/src/code-mode-executor.ts +50 -0
  29. package/src/index.ts +1 -1
  30. package/src/interactive-browser.ts +176 -0
  31. package/src/layers.ts +16 -1
  32. package/src/memory.ts +42 -3
  33. package/src/prepared-admission.ts +1 -0
  34. package/src/progress-wait.ts +14 -0
  35. package/src/protected-browser/binding.ts +185 -0
  36. package/src/protected-browser/inspect-frame.ts +82 -0
  37. package/src/protected-browser/native.ts +384 -0
  38. package/src/protected-browser/policy.ts +594 -0
  39. package/src/protected-browser.ts +2 -0
  40. package/src/scheduling.ts +34 -0
  41. package/src/subscriptions.ts +50 -0
  42. package/src/thread-object.ts +55 -1
  43. package/src/transport.ts +1 -0
  44. package/src/wake-scheduler.ts +1 -0
@@ -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({
@@ -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) =>