browser-pilot 0.0.15 → 0.0.16
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 +16 -3
- package/dist/actions.cjs +60 -45
- package/dist/actions.d.cts +2 -2
- package/dist/actions.d.ts +2 -2
- package/dist/actions.mjs +1 -1
- package/dist/{browser-MEWT75IB.mjs → browser-ZCR6AA4D.mjs} +2 -2
- package/dist/browser.cjs +455 -67
- package/dist/browser.d.cts +3 -3
- package/dist/browser.d.ts +3 -3
- package/dist/browser.mjs +3 -3
- package/dist/{chunk-USYSHCI3.mjs → chunk-6GBYX7C2.mjs} +87 -62
- package/dist/chunk-EZNZ72VA.mjs +563 -0
- package/dist/{chunk-ZAXQ5OTV.mjs → chunk-NNEHWWHL.mjs} +23 -9
- package/dist/{chunk-WPNW23CE.mjs → chunk-TJ5B56NV.mjs} +345 -7
- package/dist/{chunk-7YVCOL2W.mjs → chunk-V3VLBQAM.mjs} +60 -45
- package/dist/cli.mjs +530 -381
- package/dist/index.cjs +419 -55
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +19 -7
- package/dist/{page-XPS6IC6V.mjs → page-IUUTJ3SW.mjs} +1 -1
- package/dist/providers.cjs +637 -2
- package/dist/providers.d.cts +2 -2
- package/dist/providers.d.ts +2 -2
- package/dist/providers.mjs +17 -3
- package/dist/{types-C9ySEdOX.d.cts → types-BflRmiDz.d.cts} +1 -1
- package/dist/{types-Cvvf0oGu.d.ts → types-BzM-IfsL.d.ts} +1 -1
- package/dist/types-DeVSWhXj.d.cts +142 -0
- package/dist/types-DeVSWhXj.d.ts +142 -0
- package/package.json +1 -1
- package/dist/chunk-BRAFQUMG.mjs +0 -229
- package/dist/types--wXNHUwt.d.cts +0 -56
- package/dist/types--wXNHUwt.d.ts +0 -56
package/dist/index.cjs
CHANGED
|
@@ -35,6 +35,7 @@ __export(src_exports, {
|
|
|
35
35
|
BatchExecutor: () => BatchExecutor,
|
|
36
36
|
Browser: () => Browser,
|
|
37
37
|
BrowserBaseProvider: () => BrowserBaseProvider,
|
|
38
|
+
BrowserEndpointResolutionError: () => BrowserEndpointResolutionError,
|
|
38
39
|
BrowserlessProvider: () => BrowserlessProvider,
|
|
39
40
|
CDPError: () => CDPError,
|
|
40
41
|
ElementNotFoundError: () => ElementNotFoundError,
|
|
@@ -46,12 +47,14 @@ __export(src_exports, {
|
|
|
46
47
|
Tracer: () => Tracer,
|
|
47
48
|
addBatchToPage: () => addBatchToPage,
|
|
48
49
|
bufferToBase64: () => bufferToBase64,
|
|
50
|
+
buildLocalBrowserScanTargets: () => buildLocalBrowserScanTargets,
|
|
49
51
|
calculateRMS: () => calculateRMS,
|
|
50
52
|
connect: () => connect,
|
|
51
53
|
createCDPClient: () => createCDPClient,
|
|
52
54
|
createProvider: () => createProvider,
|
|
53
55
|
devices: () => devices,
|
|
54
56
|
disableTracing: () => disableTracing,
|
|
57
|
+
discoverLocalBrowsers: () => discoverLocalBrowsers,
|
|
55
58
|
discoverTargets: () => discoverTargets,
|
|
56
59
|
enableTracing: () => enableTracing,
|
|
57
60
|
generateSilence: () => generateSilence,
|
|
@@ -61,8 +64,11 @@ __export(src_exports, {
|
|
|
61
64
|
getTracer: () => getTracer,
|
|
62
65
|
grantAudioPermissions: () => grantAudioPermissions,
|
|
63
66
|
isTranscriptionAvailable: () => isTranscriptionAvailable,
|
|
67
|
+
parseDevToolsActivePortFile: () => parseDevToolsActivePortFile,
|
|
64
68
|
parseWavHeader: () => parseWavHeader,
|
|
65
69
|
pcmToWav: () => pcmToWav,
|
|
70
|
+
resolveBrowserEndpoint: () => resolveBrowserEndpoint,
|
|
71
|
+
resolveChromeUserDataDirs: () => resolveChromeUserDataDirs,
|
|
66
72
|
transcribe: () => transcribe,
|
|
67
73
|
validateSteps: () => validateSteps,
|
|
68
74
|
waitForAnyElement: () => waitForAnyElement,
|
|
@@ -942,7 +948,9 @@ function buildTraceSummaries(events) {
|
|
|
942
948
|
};
|
|
943
949
|
}
|
|
944
950
|
function summarizeWs(events) {
|
|
945
|
-
const relevant = events.filter(
|
|
951
|
+
const relevant = events.filter(
|
|
952
|
+
(event) => event.channel === "ws" || event.event.startsWith("ws.")
|
|
953
|
+
);
|
|
946
954
|
const connections = /* @__PURE__ */ new Map();
|
|
947
955
|
for (const event of relevant) {
|
|
948
956
|
const id = event.connectionId ?? event.requestId ?? event.traceId;
|
|
@@ -972,7 +980,7 @@ function summarizeWs(events) {
|
|
|
972
980
|
}
|
|
973
981
|
const values = [...connections.values()];
|
|
974
982
|
const reconnects = values.reduce((count, connection) => {
|
|
975
|
-
return connection.closedAt && !connection.createdAt ? count : count;
|
|
983
|
+
return connection.closedAt && !connection.createdAt ? count + 1 : count;
|
|
976
984
|
}, 0);
|
|
977
985
|
return {
|
|
978
986
|
view: "ws",
|
|
@@ -1225,6 +1233,31 @@ function frameToStep(frame) {
|
|
|
1225
1233
|
}
|
|
1226
1234
|
}
|
|
1227
1235
|
|
|
1236
|
+
// src/trace/model.ts
|
|
1237
|
+
function createTraceId(prefix = "evt") {
|
|
1238
|
+
const random = Math.random().toString(36).slice(2, 10);
|
|
1239
|
+
return `${prefix}-${Date.now().toString(36)}-${random}`;
|
|
1240
|
+
}
|
|
1241
|
+
function normalizeTraceEvent(event) {
|
|
1242
|
+
return {
|
|
1243
|
+
traceId: event.traceId ?? createTraceId(event.channel),
|
|
1244
|
+
ts: event.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1245
|
+
elapsedMs: event.elapsedMs ?? 0,
|
|
1246
|
+
severity: event.severity ?? inferSeverity(event.event),
|
|
1247
|
+
data: event.data ?? {},
|
|
1248
|
+
...event
|
|
1249
|
+
};
|
|
1250
|
+
}
|
|
1251
|
+
function inferSeverity(eventName) {
|
|
1252
|
+
if (eventName.includes(".failed") || eventName.includes(".error") || eventName.includes("exception") || eventName.includes("notReady")) {
|
|
1253
|
+
return "error";
|
|
1254
|
+
}
|
|
1255
|
+
if (eventName.includes(".closed") || eventName.includes(".warn") || eventName.includes(".changed")) {
|
|
1256
|
+
return "warn";
|
|
1257
|
+
}
|
|
1258
|
+
return "info";
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1228
1261
|
// src/trace/script.ts
|
|
1229
1262
|
var TRACE_BINDING_NAME = "__bpTraceBinding";
|
|
1230
1263
|
var TRACE_SCRIPT = `
|
|
@@ -1504,31 +1537,6 @@ var TRACE_SCRIPT = `
|
|
|
1504
1537
|
})();
|
|
1505
1538
|
`;
|
|
1506
1539
|
|
|
1507
|
-
// src/trace/model.ts
|
|
1508
|
-
function createTraceId(prefix = "evt") {
|
|
1509
|
-
const random = Math.random().toString(36).slice(2, 10);
|
|
1510
|
-
return `${prefix}-${Date.now().toString(36)}-${random}`;
|
|
1511
|
-
}
|
|
1512
|
-
function normalizeTraceEvent(event) {
|
|
1513
|
-
return {
|
|
1514
|
-
traceId: event.traceId ?? createTraceId(event.channel),
|
|
1515
|
-
ts: event.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1516
|
-
elapsedMs: event.elapsedMs ?? 0,
|
|
1517
|
-
severity: event.severity ?? inferSeverity(event.event),
|
|
1518
|
-
data: event.data ?? {},
|
|
1519
|
-
...event
|
|
1520
|
-
};
|
|
1521
|
-
}
|
|
1522
|
-
function inferSeverity(eventName) {
|
|
1523
|
-
if (eventName.includes(".failed") || eventName.includes(".error") || eventName.includes("exception") || eventName.includes("notReady")) {
|
|
1524
|
-
return "error";
|
|
1525
|
-
}
|
|
1526
|
-
if (eventName.includes(".closed") || eventName.includes(".warn") || eventName.includes(".changed")) {
|
|
1527
|
-
return "warn";
|
|
1528
|
-
}
|
|
1529
|
-
return "info";
|
|
1530
|
-
}
|
|
1531
|
-
|
|
1532
1540
|
// src/trace/live.ts
|
|
1533
1541
|
function globToRegex(pattern) {
|
|
1534
1542
|
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
@@ -1545,6 +1553,15 @@ var DEFAULT_RECORDING_SKIP_ACTIONS = [
|
|
|
1545
1553
|
"text",
|
|
1546
1554
|
"screenshot"
|
|
1547
1555
|
];
|
|
1556
|
+
function readString(value) {
|
|
1557
|
+
return typeof value === "string" ? value : void 0;
|
|
1558
|
+
}
|
|
1559
|
+
function readStringOr(value, fallback = "") {
|
|
1560
|
+
return readString(value) ?? fallback;
|
|
1561
|
+
}
|
|
1562
|
+
function formatConsoleArg(entry) {
|
|
1563
|
+
return readString(entry["value"]) ?? readString(entry["description"]) ?? "";
|
|
1564
|
+
}
|
|
1548
1565
|
function loadExistingRecording(manifestPath) {
|
|
1549
1566
|
try {
|
|
1550
1567
|
const raw = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
@@ -2345,8 +2362,13 @@ Valid actions: ${valid}`);
|
|
|
2345
2362
|
await this.page.cdpClient.send("Runtime.addBinding", { name: TRACE_BINDING_NAME });
|
|
2346
2363
|
} catch {
|
|
2347
2364
|
}
|
|
2348
|
-
await this.page.cdpClient.send("Page.addScriptToEvaluateOnNewDocument", {
|
|
2349
|
-
|
|
2365
|
+
await this.page.cdpClient.send("Page.addScriptToEvaluateOnNewDocument", {
|
|
2366
|
+
source: TRACE_SCRIPT
|
|
2367
|
+
});
|
|
2368
|
+
await this.page.cdpClient.send("Runtime.evaluate", {
|
|
2369
|
+
expression: TRACE_SCRIPT,
|
|
2370
|
+
awaitPromise: false
|
|
2371
|
+
});
|
|
2350
2372
|
}
|
|
2351
2373
|
async waitForWsMessage(match, where, timeout) {
|
|
2352
2374
|
await this.ensureTraceHooks();
|
|
@@ -2364,12 +2386,12 @@ Valid actions: ${valid}`);
|
|
|
2364
2386
|
clearTimeout(timer);
|
|
2365
2387
|
};
|
|
2366
2388
|
const onCreated = (params) => {
|
|
2367
|
-
wsUrls.set(
|
|
2389
|
+
wsUrls.set(readStringOr(params["requestId"]), readStringOr(params["url"]));
|
|
2368
2390
|
};
|
|
2369
2391
|
const onFrame = (params) => {
|
|
2370
|
-
const requestId =
|
|
2392
|
+
const requestId = readStringOr(params["requestId"]);
|
|
2371
2393
|
const response = params["response"] ?? {};
|
|
2372
|
-
const payload =
|
|
2394
|
+
const payload = response.payloadData ?? "";
|
|
2373
2395
|
const url = wsUrls.get(requestId) ?? "";
|
|
2374
2396
|
if (!regex.test(url) && !regex.test(payload)) {
|
|
2375
2397
|
return;
|
|
@@ -2385,13 +2407,13 @@ Valid actions: ${valid}`);
|
|
|
2385
2407
|
return;
|
|
2386
2408
|
}
|
|
2387
2409
|
try {
|
|
2388
|
-
const parsed = JSON.parse(
|
|
2410
|
+
const parsed = JSON.parse(readStringOr(params["payload"]));
|
|
2389
2411
|
if (parsed.event !== "ws.frame.received") {
|
|
2390
2412
|
return;
|
|
2391
2413
|
}
|
|
2392
2414
|
const data = parsed.data ?? {};
|
|
2393
|
-
const payload =
|
|
2394
|
-
const url =
|
|
2415
|
+
const payload = readStringOr(data["payload"]);
|
|
2416
|
+
const url = readStringOr(data["url"]);
|
|
2395
2417
|
if (!regex.test(url) && !regex.test(payload)) {
|
|
2396
2418
|
return;
|
|
2397
2419
|
}
|
|
@@ -2400,7 +2422,7 @@ Valid actions: ${valid}`);
|
|
|
2400
2422
|
}
|
|
2401
2423
|
cleanup();
|
|
2402
2424
|
resolve({
|
|
2403
|
-
requestId:
|
|
2425
|
+
requestId: readStringOr(data["connectionId"]),
|
|
2404
2426
|
url,
|
|
2405
2427
|
payload
|
|
2406
2428
|
});
|
|
@@ -2444,13 +2466,14 @@ Valid actions: ${valid}`);
|
|
|
2444
2466
|
if (!entry || typeof entry !== "object") {
|
|
2445
2467
|
continue;
|
|
2446
2468
|
}
|
|
2447
|
-
const
|
|
2469
|
+
const record = entry;
|
|
2470
|
+
const event = readStringOr(record["event"]);
|
|
2448
2471
|
if (event !== "ws.frame.received") {
|
|
2449
2472
|
continue;
|
|
2450
2473
|
}
|
|
2451
|
-
const data =
|
|
2452
|
-
const payload =
|
|
2453
|
-
const url =
|
|
2474
|
+
const data = record["data"] ?? {};
|
|
2475
|
+
const payload = readStringOr(data["payload"]);
|
|
2476
|
+
const url = readStringOr(data["url"]);
|
|
2454
2477
|
if (!regex.test(url) && !regex.test(payload)) {
|
|
2455
2478
|
continue;
|
|
2456
2479
|
}
|
|
@@ -2458,7 +2481,7 @@ Valid actions: ${valid}`);
|
|
|
2458
2481
|
continue;
|
|
2459
2482
|
}
|
|
2460
2483
|
return {
|
|
2461
|
-
requestId:
|
|
2484
|
+
requestId: readStringOr(data["connectionId"]),
|
|
2462
2485
|
url,
|
|
2463
2486
|
payload
|
|
2464
2487
|
};
|
|
@@ -2479,13 +2502,11 @@ Valid actions: ${valid}`);
|
|
|
2479
2502
|
return;
|
|
2480
2503
|
}
|
|
2481
2504
|
const args = Array.isArray(params["args"]) ? params["args"] : [];
|
|
2482
|
-
errors.push(
|
|
2483
|
-
args.map((entry) => String(entry["value"] ?? entry["description"] ?? "")).filter(Boolean).join(" ")
|
|
2484
|
-
);
|
|
2505
|
+
errors.push(args.map(formatConsoleArg).filter(Boolean).join(" "));
|
|
2485
2506
|
};
|
|
2486
2507
|
const onException = (params) => {
|
|
2487
2508
|
const details = params["exceptionDetails"] ?? {};
|
|
2488
|
-
errors.push(
|
|
2509
|
+
errors.push(readString(details["text"]) ?? "Runtime exception");
|
|
2489
2510
|
};
|
|
2490
2511
|
const timer = setTimeout(() => {
|
|
2491
2512
|
cleanup();
|
|
@@ -3258,12 +3279,12 @@ function parseWavHeader(data) {
|
|
|
3258
3279
|
if (data.byteLength < 44) {
|
|
3259
3280
|
throw new Error("Invalid WAV: file too small");
|
|
3260
3281
|
}
|
|
3261
|
-
const riff =
|
|
3262
|
-
const wave =
|
|
3282
|
+
const riff = readString2(view, 0, 4);
|
|
3283
|
+
const wave = readString2(view, 8, 4);
|
|
3263
3284
|
if (riff !== "RIFF" || wave !== "WAVE") {
|
|
3264
3285
|
throw new Error("Invalid WAV: missing RIFF/WAVE header");
|
|
3265
3286
|
}
|
|
3266
|
-
const fmt =
|
|
3287
|
+
const fmt = readString2(view, 12, 4);
|
|
3267
3288
|
if (fmt !== "fmt ") {
|
|
3268
3289
|
throw new Error("Invalid WAV: missing fmt chunk");
|
|
3269
3290
|
}
|
|
@@ -3272,7 +3293,7 @@ function parseWavHeader(data) {
|
|
|
3272
3293
|
const bitsPerSample = view.getUint16(34, true);
|
|
3273
3294
|
let dataOffset = 36;
|
|
3274
3295
|
while (dataOffset < data.byteLength - 8) {
|
|
3275
|
-
const chunkId =
|
|
3296
|
+
const chunkId = readString2(view, dataOffset, 4);
|
|
3276
3297
|
const chunkSize = view.getUint32(dataOffset + 4, true);
|
|
3277
3298
|
if (chunkId === "data") {
|
|
3278
3299
|
return {
|
|
@@ -3303,7 +3324,7 @@ function writeString(view, offset, str) {
|
|
|
3303
3324
|
view.setUint8(offset + i, str.charCodeAt(i));
|
|
3304
3325
|
}
|
|
3305
3326
|
}
|
|
3306
|
-
function
|
|
3327
|
+
function readString2(view, offset, length) {
|
|
3307
3328
|
let str = "";
|
|
3308
3329
|
for (let i = 0; i < length; i++) {
|
|
3309
3330
|
str += String.fromCharCode(view.getUint8(offset + i));
|
|
@@ -5092,6 +5113,330 @@ async function getBrowserWebSocketUrl(host = "localhost:9222") {
|
|
|
5092
5113
|
return info.webSocketDebuggerUrl;
|
|
5093
5114
|
}
|
|
5094
5115
|
|
|
5116
|
+
// src/providers/local-discovery.ts
|
|
5117
|
+
var CHANNEL_ORDER = ["stable", "beta", "dev", "canary"];
|
|
5118
|
+
var DEFAULT_PROBE_TIMEOUT_MS = 1e3;
|
|
5119
|
+
var DevToolsActivePortParseError = class extends Error {
|
|
5120
|
+
constructor(message, reason) {
|
|
5121
|
+
super(message);
|
|
5122
|
+
this.reason = reason;
|
|
5123
|
+
this.name = "DevToolsActivePortParseError";
|
|
5124
|
+
}
|
|
5125
|
+
};
|
|
5126
|
+
function getRuntimeEnv() {
|
|
5127
|
+
if (typeof process === "undefined") {
|
|
5128
|
+
return {};
|
|
5129
|
+
}
|
|
5130
|
+
return process.env;
|
|
5131
|
+
}
|
|
5132
|
+
function getRuntimePlatform() {
|
|
5133
|
+
if (typeof process === "undefined") {
|
|
5134
|
+
return void 0;
|
|
5135
|
+
}
|
|
5136
|
+
return process.platform;
|
|
5137
|
+
}
|
|
5138
|
+
function normalizePlatform(platform) {
|
|
5139
|
+
if (platform === "darwin" || platform === "linux" || platform === "win32") {
|
|
5140
|
+
return platform;
|
|
5141
|
+
}
|
|
5142
|
+
throw new Error(`Unsupported platform: ${platform ?? "unknown"}`);
|
|
5143
|
+
}
|
|
5144
|
+
function trimTrailingSeparator(path) {
|
|
5145
|
+
return path.replace(/[\\/]+$/, "");
|
|
5146
|
+
}
|
|
5147
|
+
function joinPath(platform, ...parts) {
|
|
5148
|
+
const separator = platform === "win32" ? "\\" : "/";
|
|
5149
|
+
const cleaned = parts.map((part, index) => {
|
|
5150
|
+
if (index === 0) return trimTrailingSeparator(part);
|
|
5151
|
+
return part.replace(/^[\\/]+/, "").replace(/[\\/]+$/, "");
|
|
5152
|
+
}).filter((part) => part.length > 0);
|
|
5153
|
+
return cleaned.join(separator);
|
|
5154
|
+
}
|
|
5155
|
+
function resolveHomeDir(platform, env, explicitHomeDir) {
|
|
5156
|
+
if (explicitHomeDir) {
|
|
5157
|
+
return explicitHomeDir;
|
|
5158
|
+
}
|
|
5159
|
+
if (platform === "win32") {
|
|
5160
|
+
return env["USERPROFILE"] ?? env["HOME"] ?? "";
|
|
5161
|
+
}
|
|
5162
|
+
return env["HOME"] ?? env["USERPROFILE"] ?? "";
|
|
5163
|
+
}
|
|
5164
|
+
function toFileFailure(target, error) {
|
|
5165
|
+
const errno = error?.code;
|
|
5166
|
+
if (errno === "ENOENT") {
|
|
5167
|
+
return {
|
|
5168
|
+
...target,
|
|
5169
|
+
reason: "missing-file",
|
|
5170
|
+
message: `DevToolsActivePort not found at ${target.portFile}`
|
|
5171
|
+
};
|
|
5172
|
+
}
|
|
5173
|
+
return {
|
|
5174
|
+
...target,
|
|
5175
|
+
reason: "unreadable-file",
|
|
5176
|
+
message: error instanceof Error ? error.message : `Could not read DevToolsActivePort at ${target.portFile}`
|
|
5177
|
+
};
|
|
5178
|
+
}
|
|
5179
|
+
function toProbeFailure(target, wsUrl, error) {
|
|
5180
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
5181
|
+
const lowerMessage = message.toLowerCase();
|
|
5182
|
+
let reason = "connection-error";
|
|
5183
|
+
if (lowerMessage.includes("refused") || lowerMessage.includes("econnrefused")) {
|
|
5184
|
+
reason = "connection-refused";
|
|
5185
|
+
} else if (lowerMessage.includes("timeout") || lowerMessage.includes("timed out")) {
|
|
5186
|
+
reason = "connection-timeout";
|
|
5187
|
+
} else if (lowerMessage.includes("closed")) {
|
|
5188
|
+
reason = "unexpected-close";
|
|
5189
|
+
} else if (lowerMessage.includes("browser.getversion") || lowerMessage.includes("cdp") || lowerMessage.includes("protocol")) {
|
|
5190
|
+
reason = "cdp-error";
|
|
5191
|
+
}
|
|
5192
|
+
return {
|
|
5193
|
+
...target,
|
|
5194
|
+
wsUrl,
|
|
5195
|
+
reason,
|
|
5196
|
+
message
|
|
5197
|
+
};
|
|
5198
|
+
}
|
|
5199
|
+
async function readTextFile(path) {
|
|
5200
|
+
const fs2 = await import("fs/promises");
|
|
5201
|
+
return fs2.readFile(path, "utf-8");
|
|
5202
|
+
}
|
|
5203
|
+
async function probeBrowserWebSocket(wsUrl, timeoutMs) {
|
|
5204
|
+
let client;
|
|
5205
|
+
try {
|
|
5206
|
+
client = await createCDPClient(wsUrl, { timeout: timeoutMs });
|
|
5207
|
+
const version = await client.send("Browser.getVersion", void 0, null);
|
|
5208
|
+
return { browserVersion: version.product };
|
|
5209
|
+
} finally {
|
|
5210
|
+
await client?.close().catch(() => {
|
|
5211
|
+
});
|
|
5212
|
+
}
|
|
5213
|
+
}
|
|
5214
|
+
var defaultDependencies = {
|
|
5215
|
+
readTextFile,
|
|
5216
|
+
probeBrowserWebSocket,
|
|
5217
|
+
getLegacyBrowserWebSocketUrl: getBrowserWebSocketUrl
|
|
5218
|
+
};
|
|
5219
|
+
function resolveChromeUserDataDirs(options = {}) {
|
|
5220
|
+
const env = options.env ?? getRuntimeEnv();
|
|
5221
|
+
const platform = normalizePlatform(options.platform ?? getRuntimePlatform());
|
|
5222
|
+
const homeDir = resolveHomeDir(platform, env, options.homeDir);
|
|
5223
|
+
if (!homeDir) {
|
|
5224
|
+
throw new Error("Could not determine home directory for local Chrome discovery");
|
|
5225
|
+
}
|
|
5226
|
+
switch (platform) {
|
|
5227
|
+
case "darwin": {
|
|
5228
|
+
const base = joinPath(platform, homeDir, "Library", "Application Support", "Google");
|
|
5229
|
+
return {
|
|
5230
|
+
stable: joinPath(platform, base, "Chrome"),
|
|
5231
|
+
beta: joinPath(platform, base, "Chrome Beta"),
|
|
5232
|
+
dev: joinPath(platform, base, "Chrome Dev"),
|
|
5233
|
+
canary: joinPath(platform, base, "Chrome Canary")
|
|
5234
|
+
};
|
|
5235
|
+
}
|
|
5236
|
+
case "linux": {
|
|
5237
|
+
const configHome = env["CHROME_CONFIG_HOME"] ?? env["XDG_CONFIG_HOME"] ?? joinPath(platform, homeDir, ".config");
|
|
5238
|
+
return {
|
|
5239
|
+
stable: joinPath(platform, configHome, "google-chrome"),
|
|
5240
|
+
beta: joinPath(platform, configHome, "google-chrome-beta"),
|
|
5241
|
+
dev: joinPath(platform, configHome, "google-chrome-dev"),
|
|
5242
|
+
canary: joinPath(platform, configHome, "google-chrome-canary")
|
|
5243
|
+
};
|
|
5244
|
+
}
|
|
5245
|
+
case "win32": {
|
|
5246
|
+
const localAppData = env["LOCALAPPDATA"] ?? joinPath(platform, homeDir, "AppData", "Local");
|
|
5247
|
+
const base = joinPath(platform, localAppData, "Google");
|
|
5248
|
+
return {
|
|
5249
|
+
stable: joinPath(platform, base, "Chrome", "User Data"),
|
|
5250
|
+
beta: joinPath(platform, base, "Chrome Beta", "User Data"),
|
|
5251
|
+
dev: joinPath(platform, base, "Chrome Dev", "User Data"),
|
|
5252
|
+
canary: joinPath(platform, base, "Chrome SxS", "User Data")
|
|
5253
|
+
};
|
|
5254
|
+
}
|
|
5255
|
+
}
|
|
5256
|
+
throw new Error(`Unsupported platform for local Chrome discovery: ${platform}`);
|
|
5257
|
+
}
|
|
5258
|
+
function buildLocalBrowserScanTargets(options = {}) {
|
|
5259
|
+
const env = options.env ?? getRuntimeEnv();
|
|
5260
|
+
const platform = normalizePlatform(options.platform ?? getRuntimePlatform());
|
|
5261
|
+
if (options.userDataDir) {
|
|
5262
|
+
return [
|
|
5263
|
+
{
|
|
5264
|
+
channel: options.channel ?? "custom",
|
|
5265
|
+
userDataDir: options.userDataDir,
|
|
5266
|
+
portFile: joinPath(platform, options.userDataDir, "DevToolsActivePort")
|
|
5267
|
+
}
|
|
5268
|
+
];
|
|
5269
|
+
}
|
|
5270
|
+
const dirs = resolveChromeUserDataDirs({
|
|
5271
|
+
platform,
|
|
5272
|
+
env,
|
|
5273
|
+
homeDir: options.homeDir
|
|
5274
|
+
});
|
|
5275
|
+
const channels = options.channel ? [options.channel] : CHANNEL_ORDER;
|
|
5276
|
+
return channels.map((channel) => ({
|
|
5277
|
+
channel,
|
|
5278
|
+
userDataDir: dirs[channel],
|
|
5279
|
+
portFile: joinPath(platform, dirs[channel], "DevToolsActivePort")
|
|
5280
|
+
}));
|
|
5281
|
+
}
|
|
5282
|
+
function parseDevToolsActivePortFile(content) {
|
|
5283
|
+
const lines = content.split(/\r?\n/u).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
5284
|
+
if (lines.length !== 2) {
|
|
5285
|
+
throw new DevToolsActivePortParseError(
|
|
5286
|
+
`Expected exactly 2 non-empty lines in DevToolsActivePort, got ${lines.length}`,
|
|
5287
|
+
"malformed-file"
|
|
5288
|
+
);
|
|
5289
|
+
}
|
|
5290
|
+
const portText = lines[0];
|
|
5291
|
+
const browserPath = lines[1];
|
|
5292
|
+
const port = Number.parseInt(portText, 10);
|
|
5293
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
5294
|
+
throw new DevToolsActivePortParseError(
|
|
5295
|
+
`Invalid DevToolsActivePort port: ${portText}`,
|
|
5296
|
+
"invalid-port"
|
|
5297
|
+
);
|
|
5298
|
+
}
|
|
5299
|
+
if (!browserPath.startsWith("/devtools/browser/") || browserPath.includes("..") || /[?#\s\\]/u.test(browserPath)) {
|
|
5300
|
+
throw new DevToolsActivePortParseError(
|
|
5301
|
+
`Invalid DevToolsActivePort browser path: ${browserPath}`,
|
|
5302
|
+
"invalid-path"
|
|
5303
|
+
);
|
|
5304
|
+
}
|
|
5305
|
+
return {
|
|
5306
|
+
port,
|
|
5307
|
+
browserPath,
|
|
5308
|
+
wsUrl: `ws://127.0.0.1:${port}${browserPath}`
|
|
5309
|
+
};
|
|
5310
|
+
}
|
|
5311
|
+
async function inspectScanTarget(target, options, deps) {
|
|
5312
|
+
let content;
|
|
5313
|
+
try {
|
|
5314
|
+
content = await deps.readTextFile(target.portFile);
|
|
5315
|
+
} catch (error) {
|
|
5316
|
+
return { kind: "failure", failure: toFileFailure(target, error) };
|
|
5317
|
+
}
|
|
5318
|
+
let parsed;
|
|
5319
|
+
try {
|
|
5320
|
+
parsed = parseDevToolsActivePortFile(content);
|
|
5321
|
+
} catch (error) {
|
|
5322
|
+
if (error instanceof DevToolsActivePortParseError) {
|
|
5323
|
+
return {
|
|
5324
|
+
kind: "failure",
|
|
5325
|
+
failure: {
|
|
5326
|
+
...target,
|
|
5327
|
+
reason: error.reason,
|
|
5328
|
+
message: error.message
|
|
5329
|
+
}
|
|
5330
|
+
};
|
|
5331
|
+
}
|
|
5332
|
+
throw error;
|
|
5333
|
+
}
|
|
5334
|
+
try {
|
|
5335
|
+
const probe = await deps.probeBrowserWebSocket(
|
|
5336
|
+
parsed.wsUrl,
|
|
5337
|
+
options.probeTimeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS
|
|
5338
|
+
);
|
|
5339
|
+
return {
|
|
5340
|
+
kind: "candidate",
|
|
5341
|
+
candidate: {
|
|
5342
|
+
...target,
|
|
5343
|
+
port: parsed.port,
|
|
5344
|
+
browserPath: parsed.browserPath,
|
|
5345
|
+
wsUrl: parsed.wsUrl,
|
|
5346
|
+
browserVersion: probe.browserVersion
|
|
5347
|
+
}
|
|
5348
|
+
};
|
|
5349
|
+
} catch (error) {
|
|
5350
|
+
return {
|
|
5351
|
+
kind: "failure",
|
|
5352
|
+
failure: toProbeFailure(target, parsed.wsUrl, error)
|
|
5353
|
+
};
|
|
5354
|
+
}
|
|
5355
|
+
}
|
|
5356
|
+
async function discoverLocalBrowsers(options = {}, deps = defaultDependencies) {
|
|
5357
|
+
const scanTargets = buildLocalBrowserScanTargets(options);
|
|
5358
|
+
const outcomes = await Promise.all(
|
|
5359
|
+
scanTargets.map((target) => inspectScanTarget(target, options, deps))
|
|
5360
|
+
);
|
|
5361
|
+
const candidates = [];
|
|
5362
|
+
const failures = [];
|
|
5363
|
+
for (const outcome of outcomes) {
|
|
5364
|
+
if (outcome.kind === "candidate") {
|
|
5365
|
+
candidates.push(outcome.candidate);
|
|
5366
|
+
} else {
|
|
5367
|
+
failures.push(outcome.failure);
|
|
5368
|
+
}
|
|
5369
|
+
}
|
|
5370
|
+
return { candidates, failures };
|
|
5371
|
+
}
|
|
5372
|
+
var BrowserEndpointResolutionError = class extends Error {
|
|
5373
|
+
constructor(code, message, details = {}) {
|
|
5374
|
+
super(message);
|
|
5375
|
+
this.code = code;
|
|
5376
|
+
this.details = details;
|
|
5377
|
+
}
|
|
5378
|
+
name = "BrowserEndpointResolutionError";
|
|
5379
|
+
};
|
|
5380
|
+
async function resolveBrowserEndpoint(options = {}, deps = defaultDependencies) {
|
|
5381
|
+
if (options.explicitWsUrl) {
|
|
5382
|
+
return {
|
|
5383
|
+
wsUrl: options.explicitWsUrl,
|
|
5384
|
+
source: "explicit-ws"
|
|
5385
|
+
};
|
|
5386
|
+
}
|
|
5387
|
+
let localDiscovery;
|
|
5388
|
+
if (options.allowLocalDiscovery ?? true) {
|
|
5389
|
+
localDiscovery = await discoverLocalBrowsers(options, deps);
|
|
5390
|
+
if (localDiscovery.candidates.length === 1) {
|
|
5391
|
+
const candidate = localDiscovery.candidates[0];
|
|
5392
|
+
return {
|
|
5393
|
+
wsUrl: candidate.wsUrl,
|
|
5394
|
+
source: "devtools-active-port",
|
|
5395
|
+
channel: candidate.channel,
|
|
5396
|
+
userDataDir: candidate.userDataDir
|
|
5397
|
+
};
|
|
5398
|
+
}
|
|
5399
|
+
if (localDiscovery.candidates.length > 1) {
|
|
5400
|
+
throw new BrowserEndpointResolutionError(
|
|
5401
|
+
"multiple-local-browsers",
|
|
5402
|
+
"Multiple local Chrome profiles are available for auto-discovery",
|
|
5403
|
+
{
|
|
5404
|
+
candidates: localDiscovery.candidates,
|
|
5405
|
+
failures: localDiscovery.failures
|
|
5406
|
+
}
|
|
5407
|
+
);
|
|
5408
|
+
}
|
|
5409
|
+
}
|
|
5410
|
+
if (options.allowLegacyHostFallback ?? true) {
|
|
5411
|
+
const legacyHost = options.legacyHost ?? "localhost:9222";
|
|
5412
|
+
try {
|
|
5413
|
+
return {
|
|
5414
|
+
wsUrl: await deps.getLegacyBrowserWebSocketUrl(legacyHost),
|
|
5415
|
+
source: "json-version"
|
|
5416
|
+
};
|
|
5417
|
+
} catch (error) {
|
|
5418
|
+
throw new BrowserEndpointResolutionError(
|
|
5419
|
+
"browser-not-found",
|
|
5420
|
+
"Could not resolve a browser endpoint",
|
|
5421
|
+
{
|
|
5422
|
+
candidates: localDiscovery?.candidates,
|
|
5423
|
+
failures: localDiscovery?.failures,
|
|
5424
|
+
legacyError: error instanceof Error ? error : new Error(String(error)),
|
|
5425
|
+
legacyHost
|
|
5426
|
+
}
|
|
5427
|
+
);
|
|
5428
|
+
}
|
|
5429
|
+
}
|
|
5430
|
+
throw new BrowserEndpointResolutionError(
|
|
5431
|
+
"browser-not-found",
|
|
5432
|
+
"Could not resolve a browser endpoint",
|
|
5433
|
+
{
|
|
5434
|
+
candidates: localDiscovery?.candidates,
|
|
5435
|
+
failures: localDiscovery?.failures
|
|
5436
|
+
}
|
|
5437
|
+
);
|
|
5438
|
+
}
|
|
5439
|
+
|
|
5095
5440
|
// src/providers/index.ts
|
|
5096
5441
|
function createProvider(options) {
|
|
5097
5442
|
switch (options.provider) {
|
|
@@ -9186,13 +9531,26 @@ var Browser = class _Browser {
|
|
|
9186
9531
|
* Connect to a browser instance
|
|
9187
9532
|
*/
|
|
9188
9533
|
static async connect(options) {
|
|
9189
|
-
|
|
9190
|
-
|
|
9534
|
+
let connectOptions = options;
|
|
9535
|
+
if (options.provider === "generic" && !options.wsUrl) {
|
|
9536
|
+
const endpoint = await resolveBrowserEndpoint({
|
|
9537
|
+
channel: options.channel,
|
|
9538
|
+
userDataDir: options.userDataDir,
|
|
9539
|
+
allowLocalDiscovery: true,
|
|
9540
|
+
allowLegacyHostFallback: true
|
|
9541
|
+
});
|
|
9542
|
+
connectOptions = {
|
|
9543
|
+
...options,
|
|
9544
|
+
wsUrl: endpoint.wsUrl
|
|
9545
|
+
};
|
|
9546
|
+
}
|
|
9547
|
+
const provider = createProvider(connectOptions);
|
|
9548
|
+
const session = await provider.createSession(connectOptions.session);
|
|
9191
9549
|
const cdp = await createCDPClient(session.wsUrl, {
|
|
9192
|
-
debug:
|
|
9193
|
-
timeout:
|
|
9550
|
+
debug: connectOptions.debug,
|
|
9551
|
+
timeout: connectOptions.timeout
|
|
9194
9552
|
});
|
|
9195
|
-
return new _Browser(cdp, provider, session,
|
|
9553
|
+
return new _Browser(cdp, provider, session, connectOptions);
|
|
9196
9554
|
}
|
|
9197
9555
|
/**
|
|
9198
9556
|
* Get or create a page by name.
|
|
@@ -9598,6 +9956,7 @@ function disableTracing() {
|
|
|
9598
9956
|
BatchExecutor,
|
|
9599
9957
|
Browser,
|
|
9600
9958
|
BrowserBaseProvider,
|
|
9959
|
+
BrowserEndpointResolutionError,
|
|
9601
9960
|
BrowserlessProvider,
|
|
9602
9961
|
CDPError,
|
|
9603
9962
|
ElementNotFoundError,
|
|
@@ -9609,12 +9968,14 @@ function disableTracing() {
|
|
|
9609
9968
|
Tracer,
|
|
9610
9969
|
addBatchToPage,
|
|
9611
9970
|
bufferToBase64,
|
|
9971
|
+
buildLocalBrowserScanTargets,
|
|
9612
9972
|
calculateRMS,
|
|
9613
9973
|
connect,
|
|
9614
9974
|
createCDPClient,
|
|
9615
9975
|
createProvider,
|
|
9616
9976
|
devices,
|
|
9617
9977
|
disableTracing,
|
|
9978
|
+
discoverLocalBrowsers,
|
|
9618
9979
|
discoverTargets,
|
|
9619
9980
|
enableTracing,
|
|
9620
9981
|
generateSilence,
|
|
@@ -9624,8 +9985,11 @@ function disableTracing() {
|
|
|
9624
9985
|
getTracer,
|
|
9625
9986
|
grantAudioPermissions,
|
|
9626
9987
|
isTranscriptionAvailable,
|
|
9988
|
+
parseDevToolsActivePortFile,
|
|
9627
9989
|
parseWavHeader,
|
|
9628
9990
|
pcmToWav,
|
|
9991
|
+
resolveBrowserEndpoint,
|
|
9992
|
+
resolveChromeUserDataDirs,
|
|
9629
9993
|
transcribe,
|
|
9630
9994
|
validateSteps,
|
|
9631
9995
|
waitForAnyElement,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export { BatchExecutor, ValidationError, ValidationResult, addBatchToPage, validateSteps } from './actions.cjs';
|
|
2
|
-
import { R as RequestPattern, a as RequestHandler, C as CaptureResult } from './types-
|
|
3
|
-
export { l as ActionOptions, m as ActionResult, A as ActionType, e as AudioChunk, f as AudioInput, g as AudioInputState, h as AudioOutput, B as BatchOptions, b as BatchResult, i as CaptureOptions, a7 as ClearCookiesOptions, n as ConsoleHandler, o as ConsoleMessage, p as ConsoleMessageType, a0 as ContinueRequestOptions, a8 as Cookie, q as CustomSelectConfig, a9 as DeleteCookieOptions, Z as DeviceDescriptor, _ as DeviceName, D as Dialog, r as DialogHandler, s as DialogType, t as Download, E as ElementInfo, u as ElementNotFoundError, v as EmulationState, w as ErrorHandler, a1 as FailRequestOptions, F as FileInput, x as FillOptions, y as FormField, z as FormOption, a2 as FulfillRequestOptions, G as GeolocationOptions, I as InteractiveElement, a3 as InterceptedRequest, N as NavigationError, H as NetworkIdleOptions, J as Page, K as PageError, L as PageSnapshot, P as PlayOptions, c as RecordOptions, a4 as RequestActions, a5 as ResourceType, j as RoundTripOptions, k as RoundTripResult, a6 as RouteOptions, aa as SetCookieOptions, M as SnapshotNode, O as SnapshotOptions, S as Step, d as StepResult, Q as SubmitOptions, T as TimeoutError, U as TypeOptions, V as UserAgentMetadata, W as UserAgentOptions, X as ViewportOptions, Y as WaitForOptions, ab as WaitOptions, ac as WaitResult, ad as WaitState, $ as devices, ae as waitForAnyElement, af as waitForElement, ag as waitForNavigation, ah as waitForNetworkIdle } from './types-
|
|
2
|
+
import { R as RequestPattern, a as RequestHandler, C as CaptureResult } from './types-BflRmiDz.cjs';
|
|
3
|
+
export { l as ActionOptions, m as ActionResult, A as ActionType, e as AudioChunk, f as AudioInput, g as AudioInputState, h as AudioOutput, B as BatchOptions, b as BatchResult, i as CaptureOptions, a7 as ClearCookiesOptions, n as ConsoleHandler, o as ConsoleMessage, p as ConsoleMessageType, a0 as ContinueRequestOptions, a8 as Cookie, q as CustomSelectConfig, a9 as DeleteCookieOptions, Z as DeviceDescriptor, _ as DeviceName, D as Dialog, r as DialogHandler, s as DialogType, t as Download, E as ElementInfo, u as ElementNotFoundError, v as EmulationState, w as ErrorHandler, a1 as FailRequestOptions, F as FileInput, x as FillOptions, y as FormField, z as FormOption, a2 as FulfillRequestOptions, G as GeolocationOptions, I as InteractiveElement, a3 as InterceptedRequest, N as NavigationError, H as NetworkIdleOptions, J as Page, K as PageError, L as PageSnapshot, P as PlayOptions, c as RecordOptions, a4 as RequestActions, a5 as ResourceType, j as RoundTripOptions, k as RoundTripResult, a6 as RouteOptions, aa as SetCookieOptions, M as SnapshotNode, O as SnapshotOptions, S as Step, d as StepResult, Q as SubmitOptions, T as TimeoutError, U as TypeOptions, V as UserAgentMetadata, W as UserAgentOptions, X as ViewportOptions, Y as WaitForOptions, ab as WaitOptions, ac as WaitResult, ad as WaitState, $ as devices, ae as waitForAnyElement, af as waitForElement, ag as waitForNavigation, ah as waitForNetworkIdle } from './types-BflRmiDz.cjs';
|
|
4
4
|
import { C as CDPClient } from './client-B5QBRgIy.cjs';
|
|
5
5
|
export { a as CDPClientOptions, c as createCDPClient } from './client-B5QBRgIy.cjs';
|
|
6
6
|
export { Browser, BrowserOptions, PageOptions, connect } from './browser.cjs';
|
|
7
7
|
export { CDPError } from './cdp.cjs';
|
|
8
8
|
export { BrowserBaseProvider, BrowserlessProvider, GenericProvider, createProvider, discoverTargets, getBrowserWebSocketUrl } from './providers.cjs';
|
|
9
|
-
export { b as ConnectOptions, C as CreateSessionOptions, P as Provider, a as ProviderSession } from './types
|
|
9
|
+
export { B as BrowserEndpointResolutionError, d as ChromeChannel, b as ConnectOptions, C as CreateSessionOptions, P as Provider, a as ProviderSession, R as ResolvedBrowserEndpoint, g as ResolvedBrowserSource, c as buildLocalBrowserScanTargets, f as discoverLocalBrowsers, p as parseDevToolsActivePortFile, r as resolveBrowserEndpoint, h as resolveChromeUserDataDirs } from './types-DeVSWhXj.cjs';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Request interception implementation
|