@effect-agent/platform-cloudflare 0.1.0-beta.13 → 0.1.0-beta.131

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 (106) hide show
  1. package/dist/Alarm.d.mts +244 -0
  2. package/dist/Alarm.mjs +947 -0
  3. package/dist/Alarm.mjs.map +1 -0
  4. package/dist/BrowserCredentials.d.mts +91 -0
  5. package/dist/BrowserCredentials.mjs +120 -0
  6. package/dist/BrowserCredentials.mjs.map +1 -0
  7. package/dist/BrowserRestCapture.d.mts +34 -0
  8. package/dist/BrowserRestCapture.mjs +238 -0
  9. package/dist/BrowserRestCapture.mjs.map +1 -0
  10. package/dist/BrowserRestCrawl.d.mts +16 -0
  11. package/dist/BrowserRestCrawl.mjs +244 -0
  12. package/dist/BrowserRestCrawl.mjs.map +1 -0
  13. package/dist/BrowserSession-DP6b-cpL.d.mts +125 -0
  14. package/dist/BrowserSession-DWoRC_iM.mjs +505 -0
  15. package/dist/BrowserSession-DWoRC_iM.mjs.map +1 -0
  16. package/dist/BrowserSession.d.mts +3 -0
  17. package/dist/BrowserSession.mjs +4 -0
  18. package/dist/CloudflareAiGateway.d.mts +64 -0
  19. package/dist/CloudflareAiGateway.mjs +70 -0
  20. package/dist/CloudflareAiGateway.mjs.map +1 -0
  21. package/dist/CloudflareBindings.d.mts +115 -0
  22. package/dist/CloudflareBindings.mjs +113 -0
  23. package/dist/CloudflareBindings.mjs.map +1 -0
  24. package/dist/CloudflareBrowser-DV6kya1H.mjs +495 -0
  25. package/dist/CloudflareBrowser-DV6kya1H.mjs.map +1 -0
  26. package/dist/CloudflareBrowser-Doe1M7R5.d.mts +80 -0
  27. package/dist/CloudflareBrowser.d.mts +2 -0
  28. package/dist/CloudflareBrowser.mjs +2 -0
  29. package/dist/CloudflareCodeMode.d.mts +44 -0
  30. package/dist/CloudflareCodeMode.mjs +616 -0
  31. package/dist/CloudflareCodeMode.mjs.map +1 -0
  32. package/dist/CloudflareConfig-DKXGo8L3.d.mts +106 -0
  33. package/dist/CloudflareConfig.d.mts +2 -0
  34. package/dist/CloudflareConfig.mjs +128 -0
  35. package/dist/CloudflareConfig.mjs.map +1 -0
  36. package/dist/CloudflareMemory.d.mts +142 -0
  37. package/dist/CloudflareMemory.mjs +202 -0
  38. package/dist/CloudflareMemory.mjs.map +1 -0
  39. package/dist/CloudflareScheduling.d.mts +52 -0
  40. package/dist/CloudflareScheduling.mjs +396 -0
  41. package/dist/CloudflareScheduling.mjs.map +1 -0
  42. package/dist/CloudflareSubscriptions.d.mts +87 -0
  43. package/dist/CloudflareSubscriptions.mjs +530 -0
  44. package/dist/CloudflareSubscriptions.mjs.map +1 -0
  45. package/dist/CloudflareThreadClient.d.mts +1752 -0
  46. package/dist/CloudflareThreadClient.mjs +382 -0
  47. package/dist/CloudflareThreadClient.mjs.map +1 -0
  48. package/dist/InteractiveBrowser-BnqY_Y-F.d.mts +228 -0
  49. package/dist/InteractiveBrowser-CxFT-Nwm.mjs +1923 -0
  50. package/dist/InteractiveBrowser-CxFT-Nwm.mjs.map +1 -0
  51. package/dist/InteractiveBrowser.d.mts +2 -0
  52. package/dist/InteractiveBrowser.mjs +2 -0
  53. package/dist/ThreadObject-CVhZC-7l.mjs +849 -0
  54. package/dist/ThreadObject-CVhZC-7l.mjs.map +1 -0
  55. package/dist/ThreadObject-D8GzJxJB.d.mts +839 -0
  56. package/dist/ThreadObject.d.mts +2 -0
  57. package/dist/ThreadObject.mjs +3 -0
  58. package/dist/WakeScheduler.d.mts +23 -0
  59. package/dist/WakeScheduler.mjs +57 -0
  60. package/dist/WakeScheduler.mjs.map +1 -0
  61. package/dist/boundary-BguazVkh.mjs +42 -0
  62. package/dist/boundary-BguazVkh.mjs.map +1 -0
  63. package/dist/index.d.mts +15 -1550
  64. package/dist/index.mjs +15 -1716
  65. package/dist/prepared-admission-DU0_T-ev.mjs +73 -0
  66. package/dist/prepared-admission-DU0_T-ev.mjs.map +1 -0
  67. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  68. package/package.json +1 -56
  69. package/src/Alarm.ts +1979 -0
  70. package/src/BrowserCredentials.ts +146 -0
  71. package/src/BrowserRestCapture.ts +477 -0
  72. package/src/BrowserRestCrawl.ts +540 -0
  73. package/src/BrowserSession.ts +624 -0
  74. package/src/CloudflareAiGateway.ts +170 -0
  75. package/src/CloudflareBindings.ts +199 -0
  76. package/src/CloudflareBrowser.ts +15 -0
  77. package/src/{code-mode-executor.ts → CloudflareCodeMode.ts} +308 -283
  78. package/src/{config.ts → CloudflareConfig.ts} +19 -12
  79. package/src/CloudflareMemory.ts +420 -0
  80. package/src/CloudflareScheduling.ts +747 -0
  81. package/src/CloudflareSubscriptions.ts +1041 -0
  82. package/src/CloudflareThreadClient.ts +809 -0
  83. package/src/InteractiveBrowser.ts +3246 -0
  84. package/src/ThreadObject.ts +1190 -0
  85. package/src/{wake-scheduler.ts → WakeScheduler.ts} +32 -26
  86. package/src/index.ts +14 -23
  87. package/src/internal/boundary.ts +55 -0
  88. package/src/internal/browser-binding.ts +322 -0
  89. package/src/internal/browser-credentials.ts +362 -0
  90. package/src/internal/browser-failure.ts +92 -0
  91. package/src/internal/browser-file-selection.ts +126 -0
  92. package/src/internal/browser-quick-action.ts +857 -0
  93. package/src/internal/browser-readonly-live-view.ts +111 -0
  94. package/src/internal/browser-session-lifecycle.ts +193 -0
  95. package/src/internal/layers.ts +773 -0
  96. package/src/internal/message-delivery.ts +131 -0
  97. package/src/internal/prepared-admission.ts +116 -0
  98. package/src/internal/progress-wait.ts +121 -0
  99. package/src/internal/transport.ts +44 -0
  100. package/dist/index.mjs.map +0 -1
  101. package/src/alarm.ts +0 -334
  102. package/src/bindings.ts +0 -145
  103. package/src/client.ts +0 -646
  104. package/src/conversation-object.ts +0 -768
  105. package/src/layers.ts +0 -376
  106. package/src/transport.ts +0 -38
@@ -0,0 +1,111 @@
1
+ import { Context, Effect, Layer, Redacted, Schema, Stream } from "effect";
2
+ import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/unstable/http";
3
+
4
+ import { BrowserRunLiveViewRequest, BrowserRunLiveViewResult } from "../InteractiveBrowser.ts";
5
+ import { browserFailure, BrowserRunFailure } from "./browser-failure.ts";
6
+ import type { BrowserRunLifecycleOptions } from "./browser-session-lifecycle.ts";
7
+
8
+ const Identity = Schema.Struct({
9
+ sessionId: Schema.String.check(Schema.isUUID()),
10
+ targetId: Schema.NonEmptyString.check(Schema.isMaxLength(256)),
11
+ });
12
+
13
+ const Reply = Schema.fromJsonString(
14
+ Schema.Struct({
15
+ id: Identity.fields.targetId,
16
+ options: Schema.Struct({
17
+ mode: Schema.Literal("tab"),
18
+ guardrails: Schema.Struct({ mode: Schema.Literal("readonly") }),
19
+ }),
20
+ devtoolsFrontendUrl: Schema.String,
21
+ }),
22
+ );
23
+
24
+ const operation = "session.readonlyLiveView";
25
+
26
+ /** Only the REST endpoint can mint provider-enforced read-only connections. */
27
+ export class BrowserRunReadonlyLiveView extends Context.Service<
28
+ BrowserRunReadonlyLiveView,
29
+ {
30
+ readonly mint: (
31
+ sessionId: Redacted.Redacted<string>,
32
+ targetId: Redacted.Redacted<string>,
33
+ request: BrowserRunLiveViewRequest,
34
+ ) => Effect.Effect<BrowserRunLiveViewResult, BrowserRunFailure>;
35
+ }
36
+ >()("@effect-agent/platform-cloudflare/internal/BrowserRunReadonlyLiveView") {
37
+ static layer(options: BrowserRunLifecycleOptions) {
38
+ return Layer.effect(
39
+ this,
40
+ Effect.gen(function* () {
41
+ const client = yield* HttpClient.HttpClient;
42
+
43
+ const mint = Effect.fnUntraced(
44
+ function* (
45
+ sessionId: Redacted.Redacted<string>,
46
+ targetId: Redacted.Redacted<string>,
47
+ request: BrowserRunLiveViewRequest,
48
+ ) {
49
+ const identity = yield* Schema.decodeEffect(Identity)({
50
+ sessionId: Redacted.value(sessionId),
51
+ targetId: Redacted.value(targetId),
52
+ });
53
+
54
+ const input = yield* Schema.decodeEffect(BrowserRunLiveViewRequest)(request);
55
+
56
+ const response = yield* client
57
+ .execute(
58
+ HttpClientRequest.post(
59
+ `https://api.cloudflare.com/client/v4/accounts/${options.accountId}/browser-rendering/devtools/browser/${identity.sessionId}/live_view`,
60
+ ).pipe(
61
+ HttpClientRequest.bearerToken(options.apiToken),
62
+ HttpClientRequest.bodyJsonUnsafe({
63
+ mode: input.mode,
64
+ expiresInMs: input.expiresInMs,
65
+ targetId: identity.targetId,
66
+ guardrails: { mode: "readonly" },
67
+ }),
68
+ ),
69
+ )
70
+ .pipe(Effect.provideService(FetchHttpClient.RequestInit, { redirect: "manual" }));
71
+
72
+ if (response.status !== 200)
73
+ return yield* new BrowserRunFailure({
74
+ operation,
75
+ reason: "provider",
76
+ status: response.status,
77
+ });
78
+
79
+ const bytes = yield* Stream.runFoldEffect(
80
+ response.stream,
81
+ () => new Uint8Array(),
82
+ (body, chunk) => {
83
+ if (body.byteLength + chunk.byteLength > 16_384)
84
+ return Effect.fail(new BrowserRunFailure({ operation, reason: "malformed" }));
85
+ const combined = new Uint8Array(body.byteLength + chunk.byteLength);
86
+
87
+ combined.set(body);
88
+ combined.set(chunk, body.byteLength);
89
+
90
+ return Effect.succeed(combined);
91
+ },
92
+ );
93
+
94
+ const reply = yield* Schema.decodeEffect(Reply)(new TextDecoder().decode(bytes));
95
+
96
+ if (reply.id !== identity.targetId)
97
+ return yield* new BrowserRunFailure({ operation, reason: "malformed" });
98
+
99
+ return yield* Schema.decodeEffect(BrowserRunLiveViewResult)({
100
+ devtoolsFrontendUrl: Redacted.make(reply.devtoolsFrontendUrl),
101
+ });
102
+ },
103
+ Effect.mapError((cause) => browserFailure(operation, cause)),
104
+ Effect.withTracerEnabled(false),
105
+ );
106
+
107
+ return { mint };
108
+ }),
109
+ );
110
+ }
111
+ }
@@ -0,0 +1,193 @@
1
+ import { Context, Effect, Layer, Option, Redacted, Schema, Stream } from "effect";
2
+ import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/unstable/http";
3
+
4
+ import { browserFailure } from "./browser-failure.ts";
5
+
6
+ export class BrowserRunCleanupError extends Schema.TaggedError<BrowserRunCleanupError>()(
7
+ "BrowserRunCleanupError",
8
+ {
9
+ reason: Schema.Literals([
10
+ "configuration",
11
+ "authorization",
12
+ "rate-limited",
13
+ "provider",
14
+ "malformed",
15
+ "timeout",
16
+ "pending",
17
+ ]),
18
+ status: Schema.optionalKey(Schema.Int),
19
+ cause: Schema.optionalKey(Schema.Defect()),
20
+ },
21
+ ) {}
22
+
23
+ export interface BrowserRunLifecycleOptions {
24
+ readonly accountId: string;
25
+ readonly apiToken: Redacted.Redacted<string>;
26
+ }
27
+
28
+ const Identity = Schema.String.check(Schema.isUUID());
29
+ const Account = Schema.String.check(Schema.isPattern(/^[a-f0-9]{32}$/));
30
+ const Closed = Schema.Struct({ status: Schema.Literals(["closing", "closed"]) });
31
+ const Metadata = Schema.Struct({ sessionId: Identity, endTime: Schema.optionalKey(Schema.Finite) });
32
+ // This exact provider response is accepted only on a fixed-origin, authenticated,
33
+ // exact-session request. An arbitrary 404 or a listing omission is never absence.
34
+ const Absent = Schema.Struct({ error: Schema.Literal("Session not found") });
35
+
36
+ export class BrowserRunSessionLifecycle extends Context.Service<
37
+ BrowserRunSessionLifecycle,
38
+ {
39
+ readonly close: (
40
+ sessionId: Redacted.Redacted<string>,
41
+ ) => Effect.Effect<void, BrowserRunCleanupError>;
42
+ }
43
+ >()("@effect-agent/platform-cloudflare/BrowserRunSessionLifecycle") {
44
+ static layer(options: BrowserRunLifecycleOptions) {
45
+ return Layer.effect(
46
+ this,
47
+ Effect.gen(function* () {
48
+ if (
49
+ !Schema.is(Account)(options.accountId) ||
50
+ Redacted.value(options.apiToken).length === 0
51
+ ) {
52
+ return yield* new BrowserRunCleanupError({ reason: "configuration" });
53
+ }
54
+ const client = yield* HttpClient.HttpClient;
55
+
56
+ const request = Effect.fn("BrowserRunSessionLifecycle.request")(function* (
57
+ method: "GET" | "DELETE",
58
+ sessionId: string,
59
+ ) {
60
+ const path = method === "DELETE" ? "browser" : "session";
61
+
62
+ const response = yield* client
63
+ .execute(
64
+ HttpClientRequest.make(method)(
65
+ `https://api.cloudflare.com/client/v4/accounts/${options.accountId}/browser-rendering/devtools/${path}/${sessionId}`,
66
+ ).pipe(HttpClientRequest.bearerToken(options.apiToken)),
67
+ )
68
+ .pipe(
69
+ // workerd supports manual/follow, not error. Reject every redirect below.
70
+ Effect.provideService(FetchHttpClient.RequestInit, { redirect: "manual" }),
71
+ Effect.mapError(
72
+ (cause) =>
73
+ new BrowserRunCleanupError({
74
+ reason: "provider",
75
+ cause: browserFailure("browser.close.request", cause),
76
+ }),
77
+ ),
78
+ );
79
+
80
+ if (response.status === 401 || response.status === 403)
81
+ return yield* new BrowserRunCleanupError({
82
+ reason: "authorization",
83
+ status: response.status,
84
+ });
85
+ if (response.status === 429)
86
+ return yield* new BrowserRunCleanupError({
87
+ reason: "rate-limited",
88
+ status: response.status,
89
+ });
90
+ if (response.status !== 200 && response.status !== 404)
91
+ return yield* new BrowserRunCleanupError({
92
+ reason: "provider",
93
+ status: response.status,
94
+ });
95
+ if (response.headers["content-type"]?.split(";", 1)[0]?.trim() !== "application/json")
96
+ return yield* new BrowserRunCleanupError({ reason: "malformed" });
97
+
98
+ const bytes = yield* Stream.runFoldEffect(
99
+ response.stream,
100
+ () => new Uint8Array(),
101
+ (body, chunk) => {
102
+ if (body.byteLength + chunk.byteLength > 16_384)
103
+ return Effect.fail(new BrowserRunCleanupError({ reason: "malformed" }));
104
+ const combined = new Uint8Array(body.byteLength + chunk.byteLength);
105
+
106
+ combined.set(body);
107
+ combined.set(chunk, body.byteLength);
108
+
109
+ return Effect.succeed(combined);
110
+ },
111
+ ).pipe(
112
+ Effect.mapError(
113
+ (cause) =>
114
+ new BrowserRunCleanupError({
115
+ reason: "malformed",
116
+ cause: browserFailure("browser.close.response", cause),
117
+ }),
118
+ ),
119
+ );
120
+
121
+ const body = yield* Effect.try({
122
+ try: () => new TextDecoder("utf-8", { fatal: true, ignoreBOM: false }).decode(bytes),
123
+ catch: (cause) =>
124
+ new BrowserRunCleanupError({
125
+ reason: "malformed",
126
+ cause: browserFailure("browser.close.decode", cause),
127
+ }),
128
+ });
129
+
130
+ if (response.status === 404) {
131
+ const absent = Schema.decodeOption(Schema.fromJsonString(Absent))(body, {
132
+ onExcessProperty: "error",
133
+ });
134
+
135
+ if (Option.isSome(absent)) return true;
136
+
137
+ return yield* new BrowserRunCleanupError({ reason: "malformed" });
138
+ }
139
+ if (method === "DELETE") {
140
+ const result = yield* Schema.decodeEffect(Schema.fromJsonString(Closed))(body).pipe(
141
+ Effect.mapError(
142
+ (cause) =>
143
+ new BrowserRunCleanupError({
144
+ reason: "malformed",
145
+ cause: browserFailure("browser.close.response", cause),
146
+ }),
147
+ ),
148
+ );
149
+
150
+ return result.status === "closed";
151
+ }
152
+
153
+ const result = yield* Schema.decodeEffect(Schema.fromJsonString(Metadata))(body).pipe(
154
+ Effect.mapError(
155
+ (cause) =>
156
+ new BrowserRunCleanupError({
157
+ reason: "malformed",
158
+ cause: browserFailure("browser.close.response", cause),
159
+ }),
160
+ ),
161
+ );
162
+
163
+ if (result.sessionId !== sessionId)
164
+ return yield* new BrowserRunCleanupError({ reason: "malformed" });
165
+
166
+ return result.endTime !== undefined && result.endTime > 0;
167
+ });
168
+
169
+ const close = Effect.fn("BrowserRunSessionLifecycle.close")(
170
+ function* (sessionId: Redacted.Redacted<string>) {
171
+ const id = yield* Schema.decodeEffect(Identity)(Redacted.value(sessionId)).pipe(
172
+ Effect.mapError(() => new BrowserRunCleanupError({ reason: "configuration" })),
173
+ );
174
+
175
+ if (yield* request("DELETE", id)) return;
176
+ for (let read = 0; read < 2; read++) {
177
+ if (yield* request("GET", id)) return;
178
+ }
179
+
180
+ return yield* new BrowserRunCleanupError({ reason: "pending" });
181
+ },
182
+ Effect.timeoutOrElse({
183
+ duration: "10 seconds",
184
+ orElse: () => Effect.fail(new BrowserRunCleanupError({ reason: "timeout" })),
185
+ }),
186
+ Effect.withTracerEnabled(false),
187
+ );
188
+
189
+ return { close };
190
+ }),
191
+ );
192
+ }
193
+ }