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
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-LCNFBXB5.mjs";
|
|
4
4
|
import {
|
|
5
5
|
Page
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-6GBYX7C2.mjs";
|
|
7
7
|
|
|
8
8
|
// src/providers/browserbase.ts
|
|
9
9
|
var BrowserBaseProvider = class {
|
|
@@ -190,6 +190,330 @@ async function getBrowserWebSocketUrl(host = "localhost:9222") {
|
|
|
190
190
|
return info.webSocketDebuggerUrl;
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
+
// src/providers/local-discovery.ts
|
|
194
|
+
var CHANNEL_ORDER = ["stable", "beta", "dev", "canary"];
|
|
195
|
+
var DEFAULT_PROBE_TIMEOUT_MS = 1e3;
|
|
196
|
+
var DevToolsActivePortParseError = class extends Error {
|
|
197
|
+
constructor(message, reason) {
|
|
198
|
+
super(message);
|
|
199
|
+
this.reason = reason;
|
|
200
|
+
this.name = "DevToolsActivePortParseError";
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
function getRuntimeEnv() {
|
|
204
|
+
if (typeof process === "undefined") {
|
|
205
|
+
return {};
|
|
206
|
+
}
|
|
207
|
+
return process.env;
|
|
208
|
+
}
|
|
209
|
+
function getRuntimePlatform() {
|
|
210
|
+
if (typeof process === "undefined") {
|
|
211
|
+
return void 0;
|
|
212
|
+
}
|
|
213
|
+
return process.platform;
|
|
214
|
+
}
|
|
215
|
+
function normalizePlatform(platform) {
|
|
216
|
+
if (platform === "darwin" || platform === "linux" || platform === "win32") {
|
|
217
|
+
return platform;
|
|
218
|
+
}
|
|
219
|
+
throw new Error(`Unsupported platform: ${platform ?? "unknown"}`);
|
|
220
|
+
}
|
|
221
|
+
function trimTrailingSeparator(path) {
|
|
222
|
+
return path.replace(/[\\/]+$/, "");
|
|
223
|
+
}
|
|
224
|
+
function joinPath(platform, ...parts) {
|
|
225
|
+
const separator = platform === "win32" ? "\\" : "/";
|
|
226
|
+
const cleaned = parts.map((part, index) => {
|
|
227
|
+
if (index === 0) return trimTrailingSeparator(part);
|
|
228
|
+
return part.replace(/^[\\/]+/, "").replace(/[\\/]+$/, "");
|
|
229
|
+
}).filter((part) => part.length > 0);
|
|
230
|
+
return cleaned.join(separator);
|
|
231
|
+
}
|
|
232
|
+
function resolveHomeDir(platform, env, explicitHomeDir) {
|
|
233
|
+
if (explicitHomeDir) {
|
|
234
|
+
return explicitHomeDir;
|
|
235
|
+
}
|
|
236
|
+
if (platform === "win32") {
|
|
237
|
+
return env["USERPROFILE"] ?? env["HOME"] ?? "";
|
|
238
|
+
}
|
|
239
|
+
return env["HOME"] ?? env["USERPROFILE"] ?? "";
|
|
240
|
+
}
|
|
241
|
+
function toFileFailure(target, error) {
|
|
242
|
+
const errno = error?.code;
|
|
243
|
+
if (errno === "ENOENT") {
|
|
244
|
+
return {
|
|
245
|
+
...target,
|
|
246
|
+
reason: "missing-file",
|
|
247
|
+
message: `DevToolsActivePort not found at ${target.portFile}`
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
...target,
|
|
252
|
+
reason: "unreadable-file",
|
|
253
|
+
message: error instanceof Error ? error.message : `Could not read DevToolsActivePort at ${target.portFile}`
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
function toProbeFailure(target, wsUrl, error) {
|
|
257
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
258
|
+
const lowerMessage = message.toLowerCase();
|
|
259
|
+
let reason = "connection-error";
|
|
260
|
+
if (lowerMessage.includes("refused") || lowerMessage.includes("econnrefused")) {
|
|
261
|
+
reason = "connection-refused";
|
|
262
|
+
} else if (lowerMessage.includes("timeout") || lowerMessage.includes("timed out")) {
|
|
263
|
+
reason = "connection-timeout";
|
|
264
|
+
} else if (lowerMessage.includes("closed")) {
|
|
265
|
+
reason = "unexpected-close";
|
|
266
|
+
} else if (lowerMessage.includes("browser.getversion") || lowerMessage.includes("cdp") || lowerMessage.includes("protocol")) {
|
|
267
|
+
reason = "cdp-error";
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
...target,
|
|
271
|
+
wsUrl,
|
|
272
|
+
reason,
|
|
273
|
+
message
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
async function readTextFile(path) {
|
|
277
|
+
const fs = await import("fs/promises");
|
|
278
|
+
return fs.readFile(path, "utf-8");
|
|
279
|
+
}
|
|
280
|
+
async function probeBrowserWebSocket(wsUrl, timeoutMs) {
|
|
281
|
+
let client;
|
|
282
|
+
try {
|
|
283
|
+
client = await createCDPClient(wsUrl, { timeout: timeoutMs });
|
|
284
|
+
const version = await client.send("Browser.getVersion", void 0, null);
|
|
285
|
+
return { browserVersion: version.product };
|
|
286
|
+
} finally {
|
|
287
|
+
await client?.close().catch(() => {
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
var defaultDependencies = {
|
|
292
|
+
readTextFile,
|
|
293
|
+
probeBrowserWebSocket,
|
|
294
|
+
getLegacyBrowserWebSocketUrl: getBrowserWebSocketUrl
|
|
295
|
+
};
|
|
296
|
+
function resolveChromeUserDataDirs(options = {}) {
|
|
297
|
+
const env = options.env ?? getRuntimeEnv();
|
|
298
|
+
const platform = normalizePlatform(options.platform ?? getRuntimePlatform());
|
|
299
|
+
const homeDir = resolveHomeDir(platform, env, options.homeDir);
|
|
300
|
+
if (!homeDir) {
|
|
301
|
+
throw new Error("Could not determine home directory for local Chrome discovery");
|
|
302
|
+
}
|
|
303
|
+
switch (platform) {
|
|
304
|
+
case "darwin": {
|
|
305
|
+
const base = joinPath(platform, homeDir, "Library", "Application Support", "Google");
|
|
306
|
+
return {
|
|
307
|
+
stable: joinPath(platform, base, "Chrome"),
|
|
308
|
+
beta: joinPath(platform, base, "Chrome Beta"),
|
|
309
|
+
dev: joinPath(platform, base, "Chrome Dev"),
|
|
310
|
+
canary: joinPath(platform, base, "Chrome Canary")
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
case "linux": {
|
|
314
|
+
const configHome = env["CHROME_CONFIG_HOME"] ?? env["XDG_CONFIG_HOME"] ?? joinPath(platform, homeDir, ".config");
|
|
315
|
+
return {
|
|
316
|
+
stable: joinPath(platform, configHome, "google-chrome"),
|
|
317
|
+
beta: joinPath(platform, configHome, "google-chrome-beta"),
|
|
318
|
+
dev: joinPath(platform, configHome, "google-chrome-dev"),
|
|
319
|
+
canary: joinPath(platform, configHome, "google-chrome-canary")
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
case "win32": {
|
|
323
|
+
const localAppData = env["LOCALAPPDATA"] ?? joinPath(platform, homeDir, "AppData", "Local");
|
|
324
|
+
const base = joinPath(platform, localAppData, "Google");
|
|
325
|
+
return {
|
|
326
|
+
stable: joinPath(platform, base, "Chrome", "User Data"),
|
|
327
|
+
beta: joinPath(platform, base, "Chrome Beta", "User Data"),
|
|
328
|
+
dev: joinPath(platform, base, "Chrome Dev", "User Data"),
|
|
329
|
+
canary: joinPath(platform, base, "Chrome SxS", "User Data")
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
throw new Error(`Unsupported platform for local Chrome discovery: ${platform}`);
|
|
334
|
+
}
|
|
335
|
+
function buildLocalBrowserScanTargets(options = {}) {
|
|
336
|
+
const env = options.env ?? getRuntimeEnv();
|
|
337
|
+
const platform = normalizePlatform(options.platform ?? getRuntimePlatform());
|
|
338
|
+
if (options.userDataDir) {
|
|
339
|
+
return [
|
|
340
|
+
{
|
|
341
|
+
channel: options.channel ?? "custom",
|
|
342
|
+
userDataDir: options.userDataDir,
|
|
343
|
+
portFile: joinPath(platform, options.userDataDir, "DevToolsActivePort")
|
|
344
|
+
}
|
|
345
|
+
];
|
|
346
|
+
}
|
|
347
|
+
const dirs = resolveChromeUserDataDirs({
|
|
348
|
+
platform,
|
|
349
|
+
env,
|
|
350
|
+
homeDir: options.homeDir
|
|
351
|
+
});
|
|
352
|
+
const channels = options.channel ? [options.channel] : CHANNEL_ORDER;
|
|
353
|
+
return channels.map((channel) => ({
|
|
354
|
+
channel,
|
|
355
|
+
userDataDir: dirs[channel],
|
|
356
|
+
portFile: joinPath(platform, dirs[channel], "DevToolsActivePort")
|
|
357
|
+
}));
|
|
358
|
+
}
|
|
359
|
+
function parseDevToolsActivePortFile(content) {
|
|
360
|
+
const lines = content.split(/\r?\n/u).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
361
|
+
if (lines.length !== 2) {
|
|
362
|
+
throw new DevToolsActivePortParseError(
|
|
363
|
+
`Expected exactly 2 non-empty lines in DevToolsActivePort, got ${lines.length}`,
|
|
364
|
+
"malformed-file"
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
const portText = lines[0];
|
|
368
|
+
const browserPath = lines[1];
|
|
369
|
+
const port = Number.parseInt(portText, 10);
|
|
370
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
371
|
+
throw new DevToolsActivePortParseError(
|
|
372
|
+
`Invalid DevToolsActivePort port: ${portText}`,
|
|
373
|
+
"invalid-port"
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
if (!browserPath.startsWith("/devtools/browser/") || browserPath.includes("..") || /[?#\s\\]/u.test(browserPath)) {
|
|
377
|
+
throw new DevToolsActivePortParseError(
|
|
378
|
+
`Invalid DevToolsActivePort browser path: ${browserPath}`,
|
|
379
|
+
"invalid-path"
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
return {
|
|
383
|
+
port,
|
|
384
|
+
browserPath,
|
|
385
|
+
wsUrl: `ws://127.0.0.1:${port}${browserPath}`
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
async function inspectScanTarget(target, options, deps) {
|
|
389
|
+
let content;
|
|
390
|
+
try {
|
|
391
|
+
content = await deps.readTextFile(target.portFile);
|
|
392
|
+
} catch (error) {
|
|
393
|
+
return { kind: "failure", failure: toFileFailure(target, error) };
|
|
394
|
+
}
|
|
395
|
+
let parsed;
|
|
396
|
+
try {
|
|
397
|
+
parsed = parseDevToolsActivePortFile(content);
|
|
398
|
+
} catch (error) {
|
|
399
|
+
if (error instanceof DevToolsActivePortParseError) {
|
|
400
|
+
return {
|
|
401
|
+
kind: "failure",
|
|
402
|
+
failure: {
|
|
403
|
+
...target,
|
|
404
|
+
reason: error.reason,
|
|
405
|
+
message: error.message
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
throw error;
|
|
410
|
+
}
|
|
411
|
+
try {
|
|
412
|
+
const probe = await deps.probeBrowserWebSocket(
|
|
413
|
+
parsed.wsUrl,
|
|
414
|
+
options.probeTimeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS
|
|
415
|
+
);
|
|
416
|
+
return {
|
|
417
|
+
kind: "candidate",
|
|
418
|
+
candidate: {
|
|
419
|
+
...target,
|
|
420
|
+
port: parsed.port,
|
|
421
|
+
browserPath: parsed.browserPath,
|
|
422
|
+
wsUrl: parsed.wsUrl,
|
|
423
|
+
browserVersion: probe.browserVersion
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
} catch (error) {
|
|
427
|
+
return {
|
|
428
|
+
kind: "failure",
|
|
429
|
+
failure: toProbeFailure(target, parsed.wsUrl, error)
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
async function discoverLocalBrowsers(options = {}, deps = defaultDependencies) {
|
|
434
|
+
const scanTargets = buildLocalBrowserScanTargets(options);
|
|
435
|
+
const outcomes = await Promise.all(
|
|
436
|
+
scanTargets.map((target) => inspectScanTarget(target, options, deps))
|
|
437
|
+
);
|
|
438
|
+
const candidates = [];
|
|
439
|
+
const failures = [];
|
|
440
|
+
for (const outcome of outcomes) {
|
|
441
|
+
if (outcome.kind === "candidate") {
|
|
442
|
+
candidates.push(outcome.candidate);
|
|
443
|
+
} else {
|
|
444
|
+
failures.push(outcome.failure);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
return { candidates, failures };
|
|
448
|
+
}
|
|
449
|
+
var BrowserEndpointResolutionError = class extends Error {
|
|
450
|
+
constructor(code, message, details = {}) {
|
|
451
|
+
super(message);
|
|
452
|
+
this.code = code;
|
|
453
|
+
this.details = details;
|
|
454
|
+
}
|
|
455
|
+
name = "BrowserEndpointResolutionError";
|
|
456
|
+
};
|
|
457
|
+
async function resolveBrowserEndpoint(options = {}, deps = defaultDependencies) {
|
|
458
|
+
if (options.explicitWsUrl) {
|
|
459
|
+
return {
|
|
460
|
+
wsUrl: options.explicitWsUrl,
|
|
461
|
+
source: "explicit-ws"
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
let localDiscovery;
|
|
465
|
+
if (options.allowLocalDiscovery ?? true) {
|
|
466
|
+
localDiscovery = await discoverLocalBrowsers(options, deps);
|
|
467
|
+
if (localDiscovery.candidates.length === 1) {
|
|
468
|
+
const candidate = localDiscovery.candidates[0];
|
|
469
|
+
return {
|
|
470
|
+
wsUrl: candidate.wsUrl,
|
|
471
|
+
source: "devtools-active-port",
|
|
472
|
+
channel: candidate.channel,
|
|
473
|
+
userDataDir: candidate.userDataDir
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
if (localDiscovery.candidates.length > 1) {
|
|
477
|
+
throw new BrowserEndpointResolutionError(
|
|
478
|
+
"multiple-local-browsers",
|
|
479
|
+
"Multiple local Chrome profiles are available for auto-discovery",
|
|
480
|
+
{
|
|
481
|
+
candidates: localDiscovery.candidates,
|
|
482
|
+
failures: localDiscovery.failures
|
|
483
|
+
}
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
if (options.allowLegacyHostFallback ?? true) {
|
|
488
|
+
const legacyHost = options.legacyHost ?? "localhost:9222";
|
|
489
|
+
try {
|
|
490
|
+
return {
|
|
491
|
+
wsUrl: await deps.getLegacyBrowserWebSocketUrl(legacyHost),
|
|
492
|
+
source: "json-version"
|
|
493
|
+
};
|
|
494
|
+
} catch (error) {
|
|
495
|
+
throw new BrowserEndpointResolutionError(
|
|
496
|
+
"browser-not-found",
|
|
497
|
+
"Could not resolve a browser endpoint",
|
|
498
|
+
{
|
|
499
|
+
candidates: localDiscovery?.candidates,
|
|
500
|
+
failures: localDiscovery?.failures,
|
|
501
|
+
legacyError: error instanceof Error ? error : new Error(String(error)),
|
|
502
|
+
legacyHost
|
|
503
|
+
}
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
throw new BrowserEndpointResolutionError(
|
|
508
|
+
"browser-not-found",
|
|
509
|
+
"Could not resolve a browser endpoint",
|
|
510
|
+
{
|
|
511
|
+
candidates: localDiscovery?.candidates,
|
|
512
|
+
failures: localDiscovery?.failures
|
|
513
|
+
}
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
|
|
193
517
|
// src/providers/index.ts
|
|
194
518
|
function createProvider(options) {
|
|
195
519
|
switch (options.provider) {
|
|
@@ -272,13 +596,26 @@ var Browser = class _Browser {
|
|
|
272
596
|
* Connect to a browser instance
|
|
273
597
|
*/
|
|
274
598
|
static async connect(options) {
|
|
275
|
-
|
|
276
|
-
|
|
599
|
+
let connectOptions = options;
|
|
600
|
+
if (options.provider === "generic" && !options.wsUrl) {
|
|
601
|
+
const endpoint = await resolveBrowserEndpoint({
|
|
602
|
+
channel: options.channel,
|
|
603
|
+
userDataDir: options.userDataDir,
|
|
604
|
+
allowLocalDiscovery: true,
|
|
605
|
+
allowLegacyHostFallback: true
|
|
606
|
+
});
|
|
607
|
+
connectOptions = {
|
|
608
|
+
...options,
|
|
609
|
+
wsUrl: endpoint.wsUrl
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
const provider = createProvider(connectOptions);
|
|
613
|
+
const session = await provider.createSession(connectOptions.session);
|
|
277
614
|
const cdp = await createCDPClient(session.wsUrl, {
|
|
278
|
-
debug:
|
|
279
|
-
timeout:
|
|
615
|
+
debug: connectOptions.debug,
|
|
616
|
+
timeout: connectOptions.timeout
|
|
280
617
|
});
|
|
281
|
-
return new _Browser(cdp, provider, session,
|
|
618
|
+
return new _Browser(cdp, provider, session, connectOptions);
|
|
282
619
|
}
|
|
283
620
|
/**
|
|
284
621
|
* Get or create a page by name.
|
|
@@ -460,7 +797,8 @@ function connect(options) {
|
|
|
460
797
|
}
|
|
461
798
|
|
|
462
799
|
export {
|
|
463
|
-
|
|
800
|
+
BrowserEndpointResolutionError,
|
|
801
|
+
resolveBrowserEndpoint,
|
|
464
802
|
Browser,
|
|
465
803
|
connect
|
|
466
804
|
};
|
|
@@ -860,7 +860,9 @@ function buildTraceSummaries(events) {
|
|
|
860
860
|
};
|
|
861
861
|
}
|
|
862
862
|
function summarizeWs(events) {
|
|
863
|
-
const relevant = events.filter(
|
|
863
|
+
const relevant = events.filter(
|
|
864
|
+
(event) => event.channel === "ws" || event.event.startsWith("ws.")
|
|
865
|
+
);
|
|
864
866
|
const connections = /* @__PURE__ */ new Map();
|
|
865
867
|
for (const event of relevant) {
|
|
866
868
|
const id = event.connectionId ?? event.requestId ?? event.traceId;
|
|
@@ -890,7 +892,7 @@ function summarizeWs(events) {
|
|
|
890
892
|
}
|
|
891
893
|
const values = [...connections.values()];
|
|
892
894
|
const reconnects = values.reduce((count, connection) => {
|
|
893
|
-
return connection.closedAt && !connection.createdAt ? count : count;
|
|
895
|
+
return connection.closedAt && !connection.createdAt ? count + 1 : count;
|
|
894
896
|
}, 0);
|
|
895
897
|
return {
|
|
896
898
|
view: "ws",
|
|
@@ -1143,6 +1145,31 @@ function frameToStep(frame) {
|
|
|
1143
1145
|
}
|
|
1144
1146
|
}
|
|
1145
1147
|
|
|
1148
|
+
// src/trace/model.ts
|
|
1149
|
+
function createTraceId(prefix = "evt") {
|
|
1150
|
+
const random = Math.random().toString(36).slice(2, 10);
|
|
1151
|
+
return `${prefix}-${Date.now().toString(36)}-${random}`;
|
|
1152
|
+
}
|
|
1153
|
+
function normalizeTraceEvent(event) {
|
|
1154
|
+
return {
|
|
1155
|
+
traceId: event.traceId ?? createTraceId(event.channel),
|
|
1156
|
+
ts: event.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1157
|
+
elapsedMs: event.elapsedMs ?? 0,
|
|
1158
|
+
severity: event.severity ?? inferSeverity(event.event),
|
|
1159
|
+
data: event.data ?? {},
|
|
1160
|
+
...event
|
|
1161
|
+
};
|
|
1162
|
+
}
|
|
1163
|
+
function inferSeverity(eventName) {
|
|
1164
|
+
if (eventName.includes(".failed") || eventName.includes(".error") || eventName.includes("exception") || eventName.includes("notReady")) {
|
|
1165
|
+
return "error";
|
|
1166
|
+
}
|
|
1167
|
+
if (eventName.includes(".closed") || eventName.includes(".warn") || eventName.includes(".changed")) {
|
|
1168
|
+
return "warn";
|
|
1169
|
+
}
|
|
1170
|
+
return "info";
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1146
1173
|
// src/trace/script.ts
|
|
1147
1174
|
var TRACE_BINDING_NAME = "__bpTraceBinding";
|
|
1148
1175
|
var TRACE_SCRIPT = `
|
|
@@ -1422,31 +1449,6 @@ var TRACE_SCRIPT = `
|
|
|
1422
1449
|
})();
|
|
1423
1450
|
`;
|
|
1424
1451
|
|
|
1425
|
-
// src/trace/model.ts
|
|
1426
|
-
function createTraceId(prefix = "evt") {
|
|
1427
|
-
const random = Math.random().toString(36).slice(2, 10);
|
|
1428
|
-
return `${prefix}-${Date.now().toString(36)}-${random}`;
|
|
1429
|
-
}
|
|
1430
|
-
function normalizeTraceEvent(event) {
|
|
1431
|
-
return {
|
|
1432
|
-
traceId: event.traceId ?? createTraceId(event.channel),
|
|
1433
|
-
ts: event.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1434
|
-
elapsedMs: event.elapsedMs ?? 0,
|
|
1435
|
-
severity: event.severity ?? inferSeverity(event.event),
|
|
1436
|
-
data: event.data ?? {},
|
|
1437
|
-
...event
|
|
1438
|
-
};
|
|
1439
|
-
}
|
|
1440
|
-
function inferSeverity(eventName) {
|
|
1441
|
-
if (eventName.includes(".failed") || eventName.includes(".error") || eventName.includes("exception") || eventName.includes("notReady")) {
|
|
1442
|
-
return "error";
|
|
1443
|
-
}
|
|
1444
|
-
if (eventName.includes(".closed") || eventName.includes(".warn") || eventName.includes(".changed")) {
|
|
1445
|
-
return "warn";
|
|
1446
|
-
}
|
|
1447
|
-
return "info";
|
|
1448
|
-
}
|
|
1449
|
-
|
|
1450
1452
|
// src/trace/live.ts
|
|
1451
1453
|
function globToRegex(pattern) {
|
|
1452
1454
|
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
@@ -1463,6 +1465,15 @@ var DEFAULT_RECORDING_SKIP_ACTIONS = [
|
|
|
1463
1465
|
"text",
|
|
1464
1466
|
"screenshot"
|
|
1465
1467
|
];
|
|
1468
|
+
function readString(value) {
|
|
1469
|
+
return typeof value === "string" ? value : void 0;
|
|
1470
|
+
}
|
|
1471
|
+
function readStringOr(value, fallback = "") {
|
|
1472
|
+
return readString(value) ?? fallback;
|
|
1473
|
+
}
|
|
1474
|
+
function formatConsoleArg(entry) {
|
|
1475
|
+
return readString(entry["value"]) ?? readString(entry["description"]) ?? "";
|
|
1476
|
+
}
|
|
1466
1477
|
function loadExistingRecording(manifestPath) {
|
|
1467
1478
|
try {
|
|
1468
1479
|
const raw = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
@@ -2263,8 +2274,13 @@ Valid actions: ${valid}`);
|
|
|
2263
2274
|
await this.page.cdpClient.send("Runtime.addBinding", { name: TRACE_BINDING_NAME });
|
|
2264
2275
|
} catch {
|
|
2265
2276
|
}
|
|
2266
|
-
await this.page.cdpClient.send("Page.addScriptToEvaluateOnNewDocument", {
|
|
2267
|
-
|
|
2277
|
+
await this.page.cdpClient.send("Page.addScriptToEvaluateOnNewDocument", {
|
|
2278
|
+
source: TRACE_SCRIPT
|
|
2279
|
+
});
|
|
2280
|
+
await this.page.cdpClient.send("Runtime.evaluate", {
|
|
2281
|
+
expression: TRACE_SCRIPT,
|
|
2282
|
+
awaitPromise: false
|
|
2283
|
+
});
|
|
2268
2284
|
}
|
|
2269
2285
|
async waitForWsMessage(match, where, timeout) {
|
|
2270
2286
|
await this.ensureTraceHooks();
|
|
@@ -2282,12 +2298,12 @@ Valid actions: ${valid}`);
|
|
|
2282
2298
|
clearTimeout(timer);
|
|
2283
2299
|
};
|
|
2284
2300
|
const onCreated = (params) => {
|
|
2285
|
-
wsUrls.set(
|
|
2301
|
+
wsUrls.set(readStringOr(params["requestId"]), readStringOr(params["url"]));
|
|
2286
2302
|
};
|
|
2287
2303
|
const onFrame = (params) => {
|
|
2288
|
-
const requestId =
|
|
2304
|
+
const requestId = readStringOr(params["requestId"]);
|
|
2289
2305
|
const response = params["response"] ?? {};
|
|
2290
|
-
const payload =
|
|
2306
|
+
const payload = response.payloadData ?? "";
|
|
2291
2307
|
const url = wsUrls.get(requestId) ?? "";
|
|
2292
2308
|
if (!regex.test(url) && !regex.test(payload)) {
|
|
2293
2309
|
return;
|
|
@@ -2303,13 +2319,13 @@ Valid actions: ${valid}`);
|
|
|
2303
2319
|
return;
|
|
2304
2320
|
}
|
|
2305
2321
|
try {
|
|
2306
|
-
const parsed = JSON.parse(
|
|
2322
|
+
const parsed = JSON.parse(readStringOr(params["payload"]));
|
|
2307
2323
|
if (parsed.event !== "ws.frame.received") {
|
|
2308
2324
|
return;
|
|
2309
2325
|
}
|
|
2310
2326
|
const data = parsed.data ?? {};
|
|
2311
|
-
const payload =
|
|
2312
|
-
const url =
|
|
2327
|
+
const payload = readStringOr(data["payload"]);
|
|
2328
|
+
const url = readStringOr(data["url"]);
|
|
2313
2329
|
if (!regex.test(url) && !regex.test(payload)) {
|
|
2314
2330
|
return;
|
|
2315
2331
|
}
|
|
@@ -2318,7 +2334,7 @@ Valid actions: ${valid}`);
|
|
|
2318
2334
|
}
|
|
2319
2335
|
cleanup();
|
|
2320
2336
|
resolve({
|
|
2321
|
-
requestId:
|
|
2337
|
+
requestId: readStringOr(data["connectionId"]),
|
|
2322
2338
|
url,
|
|
2323
2339
|
payload
|
|
2324
2340
|
});
|
|
@@ -2362,13 +2378,14 @@ Valid actions: ${valid}`);
|
|
|
2362
2378
|
if (!entry || typeof entry !== "object") {
|
|
2363
2379
|
continue;
|
|
2364
2380
|
}
|
|
2365
|
-
const
|
|
2381
|
+
const record = entry;
|
|
2382
|
+
const event = readStringOr(record["event"]);
|
|
2366
2383
|
if (event !== "ws.frame.received") {
|
|
2367
2384
|
continue;
|
|
2368
2385
|
}
|
|
2369
|
-
const data =
|
|
2370
|
-
const payload =
|
|
2371
|
-
const url =
|
|
2386
|
+
const data = record["data"] ?? {};
|
|
2387
|
+
const payload = readStringOr(data["payload"]);
|
|
2388
|
+
const url = readStringOr(data["url"]);
|
|
2372
2389
|
if (!regex.test(url) && !regex.test(payload)) {
|
|
2373
2390
|
continue;
|
|
2374
2391
|
}
|
|
@@ -2376,7 +2393,7 @@ Valid actions: ${valid}`);
|
|
|
2376
2393
|
continue;
|
|
2377
2394
|
}
|
|
2378
2395
|
return {
|
|
2379
|
-
requestId:
|
|
2396
|
+
requestId: readStringOr(data["connectionId"]),
|
|
2380
2397
|
url,
|
|
2381
2398
|
payload
|
|
2382
2399
|
};
|
|
@@ -2397,13 +2414,11 @@ Valid actions: ${valid}`);
|
|
|
2397
2414
|
return;
|
|
2398
2415
|
}
|
|
2399
2416
|
const args = Array.isArray(params["args"]) ? params["args"] : [];
|
|
2400
|
-
errors.push(
|
|
2401
|
-
args.map((entry) => String(entry["value"] ?? entry["description"] ?? "")).filter(Boolean).join(" ")
|
|
2402
|
-
);
|
|
2417
|
+
errors.push(args.map(formatConsoleArg).filter(Boolean).join(" "));
|
|
2403
2418
|
};
|
|
2404
2419
|
const onException = (params) => {
|
|
2405
2420
|
const details = params["exceptionDetails"] ?? {};
|
|
2406
|
-
errors.push(
|
|
2421
|
+
errors.push(readString(details["text"]) ?? "Runtime exception");
|
|
2407
2422
|
};
|
|
2408
2423
|
const timer = setTimeout(() => {
|
|
2409
2424
|
cleanup();
|