@yielded/agent-platform-cloudflare 0.1.0-beta.173 → 0.1.0-beta.174

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 (70) hide show
  1. package/dist/{Alarm-BMEAZo3p.mjs → Alarm-4J9B8Fg8.mjs} +54 -32
  2. package/dist/Alarm-4J9B8Fg8.mjs.map +1 -0
  3. package/dist/Alarm.mjs +1 -1
  4. package/dist/BrowserRestCapture.mjs.map +1 -1
  5. package/dist/BrowserRestCrawl.mjs.map +1 -1
  6. package/dist/{BrowserSession-Bx0V1-6_.d.mts → BrowserSession-Cojp7nth.d.mts} +3 -2
  7. package/dist/{BrowserSession-BfNmyayH.mjs → BrowserSession-aovMjfL4.mjs} +14 -14
  8. package/dist/BrowserSession-aovMjfL4.mjs.map +1 -0
  9. package/dist/BrowserSession.d.mts +1 -1
  10. package/dist/BrowserSession.mjs +2 -2
  11. package/dist/BrowserUse.d.mts +40 -64
  12. package/dist/BrowserUse.mjs +223 -2
  13. package/dist/BrowserUse.mjs.map +1 -0
  14. package/dist/CloudflareBrowser-Vt8qTdYW.mjs.map +1 -1
  15. package/dist/CloudflareCodeMode.mjs.map +1 -1
  16. package/dist/CloudflareScheduling.mjs +9 -9
  17. package/dist/CloudflareScheduling.mjs.map +1 -1
  18. package/dist/CloudflareSubscriptions.mjs +15 -15
  19. package/dist/CloudflareSubscriptions.mjs.map +1 -1
  20. package/dist/{CloudflareThreadClient-DgZVrZzF.mjs → CloudflareThreadClient-DU548EEj.mjs} +42 -39
  21. package/dist/CloudflareThreadClient-DU548EEj.mjs.map +1 -0
  22. package/dist/{CloudflareThreadClient-HO_3rkM7.d.mts → CloudflareThreadClient-lTm6baDP.d.mts} +362 -362
  23. package/dist/CloudflareThreadClient.d.mts +1 -1
  24. package/dist/CloudflareThreadClient.mjs +1 -1
  25. package/dist/{InteractiveBrowser-LdKzQeLR.mjs → InteractiveBrowser-BHNlwjZL.mjs} +40 -31
  26. package/dist/InteractiveBrowser-BHNlwjZL.mjs.map +1 -0
  27. package/dist/InteractiveBrowser.mjs +1 -1
  28. package/dist/{ThreadObject-CRbLbdXM.d.mts → ThreadObject-BLYgzcdT.d.mts} +15 -15
  29. package/dist/{ThreadObject-CGIaz6Jv.mjs → ThreadObject-C2LF3btz.mjs} +13 -14
  30. package/dist/ThreadObject-C2LF3btz.mjs.map +1 -0
  31. package/dist/ThreadObject.d.mts +1 -1
  32. package/dist/ThreadObject.mjs +1 -1
  33. package/dist/WakeScheduler.d.mts +1 -1
  34. package/dist/WakeScheduler.mjs +8 -3
  35. package/dist/WakeScheduler.mjs.map +1 -1
  36. package/dist/index.d.mts +3 -3
  37. package/dist/index.mjs +5 -5
  38. package/dist/{prepared-admission-CSdzFM_v.mjs → prepared-admission-BoUPHSNQ.mjs} +2 -2
  39. package/dist/{prepared-admission-CSdzFM_v.mjs.map → prepared-admission-BoUPHSNQ.mjs.map} +1 -1
  40. package/package.json +1 -1
  41. package/src/Alarm.ts +82 -39
  42. package/src/BrowserRestCapture.ts +1 -0
  43. package/src/BrowserRestCrawl.ts +1 -0
  44. package/src/BrowserSession.ts +3 -2
  45. package/src/BrowserUse.ts +287 -1504
  46. package/src/CloudflareCodeMode.ts +6 -0
  47. package/src/CloudflareScheduling.ts +103 -103
  48. package/src/CloudflareSubscriptions.ts +192 -199
  49. package/src/CloudflareThreadClient.ts +256 -268
  50. package/src/InteractiveBrowser.ts +43 -17
  51. package/src/ThreadObject.ts +35 -24
  52. package/src/WakeScheduler.ts +12 -9
  53. package/src/internal/browser-binding.ts +8 -0
  54. package/src/internal/browser-credentials.ts +18 -13
  55. package/src/internal/browser-file-selection.ts +13 -2
  56. package/src/internal/browser-quick-action.ts +1 -0
  57. package/src/internal/browser-session-lifecycle.ts +32 -36
  58. package/src/internal/due-queue.ts +38 -19
  59. package/src/internal/layers.ts +53 -53
  60. package/dist/Alarm-BMEAZo3p.mjs.map +0 -1
  61. package/dist/BrowserSession-BfNmyayH.mjs.map +0 -1
  62. package/dist/BrowserUse-Bc2JdLW2.mjs +0 -1528
  63. package/dist/BrowserUse-Bc2JdLW2.mjs.map +0 -1
  64. package/dist/CloudflareThreadClient-DgZVrZzF.mjs.map +0 -1
  65. package/dist/InteractiveBrowser-LdKzQeLR.mjs.map +0 -1
  66. package/dist/ThreadObject-CGIaz6Jv.mjs.map +0 -1
  67. package/dist/page-function-CmUCcyNP.mjs +0 -11
  68. package/dist/page-function-CmUCcyNP.mjs.map +0 -1
  69. package/src/internal/browser-dom.ts +0 -886
  70. package/src/internal/browser-jev-dom.ts +0 -362
@@ -49,7 +49,7 @@ export class BrowserRunSessionLifecycle extends Context.Service<
49
49
  !Schema.is(Account)(options.accountId) ||
50
50
  Redacted.value(options.apiToken).length === 0
51
51
  ) {
52
- return yield* new BrowserRunCleanupError({ reason: "configuration" });
52
+ return yield* BrowserRunCleanupError.make({ reason: "configuration" });
53
53
  }
54
54
  const client = yield* HttpClient.HttpClient;
55
55
 
@@ -65,39 +65,38 @@ export class BrowserRunSessionLifecycle extends Context.Service<
65
65
  .pipe(
66
66
  // workerd supports manual/follow, not error. Reject every redirect below.
67
67
  Effect.provideService(FetchHttpClient.RequestInit, { redirect: "manual" }),
68
- Effect.mapError(
69
- (cause) =>
70
- new BrowserRunCleanupError({
71
- reason: "provider",
72
- cause: browserFailure("browser.close.request", cause),
73
- }),
68
+ Effect.mapError((cause) =>
69
+ BrowserRunCleanupError.make({
70
+ reason: "provider",
71
+ cause: browserFailure("browser.close.request", cause),
72
+ }),
74
73
  ),
75
74
  );
76
75
 
77
76
  if (response.status === 401 || response.status === 403)
78
- return yield* new BrowserRunCleanupError({
77
+ return yield* BrowserRunCleanupError.make({
79
78
  reason: "authorization",
80
79
  status: response.status,
81
80
  });
82
81
  if (response.status === 429)
83
- return yield* new BrowserRunCleanupError({
82
+ return yield* BrowserRunCleanupError.make({
84
83
  reason: "rate-limited",
85
84
  status: response.status,
86
85
  });
87
86
  if (response.status !== 200 && response.status !== 404)
88
- return yield* new BrowserRunCleanupError({
87
+ return yield* BrowserRunCleanupError.make({
89
88
  reason: "provider",
90
89
  status: response.status,
91
90
  });
92
91
  if (response.headers["content-type"]?.split(";", 1)[0]?.trim() !== "application/json")
93
- return yield* new BrowserRunCleanupError({ reason: "malformed" });
92
+ return yield* BrowserRunCleanupError.make({ reason: "malformed" });
94
93
 
95
94
  const bytes = yield* Stream.runFoldEffect(
96
95
  response.stream,
97
96
  () => new Uint8Array(),
98
97
  (body, chunk) => {
99
98
  if (body.byteLength + chunk.byteLength > 16_384)
100
- return Effect.fail(new BrowserRunCleanupError({ reason: "malformed" }));
99
+ return Effect.fail(BrowserRunCleanupError.make({ reason: "malformed" }));
101
100
  const combined = new Uint8Array(body.byteLength + chunk.byteLength);
102
101
 
103
102
  combined.set(body);
@@ -106,19 +105,18 @@ export class BrowserRunSessionLifecycle extends Context.Service<
106
105
  return Effect.succeed(combined);
107
106
  },
108
107
  ).pipe(
109
- Effect.mapError(
110
- (cause) =>
111
- new BrowserRunCleanupError({
112
- reason: "malformed",
113
- cause: browserFailure("browser.close.response", cause),
114
- }),
108
+ Effect.mapError((cause) =>
109
+ BrowserRunCleanupError.make({
110
+ reason: "malformed",
111
+ cause: browserFailure("browser.close.response", cause),
112
+ }),
115
113
  ),
116
114
  );
117
115
 
118
116
  const body = yield* Effect.try({
119
117
  try: () => new TextDecoder("utf-8", { fatal: true, ignoreBOM: false }).decode(bytes),
120
118
  catch: (cause) =>
121
- new BrowserRunCleanupError({
119
+ BrowserRunCleanupError.make({
122
120
  reason: "malformed",
123
121
  cause: browserFailure("browser.close.decode", cause),
124
122
  }),
@@ -131,16 +129,15 @@ export class BrowserRunSessionLifecycle extends Context.Service<
131
129
 
132
130
  if (Option.isSome(absent)) return true;
133
131
 
134
- return yield* new BrowserRunCleanupError({ reason: "malformed" });
132
+ return yield* BrowserRunCleanupError.make({ reason: "malformed" });
135
133
  }
136
134
  if (method === "DELETE") {
137
135
  const result = yield* Schema.decodeEffect(Schema.fromJsonString(Closed))(body).pipe(
138
- Effect.mapError(
139
- (cause) =>
140
- new BrowserRunCleanupError({
141
- reason: "malformed",
142
- cause: browserFailure("browser.close.response", cause),
143
- }),
136
+ Effect.mapError((cause) =>
137
+ BrowserRunCleanupError.make({
138
+ reason: "malformed",
139
+ cause: browserFailure("browser.close.response", cause),
140
+ }),
144
141
  ),
145
142
  );
146
143
 
@@ -148,17 +145,16 @@ export class BrowserRunSessionLifecycle extends Context.Service<
148
145
  }
149
146
 
150
147
  const result = yield* Schema.decodeEffect(Schema.fromJsonString(Metadata))(body).pipe(
151
- Effect.mapError(
152
- (cause) =>
153
- new BrowserRunCleanupError({
154
- reason: "malformed",
155
- cause: browserFailure("browser.close.response", cause),
156
- }),
148
+ Effect.mapError((cause) =>
149
+ BrowserRunCleanupError.make({
150
+ reason: "malformed",
151
+ cause: browserFailure("browser.close.response", cause),
152
+ }),
157
153
  ),
158
154
  );
159
155
 
160
156
  if (result.sessionId !== sessionId)
161
- return yield* new BrowserRunCleanupError({ reason: "malformed" });
157
+ return yield* BrowserRunCleanupError.make({ reason: "malformed" });
162
158
 
163
159
  return result.endTime !== undefined && result.endTime > 0;
164
160
  });
@@ -166,7 +162,7 @@ export class BrowserRunSessionLifecycle extends Context.Service<
166
162
  const close = Effect.fnUntraced(
167
163
  function* (sessionId: Redacted.Redacted<string>) {
168
164
  const id = yield* Schema.decodeEffect(Identity)(Redacted.value(sessionId)).pipe(
169
- Effect.mapError(() => new BrowserRunCleanupError({ reason: "configuration" })),
165
+ Effect.mapError(() => BrowserRunCleanupError.make({ reason: "configuration" })),
170
166
  );
171
167
 
172
168
  if (yield* request("DELETE", id)) return;
@@ -174,11 +170,11 @@ export class BrowserRunSessionLifecycle extends Context.Service<
174
170
  if (yield* request("GET", id)) return;
175
171
  }
176
172
 
177
- return yield* new BrowserRunCleanupError({ reason: "pending" });
173
+ return yield* BrowserRunCleanupError.make({ reason: "pending" });
178
174
  },
179
175
  Effect.timeoutOrElse({
180
176
  duration: "10 seconds",
181
- orElse: () => Effect.fail(new BrowserRunCleanupError({ reason: "timeout" })),
177
+ orElse: () => Effect.fail(BrowserRunCleanupError.make({ reason: "timeout" })),
182
178
  }),
183
179
  Effect.withTracerEnabled(false),
184
180
  );
@@ -139,10 +139,9 @@ export const make = (storage: DurableObjectStorage) => {
139
139
 
140
140
  // Nine bindings per lane stay below Durable Object SQLite's 100-parameter limit.
141
141
  const write = (changes: ReadonlyArray<Change>) => {
142
- const rows = decode(
143
- sql
144
- .exec(
145
- `WITH changes (id, revision, dueAt, stalls, progressKey, notBefore, state, reported, expected_revision) AS (
142
+ const rows = sql
143
+ .exec(
144
+ `WITH changes (id, revision, dueAt, stalls, progressKey, notBefore, state, reported, expected_revision) AS (
146
145
  VALUES ${changes.map(() => "(?, ?, ?, ?, ?, ?, ?, ?, ?)").join(", ")}
147
146
  ) INSERT INTO platform_cloudflare_due_queue
148
147
  (id, revision, dueAt, stalls, progressKey, notBefore, state, reported)
@@ -152,24 +151,24 @@ export const make = (storage: DurableObjectStorage) => {
152
151
  notBefore = excluded.notBefore, state = excluded.state, reported = excluded.reported
153
152
  WHERE platform_cloudflare_due_queue.revision = (
154
153
  SELECT expected_revision FROM changes WHERE changes.id = excluded.id
155
- ) RETURNING id, revision, dueAt, stalls, progressKey, notBefore, state, reported`,
156
- ...changes.flatMap(({ before, after }) => [
157
- after.id,
158
- after.revision,
159
- after.dueAt,
160
- after.stalls,
161
- after.progressKey,
162
- after.notBefore,
163
- after.state,
164
- after.reported,
165
- before?.revision ?? -1,
166
- ]),
167
- )
168
- .toArray(),
169
- );
154
+ ) RETURNING 1`,
155
+ ...changes.flatMap(({ before, after }) => [
156
+ after.id,
157
+ after.revision,
158
+ after.dueAt,
159
+ after.stalls,
160
+ after.progressKey,
161
+ after.notBefore,
162
+ after.state,
163
+ after.reported,
164
+ before?.revision ?? -1,
165
+ ]),
166
+ )
167
+ .toArray();
170
168
 
171
169
  // Partial revision acceptance must reject the enclosing source transaction.
172
170
  if (rows.length !== changes.length)
171
+ // oxlint-disable-next-line effect/no-untyped-throw, effect/no-native-error -- Native storage transaction must roll back partial revision acceptance; its Effect adapter maps the cause.
173
172
  throw new Error("Maintenance due revision changed during transaction");
174
173
  };
175
174
 
@@ -204,6 +203,7 @@ export const make = (storage: DurableObjectStorage) => {
204
203
  return result;
205
204
  } catch (cause) {
206
205
  if (frame !== undefined) finish(frame, false);
206
+ // oxlint-disable-next-line effect/no-untyped-throw -- Native transaction Promise must reject with the original failure after invalidating speculative state.
207
207
  throw cause;
208
208
  }
209
209
  };
@@ -302,6 +302,24 @@ export const make = (storage: DurableObjectStorage) => {
302
302
  );
303
303
  };
304
304
 
305
+ /** Native checkpoints fence the generation, not each source commit. Once progress
306
+ * resets a claimed lane, further native commits owe the same recovery opportunity.
307
+ * A new claim, deadline, or retry budget makes the next commit advance it again. */
308
+ const progressNative = (dueAt: number) => {
309
+ const row = read().find((row) => row.id === Native);
310
+
311
+ if (
312
+ row?.state === "pending" &&
313
+ row.dueAt !== null &&
314
+ row.dueAt <= dueAt &&
315
+ row.stalls === 0 &&
316
+ row.notBefore === 0 &&
317
+ row.reported === 0
318
+ )
319
+ return;
320
+ dirty(Native, dueAt, true);
321
+ };
322
+
305
323
  /** A strictly increasing source cursor; old or repeated notices cannot renew a budget. */
306
324
  const progress = (id: string, dueAt: number, cursor: bigint) => {
307
325
  Schema.decodeSync(Schema.BigInt.check(Schema.isGreaterThanOrEqualToBigInt(0n)))(cursor);
@@ -416,6 +434,7 @@ export const make = (storage: DurableObjectStorage) => {
416
434
  transaction,
417
435
  read,
418
436
  dirty,
437
+ progressNative,
419
438
  progress,
420
439
  register,
421
440
  claim,
@@ -638,6 +638,7 @@ const sharedLayer = <A, E, R, PE = never, PR = never>(
638
638
  const owner = yield* SqlStorageOwner;
639
639
  const mutations = yield* ThreadMutationGate;
640
640
 
641
+ // oxlint-disable-next-line effect/no-native-error -- Missing host SQL ownership is an assembly defect, not a recoverable workflow failure.
641
642
  if (owner === undefined) return yield* Effect.die(new Error("SQL owner unavailable"));
642
643
 
643
644
  return {
@@ -889,61 +890,60 @@ const sharedLayer = <A, E, R, PE = never, PR = never>(
889
890
  return Context.make(ThreadStore, observedStore).pipe(
890
891
  Context.add(StorageOwner, storageOwner),
891
892
  Context.add(SettlementPublisher, {
892
- publish: (input) =>
893
- Effect.gen(function* () {
894
- const { request } = yield* validatePublication(input);
895
-
896
- return yield* mutations
897
- .withMutation(
898
- sourceCommits
899
- .withPermit(
900
- settlementPublisher.publish(request).pipe(
901
- Effect.tap((result) =>
902
- result.replayed
903
- ? Effect.void
904
- : index
905
- .applyCommitted(
906
- request.append,
907
- AppendResult.make({
908
- firstSequence: result.tailSequence,
909
- lastSequence: result.tailSequence,
910
-
911
- replayed: false,
912
- }),
913
- )
914
- .pipe(
915
- Effect.catchCause((cause) =>
916
- Cause.hasInterrupts(cause)
917
- ? Effect.interrupt
918
- : Effect.logError(
919
- "Thread projection deferred after settlement publication",
920
- cause,
921
- ),
922
- ),
893
+ publish: Effect.fnUntraced(function* (input) {
894
+ const { request } = yield* validatePublication(input);
895
+
896
+ return yield* mutations
897
+ .withMutation(
898
+ sourceCommits
899
+ .withPermit(
900
+ settlementPublisher.publish(request).pipe(
901
+ Effect.tap((result) =>
902
+ result.replayed
903
+ ? Effect.void
904
+ : index
905
+ .applyCommitted(
906
+ request.append,
907
+ AppendResult.make({
908
+ firstSequence: result.tailSequence,
909
+ lastSequence: result.tailSequence,
910
+
911
+ replayed: false,
912
+ }),
913
+ )
914
+ .pipe(
915
+ Effect.catchCause((cause) =>
916
+ Cause.hasInterrupts(cause)
917
+ ? Effect.interrupt
918
+ : Effect.logError(
919
+ "Thread projection deferred after settlement publication",
920
+ cause,
921
+ ),
923
922
  ),
924
- ),
923
+ ),
925
924
  ),
926
- )
927
- .pipe(Effect.tap(() => afterCommit)),
928
- {
929
- lanes: [
930
- ...(options.projection === undefined ? [] : [DueQueue.Projection]),
931
- ...(options.lifecyclePublication === undefined
932
- ? []
933
- : [DueQueue.Lifecycle]),
934
- ],
935
- },
936
- )
937
- .pipe(
938
- Effect.catchTag("DurableAlarmError", (cause) =>
939
- ThreadStoreError.make({
940
- operation: "prearm settlement publication",
941
- message: cause.message,
942
- cause,
943
- }),
944
- ),
945
- );
946
- }),
925
+ ),
926
+ )
927
+ .pipe(Effect.tap(() => afterCommit)),
928
+ {
929
+ lanes: [
930
+ ...(options.projection === undefined ? [] : [DueQueue.Projection]),
931
+ ...(options.lifecyclePublication === undefined
932
+ ? []
933
+ : [DueQueue.Lifecycle]),
934
+ ],
935
+ },
936
+ )
937
+ .pipe(
938
+ Effect.catchTag("DurableAlarmError", (cause) =>
939
+ ThreadStoreError.make({
940
+ operation: "prearm settlement publication",
941
+ message: cause.message,
942
+ cause,
943
+ }),
944
+ ),
945
+ );
946
+ }),
947
947
  }),
948
948
  Context.add(SubmissionLedger, {
949
949
  ...ledger,