effect-browserbase 0.1.0-beta.102 → 0.1.0-beta.104

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.
@@ -0,0 +1,439 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
+ import { Identifier } from "./References.mjs";
3
+ import { BrowserError } from "./Errors.mjs";
4
+ import { AutomationOptions, BrowserPolicy, Viewport } from "./BrowserData.mjs";
5
+ import { a as reported } from "./Acquisition-WBafHwXH.mjs";
6
+ import { d as empty } from "./Bootstrap-BXuzZojd.mjs";
7
+ import { a as connectPlaywrightEndpoint, s as fromNativeAttempt } from "./BrowserBinding-DlJTGYZL.mjs";
8
+ import { c as preparePlan, i as checked, l as compileBootstrap, o as makeSession, s as makeBindings, t as acquireSession } from "./Session-D4nT9hOO.mjs";
9
+ import { Cause, Clock, Context, Duration, Effect, Exit, Layer, Option, Path, Redacted, Schema, Scope } from "effect";
10
+ import { spawn } from "node:child_process";
11
+ import { mkdtemp, readFile, rm } from "node:fs/promises";
12
+ import { tmpdir } from "node:os";
13
+ //#region src/internal/browser/LocalData.ts
14
+ /** Identifies this local ownership lifetime, not a Browserbase resource or a reusable endpoint. */
15
+ var LocalReference = class extends Schema.Class("LocalBrowserReference")({
16
+ provider: Schema.Literal("local"),
17
+ id: Identifier
18
+ }) {};
19
+ var LocalCleanupIssue = class extends Schema.Class("LocalBrowserCleanupIssue")({
20
+ step: Schema.Literals([
21
+ "fence",
22
+ "capture",
23
+ "initialization",
24
+ "disconnect",
25
+ "terminate",
26
+ "profile"
27
+ ]),
28
+ reason: Schema.Literals([
29
+ "timeout",
30
+ "failed",
31
+ "interrupted"
32
+ ])
33
+ }) {};
34
+ /** Connection teardown and observed process exit are separate facts; no provider status exists. */
35
+ var LocalCleanupResult = class extends Schema.Class("LocalBrowserCleanupResult")({
36
+ reference: LocalReference,
37
+ ownership: Schema.Literals(["owned", "borrowed"]),
38
+ connection: Schema.Literals([
39
+ "closed",
40
+ "failed",
41
+ "not-connected",
42
+ "pending"
43
+ ]),
44
+ process: Schema.Literals([
45
+ "terminated",
46
+ "unknown",
47
+ "not-owned"
48
+ ]),
49
+ issues: Schema.Array(LocalCleanupIssue).check(Schema.isMaxLength(16))
50
+ }) {};
51
+ const Text = Schema.NonEmptyString.check(Schema.isMaxLength(4096), Schema.isPattern(/^[^\u0000\r\n]+$/u));
52
+ const Port = Schema.Int.check(Schema.isBetween({
53
+ minimum: 1,
54
+ maximum: 65535
55
+ }));
56
+ /** Only a concrete loopback WebSocket is admitted: no HTTP discovery redirects or remote DNS. */
57
+ const LocalEndpoint = Text.check(Schema.makeFilter((value) => {
58
+ try {
59
+ const url = new URL(value);
60
+ return url.protocol === "ws:" && ["127.0.0.1", "[::1]"].includes(url.hostname) && Schema.is(Port)(Number(url.port)) && !url.username && !url.password && !url.search && !url.hash && /^\/devtools\/browser\/[A-Za-z0-9_-]+$/u.test(url.pathname);
61
+ } catch {
62
+ return false;
63
+ }
64
+ }));
65
+ const ProxyServer = Text.check(Schema.makeFilter((value) => {
66
+ try {
67
+ const url = new URL(value);
68
+ return [
69
+ "http:",
70
+ "https:",
71
+ "socks5:"
72
+ ].includes(url.protocol) && url.hostname.length > 0 && !url.username && !url.password && !url.search && !url.hash && ["", "/"].includes(url.pathname);
73
+ } catch {
74
+ return false;
75
+ }
76
+ }));
77
+ /** These arguments belong to the launcher; silently overriding them would change ownership. */
78
+ const Argument = Text.check(Schema.makeFilter((value) => value.startsWith("--") && !/^--(?:user-data-dir|remote-debugging[^=]*|headless|no-sandbox|disable-setuid-sandbox|single-process|proxy-server|proxy-bypass-list)(?:=|$)/u.test(value)));
79
+ const LocalLaunch = Schema.Struct({
80
+ executablePath: Schema.optionalKey(Text),
81
+ headless: Schema.optionalKey(Schema.Boolean),
82
+ /** Enabled by default; a trusted host must explicitly choose a sandbox exception. */
83
+ chromiumSandbox: Schema.optionalKey(Schema.Boolean),
84
+ args: Schema.optionalKey(Schema.Array(Argument).check(Schema.isMaxLength(64))),
85
+ proxy: Schema.optionalKey(Schema.Struct({
86
+ server: ProxyServer,
87
+ bypass: Schema.optionalKey(Text)
88
+ })),
89
+ startupTimeoutMillis: Schema.optionalKey(Schema.Int.check(Schema.isBetween({
90
+ minimum: 1,
91
+ maximum: 6e4
92
+ })))
93
+ });
94
+ //#endregion
95
+ //#region src/internal/browser/LocalProcess.ts
96
+ /** Explicit host sandbox/proxy choices; the owned profile and debugger endpoint cannot be replaced. */
97
+ const launchArguments = (options, directory) => [
98
+ "--no-first-run",
99
+ "--no-default-browser-check",
100
+ "--remote-debugging-address=127.0.0.1",
101
+ "--remote-debugging-port=0",
102
+ `--user-data-dir=${directory}`,
103
+ ...options.headless === false ? [] : ["--headless=new"],
104
+ ...options.chromiumSandbox === false ? ["--no-sandbox"] : [],
105
+ ...options.proxy === void 0 ? [] : [`--proxy-server=${options.proxy.server}`, `--proxy-bypass-list=${options.proxy.bypass ?? "<-loopback>"}`],
106
+ ...options.args ?? [],
107
+ "about:blank"
108
+ ];
109
+ const failure = (operation, reason) => BrowserError.make({
110
+ operation,
111
+ reason,
112
+ outcome: operation === "close" ? "unknown" : "undispatched"
113
+ });
114
+ const exited = (child) => child.exitCode !== null || child.signalCode !== null;
115
+ /** POSIX groups keep Chromium's helpers inside the same owned termination boundary. */
116
+ const alive = (pid) => {
117
+ try {
118
+ process.kill(-pid, 0);
119
+ return true;
120
+ } catch (error) {
121
+ if (error instanceof Error && "code" in error && error.code === "ESRCH") return false;
122
+ throw error;
123
+ }
124
+ };
125
+ const signalGroup = (pid, signal) => {
126
+ try {
127
+ process.kill(-pid, signal);
128
+ } catch (error) {
129
+ if (!(error instanceof Error && "code" in error && error.code === "ESRCH")) throw error;
130
+ }
131
+ };
132
+ /** Called once; observes parent and helper exit, rather than treating a sent signal as cleanup. */
133
+ const terminate = Effect.fnUntraced(function* (child, pid, clock) {
134
+ const stopped = Effect.try({
135
+ try: () => exited(child) && !alive(pid),
136
+ catch: () => failure("close", "failed")
137
+ });
138
+ const signal = (value) => Effect.try({
139
+ try: () => signalGroup(pid, value),
140
+ catch: () => failure("close", "failed")
141
+ });
142
+ const pause = clock.sleep(Duration.millis(20));
143
+ yield* signal("SIGTERM");
144
+ const graceful = clock.monotonicTimeNanosUnsafe() + 1500000000n;
145
+ while (!(yield* stopped) && clock.monotonicTimeNanosUnsafe() < graceful) yield* pause;
146
+ if (yield* stopped) return;
147
+ yield* signal("SIGKILL");
148
+ const forced = clock.monotonicTimeNanosUnsafe() + 1000000000n;
149
+ while (!(yield* stopped) && clock.monotonicTimeNanosUnsafe() < forced) yield* pause;
150
+ if (!(yield* stopped)) return yield* failure("close", "timeout");
151
+ });
152
+ /** Start only Chromium's process. The shared owner later opens its sole CDP connection. */
153
+ const launch = Effect.fnUntraced(function* (options) {
154
+ if (process.platform === "win32") return yield* failure("launch", "unsupported");
155
+ const path = yield* Path.Path.pipe(Effect.provide(Path.layer));
156
+ const clock = yield* Clock.Clock;
157
+ const executable = options.executablePath ?? (yield* Effect.tryPromise({
158
+ try: async () => (await import("playwright-core")).chromium.executablePath(),
159
+ catch: () => failure("launch", "failed")
160
+ }));
161
+ const directory = yield* Effect.tryPromise({
162
+ try: () => mkdtemp(path.join(tmpdir(), "effect-local-browser-")),
163
+ catch: () => failure("launch", "failed")
164
+ });
165
+ const removeProfile = Effect.tryPromise({
166
+ try: () => rm(directory, {
167
+ recursive: true,
168
+ force: true,
169
+ maxRetries: 5,
170
+ retryDelay: 50
171
+ }),
172
+ catch: () => failure("close", "failed")
173
+ });
174
+ let child;
175
+ return yield* Effect.gen(function* () {
176
+ const launched = yield* Effect.tryPromise({
177
+ try: () => {
178
+ const spawned = spawn(executable, launchArguments(options, directory), {
179
+ cwd: directory,
180
+ stdio: [
181
+ "ignore",
182
+ "ignore",
183
+ "ignore"
184
+ ],
185
+ detached: true
186
+ });
187
+ child = spawned;
188
+ return new Promise((resolve, reject) => {
189
+ spawned.once("spawn", () => resolve(spawned));
190
+ spawned.once("error", reject);
191
+ });
192
+ },
193
+ catch: () => failure("launch", "failed")
194
+ });
195
+ const pid = launched.pid;
196
+ if (pid === void 0) return yield* failure("launch", "failed");
197
+ return {
198
+ connection: (timeoutMillis) => Effect.gen(function* () {
199
+ const deadline = clock.monotonicTimeNanosUnsafe() + BigInt(Math.ceil(Math.min(timeoutMillis, options.startupTimeoutMillis ?? 15e3))) * 1000000n;
200
+ while (clock.monotonicTimeNanosUnsafe() < deadline) {
201
+ if (exited(launched)) return yield* failure("connect", "closed");
202
+ const portFile = yield* Effect.tryPromise({
203
+ try: (signal) => readFile(path.join(directory, "DevToolsActivePort"), {
204
+ encoding: "utf8",
205
+ signal
206
+ }).catch((error) => {
207
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") return void 0;
208
+ throw error;
209
+ }),
210
+ catch: () => failure("connect", "transport")
211
+ });
212
+ const lines = portFile === void 0 ? [] : portFile.trim().split("\n");
213
+ if (lines.length >= 2) {
214
+ const endpoint = `ws://127.0.0.1:${lines[0]}${lines[1]}`;
215
+ if (!Schema.is(LocalEndpoint)(endpoint)) return yield* failure("connect", "malformed");
216
+ return Redacted.make(endpoint);
217
+ }
218
+ yield* clock.sleep(Duration.millis(20));
219
+ }
220
+ return yield* failure("connect", "timeout");
221
+ }),
222
+ terminate: yield* Effect.cached(terminate(launched, pid, clock).pipe(Effect.uninterruptible)),
223
+ removeProfile
224
+ };
225
+ }).pipe(Effect.onExit((exit) => Exit.isSuccess(exit) ? Effect.void : Effect.gen(function* () {
226
+ if (child?.pid === void 0) {
227
+ yield* removeProfile.pipe(Effect.ignore);
228
+ return;
229
+ }
230
+ const stopped = yield* terminate(child, child.pid, clock).pipe(Effect.exit);
231
+ if (Exit.isSuccess(stopped)) yield* removeProfile.pipe(Effect.ignore);
232
+ })));
233
+ });
234
+ //#endregion
235
+ //#region src/internal/browser/LocalSession.ts
236
+ /** Same maintained driver, with a separately validated host endpoint and no provider identity. */
237
+ const localEngine = fromNativeAttempt(async (request, signal) => {
238
+ if (!Schema.is(LocalEndpoint)(request.connection)) throw BrowserError.make({
239
+ operation: "connect",
240
+ reason: "configuration",
241
+ outcome: "undispatched"
242
+ });
243
+ return connectPlaywrightEndpoint(request.connection, signal, request.options, request.events);
244
+ });
245
+ /** Each teardown step runs even when a preceding step fails. Only observed exit permits profile removal. */
246
+ const makeLocalCleanup = Effect.fnUntraced(function* (reference, local, process) {
247
+ let latest;
248
+ return {
249
+ close: yield* Effect.cached(Effect.uninterruptible(Effect.gen(function* () {
250
+ const issues = [];
251
+ const step = (name, action) => action.pipe(Effect.interruptible, Effect.timeoutOrElse({
252
+ duration: 3e3,
253
+ orElse: () => Effect.fail(LocalCleanupIssue.make({
254
+ step: name,
255
+ reason: "timeout"
256
+ }))
257
+ }), Effect.exit, Effect.tap((exit) => Effect.sync(() => {
258
+ if (Exit.isSuccess(exit)) return;
259
+ const error = Cause.findErrorOption(exit.cause);
260
+ issues.push(LocalCleanupIssue.make({
261
+ step: name,
262
+ reason: Option.isSome(error) && error.value instanceof LocalCleanupIssue ? error.value.reason : Cause.hasInterrupts(exit.cause) ? "interrupted" : "failed"
263
+ }));
264
+ })));
265
+ yield* step("fence", local.fence);
266
+ yield* step("capture", local.capture);
267
+ yield* step("initialization", local.initialization);
268
+ const disconnected = yield* step("disconnect", local.disconnect);
269
+ const terminated = process === void 0 ? void 0 : yield* step("terminate", process.terminate);
270
+ if (process !== void 0 && terminated !== void 0 && Exit.isSuccess(terminated)) yield* step("profile", process.removeProfile);
271
+ const result = LocalCleanupResult.make({
272
+ reference,
273
+ ownership: process === void 0 ? "borrowed" : "owned",
274
+ connection: Exit.isSuccess(disconnected) ? disconnected.value : "failed",
275
+ process: terminated === void 0 ? "not-owned" : Exit.isSuccess(terminated) ? "terminated" : "unknown",
276
+ issues
277
+ });
278
+ Object.freeze(result.issues);
279
+ latest = Object.freeze(result);
280
+ return latest;
281
+ }))),
282
+ result: Effect.sync(() => Option.fromNullishOr(latest))
283
+ };
284
+ });
285
+ const acquireLocal = (endpoint, options, onCleanup) => (local) => Effect.uninterruptible(Effect.gen(function* () {
286
+ const process = endpoint === void 0 ? yield* launch(options) : void 0;
287
+ const reference = Object.freeze(LocalReference.make({
288
+ provider: "local",
289
+ id: globalThis.crypto.randomUUID()
290
+ }));
291
+ const cleanup = yield* makeLocalCleanup(reference, local, process);
292
+ let closing = false;
293
+ const release = yield* Effect.cached(Effect.gen(function* () {
294
+ closing = true;
295
+ const result = yield* cleanup.close;
296
+ if (onCleanup !== void 0) yield* reported(onCleanup(result));
297
+ return result;
298
+ }).pipe(Effect.uninterruptible));
299
+ yield* Effect.addFinalizer(() => release.pipe(Effect.asVoid));
300
+ return {
301
+ reference,
302
+ connection: (timeoutMillis) => Effect.suspend(() => {
303
+ if (closing) return Effect.fail(BrowserError.make({
304
+ operation: "connect",
305
+ reason: "closed",
306
+ outcome: "undispatched"
307
+ }));
308
+ if (process !== void 0) return process.connection(timeoutMillis);
309
+ return endpoint === void 0 ? Effect.fail(BrowserError.make({
310
+ operation: "connect",
311
+ reason: "configuration",
312
+ outcome: "undispatched"
313
+ })) : checked(LocalEndpoint, Redacted.value(endpoint), "connect").pipe(Effect.map(Redacted.make));
314
+ }),
315
+ release,
316
+ cleanupResult: cleanup.result
317
+ };
318
+ }));
319
+ const ownedLocal = (options, onCleanup) => acquireLocal(void 0, options, onCleanup);
320
+ const borrowedLocal = (endpoint, onCleanup) => acquireLocal(endpoint, {}, onCleanup);
321
+ //#endregion
322
+ //#region src/LocalBrowser.ts
323
+ var LocalBrowser_exports = /* @__PURE__ */ __exportAll({
324
+ LocalBrowser: () => LocalBrowser,
325
+ LocalCleanupIssue: () => LocalCleanupIssue,
326
+ LocalCleanupResult: () => LocalCleanupResult,
327
+ LocalLaunch: () => LocalLaunch,
328
+ LocalReference: () => LocalReference
329
+ });
330
+ var LocalBrowser = class LocalBrowser extends Context.Service()("effect-browserbase/LocalBrowser") {
331
+ static layer(options = {}) {
332
+ return Layer.effect(LocalBrowser, Effect.gen(function* () {
333
+ const automation = yield* checked(AutomationOptions, {
334
+ ...options.actionTimeoutMillis === void 0 ? {} : { actionTimeoutMillis: options.actionTimeoutMillis },
335
+ ...options.maxPages === void 0 ? {} : { maxPages: options.maxPages },
336
+ ...options.initialPage === void 0 ? {} : { initialPage: options.initialPage },
337
+ ...options.popupPolicy === void 0 ? {} : { popupPolicy: options.popupPolicy },
338
+ ...options.dialogPolicy === void 0 ? {} : { dialogPolicy: options.dialogPolicy },
339
+ ...options.pageControl === void 0 ? {} : { pageControl: options.pageControl }
340
+ }, "configure");
341
+ const launchInput = yield* checked(LocalLaunch, options.launch ?? {}, "configure");
342
+ const launch = Object.freeze({
343
+ ...launchInput,
344
+ ...launchInput.args === void 0 ? {} : { args: Object.freeze([...launchInput.args]) },
345
+ ...launchInput.proxy === void 0 ? {} : { proxy: Object.freeze({ ...launchInput.proxy }) }
346
+ });
347
+ const viewport = yield* checked(Viewport, options.viewport ?? {
348
+ width: 1280,
349
+ height: 720
350
+ }, "configure");
351
+ const pageControl = automation.pageControl ?? false;
352
+ const popupPolicy = automation.popupPolicy ?? "retain";
353
+ const dialogPolicy = automation.dialogPolicy ?? "dismiss";
354
+ if (pageControl && (popupPolicy === "pause" || dialogPolicy === "pause")) return yield* BrowserError.make({
355
+ operation: "configure",
356
+ reason: "unsupported",
357
+ outcome: "undispatched"
358
+ });
359
+ if (Object.prototype.hasOwnProperty.call(options, "bootstrap")) return yield* BrowserError.make({
360
+ operation: "configure",
361
+ reason: "configuration",
362
+ outcome: "undispatched"
363
+ });
364
+ const driver = {
365
+ viewport,
366
+ pageControl,
367
+ popupPolicy,
368
+ dialogPolicy,
369
+ maxPages: automation.maxPages ?? 10
370
+ };
371
+ const acquire = Effect.fnUntraced(function* (policy, request = {}, attachment) {
372
+ const fixed = yield* checked(BrowserPolicy, policy, "configure");
373
+ const plan = yield* preparePlan(request.bootstrap ?? empty);
374
+ const scope = yield* Scope.fork(yield* Scope.Scope, "sequential");
375
+ const bindings = yield* makeBindings(plan).pipe(Scope.provide(scope));
376
+ const bootstrap = compileBootstrap(plan);
377
+ const selection = attachment !== void 0 ? {
378
+ newPage: false,
379
+ preserveViewport: true,
380
+ ...attachment.targetId === void 0 ? {} : { initialTargetId: attachment.targetId }
381
+ } : automation.initialPage === void 0 ? {} : "targetId" in automation.initialPage ? { initialTargetId: automation.initialPage.targetId } : { newPage: true };
382
+ const acquired = yield* acquireSession({
383
+ maxActions: fixed.maxActions,
384
+ maxElapsedMillis: fixed.maxElapsedMillis,
385
+ actionTimeoutMillis: automation.actionTimeoutMillis ?? 1e4
386
+ }, {
387
+ remote: attachment === void 0 ? ownedLocal(launch, options.onCleanup) : borrowedLocal(attachment.endpoint, options.onCleanup),
388
+ engine: localEngine,
389
+ keepAlive: false,
390
+ driver: {
391
+ ...driver,
392
+ ...selection,
393
+ ...bootstrap === void 0 ? {} : { bootstrap }
394
+ },
395
+ connectBindings: bindings.connect,
396
+ maxReturnedBytes: fixed.maxReturnedBytes
397
+ }).pipe(Scope.provide(scope));
398
+ const connected = yield* Effect.cached(acquired.connect.pipe(Effect.map((controls) => Object.assign(makeSession(controls, bindings), {
399
+ reference: controls.reference,
400
+ close: controls.close,
401
+ cleanupResult: controls.cleanupResult
402
+ }))));
403
+ return {
404
+ reference: acquired.reference,
405
+ failure: bindings.failure,
406
+ close: acquired.close,
407
+ connect: Effect.raceFirst(bindings.failure, acquired.connect.pipe(Effect.andThen(connected))).pipe(Effect.onError(() => acquired.close.pipe(Effect.asVoid)))
408
+ };
409
+ });
410
+ return LocalBrowser.of({
411
+ acquire,
412
+ open: (policy, request) => acquire(policy, request).pipe(Effect.flatMap((acquired) => acquired.connect)),
413
+ attach: (endpoint, request) => Effect.gen(function* () {
414
+ const address = yield* checked(LocalEndpoint, Redacted.value(endpoint), "connect");
415
+ const targetId = request.target === void 0 ? void 0 : yield* checked(Identifier, request.target.targetId, "configure");
416
+ return yield* (yield* acquire(request.policy, request, {
417
+ endpoint: Redacted.make(address),
418
+ ...targetId === void 0 ? {} : { targetId }
419
+ })).connect;
420
+ }),
421
+ withBrowser: (policy, request, use) => Effect.scoped(Effect.gen(function* () {
422
+ const session = yield* (yield* acquire(policy, request)).connect;
423
+ const result = yield* Effect.raceFirst(session.failure, Effect.suspend(() => use(session)));
424
+ const cleanup = yield* session.close;
425
+ if (cleanup.connection !== "closed" || cleanup.process !== "terminated" || cleanup.issues.length > 0) return yield* BrowserError.make({
426
+ operation: "close",
427
+ reason: "failed",
428
+ outcome: "unknown"
429
+ });
430
+ return result;
431
+ }))
432
+ });
433
+ }));
434
+ }
435
+ };
436
+ //#endregion
437
+ export { LocalLaunch as a, LocalCleanupResult as i, LocalBrowser_exports as n, LocalReference as o, LocalCleanupIssue as r, LocalBrowser as t };
438
+
439
+ //# sourceMappingURL=LocalBrowser-DsQLWNL1.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LocalBrowser-DsQLWNL1.mjs","names":["Bootstrap.empty"],"sources":["../src/internal/browser/LocalData.ts","../src/internal/browser/LocalProcess.ts","../src/internal/browser/LocalSession.ts","../src/LocalBrowser.ts"],"sourcesContent":["import { Schema } from \"effect\";\n\nimport { Identifier } from \"../../References.ts\";\n\n/** Identifies this local ownership lifetime, not a Browserbase resource or a reusable endpoint. */\nexport class LocalReference extends Schema.Class<LocalReference>(\"LocalBrowserReference\")({\n provider: Schema.Literal(\"local\"),\n id: Identifier,\n}) {}\n\nexport class LocalCleanupIssue extends Schema.Class<LocalCleanupIssue>(\"LocalBrowserCleanupIssue\")({\n step: Schema.Literals([\n \"fence\",\n \"capture\",\n \"initialization\",\n \"disconnect\",\n \"terminate\",\n \"profile\",\n ]),\n reason: Schema.Literals([\"timeout\", \"failed\", \"interrupted\"]),\n}) {}\n\n/** Connection teardown and observed process exit are separate facts; no provider status exists. */\nexport class LocalCleanupResult extends Schema.Class<LocalCleanupResult>(\n \"LocalBrowserCleanupResult\",\n)({\n reference: LocalReference,\n ownership: Schema.Literals([\"owned\", \"borrowed\"]),\n connection: Schema.Literals([\"closed\", \"failed\", \"not-connected\", \"pending\"]),\n process: Schema.Literals([\"terminated\", \"unknown\", \"not-owned\"]),\n issues: Schema.Array(LocalCleanupIssue).check(Schema.isMaxLength(16)),\n}) {}\n\nconst Text = Schema.NonEmptyString.check(\n Schema.isMaxLength(4096),\n Schema.isPattern(/^[^\\u0000\\r\\n]+$/u),\n);\n\nconst Port = Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 65535 }));\n\n/** Only a concrete loopback WebSocket is admitted: no HTTP discovery redirects or remote DNS. */\nexport const LocalEndpoint = Text.check(\n Schema.makeFilter((value) => {\n try {\n const url = new URL(value);\n\n return (\n url.protocol === \"ws:\" &&\n [\"127.0.0.1\", \"[::1]\"].includes(url.hostname) &&\n Schema.is(Port)(Number(url.port)) &&\n !url.username &&\n !url.password &&\n !url.search &&\n !url.hash &&\n /^\\/devtools\\/browser\\/[A-Za-z0-9_-]+$/u.test(url.pathname)\n );\n } catch {\n return false;\n }\n }),\n);\n\nconst ProxyServer = Text.check(\n Schema.makeFilter((value) => {\n try {\n const url = new URL(value);\n\n return (\n [\"http:\", \"https:\", \"socks5:\"].includes(url.protocol) &&\n url.hostname.length > 0 &&\n !url.username &&\n !url.password &&\n !url.search &&\n !url.hash &&\n [\"\", \"/\"].includes(url.pathname)\n );\n } catch {\n return false;\n }\n }),\n);\n\n/** These arguments belong to the launcher; silently overriding them would change ownership. */\nconst Argument = Text.check(\n Schema.makeFilter(\n (value) =>\n value.startsWith(\"--\") &&\n !/^--(?:user-data-dir|remote-debugging[^=]*|headless|no-sandbox|disable-setuid-sandbox|single-process|proxy-server|proxy-bypass-list)(?:=|$)/u.test(\n value,\n ),\n ),\n);\n\nexport const LocalLaunch = Schema.Struct({\n executablePath: Schema.optionalKey(Text),\n headless: Schema.optionalKey(Schema.Boolean),\n /** Enabled by default; a trusted host must explicitly choose a sandbox exception. */\n chromiumSandbox: Schema.optionalKey(Schema.Boolean),\n args: Schema.optionalKey(Schema.Array(Argument).check(Schema.isMaxLength(64))),\n proxy: Schema.optionalKey(\n Schema.Struct({\n server: ProxyServer,\n bypass: Schema.optionalKey(Text),\n }),\n ),\n startupTimeoutMillis: Schema.optionalKey(\n Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 60000 })),\n ),\n});\n\nexport type LocalLaunch = typeof LocalLaunch.Type;\n","// rc.115's NodeChildProcessSpawner exposes leader exit, but its bounded group wait can\n// succeed with surviving members. This boundary must observe the leader AND group gone.\n// @effect-diagnostics-next-line nodeBuiltinImport:off\nimport { spawn, type ChildProcess } from \"node:child_process\";\n// FileSystem.remove exposes recursive/force only, not rm's per-entry OS-error retries.\n// Keep native profile creation/read/removal together; removal follows confirmed group exit.\n// @effect-diagnostics-next-line nodeBuiltinImport:off\nimport { mkdtemp, readFile, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\n\nimport { Clock, Duration, Effect, Exit, Path, Redacted, Schema } from \"effect\";\n\nimport { BrowserError } from \"../../Errors.ts\";\nimport { LocalEndpoint, type LocalLaunch } from \"./LocalData.ts\";\n\nexport interface LocalProcess {\n readonly connection: (\n timeoutMillis: number,\n ) => Effect.Effect<Redacted.Redacted<string>, BrowserError>;\n readonly terminate: Effect.Effect<void, BrowserError>;\n readonly removeProfile: Effect.Effect<void, BrowserError>;\n}\n\n/** Explicit host sandbox/proxy choices; the owned profile and debugger endpoint cannot be replaced. */\nexport const launchArguments = (options: LocalLaunch, directory: string): string[] => [\n \"--no-first-run\",\n \"--no-default-browser-check\",\n \"--remote-debugging-address=127.0.0.1\",\n \"--remote-debugging-port=0\",\n `--user-data-dir=${directory}`,\n ...(options.headless === false ? [] : [\"--headless=new\"]),\n ...(options.chromiumSandbox === false ? [\"--no-sandbox\"] : []),\n ...(options.proxy === undefined\n ? []\n : [\n `--proxy-server=${options.proxy.server}`,\n // Chromium otherwise bypasses proxies for loopback. The host may deliberately override it.\n `--proxy-bypass-list=${options.proxy.bypass ?? \"<-loopback>\"}`,\n ]),\n ...(options.args ?? []),\n \"about:blank\",\n];\n\nconst failure = (operation: \"launch\" | \"connect\" | \"close\", reason: BrowserError[\"reason\"]) =>\n BrowserError.make({\n operation,\n reason,\n outcome: operation === \"close\" ? \"unknown\" : \"undispatched\",\n });\n\nconst exited = (child: ChildProcess) => child.exitCode !== null || child.signalCode !== null;\n\n/** POSIX groups keep Chromium's helpers inside the same owned termination boundary. */\nconst alive = (pid: number): boolean => {\n try {\n process.kill(-pid, 0);\n\n return true;\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ESRCH\") return false;\n throw error;\n }\n};\n\nconst signalGroup = (pid: number, signal: NodeJS.Signals) => {\n try {\n process.kill(-pid, signal);\n } catch (error) {\n if (!(error instanceof Error && \"code\" in error && error.code === \"ESRCH\")) throw error;\n }\n};\n\n/** Called once; observes parent and helper exit, rather than treating a sent signal as cleanup. */\nconst terminate = Effect.fnUntraced(function* (\n child: ChildProcess,\n pid: number,\n clock: Clock.Clock,\n): Effect.fn.Return<void, BrowserError> {\n const stopped = Effect.try({\n try: () => exited(child) && !alive(pid),\n catch: () => failure(\"close\", \"failed\"),\n });\n\n const signal = (value: NodeJS.Signals) =>\n Effect.try({ try: () => signalGroup(pid, value), catch: () => failure(\"close\", \"failed\") });\n\n const pause = clock.sleep(Duration.millis(20));\n\n yield* signal(\"SIGTERM\");\n const graceful = clock.monotonicTimeNanosUnsafe() + 1_500_000_000n;\n\n while (!(yield* stopped) && clock.monotonicTimeNanosUnsafe() < graceful) yield* pause;\n if (yield* stopped) return;\n yield* signal(\"SIGKILL\");\n const forced = clock.monotonicTimeNanosUnsafe() + 1_000_000_000n;\n\n while (!(yield* stopped) && clock.monotonicTimeNanosUnsafe() < forced) yield* pause;\n if (!(yield* stopped)) return yield* failure(\"close\", \"timeout\");\n});\n\n/** Start only Chromium's process. The shared owner later opens its sole CDP connection. */\nexport const launch = Effect.fnUntraced(function* (\n options: LocalLaunch,\n): Effect.fn.Return<LocalProcess, BrowserError> {\n if (process.platform === \"win32\") return yield* failure(\"launch\", \"unsupported\");\n const path = yield* Path.Path.pipe(Effect.provide(Path.layer));\n const clock = yield* Clock.Clock;\n\n const executable =\n options.executablePath ??\n (yield* Effect.tryPromise({\n try: async () => (await import(\"playwright-core\")).chromium.executablePath(),\n catch: () => failure(\"launch\", \"failed\"),\n }));\n\n const directory = yield* Effect.tryPromise({\n try: () => mkdtemp(path.join(tmpdir(), \"effect-local-browser-\")),\n catch: () => failure(\"launch\", \"failed\"),\n });\n\n const removeProfile = Effect.tryPromise({\n try: () => rm(directory, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 }),\n catch: () => failure(\"close\", \"failed\"),\n });\n\n let child: ChildProcess | undefined;\n\n return yield* Effect.gen(function* () {\n const launched = yield* Effect.tryPromise({\n try: () => {\n const spawned = spawn(executable, launchArguments(options, directory), {\n cwd: directory,\n stdio: [\"ignore\", \"ignore\", \"ignore\"],\n detached: true,\n });\n\n child = spawned;\n\n return new Promise<ChildProcess>((resolve, reject) => {\n spawned.once(\"spawn\", () => resolve(spawned));\n spawned.once(\"error\", reject);\n });\n },\n catch: () => failure(\"launch\", \"failed\"),\n });\n\n const pid = launched.pid;\n\n if (pid === undefined) return yield* failure(\"launch\", \"failed\");\n\n // One termination continues to its own bounded group-exit decision even if a waiter cancels.\n const closing = yield* Effect.cached(\n terminate(launched, pid, clock).pipe(Effect.uninterruptible),\n );\n\n return {\n connection: (timeoutMillis) =>\n Effect.gen(function* () {\n const deadline =\n clock.monotonicTimeNanosUnsafe() +\n BigInt(Math.ceil(Math.min(timeoutMillis, options.startupTimeoutMillis ?? 15000))) *\n 1_000_000n;\n\n while (clock.monotonicTimeNanosUnsafe() < deadline) {\n if (exited(launched)) return yield* failure(\"connect\", \"closed\");\n\n const portFile = yield* Effect.tryPromise({\n try: (signal) =>\n readFile(path.join(directory, \"DevToolsActivePort\"), {\n encoding: \"utf8\",\n signal,\n }).catch((error: unknown) => {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\")\n return undefined;\n throw error;\n }),\n catch: () => failure(\"connect\", \"transport\"),\n });\n\n // Chromium creates DevToolsActivePort before it writes the port and path into it. A\n // file without both lines is startup still in progress, not an endpoint; only a\n // complete file that is not a loopback DevTools endpoint is malformed.\n const lines = portFile === undefined ? [] : portFile.trim().split(\"\\n\");\n\n if (lines.length >= 2) {\n const endpoint = `ws://127.0.0.1:${lines[0]}${lines[1]}`;\n\n if (!Schema.is(LocalEndpoint)(endpoint))\n return yield* failure(\"connect\", \"malformed\");\n\n return Redacted.make(endpoint);\n }\n yield* clock.sleep(Duration.millis(20));\n }\n\n return yield* failure(\"connect\", \"timeout\");\n }),\n terminate: closing,\n removeProfile,\n } satisfies LocalProcess;\n }).pipe(\n Effect.onExit((exit) =>\n Exit.isSuccess(exit)\n ? Effect.void\n : Effect.gen(function* () {\n if (child?.pid === undefined) {\n yield* removeProfile.pipe(Effect.ignore);\n\n return;\n }\n const stopped = yield* terminate(child, child.pid, clock).pipe(Effect.exit);\n\n if (Exit.isSuccess(stopped)) yield* removeProfile.pipe(Effect.ignore);\n }),\n ),\n );\n});\n","import { Cause, Effect, Exit, Option, Redacted, Schema } from \"effect\";\n\nimport { BrowserError } from \"../../Errors.ts\";\nimport { reported, type LocalCleanup } from \"../session/Cleanup.ts\";\nimport { fromNativeAttempt } from \"./Binding.ts\";\nimport {\n LocalCleanupIssue,\n LocalCleanupResult,\n LocalEndpoint,\n LocalReference,\n type LocalLaunch,\n} from \"./LocalData.ts\";\nimport { launch, type LocalProcess } from \"./LocalProcess.ts\";\nimport { connectPlaywrightEndpoint } from \"./Playwright.ts\";\nimport { checked } from \"./PublicSession.ts\";\nimport type { RemoteSource, SessionLease } from \"./Session.ts\";\n\nexport interface LocalLease extends SessionLease {\n readonly reference: LocalReference;\n readonly release: Effect.Effect<LocalCleanupResult>;\n readonly cleanupResult: Effect.Effect<Option.Option<LocalCleanupResult>>;\n}\n\n/** Same maintained driver, with a separately validated host endpoint and no provider identity. */\nexport const localEngine = fromNativeAttempt(async (request, signal) => {\n if (!Schema.is(LocalEndpoint)(request.connection))\n throw BrowserError.make({\n operation: \"connect\",\n reason: \"configuration\",\n outcome: \"undispatched\",\n });\n\n return connectPlaywrightEndpoint(request.connection, signal, request.options, request.events);\n});\n\n/** Each teardown step runs even when a preceding step fails. Only observed exit permits profile removal. */\nexport const makeLocalCleanup = Effect.fnUntraced(function* (\n reference: LocalReference,\n local: LocalCleanup,\n process: LocalProcess | undefined,\n) {\n let latest: LocalCleanupResult | undefined;\n\n const close = yield* Effect.cached(\n Effect.uninterruptible(\n Effect.gen(function* () {\n const issues: LocalCleanupIssue[] = [];\n\n const step = <A, E>(name: LocalCleanupIssue[\"step\"], action: Effect.Effect<A, E>) =>\n action.pipe(\n Effect.interruptible,\n Effect.timeoutOrElse({\n duration: 3000,\n orElse: () => Effect.fail(LocalCleanupIssue.make({ step: name, reason: \"timeout\" })),\n }),\n Effect.exit,\n Effect.tap((exit) =>\n Effect.sync(() => {\n if (Exit.isSuccess(exit)) return;\n const error = Cause.findErrorOption(exit.cause);\n\n issues.push(\n LocalCleanupIssue.make({\n step: name,\n reason:\n Option.isSome(error) && error.value instanceof LocalCleanupIssue\n ? error.value.reason\n : Cause.hasInterrupts(exit.cause)\n ? \"interrupted\"\n : \"failed\",\n }),\n );\n }),\n ),\n );\n\n yield* step(\"fence\", local.fence);\n yield* step(\"capture\", local.capture);\n yield* step(\"initialization\", local.initialization);\n const disconnected = yield* step(\"disconnect\", local.disconnect);\n\n const terminated =\n process === undefined ? undefined : yield* step(\"terminate\", process.terminate);\n\n if (process !== undefined && terminated !== undefined && Exit.isSuccess(terminated))\n yield* step(\"profile\", process.removeProfile);\n\n const result = LocalCleanupResult.make({\n reference,\n ownership: process === undefined ? \"borrowed\" : \"owned\",\n connection: Exit.isSuccess(disconnected) ? disconnected.value : \"failed\",\n process:\n terminated === undefined\n ? \"not-owned\"\n : Exit.isSuccess(terminated)\n ? \"terminated\"\n : \"unknown\",\n issues,\n });\n\n Object.freeze(result.issues);\n latest = Object.freeze(result);\n\n return latest;\n }),\n ),\n );\n\n return { close, result: Effect.sync(() => Option.fromNullishOr(latest)) };\n});\n\nconst acquireLocal =\n (\n endpoint: Redacted.Redacted<string> | undefined,\n options: LocalLaunch,\n onCleanup?: (result: LocalCleanupResult) => Effect.Effect<void>,\n ): RemoteSource<LocalLease, BrowserError, never> =>\n (local) =>\n Effect.uninterruptible(\n Effect.gen(function* () {\n // The process cannot escape between spawn and finalizer registration. Startup waiting happens\n // later in connect, where it is interruptible and the owning finalizer is already installed.\n const process = endpoint === undefined ? yield* launch(options) : undefined;\n\n const reference = Object.freeze(\n LocalReference.make({ provider: \"local\", id: globalThis.crypto.randomUUID() }),\n );\n\n const cleanup = yield* makeLocalCleanup(reference, local, process);\n let closing = false;\n\n const release = yield* Effect.cached(\n Effect.gen(function* () {\n closing = true;\n const result = yield* cleanup.close;\n\n if (onCleanup !== undefined) yield* reported(onCleanup(result));\n\n return result;\n }).pipe(Effect.uninterruptible),\n );\n\n yield* Effect.addFinalizer(() => release.pipe(Effect.asVoid));\n\n return {\n reference,\n connection: (timeoutMillis) =>\n Effect.suspend(() => {\n if (closing)\n return Effect.fail(\n BrowserError.make({\n operation: \"connect\",\n reason: \"closed\",\n outcome: \"undispatched\",\n }),\n );\n if (process !== undefined) return process.connection(timeoutMillis);\n\n return endpoint === undefined\n ? Effect.fail(\n BrowserError.make({\n operation: \"connect\",\n reason: \"configuration\",\n outcome: \"undispatched\",\n }),\n )\n : checked(LocalEndpoint, Redacted.value(endpoint), \"connect\").pipe(\n Effect.map(Redacted.make),\n );\n }),\n release,\n cleanupResult: cleanup.result,\n } satisfies LocalLease;\n }),\n );\n\nexport const ownedLocal = (\n options: LocalLaunch,\n onCleanup?: (result: LocalCleanupResult) => Effect.Effect<void>,\n) => acquireLocal(undefined, options, onCleanup);\n\nexport const borrowedLocal = (\n endpoint: Redacted.Redacted<string>,\n onCleanup?: (result: LocalCleanupResult) => Effect.Effect<void>,\n) => acquireLocal(endpoint, {}, onCleanup);\n","import { Context, Effect, Layer, type Option, Redacted, Scope } from \"effect\";\n\nimport * as Bootstrap from \"./Bootstrap.ts\";\nimport type { BrowserSession, OpenOptions } from \"./Browser.ts\";\nimport { AutomationOptions, BrowserPolicy, Viewport } from \"./BrowserData.ts\";\nimport { BrowserError, type InitializationError } from \"./Errors.ts\";\nimport { makeBindings, preparePlan } from \"./internal/browser/Bindings.ts\";\nimport { compileBootstrap } from \"./internal/browser/Bootstrap.ts\";\nimport type { DriverOptions } from \"./internal/browser/Driver.ts\";\nimport type { LocalCleanupResult } from \"./internal/browser/LocalData.ts\";\nimport { LocalEndpoint, LocalLaunch, type LocalReference } from \"./internal/browser/LocalData.ts\";\nimport { borrowedLocal, localEngine, ownedLocal } from \"./internal/browser/LocalSession.ts\";\nimport { checked, makeSession } from \"./internal/browser/PublicSession.ts\";\nimport { acquireSession } from \"./internal/browser/Session.ts\";\nimport { Identifier } from \"./References.ts\";\n\nexport {\n LocalCleanupIssue,\n LocalCleanupResult,\n LocalLaunch,\n LocalReference,\n} from \"./internal/browser/LocalData.ts\";\n\n/** Host-only process configuration. Building this layer neither loads Playwright nor starts Chromium. */\nexport interface LocalBrowserOptions extends AutomationOptions {\n readonly launch?: LocalLaunch;\n readonly viewport?: Viewport;\n readonly onCleanup?: (result: LocalCleanupResult) => Effect.Effect<void>;\n}\n\n/** A local lifetime has modeled browser authority, never Browserbase resource or release authority. */\nexport interface LocalSession<E = never> extends BrowserSession<E> {\n readonly reference: LocalReference;\n readonly close: Effect.Effect<LocalCleanupResult>;\n readonly cleanupResult: Effect.Effect<Option.Option<LocalCleanupResult>>;\n}\n\nexport interface LocalAcquisition<E = never> {\n readonly reference: LocalReference;\n readonly failure: Effect.Effect<never, E | InitializationError>;\n readonly connect: Effect.Effect<LocalSession<E>, BrowserError | InitializationError | E>;\n readonly close: Effect.Effect<LocalCleanupResult>;\n}\n\nexport interface LocalAttachRequest<E = never, R = never> extends OpenOptions<E, R> {\n readonly policy: BrowserPolicy;\n /** Resolve this exact target; without it, multiple open pages are an ambiguity error. */\n readonly target?: { readonly targetId: string };\n}\n\nexport class LocalBrowser extends Context.Service<\n LocalBrowser,\n {\n readonly acquire: <E = never, R = never>(\n policy: BrowserPolicy,\n request?: OpenOptions<E, R>,\n ) => Effect.Effect<LocalAcquisition<E>, BrowserError, Scope.Scope | Exclude<R, Scope.Scope>>;\n readonly open: <E = never, R = never>(\n policy: BrowserPolicy,\n request?: OpenOptions<E, R>,\n ) => Effect.Effect<\n LocalSession<E>,\n BrowserError | InitializationError | E,\n Scope.Scope | Exclude<R, Scope.Scope>\n >;\n /** A concrete loopback ws://.../devtools/browser/... endpoint; this scope owns only its connection. */\n readonly attach: <E = never, R = never>(\n endpoint: Redacted.Redacted<string>,\n request: LocalAttachRequest<E, R>,\n ) => Effect.Effect<\n LocalSession<E>,\n BrowserError | InitializationError | E,\n Scope.Scope | Exclude<R, Scope.Scope>\n >;\n readonly withBrowser: <E, R, A, E2, R2>(\n policy: BrowserPolicy,\n request: OpenOptions<E, R>,\n use: (session: LocalSession<E>) => Effect.Effect<A, E2, R2>,\n ) => Effect.Effect<\n A,\n BrowserError | InitializationError | E | E2,\n Exclude<R | R2, Scope.Scope>\n >;\n }\n>()(\"effect-browserbase/LocalBrowser\") {\n static layer(options: LocalBrowserOptions = {}): Layer.Layer<LocalBrowser, BrowserError> {\n return Layer.effect(\n LocalBrowser,\n Effect.gen(function* () {\n const automation = yield* checked(\n AutomationOptions,\n {\n ...(options.actionTimeoutMillis === undefined\n ? {}\n : { actionTimeoutMillis: options.actionTimeoutMillis }),\n ...(options.maxPages === undefined ? {} : { maxPages: options.maxPages }),\n ...(options.initialPage === undefined ? {} : { initialPage: options.initialPage }),\n ...(options.popupPolicy === undefined ? {} : { popupPolicy: options.popupPolicy }),\n ...(options.dialogPolicy === undefined ? {} : { dialogPolicy: options.dialogPolicy }),\n ...(options.pageControl === undefined ? {} : { pageControl: options.pageControl }),\n },\n \"configure\",\n );\n\n const launchInput = yield* checked(LocalLaunch, options.launch ?? {}, \"configure\");\n\n const launch = Object.freeze({\n ...launchInput,\n ...(launchInput.args === undefined ? {} : { args: Object.freeze([...launchInput.args]) }),\n ...(launchInput.proxy === undefined\n ? {}\n : { proxy: Object.freeze({ ...launchInput.proxy }) }),\n });\n\n const viewport = yield* checked(\n Viewport,\n options.viewport ?? { width: 1280, height: 720 },\n \"configure\",\n );\n\n const pageControl = automation.pageControl ?? false;\n const popupPolicy = automation.popupPolicy ?? \"retain\";\n const dialogPolicy = automation.dialogPolicy ?? \"dismiss\";\n\n if (pageControl && (popupPolicy === \"pause\" || dialogPolicy === \"pause\"))\n return yield* BrowserError.make({\n operation: \"configure\",\n reason: \"unsupported\",\n outcome: \"undispatched\",\n });\n if (Object.prototype.hasOwnProperty.call(options, \"bootstrap\"))\n return yield* BrowserError.make({\n operation: \"configure\",\n reason: \"configuration\",\n outcome: \"undispatched\",\n });\n\n const driver: DriverOptions = {\n viewport,\n pageControl,\n popupPolicy,\n dialogPolicy,\n maxPages: automation.maxPages ?? 10,\n };\n\n const acquire = Effect.fnUntraced(function* <E = never, R = never>(\n policy: BrowserPolicy,\n request: OpenOptions<E, R> = {},\n attachment?: { readonly endpoint: Redacted.Redacted<string>; readonly targetId?: string },\n ) {\n const fixed = yield* checked(BrowserPolicy, policy, \"configure\");\n const plan = yield* preparePlan<E, R>(request.bootstrap ?? Bootstrap.empty);\n const scope = yield* Scope.fork(yield* Scope.Scope, \"sequential\");\n const bindings = yield* makeBindings(plan).pipe(Scope.provide(scope));\n const bootstrap = compileBootstrap(plan);\n\n const selection =\n attachment !== undefined\n ? {\n newPage: false,\n preserveViewport: true,\n ...(attachment.targetId === undefined\n ? {}\n : { initialTargetId: attachment.targetId }),\n }\n : automation.initialPage === undefined\n ? {}\n : \"targetId\" in automation.initialPage\n ? { initialTargetId: automation.initialPage.targetId }\n : { newPage: true };\n\n const acquired = yield* acquireSession(\n {\n maxActions: fixed.maxActions,\n maxElapsedMillis: fixed.maxElapsedMillis,\n actionTimeoutMillis: automation.actionTimeoutMillis ?? 10000,\n },\n {\n remote:\n attachment === undefined\n ? ownedLocal(launch, options.onCleanup)\n : borrowedLocal(attachment.endpoint, options.onCleanup),\n engine: localEngine,\n keepAlive: false,\n driver: {\n ...driver,\n ...selection,\n ...(bootstrap === undefined ? {} : { bootstrap }),\n },\n connectBindings: bindings.connect,\n maxReturnedBytes: fixed.maxReturnedBytes,\n },\n ).pipe(Scope.provide(scope));\n\n const connected = yield* Effect.cached(\n acquired.connect.pipe(\n Effect.map((controls): LocalSession<E> =>\n Object.assign(makeSession(controls, bindings), {\n reference: controls.reference,\n close: controls.close,\n cleanupResult: controls.cleanupResult,\n }),\n ),\n ),\n );\n\n return {\n reference: acquired.reference,\n failure: bindings.failure,\n close: acquired.close,\n connect: Effect.raceFirst(\n bindings.failure,\n acquired.connect.pipe(Effect.andThen(connected)),\n ).pipe(Effect.onError(() => acquired.close.pipe(Effect.asVoid))),\n } satisfies LocalAcquisition<E>;\n });\n\n return LocalBrowser.of({\n acquire,\n open: (policy, request) =>\n acquire(policy, request).pipe(Effect.flatMap((acquired) => acquired.connect)),\n attach: (endpoint, request) =>\n Effect.gen(function* () {\n const address = yield* checked(LocalEndpoint, Redacted.value(endpoint), \"connect\");\n\n const targetId =\n request.target === undefined\n ? undefined\n : yield* checked(Identifier, request.target.targetId, \"configure\");\n\n return yield* (yield* acquire(request.policy, request, {\n endpoint: Redacted.make(address),\n ...(targetId === undefined ? {} : { targetId }),\n })).connect;\n }),\n withBrowser: (policy, request, use) =>\n Effect.scoped(\n Effect.gen(function* () {\n const session = yield* (yield* acquire(policy, request)).connect;\n\n const result = yield* Effect.raceFirst(\n session.failure,\n Effect.suspend(() => use(session)),\n );\n\n const cleanup = yield* session.close;\n\n if (\n cleanup.connection !== \"closed\" ||\n cleanup.process !== \"terminated\" ||\n cleanup.issues.length > 0\n )\n return yield* BrowserError.make({\n operation: \"close\",\n reason: \"failed\",\n outcome: \"unknown\",\n });\n\n return result;\n }),\n ),\n });\n }),\n );\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { c as LocalCleanupResult, i as LocalBrowserOptions, l as LocalLaunch, n as LocalAttachRequest, o as LocalSession, r as LocalBrowser, s as LocalCleanupIssue, t as LocalAcquisition, u as LocalReference } from "./LocalBrowser-BLancJ3R.mjs";
2
+ export { LocalAcquisition, LocalAttachRequest, LocalBrowser, LocalBrowserOptions, LocalCleanupIssue, LocalCleanupResult, LocalLaunch, LocalReference, LocalSession };
@@ -0,0 +1,2 @@
1
+ import { a as LocalLaunch, i as LocalCleanupResult, o as LocalReference, r as LocalCleanupIssue, t as LocalBrowser } from "./LocalBrowser-DsQLWNL1.mjs";
2
+ export { LocalBrowser, LocalCleanupIssue, LocalCleanupResult, LocalLaunch, LocalReference };
@@ -1,16 +1,16 @@
1
1
  import { BrowserError } from "./Errors.mjs";
2
2
  import { D as PageSuspension, E as PageInfo, T as PageExecutionState } from "./BrowserData-LpcAuAub.mjs";
3
- import { BrowserbaseSession } from "./Browser.mjs";
3
+ import { BrowserSession } from "./Browser.mjs";
4
4
  import { Effect } from "effect";
5
5
  declare namespace PageControl_d_exports {
6
6
  export { PageExecutionState, PageSuspension, resume, state, suspend };
7
7
  }
8
8
  /** Last acknowledged state; no remote guarantee survives connection loss or external control. */
9
- export declare const state: <E>(session: BrowserbaseSession<E>, page: PageInfo) => Effect.Effect<PageExecutionState, BrowserError>;
9
+ export declare const state: <E>(session: BrowserSession<E>, page: PageInfo) => Effect.Effect<PageExecutionState, BrowserError>;
10
10
  /** Explicit host-only hold requiring InteractiveOptions.pageControl; capture ACKs never invoke it. */
11
- export declare const suspend: <E>(session: BrowserbaseSession<E>, page: PageInfo) => Effect.Effect<PageSuspension, BrowserError>;
11
+ export declare const suspend: <E>(session: BrowserSession<E>, page: PageInfo) => Effect.Effect<PageSuspension, BrowserError>;
12
12
  /** Consumes the exact live receipt. Activation is intentional; stale receipts never replay commands. */
13
- export declare const resume: <E>(session: BrowserbaseSession<E>, receipt: PageSuspension) => Effect.Effect<void, BrowserError>;
13
+ export declare const resume: <E>(session: BrowserSession<E>, receipt: PageSuspension) => Effect.Effect<void, BrowserError>;
14
14
  //#endregion
15
15
  export { PageExecutionState, PageSuspension, PageControl_d_exports as t };
16
16
  //# sourceMappingURL=PageControl.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PageControl.mjs","names":[],"sources":["../src/PageControl.ts"],"sourcesContent":["import { Effect, Schema } from \"effect\";\n\nimport type { BrowserbaseSession } from \"./Browser.ts\";\nimport { type PageExecutionState, PageInfo, PageSuspension } from \"./BrowserData.ts\";\nimport { BrowserError } from \"./Errors.ts\";\nimport { pageControl } from \"./internal/browser/PageControlAssociation.ts\";\nexport { PageExecutionState, PageSuspension } from \"./BrowserData.ts\";\n\nconst owner = <E>(session: BrowserbaseSession<E>) =>\n Effect.suspend(() => {\n const port = pageControl(session);\n\n return port === undefined\n ? Effect.fail(\n BrowserError.make({\n operation: \"page-control\",\n reason: \"unsupported\",\n outcome: \"undispatched\",\n }),\n )\n : Effect.succeed(port);\n });\n\nconst invalid = () =>\n BrowserError.make({\n operation: \"page-control\",\n reason: \"configuration\",\n outcome: \"undispatched\",\n });\n\n/** Last acknowledged state; no remote guarantee survives connection loss or external control. */\nexport const state = <E>(\n session: BrowserbaseSession<E>,\n page: PageInfo,\n): Effect.Effect<PageExecutionState, BrowserError> =>\n Schema.decodeEffect(PageInfo)(page).pipe(\n Effect.mapError(invalid),\n Effect.map((value) => Object.freeze(PageInfo.make({ ...value }))),\n Effect.flatMap((value) => owner(session).pipe(Effect.flatMap((port) => port.state(value)))),\n );\n\n/** Explicit host-only hold requiring InteractiveOptions.pageControl; capture ACKs never invoke it. */\nexport const suspend = <E>(\n session: BrowserbaseSession<E>,\n page: PageInfo,\n): Effect.Effect<PageSuspension, BrowserError> =>\n Schema.decodeEffect(PageInfo)(page).pipe(\n Effect.mapError(invalid),\n Effect.map((value) => Object.freeze(PageInfo.make({ ...value }))),\n Effect.flatMap((value) => owner(session).pipe(Effect.flatMap((port) => port.suspend(value)))),\n );\n\n/** Consumes the exact live receipt. Activation is intentional; stale receipts never replay commands. */\nexport const resume = <E>(\n session: BrowserbaseSession<E>,\n receipt: PageSuspension,\n): Effect.Effect<void, BrowserError> =>\n Schema.decodeEffect(PageSuspension)(receipt).pipe(\n Effect.mapError(invalid),\n Effect.map((value) => Object.freeze(PageSuspension.make({ ...value }))),\n Effect.flatMap((value) => owner(session).pipe(Effect.flatMap((port) => port.resume(value)))),\n );\n"],"mappings":";;;;;;;;;;;;;AAQA,MAAM,SAAY,YAChB,OAAO,cAAc;CACnB,MAAM,OAAO,YAAY,OAAO;CAEhC,OAAO,SAAS,KAAA,IACZ,OAAO,KACL,aAAa,KAAK;EAChB,WAAW;EACX,QAAQ;EACR,SAAS;CACX,CAAC,CACH,IACA,OAAO,QAAQ,IAAI;AACzB,CAAC;AAEH,MAAM,gBACJ,aAAa,KAAK;CAChB,WAAW;CACX,QAAQ;CACR,SAAS;AACX,CAAC;;AAGH,MAAa,SACX,SACA,SAEA,OAAO,aAAa,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,KAClC,OAAO,SAAS,OAAO,GACvB,OAAO,KAAK,UAAU,OAAO,OAAO,SAAS,KAAK,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,GAChE,OAAO,SAAS,UAAU,MAAM,OAAO,CAAC,CAAC,KAAK,OAAO,SAAS,SAAS,KAAK,MAAM,KAAK,CAAC,CAAC,CAAC,CAC5F;;AAGF,MAAa,WACX,SACA,SAEA,OAAO,aAAa,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,KAClC,OAAO,SAAS,OAAO,GACvB,OAAO,KAAK,UAAU,OAAO,OAAO,SAAS,KAAK,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,GAChE,OAAO,SAAS,UAAU,MAAM,OAAO,CAAC,CAAC,KAAK,OAAO,SAAS,SAAS,KAAK,QAAQ,KAAK,CAAC,CAAC,CAAC,CAC9F;;AAGF,MAAa,UACX,SACA,YAEA,OAAO,aAAa,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,KAC3C,OAAO,SAAS,OAAO,GACvB,OAAO,KAAK,UAAU,OAAO,OAAO,eAAe,KAAK,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,GACtE,OAAO,SAAS,UAAU,MAAM,OAAO,CAAC,CAAC,KAAK,OAAO,SAAS,SAAS,KAAK,OAAO,KAAK,CAAC,CAAC,CAAC,CAC7F"}
1
+ {"version":3,"file":"PageControl.mjs","names":[],"sources":["../src/PageControl.ts"],"sourcesContent":["import { Effect, Schema } from \"effect\";\n\nimport type { BrowserSession } from \"./Browser.ts\";\nimport { type PageExecutionState, PageInfo, PageSuspension } from \"./BrowserData.ts\";\nimport { BrowserError } from \"./Errors.ts\";\nimport { pageControl } from \"./internal/browser/PageControlAssociation.ts\";\nexport { PageExecutionState, PageSuspension } from \"./BrowserData.ts\";\n\nconst owner = <E>(session: BrowserSession<E>) =>\n Effect.suspend(() => {\n const port = pageControl(session);\n\n return port === undefined\n ? Effect.fail(\n BrowserError.make({\n operation: \"page-control\",\n reason: \"unsupported\",\n outcome: \"undispatched\",\n }),\n )\n : Effect.succeed(port);\n });\n\nconst invalid = () =>\n BrowserError.make({\n operation: \"page-control\",\n reason: \"configuration\",\n outcome: \"undispatched\",\n });\n\n/** Last acknowledged state; no remote guarantee survives connection loss or external control. */\nexport const state = <E>(\n session: BrowserSession<E>,\n page: PageInfo,\n): Effect.Effect<PageExecutionState, BrowserError> =>\n Schema.decodeEffect(PageInfo)(page).pipe(\n Effect.mapError(invalid),\n Effect.map((value) => Object.freeze(PageInfo.make({ ...value }))),\n Effect.flatMap((value) => owner(session).pipe(Effect.flatMap((port) => port.state(value)))),\n );\n\n/** Explicit host-only hold requiring InteractiveOptions.pageControl; capture ACKs never invoke it. */\nexport const suspend = <E>(\n session: BrowserSession<E>,\n page: PageInfo,\n): Effect.Effect<PageSuspension, BrowserError> =>\n Schema.decodeEffect(PageInfo)(page).pipe(\n Effect.mapError(invalid),\n Effect.map((value) => Object.freeze(PageInfo.make({ ...value }))),\n Effect.flatMap((value) => owner(session).pipe(Effect.flatMap((port) => port.suspend(value)))),\n );\n\n/** Consumes the exact live receipt. Activation is intentional; stale receipts never replay commands. */\nexport const resume = <E>(\n session: BrowserSession<E>,\n receipt: PageSuspension,\n): Effect.Effect<void, BrowserError> =>\n Schema.decodeEffect(PageSuspension)(receipt).pipe(\n Effect.mapError(invalid),\n Effect.map((value) => Object.freeze(PageSuspension.make({ ...value }))),\n Effect.flatMap((value) => owner(session).pipe(Effect.flatMap((port) => port.resume(value)))),\n );\n"],"mappings":";;;;;;;;;;;;;AAQA,MAAM,SAAY,YAChB,OAAO,cAAc;CACnB,MAAM,OAAO,YAAY,OAAO;CAEhC,OAAO,SAAS,KAAA,IACZ,OAAO,KACL,aAAa,KAAK;EAChB,WAAW;EACX,QAAQ;EACR,SAAS;CACX,CAAC,CACH,IACA,OAAO,QAAQ,IAAI;AACzB,CAAC;AAEH,MAAM,gBACJ,aAAa,KAAK;CAChB,WAAW;CACX,QAAQ;CACR,SAAS;AACX,CAAC;;AAGH,MAAa,SACX,SACA,SAEA,OAAO,aAAa,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,KAClC,OAAO,SAAS,OAAO,GACvB,OAAO,KAAK,UAAU,OAAO,OAAO,SAAS,KAAK,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,GAChE,OAAO,SAAS,UAAU,MAAM,OAAO,CAAC,CAAC,KAAK,OAAO,SAAS,SAAS,KAAK,MAAM,KAAK,CAAC,CAAC,CAAC,CAC5F;;AAGF,MAAa,WACX,SACA,SAEA,OAAO,aAAa,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,KAClC,OAAO,SAAS,OAAO,GACvB,OAAO,KAAK,UAAU,OAAO,OAAO,SAAS,KAAK,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,GAChE,OAAO,SAAS,UAAU,MAAM,OAAO,CAAC,CAAC,KAAK,OAAO,SAAS,SAAS,KAAK,QAAQ,KAAK,CAAC,CAAC,CAAC,CAC9F;;AAGF,MAAa,UACX,SACA,YAEA,OAAO,aAAa,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,KAC3C,OAAO,SAAS,OAAO,GACvB,OAAO,KAAK,UAAU,OAAO,OAAO,eAAe,KAAK,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,GACtE,OAAO,SAAS,UAAU,MAAM,OAAO,CAAC,CAAC,KAAK,OAAO,SAAS,SAAS,KAAK,OAAO,KAAK,CAAC,CAAC,CAAC,CAC7F"}