effect-browser 0.2.0-beta.9 → 0.3.0-beta.10
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.
- package/README.md +849 -1161
- package/dist/Browser-S4kvpmqa.mjs +605 -0
- package/dist/Browser-S4kvpmqa.mjs.map +1 -0
- package/dist/Browser.d.mts +127 -3
- package/dist/Browser.mjs +2 -22
- package/dist/BrowserError-Coy7EW1N.d.mts +140 -0
- package/dist/BrowserError.d.mts +2 -0
- package/dist/BrowserError.mjs +211 -0
- package/dist/BrowserError.mjs.map +1 -0
- package/dist/BrowserEvent-BRu2juEz.d.mts +279 -0
- package/dist/BrowserEvent.d.mts +2 -0
- package/dist/BrowserEvent.mjs +297 -0
- package/dist/BrowserEvent.mjs.map +1 -0
- package/dist/Cdp.d.mts +32 -0
- package/dist/Cdp.mjs +61 -0
- package/dist/Cdp.mjs.map +1 -0
- package/dist/Change-DNvztNLu.mjs +138 -0
- package/dist/Change-DNvztNLu.mjs.map +1 -0
- package/dist/Change-iMlcuzVD.d.mts +71 -0
- package/dist/Change.d.mts +2 -0
- package/dist/Change.mjs +2 -0
- package/dist/Chromium.d.mts +29 -81
- package/dist/Chromium.mjs +57 -392
- package/dist/Chromium.mjs.map +1 -1
- package/dist/Expect.d.mts +62 -0
- package/dist/Expect.mjs +114 -0
- package/dist/Expect.mjs.map +1 -0
- package/dist/Frame-BERmf_gM.d.mts +117 -0
- package/dist/Frame.d.mts +2 -0
- package/dist/Frame.mjs +123 -0
- package/dist/Frame.mjs.map +1 -0
- package/dist/Moment.d.mts +2 -0
- package/dist/Moment.mjs +288 -0
- package/dist/Moment.mjs.map +1 -0
- package/dist/Motion.d.mts +40 -0
- package/dist/Motion.mjs +122 -0
- package/dist/Motion.mjs.map +1 -0
- package/dist/Page-B5cjaUp5.mjs +618 -0
- package/dist/Page-B5cjaUp5.mjs.map +1 -0
- package/dist/Page-BlPjfibv.d.mts +595 -0
- package/dist/Page.d.mts +2 -0
- package/dist/Page.mjs +2 -0
- package/dist/Plan-BI8XGvDu.d.mts +209 -0
- package/dist/Plan-D1wrJVs8.mjs +508 -0
- package/dist/Plan-D1wrJVs8.mjs.map +1 -0
- package/dist/Plan.d.mts +2 -3
- package/dist/Plan.mjs +2 -2
- package/dist/Policy.d.mts +76 -0
- package/dist/Policy.mjs +237 -0
- package/dist/Policy.mjs.map +1 -0
- package/dist/Presentation.d.mts +48 -0
- package/dist/Presentation.mjs +117 -0
- package/dist/Presentation.mjs.map +1 -0
- package/dist/Snapshot-B34hZ4Jl.d.mts +68 -0
- package/dist/Snapshot.d.mts +2 -0
- package/dist/Snapshot.mjs +79 -0
- package/dist/Snapshot.mjs.map +1 -0
- package/dist/Stage.d.mts +64 -0
- package/dist/Stage.mjs +237 -0
- package/dist/Stage.mjs.map +1 -0
- package/dist/Supervisor-CYWFK3vM.d.mts +280 -0
- package/dist/Supervisor-TNKNOVzu.mjs +599 -0
- package/dist/Supervisor-TNKNOVzu.mjs.map +1 -0
- package/dist/Supervisor.d.mts +2 -0
- package/dist/Supervisor.mjs +2 -0
- package/dist/context-B6xr8nVi.mjs +261 -0
- package/dist/context-B6xr8nVi.mjs.map +1 -0
- package/dist/index.d.mts +17 -14
- package/dist/index.mjs +18 -13
- package/dist/match.inpage-xOe9LNO0.mjs +48 -0
- package/dist/match.inpage-xOe9LNO0.mjs.map +1 -0
- package/dist/page-B8tUQELg.mjs +5073 -0
- package/dist/page-B8tUQELg.mjs.map +1 -0
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/dist/url-Cd04Okid.mjs +264 -0
- package/dist/url-Cd04Okid.mjs.map +1 -0
- package/package.json +96 -61
- package/src/Browser.ts +666 -0
- package/src/BrowserError.ts +234 -0
- package/src/BrowserEvent.ts +296 -0
- package/src/Cdp.ts +101 -0
- package/src/Change.ts +88 -0
- package/src/Chromium.ts +102 -0
- package/src/Expect.ts +180 -0
- package/src/Frame.ts +130 -0
- package/src/Moment.ts +479 -0
- package/src/Motion.ts +166 -0
- package/src/Page.ts +522 -0
- package/src/Plan.ts +663 -0
- package/src/Policy.ts +325 -0
- package/src/Presentation.ts +195 -0
- package/src/Snapshot.ts +89 -0
- package/src/Stage.ts +467 -0
- package/src/Supervisor.ts +599 -0
- package/src/index.ts +20 -0
- package/src/internal/input/actions.ts +610 -0
- package/src/internal/input/dispatch.ts +161 -0
- package/src/internal/input/edit.inpage.ts +162 -0
- package/src/internal/input/evidence.inpage.ts +164 -0
- package/src/internal/input/gate.ts +224 -0
- package/src/internal/input/guard.inpage.ts +605 -0
- package/src/internal/input/guard.ts +184 -0
- package/src/internal/input/keyboard.ts +112 -0
- package/src/internal/input/keys.ts +127 -0
- package/src/internal/input/perform.ts +376 -0
- package/src/internal/input/pointer.ts +153 -0
- package/src/internal/input/replies.ts +195 -0
- package/src/internal/input/settle.ts +50 -0
- package/src/internal/input/style.ts +186 -0
- package/src/internal/input/targets.inpage.ts +293 -0
- package/src/internal/input/targets.ts +148 -0
- package/src/internal/page/bridge.ts +386 -0
- package/src/internal/page/context.ts +312 -0
- package/src/internal/page/lane.ts +311 -0
- package/src/internal/page/navigation.ts +183 -0
- package/src/internal/page/openings.ts +87 -0
- package/src/internal/page/page.ts +165 -0
- package/src/internal/page/url.ts +100 -0
- package/src/internal/page/viewport.ts +43 -0
- package/src/internal/pictures/capture.ts +776 -0
- package/src/internal/pictures/clock.ts +141 -0
- package/src/internal/pictures/counts.ts +92 -0
- package/src/internal/pictures/pictures.ts +520 -0
- package/src/internal/pictures/transport.ts +242 -0
- package/src/internal/reading/choose.ts +100 -0
- package/src/internal/reading/context.inpage.ts +201 -0
- package/src/internal/reading/controls.inpage.ts +158 -0
- package/src/internal/reading/expect.inpage.ts +70 -0
- package/src/internal/reading/match.inpage.ts +92 -0
- package/src/internal/reading/names.inpage.ts +306 -0
- package/src/internal/reading/outline.inpage.ts +260 -0
- package/src/internal/reading/reading.ts +223 -0
- package/src/internal/reading/ready.inpage.ts +164 -0
- package/src/internal/reading/ready.ts +111 -0
- package/src/internal/reading/subjects.inpage.ts +188 -0
- package/src/internal/reading/text.inpage.ts +135 -0
- package/src/internal/reading/walk.inpage.ts +220 -0
- package/src/internal/supervisor/lifecycle.ts +416 -0
- package/src/internal/timeline/changes.inpage.ts +216 -0
- package/src/internal/timeline/changes.ts +100 -0
- package/src/internal/timeline/events.ts +94 -0
- package/src/internal/timeline/fold.inpage.ts +123 -0
- package/src/internal/timeline/history.inpage.ts +229 -0
- package/src/internal/timeline/marks.inpage.ts +207 -0
- package/src/internal/timeline/record.inpage.ts +133 -0
- package/src/internal/timeline/sight.inpage.ts +122 -0
- package/src/internal/timeline/window.ts +96 -0
- package/src/internal/timeline/words.ts +65 -0
- package/dist/Bootstrap-B9UUXsvF.d.mts +0 -183
- package/dist/Bootstrap-CeQOWBy6.mjs +0 -189
- package/dist/Bootstrap-CeQOWBy6.mjs.map +0 -1
- package/dist/Bootstrap.d.mts +0 -3
- package/dist/Bootstrap.mjs +0 -2
- package/dist/Browser-BF9_sORP.d.mts +0 -388
- package/dist/Browser.mjs.map +0 -1
- package/dist/BrowserData-CPIIIHol.d.mts +0 -585
- package/dist/BrowserData.d.mts +0 -3
- package/dist/BrowserData.mjs +0 -695
- package/dist/BrowserData.mjs.map +0 -1
- package/dist/BrowserRuntime-B6nT1G4X.d.mts +0 -148
- package/dist/BrowserRuntime-C1r2aSRK.mjs +0 -6820
- package/dist/BrowserRuntime-C1r2aSRK.mjs.map +0 -1
- package/dist/BrowserRuntime.d.mts +0 -3
- package/dist/BrowserRuntime.mjs +0 -3
- package/dist/Capture.d.mts +0 -56
- package/dist/Capture.mjs +0 -678
- package/dist/Capture.mjs.map +0 -1
- package/dist/CaptureData-CYriZHX1.mjs +0 -201
- package/dist/CaptureData-CYriZHX1.mjs.map +0 -1
- package/dist/CaptureData.d.mts +0 -219
- package/dist/CaptureData.mjs +0 -2
- package/dist/Errors.d.mts +0 -158
- package/dist/Errors.mjs +0 -207
- package/dist/Errors.mjs.map +0 -1
- package/dist/Images-yCG9BmRU.mjs +0 -76
- package/dist/Images-yCG9BmRU.mjs.map +0 -1
- package/dist/OperationOptions-DAeRS6O9.mjs +0 -55
- package/dist/OperationOptions-DAeRS6O9.mjs.map +0 -1
- package/dist/PageControl.d.mts +0 -15
- package/dist/PageControl.mjs +0 -34
- package/dist/PageControl.mjs.map +0 -1
- package/dist/PageRegistry-B3q9DS3g.mjs +0 -164
- package/dist/PageRegistry-B3q9DS3g.mjs.map +0 -1
- package/dist/Plan-Dyxu2q8C.mjs +0 -543
- package/dist/Plan-Dyxu2q8C.mjs.map +0 -1
- package/dist/PlanData-B668RxbQ.d.mts +0 -4831
- package/dist/PlanData.d.mts +0 -3
- package/dist/PlanData.mjs +0 -268
- package/dist/PlanData.mjs.map +0 -1
- package/dist/PlanInput-BJcPPncs.mjs +0 -75
- package/dist/PlanInput-BJcPPncs.mjs.map +0 -1
- package/dist/PublicSession-DCSMMqOj.mjs +0 -5602
- package/dist/PublicSession-DCSMMqOj.mjs.map +0 -1
- package/dist/Testing.d.mts +0 -479
- package/dist/Testing.mjs +0 -2147
- package/dist/Testing.mjs.map +0 -1
- package/dist/Timeline-fV22Xk-S.d.mts +0 -29
- package/dist/Timeline.d.mts +0 -4
- package/dist/Timeline.mjs +0 -20
- package/dist/Timeline.mjs.map +0 -1
- package/dist/TimelineData-BsOn-YGZ.d.mts +0 -3818
- package/dist/TimelineData.d.mts +0 -3
- package/dist/TimelineData.mjs +0 -482
- package/dist/TimelineData.mjs.map +0 -1
package/dist/Chromium.mjs
CHANGED
|
@@ -1,399 +1,64 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"profile"
|
|
23
|
-
]),
|
|
24
|
-
reason: Schema.Literals([
|
|
25
|
-
"timeout",
|
|
26
|
-
"failed",
|
|
27
|
-
"interrupted"
|
|
28
|
-
])
|
|
29
|
-
}) {};
|
|
30
|
-
/** Connection teardown and observed process exit are separate facts; no provider status exists. */
|
|
31
|
-
var ChromiumCleanupResult = class extends Schema.Class("ChromiumCleanupResult")({
|
|
32
|
-
reference: ChromiumReference,
|
|
33
|
-
ownership: Schema.Literals(["owned", "borrowed"]),
|
|
34
|
-
connection: Schema.Literals([
|
|
35
|
-
"closed",
|
|
36
|
-
"failed",
|
|
37
|
-
"not-connected",
|
|
38
|
-
"pending"
|
|
39
|
-
]),
|
|
40
|
-
process: Schema.Literals([
|
|
41
|
-
"terminated",
|
|
42
|
-
"unknown",
|
|
43
|
-
"not-owned"
|
|
44
|
-
]),
|
|
45
|
-
issues: Schema.Array(ChromiumCleanupIssue).check(Schema.isMaxLength(16))
|
|
46
|
-
}) {};
|
|
47
|
-
const Text = Schema.NonEmptyString.check(Schema.isMaxLength(4096), Schema.isPattern(/^[^\u0000\r\n]+$/u));
|
|
48
|
-
const Port = Schema.Int.check(Schema.isBetween({
|
|
49
|
-
minimum: 1,
|
|
50
|
-
maximum: 65535
|
|
51
|
-
}));
|
|
52
|
-
/** Only a concrete loopback WebSocket is admitted: no HTTP discovery redirects or remote DNS. */
|
|
53
|
-
const ChromiumEndpoint = Text.check(Schema.makeFilter((value) => {
|
|
54
|
-
try {
|
|
55
|
-
const url = new URL(value);
|
|
56
|
-
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);
|
|
57
|
-
} catch {
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
}));
|
|
61
|
-
const ProxyServer = Text.check(Schema.makeFilter((value) => {
|
|
62
|
-
try {
|
|
63
|
-
const url = new URL(value);
|
|
64
|
-
return [
|
|
65
|
-
"http:",
|
|
66
|
-
"https:",
|
|
67
|
-
"socks5:"
|
|
68
|
-
].includes(url.protocol) && url.hostname.length > 0 && !url.username && !url.password && !url.search && !url.hash && ["", "/"].includes(url.pathname);
|
|
69
|
-
} catch {
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
}));
|
|
73
|
-
/** These arguments belong to the launcher; silently overriding them would change ownership. */
|
|
74
|
-
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|no-startup-window)(?:=|$)/u.test(value)));
|
|
75
|
-
const ChromiumLaunch = Schema.Struct({
|
|
76
|
-
executablePath: Schema.optionalKey(Text),
|
|
77
|
-
headless: Schema.optionalKey(Schema.Boolean),
|
|
78
|
-
/** Enabled by default; a trusted host must explicitly choose a sandbox exception. */
|
|
79
|
-
chromiumSandbox: Schema.optionalKey(Schema.Boolean),
|
|
80
|
-
args: Schema.optionalKey(Schema.Array(Argument).check(Schema.isMaxLength(64))),
|
|
81
|
-
proxy: Schema.optionalKey(Schema.Struct({
|
|
82
|
-
server: ProxyServer,
|
|
83
|
-
bypass: Schema.optionalKey(Text)
|
|
84
|
-
})),
|
|
85
|
-
startupTimeoutMillis: Schema.optionalKey(Schema.Int.check(Schema.isBetween({
|
|
86
|
-
minimum: 1,
|
|
87
|
-
maximum: 6e4
|
|
88
|
-
})))
|
|
89
|
-
});
|
|
90
|
-
//#endregion
|
|
91
|
-
//#region src/internal/chromium/Process.ts
|
|
92
|
-
/** Explicit host sandbox/proxy choices; the owned profile and debugger endpoint cannot be replaced. */
|
|
93
|
-
const launchArguments = (options, directory) => [
|
|
94
|
-
"--no-first-run",
|
|
95
|
-
"--no-default-browser-check",
|
|
96
|
-
"--remote-debugging-address=127.0.0.1",
|
|
97
|
-
"--remote-debugging-port=0",
|
|
98
|
-
"--remote-debugging-pipe",
|
|
99
|
-
`--user-data-dir=${directory}`,
|
|
100
|
-
...options.headless === false ? [] : ["--headless=new"],
|
|
101
|
-
...options.chromiumSandbox === false ? ["--no-sandbox"] : [],
|
|
102
|
-
...options.proxy === void 0 ? [] : [`--proxy-server=${options.proxy.server}`, `--proxy-bypass-list=${options.proxy.bypass ?? "<-loopback>"}`],
|
|
103
|
-
...options.args ?? [],
|
|
104
|
-
"--no-startup-window"
|
|
105
|
-
];
|
|
106
|
-
const failure = (operation, reason) => BrowserError.make({
|
|
107
|
-
operation,
|
|
108
|
-
reason,
|
|
109
|
-
outcome: operation === "close" ? "unknown" : "undispatched"
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { Failed } from "./BrowserError.mjs";
|
|
3
|
+
import { i as make, t as Browser } from "./Browser-S4kvpmqa.mjs";
|
|
4
|
+
import { o as reasonOf, s as undispatched } from "./context-B6xr8nVi.mjs";
|
|
5
|
+
import { Effect, Layer } from "effect";
|
|
6
|
+
import { chromium } from "playwright-core";
|
|
7
|
+
//#region src/Chromium.ts
|
|
8
|
+
/**
|
|
9
|
+
* A local Chromium, launched for the scope and closed with it.
|
|
10
|
+
*
|
|
11
|
+
* It uses the Chromium build that `playwright-core` installs
|
|
12
|
+
* (`npx playwright-core install chromium`), unless `executablePath` names another.
|
|
13
|
+
*
|
|
14
|
+
* Signals are the program's to handle: run it with `NodeRuntime.runMain`, which interrupts it on
|
|
15
|
+
* SIGINT and SIGTERM, so the browser closes with its scope.
|
|
16
|
+
*
|
|
17
|
+
* @since 0.3.0
|
|
18
|
+
*/
|
|
19
|
+
var Chromium_exports = /* @__PURE__ */ __exportAll({
|
|
20
|
+
layer: () => layer,
|
|
21
|
+
open: () => open
|
|
110
22
|
});
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
/** Called once; observes parent and helper exit, rather than treating a sent signal as cleanup. */
|
|
130
|
-
const terminate = Effect.fnUntraced(function* (child, pid, clock) {
|
|
131
|
-
const stopped = Effect.try({
|
|
132
|
-
try: () => exited(child) && !alive(pid),
|
|
133
|
-
catch: () => failure("close", Reasons.Failed.make({}))
|
|
134
|
-
});
|
|
135
|
-
const signal = (value) => Effect.try({
|
|
136
|
-
try: () => signalGroup(pid, value),
|
|
137
|
-
catch: () => failure("close", Reasons.Failed.make({}))
|
|
138
|
-
});
|
|
139
|
-
const pause = clock.sleep(Duration.millis(20));
|
|
140
|
-
yield* signal("SIGTERM");
|
|
141
|
-
const graceful = clock.monotonicTimeNanosUnsafe() + 1500000000n;
|
|
142
|
-
while (!(yield* stopped) && clock.monotonicTimeNanosUnsafe() < graceful) yield* pause;
|
|
143
|
-
if (yield* stopped) return;
|
|
144
|
-
yield* signal("SIGKILL");
|
|
145
|
-
const forced = clock.monotonicTimeNanosUnsafe() + 1000000000n;
|
|
146
|
-
while (!(yield* stopped) && clock.monotonicTimeNanosUnsafe() < forced) yield* pause;
|
|
147
|
-
if (!(yield* stopped)) return yield* failure("close", Reasons.Timeout.make({}));
|
|
148
|
-
}, span("Chromium.terminate"));
|
|
149
|
-
/** Start only Chromium's process. The shared owner later opens its sole CDP connection. */
|
|
150
|
-
const launch = Effect.fnUntraced(function* (options) {
|
|
151
|
-
if (process.platform === "win32") return yield* failure("launch", Reasons.Unsupported.make({}));
|
|
152
|
-
const path = yield* Path.Path.pipe(Effect.provide(Path.layer));
|
|
153
|
-
const clock = yield* Clock.Clock;
|
|
154
|
-
const executable = options.executablePath ?? (yield* Effect.tryPromise({
|
|
155
|
-
try: () => import("playwright-core").then(({ chromium }) => chromium.executablePath()),
|
|
156
|
-
catch: () => failure("launch", Reasons.Failed.make({}))
|
|
157
|
-
}));
|
|
158
|
-
const directory = yield* Effect.tryPromise({
|
|
159
|
-
try: () => mkdtemp(path.join(tmpdir(), "effect-browser-chromium-")),
|
|
160
|
-
catch: () => failure("launch", Reasons.Failed.make({}))
|
|
161
|
-
});
|
|
162
|
-
const removeProfile = Effect.tryPromise({
|
|
163
|
-
try: () => rm(directory, {
|
|
164
|
-
recursive: true,
|
|
165
|
-
force: true,
|
|
166
|
-
maxRetries: 5,
|
|
167
|
-
retryDelay: 50
|
|
23
|
+
const launchTimeoutMillis = 18e4;
|
|
24
|
+
const failed = (operation, timeoutMillis) => (cause) => undispatched(operation, reasonOf(cause, timeoutMillis));
|
|
25
|
+
const sandboxFailed = /Chromium sandboxing failed|No usable sandbox/;
|
|
26
|
+
const launchFailed = (cause) => sandboxFailed.test(String(cause)) ? undispatched("launch", new Failed({ detail: "Chromium's sandbox could not start on this host: it needs unprivileged user namespaces, and a user other than root" })) : failed("launch", launchTimeoutMillis)(cause);
|
|
27
|
+
/** Launch Chromium and open a `Browser` over a fresh context. */
|
|
28
|
+
const open = Effect.fn("Chromium.open")(function* (options = {}) {
|
|
29
|
+
const launched = yield* Effect.acquireRelease(Effect.tryPromise({
|
|
30
|
+
try: () => chromium.launch({
|
|
31
|
+
headless: options.headless ?? true,
|
|
32
|
+
chromiumSandbox: options.sandbox ?? false,
|
|
33
|
+
timeout: launchTimeoutMillis,
|
|
34
|
+
handleSIGINT: false,
|
|
35
|
+
handleSIGTERM: false,
|
|
36
|
+
handleSIGHUP: false,
|
|
37
|
+
...options.executablePath === void 0 ? {} : { executablePath: options.executablePath },
|
|
38
|
+
...options.args === void 0 ? {} : { args: [...options.args] }
|
|
168
39
|
}),
|
|
169
|
-
catch:
|
|
40
|
+
catch: launchFailed
|
|
41
|
+
}).pipe(Effect.withSpan("Chromium.launch", {}, { captureStackTrace: false })), (browser) => Effect.tryPromise(() => browser.close()).pipe(Effect.ignore));
|
|
42
|
+
const context = yield* Effect.tryPromise({
|
|
43
|
+
try: () => launched.newContext({
|
|
44
|
+
viewport: options.viewport ?? {
|
|
45
|
+
width: 1280,
|
|
46
|
+
height: 720
|
|
47
|
+
},
|
|
48
|
+
deviceScaleFactor: 1,
|
|
49
|
+
...options.userAgent === void 0 ? {} : { userAgent: options.userAgent },
|
|
50
|
+
...options.locale === void 0 ? {} : { locale: options.locale }
|
|
51
|
+
}),
|
|
52
|
+
catch: failed("launch")
|
|
170
53
|
});
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
let spawned;
|
|
176
|
-
try {
|
|
177
|
-
spawned = spawn(executable, launchArguments(options, directory), {
|
|
178
|
-
cwd: directory,
|
|
179
|
-
stdio: [
|
|
180
|
-
"ignore",
|
|
181
|
-
"ignore",
|
|
182
|
-
"ignore",
|
|
183
|
-
"pipe",
|
|
184
|
-
"pipe"
|
|
185
|
-
],
|
|
186
|
-
detached: true
|
|
187
|
-
});
|
|
188
|
-
} catch {
|
|
189
|
-
failed();
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
child = spawned;
|
|
193
|
-
spawned.once("spawn", () => resume(Effect.succeed(spawned)));
|
|
194
|
-
spawned.once("error", failed);
|
|
195
|
-
});
|
|
196
|
-
const pid = launched.pid;
|
|
197
|
-
if (pid === void 0) return yield* failure("launch", Reasons.Failed.make({}));
|
|
198
|
-
return {
|
|
199
|
-
connection: (timeoutMillis) => Effect.gen(function* () {
|
|
200
|
-
const deadline = clock.monotonicTimeNanosUnsafe() + BigInt(Math.ceil(Math.min(timeoutMillis, options.startupTimeoutMillis ?? 15e3))) * 1000000n;
|
|
201
|
-
while (clock.monotonicTimeNanosUnsafe() < deadline) {
|
|
202
|
-
if (exited(launched)) return yield* failure("connect", Reasons.Closed.make({}));
|
|
203
|
-
const portFile = yield* Effect.tryPromise({
|
|
204
|
-
try: (signal) => readFile(path.join(directory, "DevToolsActivePort"), {
|
|
205
|
-
encoding: "utf8",
|
|
206
|
-
signal
|
|
207
|
-
}).catch((error) => {
|
|
208
|
-
if (error instanceof Error && "code" in error && error.code === "ENOENT") return void 0;
|
|
209
|
-
throw error;
|
|
210
|
-
}),
|
|
211
|
-
catch: () => failure("connect", Reasons.Transport.make({}))
|
|
212
|
-
});
|
|
213
|
-
const lines = portFile === void 0 ? [] : portFile.trim().split("\n");
|
|
214
|
-
if (lines.length >= 2) {
|
|
215
|
-
const endpoint = `ws://127.0.0.1:${lines[0]}${lines[1]}`;
|
|
216
|
-
if (!Schema.is(ChromiumEndpoint)(endpoint)) return yield* failure("connect", Reasons.Malformed.make({}));
|
|
217
|
-
return Redacted.make(endpoint);
|
|
218
|
-
}
|
|
219
|
-
yield* clock.sleep(Duration.millis(20));
|
|
220
|
-
}
|
|
221
|
-
return yield* failure("connect", Reasons.Timeout.make({}));
|
|
222
|
-
}).pipe(span("Chromium.ready")),
|
|
223
|
-
terminate: yield* Effect.cached(terminate(launched, pid, clock).pipe(Effect.uninterruptible)),
|
|
224
|
-
removeProfile
|
|
225
|
-
};
|
|
226
|
-
}).pipe(Effect.onExit((exit) => Exit.isSuccess(exit) ? Effect.void : Effect.gen(function* () {
|
|
227
|
-
if (child?.pid === void 0) {
|
|
228
|
-
yield* removeProfile.pipe(Effect.ignore);
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
const stopped = yield* terminate(child, child.pid, clock).pipe(Effect.exit);
|
|
232
|
-
if (Exit.isSuccess(stopped)) yield* removeProfile.pipe(Effect.ignore);
|
|
233
|
-
})));
|
|
234
|
-
}, span("Chromium.launch"));
|
|
235
|
-
//#endregion
|
|
236
|
-
//#region src/internal/chromium/Session.ts
|
|
237
|
-
/** Each teardown step runs even when a preceding step fails. Only observed exit permits profile removal. */
|
|
238
|
-
const makeChromiumCleanup = Effect.fnUntraced(function* (reference, local, process) {
|
|
239
|
-
let latest;
|
|
240
|
-
return {
|
|
241
|
-
close: yield* Effect.cached(Effect.uninterruptible(Effect.gen(function* () {
|
|
242
|
-
const issues = [];
|
|
243
|
-
const step = (name, action) => cleanupStep(action.pipe(span(`Chromium.cleanup.${name}`)), 3e3).pipe(Effect.tap((result) => Effect.sync(() => {
|
|
244
|
-
if (result._tag === "Failure") issues.push(ChromiumCleanupIssue.make({
|
|
245
|
-
step: name,
|
|
246
|
-
reason: result.reason
|
|
247
|
-
}));
|
|
248
|
-
})));
|
|
249
|
-
yield* step("fence", local.fence);
|
|
250
|
-
yield* step("capture", local.capture);
|
|
251
|
-
yield* step("initialization", local.initialization);
|
|
252
|
-
const disconnected = yield* step("disconnect", local.disconnect);
|
|
253
|
-
const terminated = process === void 0 ? void 0 : yield* step("terminate", process.terminate);
|
|
254
|
-
if (process !== void 0 && terminated !== void 0 && terminated._tag === "Success") yield* step("profile", process.removeProfile);
|
|
255
|
-
const result = ChromiumCleanupResult.make({
|
|
256
|
-
reference,
|
|
257
|
-
ownership: process === void 0 ? "borrowed" : "owned",
|
|
258
|
-
connection: disconnected._tag === "Success" ? disconnected.value : "failed",
|
|
259
|
-
process: terminated === void 0 ? "not-owned" : terminated._tag === "Success" ? "terminated" : "unknown",
|
|
260
|
-
issues
|
|
261
|
-
});
|
|
262
|
-
Object.freeze(result.issues);
|
|
263
|
-
latest = Object.freeze(result);
|
|
264
|
-
yield* annotate({
|
|
265
|
-
"browser.cleanup.connection": result.connection,
|
|
266
|
-
"browser.cleanup.process": result.process,
|
|
267
|
-
"browser.cleanup.issues": issues.length
|
|
268
|
-
});
|
|
269
|
-
return latest;
|
|
270
|
-
}).pipe(span("Chromium.cleanup")))),
|
|
271
|
-
result: Effect.sync(() => Option.fromNullishOr(latest))
|
|
272
|
-
};
|
|
54
|
+
return yield* make(context, {
|
|
55
|
+
id: `chromium-${launched.version()}`,
|
|
56
|
+
provider: "chromium"
|
|
57
|
+
}, options);
|
|
273
58
|
});
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
const process = endpoint === void 0 ? yield* launch(options) : void 0;
|
|
277
|
-
const reference = Object.freeze(ChromiumReference.make({
|
|
278
|
-
provider: "chromium",
|
|
279
|
-
id
|
|
280
|
-
}));
|
|
281
|
-
const cleanup = yield* makeChromiumCleanup(reference, local, process);
|
|
282
|
-
let closing = false;
|
|
283
|
-
const release = yield* Effect.cached(Effect.gen(function* () {
|
|
284
|
-
closing = true;
|
|
285
|
-
const result = yield* cleanup.close;
|
|
286
|
-
if (onCleanup !== void 0) yield* reported(Effect.suspend(() => onCleanup(result)));
|
|
287
|
-
return result;
|
|
288
|
-
}).pipe(span("Chromium.release"), Effect.uninterruptible));
|
|
289
|
-
yield* Effect.addFinalizer(() => release.pipe(Effect.asVoid));
|
|
290
|
-
return {
|
|
291
|
-
reference,
|
|
292
|
-
connection: (timeoutMillis) => Effect.suspend(() => {
|
|
293
|
-
if (closing) return Effect.fail(BrowserError.make({
|
|
294
|
-
operation: "connect",
|
|
295
|
-
reason: Reasons.Closed.make({}),
|
|
296
|
-
outcome: "undispatched"
|
|
297
|
-
}));
|
|
298
|
-
if (process !== void 0) return process.connection(timeoutMillis);
|
|
299
|
-
return endpoint === void 0 ? Effect.fail(BrowserError.make({
|
|
300
|
-
operation: "connect",
|
|
301
|
-
reason: Reasons.Configuration.make({}),
|
|
302
|
-
outcome: "undispatched"
|
|
303
|
-
})) : checked(ChromiumEndpoint, Redacted.value(endpoint), "connect").pipe(Effect.map(Redacted.make));
|
|
304
|
-
}),
|
|
305
|
-
release,
|
|
306
|
-
closeChecked: release.pipe(Effect.filterOrFail((result) => result.connection === "closed" && result.issues.length === 0 && (result.ownership === "borrowed" ? result.process === "not-owned" : result.process === "terminated"), () => BrowserError.make({
|
|
307
|
-
operation: "close",
|
|
308
|
-
reason: Reasons.Failed.make({}),
|
|
309
|
-
outcome: "unknown"
|
|
310
|
-
})), span("Chromium.close")),
|
|
311
|
-
cleanupResult: cleanup.result,
|
|
312
|
-
controlRetired: cleanup.result.pipe(Effect.map((result) => Option.isSome(result) && result.value.ownership === "owned" && result.value.process === "terminated"))
|
|
313
|
-
};
|
|
314
|
-
}));
|
|
315
|
-
const ownedChromium = (options, onCleanup) => acquireChromium(void 0, options, onCleanup);
|
|
316
|
-
const borrowedChromium = (endpoint, onCleanup) => acquireChromium(endpoint, {}, onCleanup);
|
|
317
|
-
//#endregion
|
|
318
|
-
//#region src/Chromium.ts
|
|
319
|
-
var Chromium = class Chromium extends Context.Service()("effect-browser/Chromium") {
|
|
320
|
-
/** Launch through the configured service; compose with Browser.scoped for supervised ownership. */
|
|
321
|
-
static launch(policy, request) {
|
|
322
|
-
return Effect.flatMap(Chromium, (browser) => browser.launch(policy, request));
|
|
323
|
-
}
|
|
324
|
-
/** Acquire the process lifetime before connecting, using the caller's scope. */
|
|
325
|
-
static acquire(policy, request) {
|
|
326
|
-
return Effect.flatMap(Chromium, (browser) => browser.acquire(policy, request));
|
|
327
|
-
}
|
|
328
|
-
/** Borrow a concrete loopback endpoint; cleanup never terminates its external process. */
|
|
329
|
-
static attach(endpoint, request) {
|
|
330
|
-
return Effect.flatMap(Chromium, (browser) => browser.attach(endpoint, request));
|
|
331
|
-
}
|
|
332
|
-
/** Chromium references, connection ids and handoff tokens come from the required `Crypto`. */
|
|
333
|
-
static layer(options = {}) {
|
|
334
|
-
return Layer.effect(Chromium, Effect.gen(function* () {
|
|
335
|
-
const launchInput = yield* checked(ChromiumLaunch, options.launch ?? {}, "configure");
|
|
336
|
-
const launch = Object.freeze({
|
|
337
|
-
...launchInput,
|
|
338
|
-
...launchInput.args === void 0 ? {} : { args: Object.freeze([...launchInput.args]) },
|
|
339
|
-
...launchInput.proxy === void 0 ? {} : { proxy: Object.freeze({ ...launchInput.proxy }) }
|
|
340
|
-
});
|
|
341
|
-
if (Object.prototype.hasOwnProperty.call(options, "bootstrap")) return yield* BrowserError.make({
|
|
342
|
-
operation: "configure",
|
|
343
|
-
reason: Reasons.Configuration.make({}),
|
|
344
|
-
outcome: "undispatched"
|
|
345
|
-
});
|
|
346
|
-
const runtime = yield* make({
|
|
347
|
-
implementation: "chromium-playwright-cdp",
|
|
348
|
-
...options.viewport === void 0 ? {} : { viewport: options.viewport },
|
|
349
|
-
automation: {
|
|
350
|
-
...options.timelineLimits === void 0 ? {} : { timelineLimits: options.timelineLimits },
|
|
351
|
-
...options.admissionLimits === void 0 ? {} : { admissionLimits: options.admissionLimits },
|
|
352
|
-
...options.observationLimits === void 0 ? {} : { observationLimits: options.observationLimits },
|
|
353
|
-
...options.actionTimeoutMillis === void 0 ? {} : { actionTimeoutMillis: options.actionTimeoutMillis },
|
|
354
|
-
...options.maxPages === void 0 ? {} : { maxPages: options.maxPages },
|
|
355
|
-
...options.maxHostReads === void 0 ? {} : { maxHostReads: options.maxHostReads },
|
|
356
|
-
...options.initialPage === void 0 ? {} : { initialPage: options.initialPage },
|
|
357
|
-
...options.popupPolicy === void 0 ? {} : { popupPolicy: options.popupPolicy },
|
|
358
|
-
...options.dialogPolicy === void 0 ? {} : { dialogPolicy: options.dialogPolicy },
|
|
359
|
-
...options.pageControl === void 0 ? {} : { pageControl: options.pageControl }
|
|
360
|
-
}
|
|
361
|
-
});
|
|
362
|
-
const crypto = yield* Crypto.Crypto;
|
|
363
|
-
const acquire = Effect.fnUntraced(function* (policy, request = {}, attachment) {
|
|
364
|
-
const source = attachment === void 0 ? ownedChromium(launch, options.onCleanup) : borrowedChromium(attachment.endpoint, options.onCleanup);
|
|
365
|
-
const acquired = yield* runtime.acquire(policy, (cleanup, deadline) => source(cleanup, deadline).pipe(Effect.provideService(Crypto.Crypto, crypto)), {
|
|
366
|
-
...request,
|
|
367
|
-
...attachment === void 0 ? {} : { existingTarget: attachment.targetId === void 0 ? {} : { targetId: attachment.targetId } }
|
|
368
|
-
});
|
|
369
|
-
const connected = yield* Effect.cached(acquired.connect.pipe(Effect.map(({ session }) => Object.assign(session, {
|
|
370
|
-
reference: acquired.reference,
|
|
371
|
-
closeChecked: session.closeChecked.pipe(Effect.andThen(acquired.lifetime.closeChecked)),
|
|
372
|
-
close: acquired.close,
|
|
373
|
-
cleanupResult: acquired.lifetime.cleanupResult
|
|
374
|
-
}))));
|
|
375
|
-
return {
|
|
376
|
-
reference: acquired.reference,
|
|
377
|
-
failure: acquired.failure,
|
|
378
|
-
close: acquired.close,
|
|
379
|
-
connect: acquired.connect.pipe(Effect.andThen(connected))
|
|
380
|
-
};
|
|
381
|
-
});
|
|
382
|
-
return Chromium.of({
|
|
383
|
-
acquire,
|
|
384
|
-
launch: (policy, request) => acquire(policy, request).pipe(Effect.flatMap((acquired) => acquired.connect)),
|
|
385
|
-
attach: (endpoint, request) => Effect.gen(function* () {
|
|
386
|
-
const address = yield* checked(ChromiumEndpoint, Redacted.value(endpoint), "connect");
|
|
387
|
-
return yield* (yield* acquire(request.policy, request, {
|
|
388
|
-
endpoint: Redacted.make(address),
|
|
389
|
-
...request.target === void 0 ? {} : { targetId: request.target.targetId }
|
|
390
|
-
})).connect;
|
|
391
|
-
})
|
|
392
|
-
});
|
|
393
|
-
}));
|
|
394
|
-
}
|
|
395
|
-
};
|
|
59
|
+
/** A `Browser` Layer that launches Chromium when built and closes it when released. */
|
|
60
|
+
const layer = (options = {}) => Layer.effect(Browser, open(options));
|
|
396
61
|
//#endregion
|
|
397
|
-
export {
|
|
62
|
+
export { layer, open, Chromium_exports as t };
|
|
398
63
|
|
|
399
64
|
//# sourceMappingURL=Chromium.mjs.map
|
package/dist/Chromium.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Chromium.mjs","names":["Trace.span","Trace.span","Trace.annotate","BrowserRuntime.make"],"sources":["../src/internal/chromium/Data.ts","../src/internal/chromium/Process.ts","../src/internal/chromium/Session.ts","../src/Chromium.ts"],"sourcesContent":["import { Schema } from \"effect\";\n\nimport { Identifier } from \"../../BrowserData.ts\";\n\n/** Identifies this Chromium ownership lifetime, not a reusable endpoint. */\nexport class ChromiumReference extends Schema.Class<ChromiumReference>(\"ChromiumReference\")({\n provider: Schema.Literal(\"chromium\"),\n id: Identifier,\n}) {}\n\nexport class ChromiumCleanupIssue extends Schema.Class<ChromiumCleanupIssue>(\n \"ChromiumCleanupIssue\",\n)({\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 ChromiumCleanupResult extends Schema.Class<ChromiumCleanupResult>(\n \"ChromiumCleanupResult\",\n)({\n reference: ChromiumReference,\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(ChromiumCleanupIssue).check(Schema.isMaxLength(16)),\n}) {}\n\nconst Text = Schema.NonEmptyString.check(\n Schema.isMaxLength(4096),\n // oxlint-disable-next-line eslint/no-control-regex -- NUL is one of the characters it rejects\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 ChromiumEndpoint = 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|no-startup-window)(?:=|$)/u.test(\n value,\n ),\n ),\n);\n\nexport const ChromiumLaunch = 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 ChromiumLaunch = typeof ChromiumLaunch.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 { Reasons, BrowserError } from \"../../Errors.ts\";\nimport * as Trace from \"../Trace.ts\";\nimport { ChromiumEndpoint, type ChromiumLaunch } from \"./Data.ts\";\n\nexport interface ChromiumProcess {\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: ChromiumLaunch, 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 \"--remote-debugging-pipe\",\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 // The shared driver creates its initial Page on the sole connection. Chromium's launch\n // Page can arrive after the debugger endpoint and race that creation.\n \"--no-startup-window\",\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\", Reasons.Failed.make({})),\n });\n\n const signal = (value: NodeJS.Signals) =>\n Effect.try({\n try: () => signalGroup(pid, value),\n catch: () => failure(\"close\", Reasons.Failed.make({})),\n });\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\", Reasons.Timeout.make({}));\n}, Trace.span(\"Chromium.terminate\"));\n\n/** Start only Chromium's process. The shared owner later opens its sole CDP connection. */\nexport const launch = Effect.fnUntraced(function* (\n options: ChromiumLaunch,\n): Effect.fn.Return<ChromiumProcess, BrowserError> {\n if (process.platform === \"win32\") return yield* failure(\"launch\", Reasons.Unsupported.make({}));\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: () => import(\"playwright-core\").then(({ chromium }) => chromium.executablePath()),\n catch: () => failure(\"launch\", Reasons.Failed.make({})),\n }));\n\n const directory = yield* Effect.tryPromise({\n try: () => mkdtemp(path.join(tmpdir(), \"effect-browser-chromium-\")),\n catch: () => failure(\"launch\", Reasons.Failed.make({})),\n });\n\n const removeProfile = Effect.tryPromise({\n try: () => rm(directory, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 }),\n catch: () => failure(\"close\", Reasons.Failed.make({})),\n });\n\n let child: ChildProcess | undefined;\n\n return yield* Effect.gen(function* () {\n // Node reports a spawn's outcome on a later tick, so its listeners attach in the same turn.\n const launched = yield* Effect.callback<ChildProcess, BrowserError>((resume) => {\n const failed = () => resume(Effect.fail(failure(\"launch\", Reasons.Failed.make({}))));\n let spawned: ChildProcess;\n\n try {\n spawned = spawn(executable, launchArguments(options, directory), {\n cwd: directory,\n // Chromium watches fd 3 for EOF and closes the browser when the host dies, including\n // SIGKILL before connect. Keep its fd 3/4 pipe pair owned by this ChildProcess; send no\n // commands on it. The shared Playwright driver still controls the loopback endpoint.\n stdio: [\"ignore\", \"ignore\", \"ignore\", \"pipe\", \"pipe\"],\n detached: true,\n });\n } catch {\n failed();\n\n return;\n }\n\n child = spawned;\n spawned.once(\"spawn\", () => resume(Effect.succeed(spawned)));\n spawned.once(\"error\", failed);\n });\n\n const pid = launched.pid;\n\n if (pid === undefined) return yield* failure(\"launch\", Reasons.Failed.make({}));\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\", Reasons.Closed.make({}));\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\", Reasons.Transport.make({})),\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(ChromiumEndpoint)(endpoint))\n return yield* failure(\"connect\", Reasons.Malformed.make({}));\n\n return Redacted.make(endpoint);\n }\n yield* clock.sleep(Duration.millis(20));\n }\n\n return yield* failure(\"connect\", Reasons.Timeout.make({}));\n }).pipe(Trace.span(\"Chromium.ready\")),\n terminate: closing,\n removeProfile,\n } satisfies ChromiumProcess;\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}, Trace.span(\"Chromium.launch\"));\n","import { Crypto, Effect, Option, Redacted } from \"effect\";\n\nimport type { Lifetime, Source } from \"../../BrowserRuntime.ts\";\nimport { BrowserError, Reasons } from \"../../Errors.ts\";\nimport { cleanupStep, reported, type ConnectionCleanup } from \"../browser/ConnectionCleanup.ts\";\nimport { checked } from \"../browser/PublicSession.ts\";\nimport { randomUuid } from \"../browser/Random.ts\";\nimport * as Trace from \"../Trace.ts\";\nimport {\n ChromiumCleanupIssue,\n ChromiumCleanupResult,\n ChromiumEndpoint,\n ChromiumReference,\n type ChromiumLaunch,\n} from \"./Data.ts\";\nimport { launch, type ChromiumProcess } from \"./Process.ts\";\n\nexport interface ChromiumLease extends Lifetime {\n readonly reference: ChromiumReference;\n readonly closeChecked: Effect.Effect<ChromiumCleanupResult, BrowserError>;\n readonly release: Effect.Effect<ChromiumCleanupResult>;\n readonly cleanupResult: Effect.Effect<Option.Option<ChromiumCleanupResult>>;\n}\n\n/** Each teardown step runs even when a preceding step fails. Only observed exit permits profile removal. */\nexport const makeChromiumCleanup = Effect.fnUntraced(function* (\n reference: ChromiumReference,\n local: ConnectionCleanup,\n process: ChromiumProcess | undefined,\n) {\n let latest: ChromiumCleanupResult | undefined;\n\n const close = yield* Effect.cached(\n Effect.uninterruptible(\n Effect.gen(function* () {\n const issues: ChromiumCleanupIssue[] = [];\n\n const step = <A, E>(name: ChromiumCleanupIssue[\"step\"], action: Effect.Effect<A, E>) =>\n cleanupStep(action.pipe(Trace.span(`Chromium.cleanup.${name}`)), 3000).pipe(\n Effect.tap((result) =>\n Effect.sync(() => {\n if (result._tag === \"Failure\")\n issues.push(ChromiumCleanupIssue.make({ step: name, reason: result.reason }));\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 && terminated._tag === \"Success\")\n yield* step(\"profile\", process.removeProfile);\n\n const result = ChromiumCleanupResult.make({\n reference,\n ownership: process === undefined ? \"borrowed\" : \"owned\",\n connection: disconnected._tag === \"Success\" ? disconnected.value : \"failed\",\n process:\n terminated === undefined\n ? \"not-owned\"\n : terminated._tag === \"Success\"\n ? \"terminated\"\n : \"unknown\",\n issues,\n });\n\n Object.freeze(result.issues);\n latest = Object.freeze(result);\n yield* Trace.annotate({\n \"browser.cleanup.connection\": result.connection,\n \"browser.cleanup.process\": result.process,\n \"browser.cleanup.issues\": issues.length,\n });\n\n return latest;\n }).pipe(Trace.span(\"Chromium.cleanup\")),\n ),\n );\n\n return { close, result: Effect.sync(() => Option.fromNullishOr(latest)) };\n});\n\nconst acquireChromium =\n (\n endpoint: Redacted.Redacted<string> | undefined,\n options: ChromiumLaunch,\n onCleanup?: (result: ChromiumCleanupResult) => Effect.Effect<void>,\n ): Source<ChromiumLease, BrowserError, Crypto.Crypto> =>\n (local) =>\n Effect.uninterruptible(\n Effect.gen(function* () {\n // Drawn first: a draw after the spawn would sit between it and finalizer registration.\n const id = yield* randomUuid(yield* Crypto.Crypto);\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 const reference = Object.freeze(ChromiumReference.make({ provider: \"chromium\", id }));\n\n const cleanup = yield* makeChromiumCleanup(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(Effect.suspend(() => onCleanup(result)));\n\n return result;\n }).pipe(Trace.span(\"Chromium.release\"), 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: Reasons.Closed.make({}),\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: Reasons.Configuration.make({}),\n outcome: \"undispatched\",\n }),\n )\n : checked(ChromiumEndpoint, Redacted.value(endpoint), \"connect\").pipe(\n Effect.map(Redacted.make),\n );\n }),\n release,\n closeChecked: release.pipe(\n Effect.filterOrFail(\n (result) =>\n result.connection === \"closed\" &&\n result.issues.length === 0 &&\n (result.ownership === \"borrowed\"\n ? result.process === \"not-owned\"\n : result.process === \"terminated\"),\n () =>\n BrowserError.make({\n operation: \"close\",\n reason: Reasons.Failed.make({}),\n outcome: \"unknown\",\n }),\n ),\n Trace.span(\"Chromium.close\"),\n ),\n cleanupResult: cleanup.result,\n controlRetired: cleanup.result.pipe(\n Effect.map(\n (result) =>\n Option.isSome(result) &&\n result.value.ownership === \"owned\" &&\n result.value.process === \"terminated\",\n ),\n ),\n } satisfies ChromiumLease;\n }),\n );\n\nexport const ownedChromium = (\n options: ChromiumLaunch,\n onCleanup?: (result: ChromiumCleanupResult) => Effect.Effect<void>,\n) => acquireChromium(undefined, options, onCleanup);\n\nexport const borrowedChromium = (\n endpoint: Redacted.Redacted<string>,\n onCleanup?: (result: ChromiumCleanupResult) => Effect.Effect<void>,\n) => acquireChromium(endpoint, {}, onCleanup);\n","import { Context, Crypto, Effect, Layer, type Option, Redacted, type Scope } from \"effect\";\n\nimport type { BrowserSession, OpenOptions } from \"./Browser.ts\";\nimport type { AutomationOptions, BrowserPolicy, Viewport } from \"./BrowserData.ts\";\nimport * as BrowserRuntime from \"./BrowserRuntime.ts\";\nimport { BrowserError, Reasons, type InitializationError } from \"./Errors.ts\";\nimport { checked } from \"./internal/browser/PublicSession.ts\";\nimport {\n ChromiumEndpoint,\n ChromiumLaunch,\n type ChromiumCleanupResult,\n type ChromiumReference,\n} from \"./internal/chromium/Data.ts\";\nimport { borrowedChromium, ownedChromium } from \"./internal/chromium/Session.ts\";\n\nexport {\n ChromiumCleanupIssue,\n ChromiumCleanupResult,\n ChromiumLaunch,\n ChromiumReference,\n} from \"./internal/chromium/Data.ts\";\n\n/** Host-only process configuration. Building this layer neither loads Playwright nor starts Chromium. */\nexport interface ChromiumOptions extends AutomationOptions {\n readonly launch?: ChromiumLaunch;\n readonly viewport?: Viewport;\n readonly onCleanup?: (result: ChromiumCleanupResult) => Effect.Effect<void>;\n}\n\n/** An owned or borrowed Chromium lifetime with one modeled browser connection. */\nexport interface ChromiumSession<E = never> extends BrowserSession<E> {\n readonly reference: ChromiumReference;\n readonly closeChecked: Effect.Effect<ChromiumCleanupResult, BrowserError>;\n readonly close: Effect.Effect<ChromiumCleanupResult>;\n readonly cleanupResult: Effect.Effect<Option.Option<ChromiumCleanupResult>>;\n}\n\nexport interface ChromiumAcquisition<E = never> {\n readonly reference: ChromiumReference;\n readonly failure: Effect.Effect<never, E | InitializationError>;\n readonly connect: Effect.Effect<ChromiumSession<E>, BrowserError | InitializationError | E>;\n readonly close: Effect.Effect<ChromiumCleanupResult>;\n}\n\nexport interface ChromiumAttachRequest<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 Chromium extends Context.Service<\n Chromium,\n {\n readonly acquire: <E = never, R = never>(\n policy: BrowserPolicy,\n request?: OpenOptions<E, R>,\n ) => Effect.Effect<ChromiumAcquisition<E>, BrowserError, Scope.Scope | Exclude<R, Scope.Scope>>;\n readonly launch: <E = never, R = never>(\n policy: BrowserPolicy,\n request?: OpenOptions<E, R>,\n ) => Effect.Effect<\n ChromiumSession<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: ChromiumAttachRequest<E, R>,\n ) => Effect.Effect<\n ChromiumSession<E>,\n BrowserError | InitializationError | E,\n Scope.Scope | Exclude<R, Scope.Scope>\n >;\n }\n>()(\"effect-browser/Chromium\") {\n /** Launch through the configured service; compose with Browser.scoped for supervised ownership. */\n static launch<E = never, R = never>(policy: BrowserPolicy, request?: OpenOptions<E, R>) {\n return Effect.flatMap(Chromium, (browser) => browser.launch(policy, request));\n }\n\n /** Acquire the process lifetime before connecting, using the caller's scope. */\n static acquire<E = never, R = never>(policy: BrowserPolicy, request?: OpenOptions<E, R>) {\n return Effect.flatMap(Chromium, (browser) => browser.acquire(policy, request));\n }\n\n /** Borrow a concrete loopback endpoint; cleanup never terminates its external process. */\n static attach<E = never, R = never>(\n endpoint: Redacted.Redacted<string>,\n request: ChromiumAttachRequest<E, R>,\n ) {\n return Effect.flatMap(Chromium, (browser) => browser.attach(endpoint, request));\n }\n\n /** Chromium references, connection ids and handoff tokens come from the required `Crypto`. */\n static layer(options: ChromiumOptions = {}): Layer.Layer<Chromium, BrowserError, Crypto.Crypto> {\n return Layer.effect(\n Chromium,\n Effect.gen(function* () {\n const launchInput = yield* checked(ChromiumLaunch, 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 if (Object.prototype.hasOwnProperty.call(options, \"bootstrap\"))\n return yield* BrowserError.make({\n operation: \"configure\",\n reason: Reasons.Configuration.make({}),\n outcome: \"undispatched\",\n });\n\n const runtime = yield* BrowserRuntime.make({\n implementation: \"chromium-playwright-cdp\",\n ...(options.viewport === undefined ? {} : { viewport: options.viewport }),\n automation: {\n ...(options.timelineLimits === undefined\n ? {}\n : { timelineLimits: options.timelineLimits }),\n ...(options.admissionLimits === undefined\n ? {}\n : { admissionLimits: options.admissionLimits }),\n ...(options.observationLimits === undefined\n ? {}\n : { observationLimits: options.observationLimits }),\n ...(options.actionTimeoutMillis === undefined\n ? {}\n : { actionTimeoutMillis: options.actionTimeoutMillis }),\n ...(options.maxPages === undefined ? {} : { maxPages: options.maxPages }),\n ...(options.maxHostReads === undefined ? {} : { maxHostReads: options.maxHostReads }),\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 });\n\n const crypto = yield* Crypto.Crypto;\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 source =\n attachment === undefined\n ? ownedChromium(launch, options.onCleanup)\n : borrowedChromium(attachment.endpoint, options.onCleanup);\n\n const acquired = yield* runtime.acquire(\n policy,\n (cleanup, deadline) =>\n source(cleanup, deadline).pipe(Effect.provideService(Crypto.Crypto, crypto)),\n {\n ...request,\n ...(attachment === undefined\n ? {}\n : {\n existingTarget:\n attachment.targetId === undefined ? {} : { targetId: attachment.targetId },\n }),\n },\n );\n\n const connected = yield* Effect.cached(\n acquired.connect.pipe(\n Effect.map(({ session }): ChromiumSession<E> =>\n Object.assign(session, {\n reference: acquired.reference,\n closeChecked: session.closeChecked.pipe(\n Effect.andThen(acquired.lifetime.closeChecked),\n ),\n close: acquired.close,\n cleanupResult: acquired.lifetime.cleanupResult,\n }),\n ),\n ),\n );\n\n return {\n reference: acquired.reference,\n failure: acquired.failure,\n close: acquired.close,\n connect: acquired.connect.pipe(Effect.andThen(connected)),\n } satisfies ChromiumAcquisition<E>;\n });\n\n return Chromium.of({\n acquire,\n launch: (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(ChromiumEndpoint, Redacted.value(endpoint), \"connect\");\n\n return yield* (yield* acquire(request.policy, request, {\n endpoint: Redacted.make(address),\n ...(request.target === undefined ? {} : { targetId: request.target.targetId }),\n })).connect;\n }),\n });\n }),\n );\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Chromium.mjs","names":["Browser.make","Browser.Browser"],"sources":["../src/Chromium.ts"],"sourcesContent":["/**\n * A local Chromium, launched for the scope and closed with it.\n *\n * It uses the Chromium build that `playwright-core` installs\n * (`npx playwright-core install chromium`), unless `executablePath` names another.\n *\n * Signals are the program's to handle: run it with `NodeRuntime.runMain`, which interrupts it on\n * SIGINT and SIGTERM, so the browser closes with its scope.\n *\n * @since 0.3.0\n */\nimport { Effect, Layer } from \"effect\";\nimport { chromium } from \"playwright-core\";\n\nimport * as Browser from \"./Browser.ts\";\nimport { type BrowserError, Failed } from \"./BrowserError.ts\";\nimport { reasonOf, undispatched } from \"./internal/page/context.ts\";\n\nexport interface Options extends Browser.Options {\n /** Defaults to true. */\n readonly headless?: boolean | undefined;\n /**\n * Run Chromium's sandbox. Defaults to false, as in Playwright, so an exploit in a page's renderer\n * runs with this process's privileges. Hosts that don't allow unprivileged user namespaces, such\n * as many containers and Ubuntu 23.10 or later by default, can't start the sandbox; opening then\n * fails and says so.\n */\n readonly sandbox?: boolean | undefined;\n /** Defaults to 1280x720 CSS pixels at a device scale factor of 1. */\n readonly viewport?: { readonly width: number; readonly height: number } | undefined;\n readonly executablePath?: string | undefined;\n readonly args?: ReadonlyArray<string> | undefined;\n readonly userAgent?: string | undefined;\n readonly locale?: string | undefined;\n}\n\n// Playwright's own default, stated so that a launch timeout reports the bound it exceeded.\nconst launchTimeoutMillis = 180_000;\n\nconst failed = (operation: string, timeoutMillis?: number) => (cause: unknown) =>\n undispatched(operation, reasonOf(cause, timeoutMillis));\n\n// Playwright puts this in place of Chromium's startup log when the sandbox could not start, in an\n// error that otherwise reads as a closed browser.\nconst sandboxFailed = /Chromium sandboxing failed|No usable sandbox/;\n\nconst launchFailed = (cause: unknown) =>\n sandboxFailed.test(String(cause))\n ? undispatched(\n \"launch\",\n new Failed({\n detail:\n \"Chromium's sandbox could not start on this host: it needs unprivileged user namespaces, and a user other than root\",\n }),\n )\n : failed(\"launch\", launchTimeoutMillis)(cause);\n\n/** Launch Chromium and open a `Browser` over a fresh context. */\nexport const open = Effect.fn(\"Chromium.open\")(function* (options: Options = {}) {\n const launched = yield* Effect.acquireRelease(\n Effect.tryPromise({\n try: () =>\n chromium.launch({\n headless: options.headless ?? true,\n chromiumSandbox: options.sandbox ?? false,\n timeout: launchTimeoutMillis,\n // The program owns its signals. Playwright's handlers close every browser on any of\n // these, and on SIGINT then exit the process, so no finalizer would run.\n handleSIGINT: false,\n handleSIGTERM: false,\n handleSIGHUP: false,\n ...(options.executablePath === undefined\n ? {}\n : { executablePath: options.executablePath }),\n ...(options.args === undefined ? {} : { args: [...options.args] }),\n }),\n catch: launchFailed,\n }).pipe(Effect.withSpan(\"Chromium.launch\", {}, { captureStackTrace: false })),\n (browser) => Effect.tryPromise(() => browser.close()).pipe(Effect.ignore),\n );\n\n const context = yield* Effect.tryPromise({\n try: () =>\n launched.newContext({\n viewport: options.viewport ?? { width: 1280, height: 720 },\n deviceScaleFactor: 1,\n ...(options.userAgent === undefined ? {} : { userAgent: options.userAgent }),\n ...(options.locale === undefined ? {} : { locale: options.locale }),\n }),\n catch: failed(\"launch\"),\n });\n\n return yield* Browser.make(\n context,\n { id: `chromium-${launched.version()}`, provider: \"chromium\" },\n options,\n );\n});\n\n/** A `Browser` Layer that launches Chromium when built and closes it when released. */\nexport const layer = (options: Options = {}): Layer.Layer<Browser.Browser, BrowserError> =>\n Layer.effect(Browser.Browser, open(options));\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAqCA,MAAM,sBAAsB;AAE5B,MAAM,UAAU,WAAmB,mBAA4B,UAC7D,aAAa,WAAW,SAAS,OAAO,aAAa,CAAC;AAIxD,MAAM,gBAAgB;AAEtB,MAAM,gBAAgB,UACpB,cAAc,KAAK,OAAO,KAAK,CAAC,IAC5B,aACE,UACA,IAAI,OAAO,EACT,QACE,qHACJ,CAAC,CACH,IACA,OAAO,UAAU,mBAAmB,CAAC,CAAC,KAAK;;AAGjD,MAAa,OAAO,OAAO,GAAG,eAAe,CAAC,CAAC,WAAW,UAAmB,CAAC,GAAG;CAC/E,MAAM,WAAW,OAAO,OAAO,eAC7B,OAAO,WAAW;EAChB,WACE,SAAS,OAAO;GACd,UAAU,QAAQ,YAAY;GAC9B,iBAAiB,QAAQ,WAAW;GACpC,SAAS;GAGT,cAAc;GACd,eAAe;GACf,cAAc;GACd,GAAI,QAAQ,mBAAmB,KAAA,IAC3B,CAAC,IACD,EAAE,gBAAgB,QAAQ,eAAe;GAC7C,GAAI,QAAQ,SAAS,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,QAAQ,IAAI,EAAE;EAClE,CAAC;EACH,OAAO;CACT,CAAC,CAAC,CAAC,KAAK,OAAO,SAAS,mBAAmB,CAAC,GAAG,EAAE,mBAAmB,MAAM,CAAC,CAAC,IAC3E,YAAY,OAAO,iBAAiB,QAAQ,MAAM,CAAC,CAAC,CAAC,KAAK,OAAO,MAAM,CAC1E;CAEA,MAAM,UAAU,OAAO,OAAO,WAAW;EACvC,WACE,SAAS,WAAW;GAClB,UAAU,QAAQ,YAAY;IAAE,OAAO;IAAM,QAAQ;GAAI;GACzD,mBAAmB;GACnB,GAAI,QAAQ,cAAc,KAAA,IAAY,CAAC,IAAI,EAAE,WAAW,QAAQ,UAAU;GAC1E,GAAI,QAAQ,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;EACnE,CAAC;EACH,OAAO,OAAO,QAAQ;CACxB,CAAC;CAED,OAAO,OAAOA,KACZ,SACA;EAAE,IAAI,YAAY,SAAS,QAAQ;EAAK,UAAU;CAAW,GAC7D,OACF;AACF,CAAC;;AAGD,MAAa,SAAS,UAAmB,CAAC,MACxC,MAAM,OAAOC,SAAiB,KAAK,OAAO,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { t as BrowserError } from "./BrowserError-Coy7EW1N.mjs";
|
|
2
|
+
import { a as FindQuery, u as Page } from "./Page-BlPjfibv.mjs";
|
|
3
|
+
import { Duration, Effect } from "effect";
|
|
4
|
+
declare namespace Expect_d_exports {
|
|
5
|
+
export { Attempt, Expectation, Options, Outcome, appeared, attempt, changed, gone, navigated };
|
|
6
|
+
}
|
|
7
|
+
/** What an action is for, as the page can tell it. */
|
|
8
|
+
export type Expectation = {
|
|
9
|
+
readonly _tag: "Appeared";
|
|
10
|
+
readonly query: FindQuery;
|
|
11
|
+
} | {
|
|
12
|
+
readonly _tag: "Gone";
|
|
13
|
+
readonly query: FindQuery;
|
|
14
|
+
} | {
|
|
15
|
+
readonly _tag: "Changed";
|
|
16
|
+
readonly query: FindQuery;
|
|
17
|
+
} | {
|
|
18
|
+
readonly _tag: "Navigated";
|
|
19
|
+
readonly url: string | RegExp | undefined;
|
|
20
|
+
};
|
|
21
|
+
/** Something the query finds. */
|
|
22
|
+
export declare const appeared: (query: FindQuery) => Expectation;
|
|
23
|
+
/** Nothing the query finds. */
|
|
24
|
+
export declare const gone: (query: FindQuery) => Expectation;
|
|
25
|
+
/**
|
|
26
|
+
* What the query finds shows something other than it did as the attempt began: other elements, or
|
|
27
|
+
* their text, values or states.
|
|
28
|
+
*/
|
|
29
|
+
export declare const changed: (query: FindQuery) => Expectation;
|
|
30
|
+
/**
|
|
31
|
+
* The page is at `url`, the whole address or a pattern; without one, at an address or in a
|
|
32
|
+
* document other than the attempt's first.
|
|
33
|
+
*/
|
|
34
|
+
export declare const navigated: (url?: string | RegExp) => Expectation;
|
|
35
|
+
/**
|
|
36
|
+
* `Done`: the action ran, and what it was for came. `AlreadyDone`: it held before the action was
|
|
37
|
+
* sent, so it was not. `NotDone`: the action ran, and it did not come within the attempt's wait.
|
|
38
|
+
*/
|
|
39
|
+
export type Outcome = "Done" | "AlreadyDone" | "NotDone";
|
|
40
|
+
export interface Options {
|
|
41
|
+
/** How long an action's effect may take to show. Defaults to 5 seconds. */
|
|
42
|
+
readonly wait?: Duration.Input | undefined;
|
|
43
|
+
}
|
|
44
|
+
export interface Attempt {
|
|
45
|
+
readonly expectation: Expectation;
|
|
46
|
+
/** Whether the expectation holds on `page` now. */
|
|
47
|
+
readonly holds: (page: Page) => Effect.Effect<boolean, BrowserError>;
|
|
48
|
+
/**
|
|
49
|
+
* `act` on `page`, unless the expectation holds there already: see the module's comment. A
|
|
50
|
+
* failure before its input went is the action's own, and nothing is checked.
|
|
51
|
+
*/
|
|
52
|
+
readonly run: (page: Page, act: (page: Page) => Effect.Effect<unknown, BrowserError>) => Effect.Effect<Outcome, BrowserError>;
|
|
53
|
+
}
|
|
54
|
+
/** Begin an attempt at `expectation` on `page`, which takes its baseline from the page now. */
|
|
55
|
+
export declare const attempt: (page: Page, expectation: Expectation, options?: Options | undefined) => Effect.Effect<{
|
|
56
|
+
expectation: Expectation;
|
|
57
|
+
holds: (target: Page) => Effect.Effect<boolean, BrowserError, never>;
|
|
58
|
+
run: (target: Page, act: (page: Page) => Effect.Effect<unknown, BrowserError>) => Effect.Effect<"AlreadyDone" | "Done" | "NotDone", BrowserError, never>;
|
|
59
|
+
}, BrowserError, never>;
|
|
60
|
+
//#endregion
|
|
61
|
+
export { Expect_d_exports as t };
|
|
62
|
+
//# sourceMappingURL=Expect.d.mts.map
|