@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.
Files changed (47) 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 +47 -34
  8. package/dist/index.mjs +3 -3
  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 → prepared-admission-BhW2eT_a.mjs} +3 -3
  14. package/dist/prepared-admission-BhW2eT_a.mjs.map +1 -0
  15. package/dist/protected-browser.d.mts +62 -0
  16. package/dist/protected-browser.mjs +714 -0
  17. package/dist/protected-browser.mjs.map +1 -0
  18. package/dist/scheduling.mjs +1 -1
  19. package/dist/scheduling.mjs.map +1 -1
  20. package/dist/subscriptions.mjs +1 -1
  21. package/dist/subscriptions.mjs.map +1 -1
  22. package/package.json +1 -81
  23. package/src/alarm.ts +277 -242
  24. package/src/bindings.ts +5 -0
  25. package/src/boundary.ts +4 -0
  26. package/src/browser-quick-action.ts +52 -0
  27. package/src/browser-rest-capture.ts +30 -0
  28. package/src/browser-rest-crawl.ts +43 -0
  29. package/src/browser-session-lifecycle.ts +18 -0
  30. package/src/client.ts +40 -0
  31. package/src/code-mode-executor.ts +50 -0
  32. package/src/interactive-browser.ts +176 -0
  33. package/src/layers.ts +13 -3
  34. package/src/memory.ts +42 -3
  35. package/src/prepared-admission.ts +1 -0
  36. package/src/progress-wait.ts +14 -0
  37. package/src/protected-browser/binding.ts +185 -0
  38. package/src/protected-browser/inspect-frame.ts +82 -0
  39. package/src/protected-browser/native.ts +384 -0
  40. package/src/protected-browser/policy.ts +594 -0
  41. package/src/protected-browser.ts +2 -0
  42. package/src/scheduling.ts +34 -0
  43. package/src/subscriptions.ts +50 -0
  44. package/src/thread-object.ts +55 -1
  45. package/src/transport.ts +1 -0
  46. package/src/wake-scheduler.ts +1 -0
  47. package/dist/prepared-admission-BKp_Upw2.mjs.map +0 -1
package/src/boundary.ts CHANGED
@@ -9,6 +9,7 @@ const boundForeignDiagnostic = (message: string): string =>
9
9
  export const safeCauseMessage = (cause: unknown, fallback: string): string => {
10
10
  try {
11
11
  const message = cause instanceof Error ? cause.message : cause;
12
+
12
13
  return boundForeignDiagnostic(typeof message === "string" ? message : String(message));
13
14
  } catch {
14
15
  return boundForeignDiagnostic(fallback);
@@ -38,9 +39,12 @@ export const cloudflareFailureSignals = (cause: unknown): CloudflareFailureSigna
38
39
  const retryableValue = Reflect.get(cause, "retryable");
39
40
  const overloadedValue = Reflect.get(cause, "overloaded");
40
41
  const resetValue = Reflect.get(cause, "durableObjectReset");
42
+
41
43
  const retryable =
42
44
  typeof retryableValue === "boolean" ? retryableValue : resetValue === true ? true : undefined;
45
+
43
46
  const overloaded = typeof overloadedValue === "boolean" ? overloadedValue : undefined;
47
+
44
48
  return {
45
49
  ...(retryable === undefined ? {} : { retryable }),
46
50
  ...(overloaded === undefined ? {} : { overloaded }),
@@ -97,6 +97,7 @@ export class BrowserQuickActionBrowserBinding extends Context.Service<
97
97
  options: BrowserQuickActionCaptureOptions,
98
98
  ): Layer.Layer<BrowserQuickActionBrowserBinding> {
99
99
  const browser = options.browser;
100
+
100
101
  const invoke = Effect.fn("BrowserQuickActionBrowserBinding.invoke")(function* (
101
102
  action: "screenshot" | "content" | "markdown" | "links" | "scrape" | "json",
102
103
  evaluate: () => Promise<Response>,
@@ -106,6 +107,7 @@ export class BrowserQuickActionBrowserBinding extends Context.Service<
106
107
  catch: (cause) => BrowserQuickActionRpcError.make({ action, cause }),
107
108
  });
108
109
  });
110
+
109
111
  return Layer.succeed(BrowserQuickActionBrowserBinding)({
110
112
  screenshot: (request) =>
111
113
  invoke("screenshot", () => browser.quickAction("screenshot", request)),
@@ -175,8 +177,10 @@ const decodeEnvelope = Schema.decodeUnknownOption(Schema.fromJsonString(QuickAct
175
177
  const quickActionCommonOptions = (request: PageCaptureRequest): BrowserRunCommonOptions => {
176
178
  const options: BrowserRunBaseOptions = {};
177
179
  const navigation = request.navigation;
180
+
178
181
  if (navigation !== undefined) {
179
182
  const goto: NonNullable<BrowserRunBaseOptions["gotoOptions"]> = {};
183
+
180
184
  if (navigation.waitUntil !== undefined) goto.waitUntil = navigation.waitUntil;
181
185
  if (navigation.timeoutMillis !== undefined) goto.timeout = navigation.timeoutMillis;
182
186
  if (Object.keys(goto).length > 0) options.gotoOptions = goto;
@@ -200,6 +204,7 @@ const quickActionCommonOptions = (request: PageCaptureRequest): BrowserRunCommon
200
204
  options.allowRequestPattern = [...request.resourcePolicy.allowRequestPatterns];
201
205
  }
202
206
  }
207
+
203
208
  return request.target._tag === "PageUrlTarget"
204
209
  ? { ...options, url: request.target.url }
205
210
  : { ...options, html: request.target.html };
@@ -211,6 +216,7 @@ const executeQuickAction = (
211
216
  request: PageCaptureRequest,
212
217
  ): Effect.Effect<Response, BrowserQuickActionRpcError> => {
213
218
  const options = quickActionCommonOptions(request);
219
+
214
220
  switch (request.action._tag) {
215
221
  case "CapturePageContent": {
216
222
  return browser.content(options);
@@ -284,6 +290,7 @@ const readBoundedResponse = Effect.fn("BrowserQuickActionCapture.readResponse")(
284
290
  request: PageCaptureRequest,
285
291
  ) {
286
292
  const body = response.body;
293
+
287
294
  if (body === null) return "";
288
295
 
289
296
  const reader = yield* Effect.acquireRelease(
@@ -293,6 +300,7 @@ const readBoundedResponse = Effect.fn("BrowserQuickActionCapture.readResponse")(
293
300
  }),
294
301
  releaseResponseReader,
295
302
  );
303
+
296
304
  const decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: false });
297
305
  let observedBytes = 0;
298
306
  let bodyText = "";
@@ -302,6 +310,7 @@ const readBoundedResponse = Effect.fn("BrowserQuickActionCapture.readResponse")(
302
310
  try: () => reader.read(),
303
311
  catch: (cause) => protocolError("Reading the Quick Action response failed", cause),
304
312
  });
313
+
305
314
  if (chunk.done) break;
306
315
 
307
316
  observedBytes += chunk.value.byteLength;
@@ -334,25 +343,32 @@ const readBoundedResponse = Effect.fn("BrowserQuickActionCapture.readResponse")(
334
343
  */
335
344
  const retryAfterMillis = (response: Response): number | undefined => {
336
345
  const header = response.headers.get("Retry-After");
346
+
337
347
  if (header === null) return undefined;
338
348
  const seconds = Number(header);
349
+
339
350
  if (!Number.isSafeInteger(seconds) || seconds < 0) return undefined;
340
351
  const millis = seconds * 1_000;
352
+
341
353
  return Number.isSafeInteger(millis) ? millis : undefined;
342
354
  };
343
355
 
344
356
  const browserMillis = (response: Response): number | undefined => {
345
357
  const header = response.headers.get("X-Browser-Ms-Used");
358
+
346
359
  if (header === null) return undefined;
347
360
  const millis = Number(header);
361
+
348
362
  return Number.isSafeInteger(millis) && millis >= 0 ? millis : undefined;
349
363
  };
350
364
 
351
365
  /** Only trusted response metadata chooses transport framing; page text never does. */
352
366
  const isJsonResponse = (response: Response): boolean => {
353
367
  const contentType = response.headers.get("Content-Type");
368
+
354
369
  if (contentType === null) return false;
355
370
  const mediaType = contentType.split(";", 1)[0]?.trim().toLowerCase();
371
+
356
372
  return mediaType === "application/json" || mediaType?.endsWith("+json") === true;
357
373
  };
358
374
 
@@ -368,6 +384,7 @@ const parseOutput = (
368
384
  );
369
385
  }
370
386
  const envelope = decodeEnvelope(bodyText);
387
+
371
388
  if (Option.isNone(envelope)) {
372
389
  return protocolError(
373
390
  "The JSON Quick Action response did not carry a valid response envelope",
@@ -386,6 +403,7 @@ const parseOutput = (
386
403
  if (typeof envelope.value.result !== "string") {
387
404
  return protocolError("The Quick Action envelope carried a non-text result");
388
405
  }
406
+
389
407
  return action._tag === "CapturePageContent"
390
408
  ? PageContentCaptured.make({ html: envelope.value.result })
391
409
  : PageMarkdownCaptured.make({ markdown: envelope.value.result });
@@ -395,9 +413,11 @@ const parseOutput = (
395
413
  _tag: "PageLinksCaptured",
396
414
  links: envelope.value.result,
397
415
  });
416
+
398
417
  if (Option.isNone(decoded)) {
399
418
  return protocolError("The links Quick Action did not return a bounded array of valid URLs");
400
419
  }
420
+
401
421
  return decoded.value;
402
422
  }
403
423
  case "CapturePageScrape": {
@@ -405,11 +425,13 @@ const parseOutput = (
405
425
  _tag: "PageScrapeCaptured",
406
426
  groups: envelope.value.result,
407
427
  });
428
+
408
429
  if (Option.isNone(decoded)) {
409
430
  return protocolError(
410
431
  "The scrape Quick Action did not return bounded grouped element records",
411
432
  );
412
433
  }
434
+
413
435
  return decoded.value;
414
436
  }
415
437
  case "CapturePageStructured": {
@@ -437,6 +459,7 @@ const makeCapture = (
437
459
  }
438
460
 
439
461
  const usesWorkersAi = request.action._tag === "CapturePageStructured";
462
+
440
463
  if (usesWorkersAi) {
441
464
  if (workersAi === undefined) {
442
465
  return yield* PageCaptureUnsupportedError.make({
@@ -467,11 +490,14 @@ const makeCapture = (
467
490
  protocolError("The browser binding rejected the Quick Action", error.cause),
468
491
  ),
469
492
  );
493
+
470
494
  const bodyText = yield* readBoundedResponse(response, request);
495
+
471
496
  if (response.status === 429) {
472
497
  const retryAfter = retryAfterMillis(response);
473
498
  const reason = isQuotaMessage(bodyText) ? "quota" : "rate";
474
499
  const cause = privateResponseCause(bodyText);
500
+
475
501
  return yield* PageCaptureRateLimitedError.make({
476
502
  implementation: browserQuickActionImplementation,
477
503
  reason,
@@ -486,12 +512,15 @@ const makeCapture = (
486
512
  if (!response.ok) {
487
513
  const message = `The Quick Action answered HTTP ${response.status}`;
488
514
  const cause = privateResponseCause(bodyText);
515
+
489
516
  if (response.status >= 500) {
490
517
  return yield* protocolError(message, cause);
491
518
  }
519
+
492
520
  return yield* navigationError(message, cause);
493
521
  }
494
522
  const output = parseOutput(request.action, bodyText, response);
523
+
495
524
  if (
496
525
  output._tag === "PageCaptureNavigationError" ||
497
526
  output._tag === "PageCaptureProtocolError"
@@ -499,6 +528,7 @@ const makeCapture = (
499
528
  return yield* output;
500
529
  }
501
530
  const millis = browserMillis(response);
531
+
502
532
  return PageCaptureResult.make({
503
533
  implementation: browserQuickActionImplementation,
504
534
  output,
@@ -543,6 +573,7 @@ export const browserQuickActionWorkersAiCaptureLayer = (): Layer.Layer<
543
573
  Effect.gen(function* () {
544
574
  const browser = yield* BrowserQuickActionBrowserBinding;
545
575
  const workersAi = yield* BrowserQuickActionWorkersAi;
576
+
546
577
  return PageCapture.of({ capture: makeCapture(browser, workersAi) });
547
578
  }),
548
579
  );
@@ -580,6 +611,7 @@ export const CloudflareBrowser = {
580
611
 
581
612
  const screenshotOptions = (request: PageScreenshotRequest): BrowserRunScreenshotOptions => {
582
613
  const options: BrowserRunBaseOptions = {};
614
+
583
615
  if (
584
616
  request.navigation?.waitUntil !== undefined ||
585
617
  request.navigation?.timeoutMillis !== undefined
@@ -610,6 +642,7 @@ const screenshotOptions = (request: PageScreenshotRequest): BrowserRunScreenshot
610
642
  if (request.resourcePolicy?.allowRequestPatterns !== undefined) {
611
643
  options.allowRequestPattern = [...request.resourcePolicy.allowRequestPatterns];
612
644
  }
645
+
613
646
  return {
614
647
  ...options,
615
648
  ...(request.target._tag === "PageUrlTarget"
@@ -643,8 +676,10 @@ const pngResponse = (response: Response): boolean =>
643
676
 
644
677
  const declaredLength = (response: Response): number | undefined => {
645
678
  const raw = response.headers.get("Content-Length");
679
+
646
680
  if (raw === null || !/^(0|[1-9][0-9]*)$/.test(raw)) return undefined;
647
681
  const length = Number(raw);
682
+
648
683
  return Number.isSafeInteger(length) ? length : undefined;
649
684
  };
650
685
 
@@ -653,22 +688,27 @@ const readScreenshot = Effect.fn("BrowserQuickActionScreenshot.read")(function*
653
688
  request: PageScreenshotRequest,
654
689
  ) {
655
690
  const body = response.body;
691
+
656
692
  if (body === null) {
657
693
  return yield* protocolError("The screenshot response had no body");
658
694
  }
659
695
  if (!pngResponse(response)) {
660
696
  yield* cancelBody(body);
697
+
661
698
  return yield* protocolError("The screenshot response was not image/png");
662
699
  }
663
700
  const length = declaredLength(response);
701
+
664
702
  if (length !== undefined && length > request.limits.maxOutputBytes) {
665
703
  yield* cancelBody(body);
704
+
666
705
  return yield* PageScreenshotOutputLimitError.make({
667
706
  implementation: browserQuickActionImplementation,
668
707
  limit: request.limits.maxOutputBytes,
669
708
  observed: length,
670
709
  });
671
710
  }
711
+
672
712
  const reader = yield* Effect.acquireRelease(
673
713
  Effect.try({
674
714
  try: () => body.getReader(),
@@ -676,13 +716,16 @@ const readScreenshot = Effect.fn("BrowserQuickActionScreenshot.read")(function*
676
716
  }),
677
717
  releaseScreenshotReader,
678
718
  );
719
+
679
720
  const chunks: Array<Uint8Array> = [];
680
721
  let observed = 0;
722
+
681
723
  while (true) {
682
724
  const next = yield* Effect.tryPromise({
683
725
  try: () => reader.read(),
684
726
  catch: (cause) => protocolError("Reading the screenshot response failed", cause),
685
727
  });
728
+
686
729
  if (next.done) break;
687
730
  observed += next.value.byteLength;
688
731
  if (observed > request.limits.maxOutputBytes) {
@@ -696,10 +739,12 @@ const readScreenshot = Effect.fn("BrowserQuickActionScreenshot.read")(function*
696
739
  }
697
740
  const bytes = new Uint8Array(observed);
698
741
  let offset = 0;
742
+
699
743
  for (const chunk of chunks) {
700
744
  bytes.set(chunk, offset);
701
745
  offset += chunk.byteLength;
702
746
  }
747
+
703
748
  return bytes;
704
749
  }, Effect.scoped);
705
750
 
@@ -714,6 +759,7 @@ const makeScreenshot = (browser: BrowserQuickActionClient): PageScreenshotCaptur
714
759
  message: "The browser binding's screenshot action exposes no engine selector",
715
760
  });
716
761
  }
762
+
717
763
  const response = yield* browser
718
764
  .screenshot(screenshotOptions(request))
719
765
  .pipe(
@@ -721,9 +767,12 @@ const makeScreenshot = (browser: BrowserQuickActionClient): PageScreenshotCaptur
721
767
  protocolError("The browser binding rejected the screenshot", error.cause),
722
768
  ),
723
769
  );
770
+
724
771
  if (response.status === 429) {
725
772
  const body = response.body;
773
+
726
774
  if (body !== null) yield* cancelBody(body);
775
+
727
776
  return yield* PageCaptureRateLimitedError.make({
728
777
  implementation: browserQuickActionImplementation,
729
778
  reason: "rate",
@@ -735,11 +784,14 @@ const makeScreenshot = (browser: BrowserQuickActionClient): PageScreenshotCaptur
735
784
  }
736
785
  if (!response.ok) {
737
786
  const body = response.body;
787
+
738
788
  if (body !== null) yield* cancelBody(body);
739
789
  const message = `The screenshot Quick Action answered HTTP ${response.status}`;
790
+
740
791
  return yield* response.status >= 500 ? protocolError(message) : navigationError(message);
741
792
  }
742
793
  const bytes = yield* readScreenshot(response, request);
794
+
743
795
  return PageScreenshotResult.make({
744
796
  implementation: browserQuickActionImplementation,
745
797
  mediaType: "image/png",
@@ -51,6 +51,7 @@ const RestSuccessEnvelope = Schema.Struct({
51
51
  errors: Schema.optionalKey(Schema.Array(Schema.Unknown)),
52
52
  meta: Schema.optionalKey(Schema.Unknown),
53
53
  });
54
+
54
55
  const RestErrorEnvelope = Schema.Struct({
55
56
  success: Schema.Literal(false),
56
57
  errors: Schema.Array(
@@ -62,6 +63,7 @@ const RestErrorEnvelope = Schema.Struct({
62
63
  result: Schema.optionalKey(Schema.Json),
63
64
  meta: Schema.optionalKey(Schema.Unknown),
64
65
  });
66
+
65
67
  const RestEnvelope = Schema.Union([RestSuccessEnvelope, RestErrorEnvelope]);
66
68
  const decodeEnvelope = Schema.decodeUnknownOption(Schema.fromJsonString(RestEnvelope));
67
69
 
@@ -86,6 +88,7 @@ const privateResponseCause = (
86
88
  if (bodyText.length === 0) return undefined;
87
89
  const token = Redacted.value(apiToken);
88
90
  const diagnostic = boundedDiagnostic(bodyText);
91
+
89
92
  return new Error(token.length === 0 ? diagnostic : diagnostic.replaceAll(token, "[REDACTED]"));
90
93
  };
91
94
 
@@ -94,8 +97,10 @@ const requestBody = (request: PageCaptureRequest): Record<string, unknown> => {
94
97
  request.target._tag === "PageUrlTarget"
95
98
  ? { url: request.target.url }
96
99
  : { html: request.target.html };
100
+
97
101
  if (request.navigation !== undefined) {
98
102
  const goto: Record<string, unknown> = {};
103
+
99
104
  if (request.navigation.waitUntil !== undefined) goto.waitUntil = request.navigation.waitUntil;
100
105
  if (request.navigation.timeoutMillis !== undefined)
101
106
  goto.timeout = request.navigation.timeoutMillis;
@@ -116,6 +121,7 @@ const requestBody = (request: PageCaptureRequest): Record<string, unknown> => {
116
121
  if (request.resourcePolicy?.allowRequestPatterns !== undefined) {
117
122
  body.allowRequestPattern = [...request.resourcePolicy.allowRequestPatterns];
118
123
  }
124
+
119
125
  return body;
120
126
  };
121
127
 
@@ -138,6 +144,7 @@ const actionName = (
138
144
 
139
145
  const actionBody = (request: PageCaptureRequest): Record<string, unknown> => {
140
146
  const body = requestBody(request);
147
+
141
148
  switch (request.action._tag) {
142
149
  case "CapturePageContent":
143
150
  case "CapturePageMarkdown":
@@ -167,8 +174,10 @@ const retryAfterMillis = (
167
174
  headers: Readonly<Record<string, string | undefined>>,
168
175
  ): number | undefined => {
169
176
  const seconds = Number(headers["retry-after"]);
177
+
170
178
  if (!Number.isSafeInteger(seconds) || seconds < 0) return undefined;
171
179
  const millis = seconds * 1_000;
180
+
172
181
  return Number.isSafeInteger(millis) ? millis : undefined;
173
182
  };
174
183
 
@@ -176,14 +185,17 @@ const browserMillis = (
176
185
  headers: Readonly<Record<string, string | undefined>>,
177
186
  ): number | undefined => {
178
187
  const millis = Number(headers["x-browser-ms-used"]);
188
+
179
189
  return Number.isSafeInteger(millis) && millis >= 0 ? millis : undefined;
180
190
  };
181
191
 
182
192
  /** Response framing is provider metadata, never content controlled by the rendered page. */
183
193
  const isJsonResponse = (headers: Readonly<Record<string, string | undefined>>): boolean => {
184
194
  const contentType = headers["content-type"];
195
+
185
196
  if (contentType === undefined) return false;
186
197
  const mediaType = contentType.split(";", 1)[0]?.trim().toLowerCase();
198
+
187
199
  return mediaType === "application/json" || mediaType?.endsWith("+json") === true;
188
200
  };
189
201
 
@@ -192,6 +204,7 @@ const readBoundedResponse = Effect.fn("BrowserRestCapture.readResponse")(functio
192
204
  request: PageCaptureRequest,
193
205
  ): Effect.fn.Return<string, PageCaptureError> {
194
206
  const decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: false });
207
+
195
208
  const chunks = yield* Stream.runFoldEffect<
196
209
  Uint8Array,
197
210
  HttpClientError.HttpClientError,
@@ -204,6 +217,7 @@ const readBoundedResponse = Effect.fn("BrowserRestCapture.readResponse")(functio
204
217
  () => ({ observed: 0, text: "" }),
205
218
  (state, chunk) => {
206
219
  const observed = state.observed + chunk.byteLength;
220
+
207
221
  if (observed > request.limits.maxOutputBytes) {
208
222
  return Effect.fail(
209
223
  PageCaptureOutputLimitError.make({
@@ -213,6 +227,7 @@ const readBoundedResponse = Effect.fn("BrowserRestCapture.readResponse")(functio
213
227
  }),
214
228
  );
215
229
  }
230
+
216
231
  return Effect.try({
217
232
  try: () => ({ observed, text: state.text + decoder.decode(chunk, { stream: true }) }),
218
233
  catch: (cause) => protocolError("Decoding the Browser Run response failed", cause),
@@ -225,6 +240,7 @@ const readBoundedResponse = Effect.fn("BrowserRestCapture.readResponse")(functio
225
240
  : protocolError("Reading the Browser Run response failed", error),
226
241
  ),
227
242
  );
243
+
228
244
  return yield* Effect.try({
229
245
  try: () => chunks.text + decoder.decode(),
230
246
  catch: (cause) => protocolError("Decoding the Browser Run response failed", cause),
@@ -237,6 +253,7 @@ const parseOutput = (
237
253
  apiToken: Redacted.Redacted<string>,
238
254
  ): PageCaptureOutput | PageCaptureNavigationError | PageCaptureProtocolError => {
239
255
  const envelope = decodeEnvelope(bodyText);
256
+
240
257
  if (Option.isNone(envelope)) {
241
258
  return protocolError(
242
259
  "The Browser Run response did not carry a valid response envelope",
@@ -255,6 +272,7 @@ const parseOutput = (
255
272
  if (typeof envelope.value.result !== "string") {
256
273
  return protocolError("The Browser Run response envelope carried a non-text result");
257
274
  }
275
+
258
276
  return action._tag === "CapturePageContent"
259
277
  ? PageContentCaptured.make({ html: envelope.value.result })
260
278
  : PageMarkdownCaptured.make({ markdown: envelope.value.result });
@@ -263,6 +281,7 @@ const parseOutput = (
263
281
  _tag: "PageLinksCaptured",
264
282
  links: envelope.value.result,
265
283
  });
284
+
266
285
  return Option.isSome(decoded)
267
286
  ? decoded.value
268
287
  : protocolError("Browser Run links did not return a bounded array of valid URLs");
@@ -272,6 +291,7 @@ const parseOutput = (
272
291
  _tag: "PageScrapeCaptured",
273
292
  groups: envelope.value.result,
274
293
  });
294
+
275
295
  return Option.isSome(decoded)
276
296
  ? decoded.value
277
297
  : protocolError("Browser Run scrape did not return bounded grouped element records");
@@ -292,6 +312,7 @@ const makeCapture = (
292
312
  request: PageCaptureRequest,
293
313
  ): Effect.fn.Return<PageCaptureResult, PageCaptureError> {
294
314
  const usesWorkersAi = request.action._tag === "CapturePageStructured";
315
+
295
316
  if (usesWorkersAi) {
296
317
  if (workersAi === undefined) {
297
318
  return yield* PageCaptureUnsupportedError.make({
@@ -318,6 +339,7 @@ const makeCapture = (
318
339
  }
319
340
  const action = actionName(request.action);
320
341
  const path = `${API_ORIGIN}/client/v4/accounts/${encodeURIComponent(options.accountId)}/browser-rendering/${action}`;
342
+
321
343
  const requestWithBody = yield* HttpClientRequest.post(path).pipe(
322
344
  request.engine === "kitesurf"
323
345
  ? HttpClientRequest.setUrlParam("browser", "kitesurf")
@@ -327,14 +349,18 @@ const makeCapture = (
327
349
  HttpClientRequest.bodyJson(actionBody(request)),
328
350
  Effect.mapError((cause) => protocolError("Encoding the Browser Run request failed", cause)),
329
351
  );
352
+
330
353
  const response = yield* client
331
354
  .execute(requestWithBody)
332
355
  .pipe(
333
356
  Effect.mapError((cause) => protocolError("Calling the Browser Run REST API failed", cause)),
334
357
  );
358
+
335
359
  const bodyText = yield* readBoundedResponse(response, request);
360
+
336
361
  if (response.status === 429) {
337
362
  const reason = isQuotaMessage(bodyText) ? "quota" : "rate";
363
+
338
364
  return yield* PageCaptureRateLimitedError.make({
339
365
  implementation: browserRestCaptureImplementation,
340
366
  reason,
@@ -361,6 +387,7 @@ const makeCapture = (
361
387
  `Browser Run answered HTTP ${String(response.status)}`,
362
388
  privateResponseCause(bodyText, options.apiToken),
363
389
  );
390
+
364
391
  return yield* error;
365
392
  }
366
393
  if (!isJsonResponse(response.headers)) {
@@ -370,12 +397,14 @@ const makeCapture = (
370
397
  );
371
398
  }
372
399
  const output = parseOutput(request.action, bodyText, options.apiToken);
400
+
373
401
  if (
374
402
  output._tag === "PageCaptureNavigationError" ||
375
403
  output._tag === "PageCaptureProtocolError"
376
404
  ) {
377
405
  return yield* output;
378
406
  }
407
+
379
408
  return PageCaptureResult.make({
380
409
  implementation: browserRestCaptureImplementation,
381
410
  output,
@@ -415,6 +444,7 @@ export const browserRestWorkersAiCaptureLayer = (
415
444
  Effect.gen(function* () {
416
445
  const client = yield* HttpClient.HttpClient;
417
446
  const workersAi = yield* BrowserQuickActionWorkersAi;
447
+
418
448
  return PageCapture.of({ capture: makeCapture(client, options, workersAi) });
419
449
  }),
420
450
  );