browser-debugger-cli 0.8.0 → 0.9.0
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 +4 -1
- package/dist/cdp/schema.d.ts +4 -1
- package/dist/cdp/schema.js +48 -7
- package/dist/commands/cdp.js +3 -2
- package/dist/commands/cleanup.d.ts +11 -0
- package/dist/commands/cleanup.js +161 -57
- package/dist/commands/console.d.ts +20 -1
- package/dist/commands/console.js +57 -17
- package/dist/commands/details.js +3 -2
- package/dist/commands/dom/DomElementResolver.d.ts +10 -3
- package/dist/commands/dom/DomElementResolver.js +35 -17
- package/dist/commands/dom/a11y.d.ts +10 -0
- package/dist/commands/dom/a11y.js +27 -5
- package/dist/commands/dom/eval.d.ts +3 -1
- package/dist/commands/dom/eval.js +29 -4
- package/dist/commands/dom/form.js +16 -62
- package/dist/commands/dom/formInteraction.js +152 -113
- package/dist/commands/dom/formSummary.d.ts +49 -0
- package/dist/commands/dom/formSummary.js +180 -0
- package/dist/commands/dom/frames.d.ts +2 -1
- package/dist/commands/dom/frames.js +17 -2
- package/dist/commands/dom/get.d.ts +6 -5
- package/dist/commands/dom/get.js +92 -82
- package/dist/commands/dom/helpers/index.d.ts +1 -1
- package/dist/commands/dom/helpers/index.js +1 -1
- package/dist/commands/dom/helpers/query.d.ts +44 -17
- package/dist/commands/dom/helpers/query.js +244 -97
- package/dist/commands/dom/helpers/runElementCommand.d.ts +10 -2
- package/dist/commands/dom/helpers/runElementCommand.js +97 -30
- package/dist/commands/dom/helpers/screenshot.d.ts +4 -1
- package/dist/commands/dom/helpers/screenshot.js +164 -49
- package/dist/commands/dom/index.d.ts +3 -1
- package/dist/commands/dom/index.js +16 -6
- package/dist/commands/dom/layout.d.ts +14 -0
- package/dist/commands/dom/layout.js +54 -0
- package/dist/commands/dom/listeners.d.ts +5 -1
- package/dist/commands/dom/listeners.js +13 -3
- package/dist/commands/dom/query.js +2 -3
- package/dist/commands/dom/screenshot.d.ts +12 -2
- package/dist/commands/dom/screenshot.js +27 -3
- package/dist/commands/dom/semanticUtils.d.ts +6 -13
- package/dist/commands/dom/semanticUtils.js +15 -19
- package/dist/commands/dom/wait.d.ts +13 -0
- package/dist/commands/dom/wait.js +83 -0
- package/dist/commands/helpJson.js +2 -2
- package/dist/commands/network/list.js +4 -11
- package/dist/commands/optionBehaviors.js +112 -21
- package/dist/commands/page.d.ts +2 -1
- package/dist/commands/page.js +41 -5
- package/dist/commands/peek.js +4 -11
- package/dist/commands/sessions.d.ts +8 -0
- package/dist/commands/sessions.js +19 -0
- package/dist/commands/shared/CommandRunner.js +4 -4
- package/dist/commands/shared/dataFetcher.js +2 -2
- package/dist/commands/shared/followMode.d.ts +21 -1
- package/dist/commands/shared/followMode.js +29 -2
- package/dist/commands/shared/handleValidationError.d.ts +2 -2
- package/dist/commands/shared/handleValidationError.js +12 -3
- package/dist/commands/shared/optionTypes.d.ts +40 -5
- package/dist/commands/shared/startHelpers.js +12 -3
- package/dist/commands/shared/validation.d.ts +3 -2
- package/dist/commands/shared/validation.js +4 -3
- package/dist/commands/start.d.ts +63 -0
- package/dist/commands/start.js +115 -15
- package/dist/commands/status.js +29 -7
- package/dist/commands/stop.js +7 -6
- package/dist/commands/tail.js +4 -11
- package/dist/commands/types.d.ts +2 -0
- package/dist/commands.js +2 -0
- package/dist/connection/chromeIdentity.d.ts +65 -0
- package/dist/connection/chromeIdentity.js +143 -0
- package/dist/connection/launcher/profilePreferences.d.ts +47 -0
- package/dist/connection/launcher/profilePreferences.js +151 -0
- package/dist/connection/launcher.d.ts +21 -2
- package/dist/connection/launcher.js +42 -16
- package/dist/connection/portReservation.d.ts +14 -4
- package/dist/connection/portReservation.js +21 -6
- package/dist/connection/startupExit.d.ts +8 -0
- package/dist/connection/startupExit.js +15 -6
- package/dist/constants.d.ts +6 -2
- package/dist/constants.js +9 -2
- package/dist/daemon/SessionController.js +23 -7
- package/dist/daemon/errors.d.ts +1 -1
- package/dist/daemon/errors.js +1 -1
- package/dist/daemon/launcher.d.ts +2 -1
- package/dist/daemon/launcher.js +5 -6
- package/dist/daemon/server/SocketServer.js +1 -2
- package/dist/daemon/session/Session.d.ts +13 -0
- package/dist/daemon/session/Session.js +57 -8
- package/dist/daemon/session/chromeConnection.d.ts +9 -0
- package/dist/daemon/session/chromeConnection.js +45 -8
- package/dist/daemon/session/commandRegistry.js +52 -62
- package/dist/daemon/session/interactions.d.ts +35 -9
- package/dist/daemon/session/interactions.js +36 -9
- package/dist/daemon/session/triggeredRequests.d.ts +67 -0
- package/dist/daemon/session/triggeredRequests.js +157 -0
- package/dist/daemon/session/types.d.ts +5 -1
- package/dist/daemon.js +5393 -1600
- package/dist/errors/messages.d.ts +387 -24
- package/dist/errors/messages.js +761 -67
- package/dist/index.js +3976 -1558
- package/dist/ipc/client.d.ts +12 -1
- package/dist/ipc/client.js +22 -3
- package/dist/ipc/protocol/commands.d.ts +89 -4
- package/dist/ipc/protocol/commands.js +2 -0
- package/dist/ipc/protocol/domTypes.d.ts +258 -7
- package/dist/ipc/session/lifecycle.d.ts +8 -1
- package/dist/ipc/session/queries.d.ts +5 -1
- package/dist/ipc/session/types.d.ts +5 -0
- package/dist/ipc/transport/index.d.ts +2 -1
- package/dist/ipc/transport/index.js +2 -2
- package/dist/runtime/dom/actionEffects.d.ts +106 -0
- package/dist/runtime/dom/actionEffects.js +256 -0
- package/dist/runtime/dom/actionEffectsScripts.d.ts +52 -0
- package/dist/runtime/dom/actionEffectsScripts.js +234 -0
- package/dist/runtime/dom/elementGeometry.d.ts +170 -0
- package/dist/runtime/dom/elementGeometry.js +553 -0
- package/dist/runtime/dom/elementInfo.d.ts +77 -0
- package/dist/runtime/dom/elementInfo.js +191 -0
- package/dist/runtime/dom/evalHelpers.d.ts +51 -6
- package/dist/runtime/dom/evalHelpers.js +136 -26
- package/dist/runtime/dom/eventListeners.d.ts +2 -1
- package/dist/runtime/dom/eventListeners.js +174 -47
- package/dist/runtime/dom/formDiscovery.d.ts +1 -1
- package/dist/runtime/dom/formDiscovery.js +116 -16
- package/dist/runtime/dom/formFillHelpers/fill.d.ts +10 -0
- package/dist/runtime/dom/formFillHelpers/fill.js +125 -10
- package/dist/runtime/dom/formFillHelpers/index.d.ts +2 -2
- package/dist/runtime/dom/formFillHelpers/index.js +2 -2
- package/dist/runtime/dom/formFillHelpers/pressKey.js +14 -3
- package/dist/runtime/dom/formFillHelpers/scroll.d.ts +3 -0
- package/dist/runtime/dom/formFillHelpers/scroll.js +60 -18
- package/dist/runtime/dom/formFillHelpers/shared.d.ts +17 -0
- package/dist/runtime/dom/formFillHelpers/shared.js +25 -1
- package/dist/runtime/dom/formFillHelpers/stability.d.ts +20 -6
- package/dist/runtime/dom/formFillHelpers/stability.js +50 -19
- package/dist/runtime/dom/formSubmitHelpers.d.ts +3 -0
- package/dist/runtime/dom/formSubmitHelpers.js +89 -15
- package/dist/runtime/dom/frameLayout.d.ts +60 -0
- package/dist/runtime/dom/frameLayout.js +140 -0
- package/dist/runtime/dom/frameOrigin.d.ts +50 -0
- package/dist/runtime/dom/frameOrigin.js +62 -0
- package/dist/runtime/dom/frameScopedConnection.d.ts +92 -0
- package/dist/runtime/dom/frameScopedConnection.js +252 -0
- package/dist/runtime/dom/frameSelection.d.ts +1 -1
- package/dist/runtime/dom/frameSelection.js +2 -2
- package/dist/runtime/dom/frames.d.ts +25 -2
- package/dist/runtime/dom/frames.js +202 -63
- package/dist/runtime/dom/layout.d.ts +67 -0
- package/dist/runtime/dom/layout.js +333 -0
- package/dist/runtime/dom/listenerPageScripts.d.ts +66 -0
- package/dist/runtime/dom/listenerPageScripts.js +279 -0
- package/dist/runtime/dom/listenerSummary.d.ts +132 -11
- package/dist/runtime/dom/listenerSummary.js +344 -22
- package/dist/runtime/dom/pageActivity.d.ts +41 -0
- package/dist/runtime/dom/pageActivity.js +123 -0
- package/dist/runtime/dom/reactEventHelpers.d.ts +58 -2
- package/dist/runtime/dom/reactEventHelpers.js +212 -41
- package/dist/runtime/dom/targetNode.d.ts +80 -27
- package/dist/runtime/dom/targetNode.js +249 -33
- package/dist/runtime/dom/wait.d.ts +25 -0
- package/dist/runtime/dom/wait.js +199 -0
- package/dist/runtime/dom/waitCondition.d.ts +71 -0
- package/dist/runtime/dom/waitCondition.js +75 -0
- package/dist/runtime/page/emulation.d.ts +51 -0
- package/dist/runtime/page/emulation.js +80 -0
- package/dist/runtime/page/loadingState.d.ts +36 -0
- package/dist/runtime/page/loadingState.js +86 -0
- package/dist/runtime/page/navigation.d.ts +46 -2
- package/dist/runtime/page/navigation.js +69 -33
- package/dist/session/QueryCacheManager.d.ts +11 -1
- package/dist/session/QueryCacheManager.js +25 -3
- package/dist/session/chromeOwners.d.ts +34 -0
- package/dist/session/chromeOwners.js +51 -0
- package/dist/session/cleanup/staleSession.d.ts +11 -1
- package/dist/session/cleanup/staleSession.js +17 -6
- package/dist/session/cleanup/userCommands.js +2 -4
- package/dist/session/metadata.d.ts +5 -1
- package/dist/session/metadata.js +2 -1
- package/dist/session/paths.d.ts +77 -3
- package/dist/session/paths.js +111 -5
- package/dist/session/port.d.ts +31 -7
- package/dist/session/port.js +50 -43
- package/dist/session/portClaims.d.ts +66 -0
- package/dist/session/portClaims.js +284 -0
- package/dist/session/sessionList.d.ts +58 -0
- package/dist/session/sessionList.js +199 -0
- package/dist/session/sessionName.d.ts +46 -0
- package/dist/session/sessionName.js +97 -0
- package/dist/telemetry/a11y.d.ts +8 -3
- package/dist/telemetry/a11y.js +92 -28
- package/dist/telemetry/requestKinds.d.ts +32 -0
- package/dist/telemetry/requestKinds.js +61 -0
- package/dist/telemetry/requestState.d.ts +31 -0
- package/dist/telemetry/requestState.js +38 -0
- package/dist/types.d.ts +80 -3
- package/dist/ui/formatters/a11y.js +3 -0
- package/dist/ui/formatters/console/chronological.d.ts +8 -0
- package/dist/ui/formatters/console/chronological.js +17 -4
- package/dist/ui/formatters/console/json.js +3 -4
- package/dist/ui/formatters/console/shared.d.ts +12 -0
- package/dist/ui/formatters/console.d.ts +2 -2
- package/dist/ui/formatters/console.js +1 -1
- package/dist/ui/formatters/details.js +2 -1
- package/dist/ui/formatters/dom.d.ts +26 -14
- package/dist/ui/formatters/dom.js +65 -52
- package/dist/ui/formatters/form.js +29 -18
- package/dist/ui/formatters/layout.d.ts +31 -0
- package/dist/ui/formatters/layout.js +53 -0
- package/dist/ui/formatters/listeners.d.ts +3 -2
- package/dist/ui/formatters/listeners.js +73 -9
- package/dist/ui/formatters/networkHeaders.js +13 -0
- package/dist/ui/formatters/preview.js +2 -1
- package/dist/ui/formatters/requestStatus.d.ts +1 -17
- package/dist/ui/formatters/requestStatus.js +2 -30
- package/dist/ui/formatters/sessions.d.ts +12 -0
- package/dist/ui/formatters/sessions.js +40 -0
- package/dist/ui/formatters/status.d.ts +21 -2
- package/dist/ui/formatters/status.js +47 -10
- package/dist/ui/formatters/triggeredRequests.d.ts +36 -0
- package/dist/ui/formatters/triggeredRequests.js +65 -0
- package/dist/ui/formatting.d.ts +10 -0
- package/dist/ui/formatting.js +28 -36
- package/dist/ui/messages/chrome.d.ts +9 -0
- package/dist/ui/messages/chrome.js +17 -5
- package/dist/ui/messages/commands.d.ts +388 -14
- package/dist/ui/messages/commands.js +664 -21
- package/dist/ui/messages/consoleMessages.d.ts +10 -0
- package/dist/ui/messages/consoleMessages.js +17 -0
- package/dist/ui/messages/hints.js +2 -1
- package/dist/ui/messages/preview.js +5 -4
- package/dist/ui/messages/session.d.ts +16 -21
- package/dist/ui/messages/session.js +28 -26
- package/dist/ui/messages/sessionCommand.d.ts +43 -0
- package/dist/ui/messages/sessionCommand.js +52 -0
- package/dist/utils/async.d.ts +8 -0
- package/dist/utils/async.js +19 -0
- package/dist/utils/http.d.ts +22 -1
- package/dist/utils/http.js +28 -9
- package/dist/utils/selectorFilters.d.ts +36 -8
- package/dist/utils/selectorFilters.js +267 -53
- package/dist/utils/shellDetection.d.ts +8 -2
- package/dist/utils/shellDetection.js +120 -33
- package/dist/utils/suggestions.d.ts +26 -0
- package/dist/utils/suggestions.js +73 -0
- package/dist/utils/taskMappings.js +10 -0
- package/dist/utils/url.d.ts +12 -2
- package/dist/utils/url.js +69 -7
- package/package.json +1 -1
- package/dist/ui/formatters/sessionFormatters.d.ts +0 -58
- package/dist/ui/formatters/sessionFormatters.js +0 -121
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { OutputFormatter } from '../formatting.js';
|
|
2
|
+
/** Label of the default session in the list */
|
|
3
|
+
const DEFAULT_SESSION_LABEL = '(default)';
|
|
4
|
+
/**
|
|
5
|
+
* Format the sessions as a table, followed by the cleanup commands of
|
|
6
|
+
* crashed and stale sessions.
|
|
7
|
+
*
|
|
8
|
+
* @param data - Sessions
|
|
9
|
+
* @returns Human-readable list
|
|
10
|
+
*/
|
|
11
|
+
export function formatSessionList(data) {
|
|
12
|
+
const fmt = new OutputFormatter();
|
|
13
|
+
if (data.sessions.length === 0) {
|
|
14
|
+
return fmt
|
|
15
|
+
.text('No running sessions')
|
|
16
|
+
.hints('Suggestions:', ['Start one: bdg <url> [--session <name>]'])
|
|
17
|
+
.build();
|
|
18
|
+
}
|
|
19
|
+
const rows = data.sessions.map((session) => [
|
|
20
|
+
session.name ?? DEFAULT_SESSION_LABEL,
|
|
21
|
+
session.state,
|
|
22
|
+
session.port?.toString() ?? '-',
|
|
23
|
+
session.daemonPid?.toString() ?? '-',
|
|
24
|
+
session.url ?? '-',
|
|
25
|
+
]);
|
|
26
|
+
const header = ['SESSION', 'STATE', 'PORT', 'PID', 'URL'];
|
|
27
|
+
const widths = header.map((title, column) => Math.max(title.length, ...rows.map((row) => row[column]?.length ?? 0)));
|
|
28
|
+
for (const row of [header, ...rows]) {
|
|
29
|
+
fmt.text(row
|
|
30
|
+
.map((cell, column) => cell.padEnd(widths[column] ?? 0))
|
|
31
|
+
.join(' ')
|
|
32
|
+
.trimEnd());
|
|
33
|
+
}
|
|
34
|
+
const cleanups = data.sessions.flatMap((session) => (session.cleanup ? [session.cleanup] : []));
|
|
35
|
+
if (cleanups.length > 0) {
|
|
36
|
+
fmt.hints('Crashed or stale sessions; clean up with:', cleanups);
|
|
37
|
+
}
|
|
38
|
+
return fmt.build();
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=sessions.js.map
|
|
@@ -2,10 +2,14 @@ import type { SessionActivity, PageState } from '../../ipc/index.js';
|
|
|
2
2
|
import { type RunningChromeInfo } from '../../session/chrome.js';
|
|
3
3
|
import type { LastSessionEnd } from '../../session/lastSession.js';
|
|
4
4
|
import type { SessionMetadata } from '../../session/metadata.js';
|
|
5
|
+
import type { ColorScheme, ViewportSize } from '../../types.js';
|
|
5
6
|
export interface StatusData {
|
|
7
|
+
/** Name of the selected session (named sessions only) */
|
|
8
|
+
session?: string;
|
|
6
9
|
active: boolean;
|
|
7
10
|
bdgPid?: number;
|
|
8
|
-
|
|
11
|
+
/** Chrome launched by bdg; null for an attached Chrome */
|
|
12
|
+
chromePid?: number | null | undefined;
|
|
9
13
|
chromeAlive?: boolean;
|
|
10
14
|
/** Attached to a Chrome bdg did not launch (`--chrome-ws-url`); it has no known PID */
|
|
11
15
|
externalChrome?: boolean;
|
|
@@ -18,6 +22,10 @@ export interface StatusData {
|
|
|
18
22
|
telemetry?: string[];
|
|
19
23
|
/** When `--timeout` stops the session (ISO time) */
|
|
20
24
|
autoStopAt?: string;
|
|
25
|
+
/** Viewport given with `--viewport` (`pageState.viewport` is the current one) */
|
|
26
|
+
viewport?: ViewportSize;
|
|
27
|
+
/** Color scheme given with `--color-scheme` (`pageState.colorScheme` is the current one) */
|
|
28
|
+
colorScheme?: ColorScheme;
|
|
21
29
|
stale?: boolean;
|
|
22
30
|
stalePid?: number;
|
|
23
31
|
warning?: string;
|
|
@@ -44,8 +52,19 @@ export interface StatusData {
|
|
|
44
52
|
* @param activity - Live activity metrics from the session
|
|
45
53
|
* @param pageState - Current page state from the session
|
|
46
54
|
* @param verbose - Also show the session's Chrome executable, mode and profile
|
|
55
|
+
* @param sessionName - Name of a named session
|
|
47
56
|
*/
|
|
48
|
-
export declare function formatSessionStatus(metadata: SessionMetadata, pid: number, activity?: SessionActivity, pageState?: PageState, verbose?: boolean): string;
|
|
57
|
+
export declare function formatSessionStatus(metadata: SessionMetadata, pid: number, activity?: SessionActivity, pageState?: PageState, verbose?: boolean, sessionName?: string): string;
|
|
58
|
+
/**
|
|
59
|
+
* Viewport and color scheme lines of the target: what the page renders with,
|
|
60
|
+
* and whether `--viewport` / `--color-scheme` set it or it is the system's.
|
|
61
|
+
* The color scheme is the `prefers-color-scheme` the page sees, not its theme.
|
|
62
|
+
*
|
|
63
|
+
* @param metadata - Session metadata (the start options)
|
|
64
|
+
* @param pageState - Page state (what the page reported)
|
|
65
|
+
* @returns Key-value pairs (none for what is unknown)
|
|
66
|
+
*/
|
|
67
|
+
export declare function appearanceLines(metadata: Pick<SessionMetadata, 'viewport' | 'colorScheme'>, pageState: PageState): Array<[string, string]>;
|
|
49
68
|
/**
|
|
50
69
|
* Convert status data to JSON format
|
|
51
70
|
*/
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { describeRunningChrome } from '../../session/chrome.js';
|
|
2
2
|
import { calculateDuration, formatTimeAgo } from '../../session/statusData.js';
|
|
3
3
|
import { OutputFormatter } from '../formatting.js';
|
|
4
|
+
import { colorSchemeLabel, sessionActiveLine } from '../messages/commands.js';
|
|
4
5
|
import { lastSessionEndText } from '../messages/session.js';
|
|
6
|
+
import { noActiveSessionMessage, sessionCommand } from '../messages/sessionCommand.js';
|
|
5
7
|
import { isProcessAlive } from '../../utils/process.js';
|
|
6
8
|
/**
|
|
7
9
|
* Format session status for human-readable output
|
|
@@ -10,13 +12,16 @@ import { isProcessAlive } from '../../utils/process.js';
|
|
|
10
12
|
* @param activity - Live activity metrics from the session
|
|
11
13
|
* @param pageState - Current page state from the session
|
|
12
14
|
* @param verbose - Also show the session's Chrome executable, mode and profile
|
|
15
|
+
* @param sessionName - Name of a named session
|
|
13
16
|
*/
|
|
14
|
-
export function formatSessionStatus(metadata, pid, activity, pageState, verbose = false) {
|
|
17
|
+
export function formatSessionStatus(metadata, pid, activity, pageState, verbose = false, sessionName) {
|
|
15
18
|
const duration = calculateDuration(metadata.startTime);
|
|
16
19
|
const chromeAlive = metadata.chromePid ? isProcessAlive(metadata.chromePid) : false;
|
|
17
20
|
const fmt = new OutputFormatter();
|
|
21
|
+
fmt.text(sessionActiveLine(pageState)).blank();
|
|
18
22
|
fmt.text('Session Status').separator('━', 50);
|
|
19
23
|
fmt.keyValueList([
|
|
24
|
+
...(sessionName ? [['Session', sessionName]] : []),
|
|
20
25
|
['Status', 'ACTIVE'],
|
|
21
26
|
['Duration', duration.formatted],
|
|
22
27
|
...(metadata.autoStopAt
|
|
@@ -38,6 +43,7 @@ export function formatSessionStatus(metadata, pid, activity, pageState, verbose
|
|
|
38
43
|
if (pageState.title) {
|
|
39
44
|
fmt.keyValue('Title', pageState.title, 18);
|
|
40
45
|
}
|
|
46
|
+
fmt.keyValueList(appearanceLines(metadata, pageState), 18);
|
|
41
47
|
}
|
|
42
48
|
if (activity) {
|
|
43
49
|
fmt.blank().text('Activity').separator('━', 50);
|
|
@@ -69,12 +75,40 @@ export function formatSessionStatus(metadata, pid, activity, pageState, verbose
|
|
|
69
75
|
fmt
|
|
70
76
|
.blank()
|
|
71
77
|
.section('Commands:', [
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
78
|
+
`Peek data: ${sessionCommand('bdg peek', sessionName ?? null)}`,
|
|
79
|
+
`Run JavaScript: ${sessionCommand('bdg dom eval <script>', sessionName ?? null)}`,
|
|
80
|
+
`End session: ${sessionCommand('bdg stop', sessionName ?? null)}`,
|
|
75
81
|
]);
|
|
76
82
|
return fmt.build();
|
|
77
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Viewport and color scheme lines of the target: what the page renders with,
|
|
86
|
+
* and whether `--viewport` / `--color-scheme` set it or it is the system's.
|
|
87
|
+
* The color scheme is the `prefers-color-scheme` the page sees, not its theme.
|
|
88
|
+
*
|
|
89
|
+
* @param metadata - Session metadata (the start options)
|
|
90
|
+
* @param pageState - Page state (what the page reported)
|
|
91
|
+
* @returns Key-value pairs (none for what is unknown)
|
|
92
|
+
*/
|
|
93
|
+
export function appearanceLines(metadata, pageState) {
|
|
94
|
+
const viewport = pageState.viewport ?? metadata.viewport;
|
|
95
|
+
const scheme = pageState.colorScheme ?? metadata.colorScheme;
|
|
96
|
+
return [
|
|
97
|
+
...(viewport
|
|
98
|
+
? [
|
|
99
|
+
[
|
|
100
|
+
'Viewport',
|
|
101
|
+
`${viewport.width}×${viewport.height}${metadata.viewport ? ` (--viewport ${metadata.viewport.width}x${metadata.viewport.height})` : ''}`,
|
|
102
|
+
],
|
|
103
|
+
]
|
|
104
|
+
: []),
|
|
105
|
+
...(scheme
|
|
106
|
+
? [
|
|
107
|
+
['Color scheme', colorSchemeLabel(scheme, metadata.colorScheme !== undefined)],
|
|
108
|
+
]
|
|
109
|
+
: []),
|
|
110
|
+
];
|
|
111
|
+
}
|
|
78
112
|
/**
|
|
79
113
|
* Convert status data to JSON format
|
|
80
114
|
*/
|
|
@@ -98,13 +132,15 @@ export function formatStatusAsJson(metadata, pid) {
|
|
|
98
132
|
return {
|
|
99
133
|
active: true,
|
|
100
134
|
bdgPid: pid,
|
|
101
|
-
chromePid: metadata.chromePid,
|
|
135
|
+
chromePid: metadata.chromePid !== undefined && metadata.chromePid > 0 ? metadata.chromePid : null,
|
|
102
136
|
...(metadata.chromePid ? { chromeAlive } : { externalChrome: true }),
|
|
103
137
|
startTime: metadata.startTime,
|
|
104
138
|
duration: duration.durationMs,
|
|
105
139
|
durationFormatted: duration.formatted,
|
|
106
140
|
port: metadata.port,
|
|
107
141
|
...(metadata.autoStopAt && { autoStopAt: new Date(metadata.autoStopAt).toISOString() }),
|
|
142
|
+
...(metadata.viewport && { viewport: metadata.viewport }),
|
|
143
|
+
...(metadata.colorScheme && { colorScheme: metadata.colorScheme }),
|
|
108
144
|
targetId: metadata.targetId,
|
|
109
145
|
webSocketDebuggerUrl: metadata.webSocketDebuggerUrl,
|
|
110
146
|
telemetry: metadata.activeTelemetry ?? ['network', 'console', 'dom'],
|
|
@@ -120,13 +156,14 @@ export function formatNoSessionMessage(data = { active: false }) {
|
|
|
120
156
|
return fmt
|
|
121
157
|
.text(`Session starting: ${data.starting.url} (${seconds}s so far)`)
|
|
122
158
|
.blank()
|
|
123
|
-
.text(
|
|
159
|
+
.text(`Commands work once "${sessionCommand('bdg <url>', data.session ?? null)}" returns.`)
|
|
124
160
|
.build();
|
|
125
161
|
}
|
|
126
162
|
if (data.ending) {
|
|
127
163
|
return fmt.text('The session is ending (its Chrome is being closed)').build();
|
|
128
164
|
}
|
|
129
|
-
|
|
165
|
+
const session = data.session ?? null;
|
|
166
|
+
fmt.text(noActiveSessionMessage(session));
|
|
130
167
|
if (data.lastSession)
|
|
131
168
|
fmt.text(lastSessionEndText(data.lastSession));
|
|
132
169
|
if (data.orphanedChromePid) {
|
|
@@ -134,10 +171,10 @@ export function formatNoSessionMessage(data = { active: false }) {
|
|
|
134
171
|
}
|
|
135
172
|
return fmt
|
|
136
173
|
.hints('Suggestions:', [
|
|
137
|
-
|
|
174
|
+
`Start a new session: ${sessionCommand('bdg <url>', session)}`,
|
|
138
175
|
data.orphanedChromePid
|
|
139
|
-
?
|
|
140
|
-
:
|
|
176
|
+
? `Close that Chrome: ${sessionCommand('bdg cleanup', session)}`
|
|
177
|
+
: `Clean up after a crash: ${sessionCommand('bdg cleanup', session)}`,
|
|
141
178
|
])
|
|
142
179
|
.build();
|
|
143
180
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Human output of the network requests a DOM action triggered.
|
|
3
|
+
*/
|
|
4
|
+
import type { TriggeredRequest } from '../../ipc/protocol/domTypes.js';
|
|
5
|
+
/** Requests listed in human output (JSON lists up to 50) */
|
|
6
|
+
export declare const MAX_TRIGGERED_REQUESTS_SHOWN = 10;
|
|
7
|
+
/**
|
|
8
|
+
* Title of the list, with how many requests there were in all (the listed
|
|
9
|
+
* rows, the "... and N more" note and the assets line add up to it).
|
|
10
|
+
*
|
|
11
|
+
* @param requests - Triggered requests in the result
|
|
12
|
+
* @param omitted - Requests the result left out
|
|
13
|
+
* @returns e.g. "Requests during the action (18):"
|
|
14
|
+
*/
|
|
15
|
+
export declare function formatTriggeredRequestsTitle(requests: TriggeredRequest[], omitted?: number): string;
|
|
16
|
+
/**
|
|
17
|
+
* One request as a line, e.g. `POST 127.0.0.1:8080/api/save → 200 (85ms)`,
|
|
18
|
+
* or `GET 127.0.0.1:8080/events → 200 (loading)` while its body still loads.
|
|
19
|
+
*
|
|
20
|
+
* @param request - Triggered request
|
|
21
|
+
* @returns Line text
|
|
22
|
+
*/
|
|
23
|
+
export declare function formatTriggeredRequest(request: TriggeredRequest): string;
|
|
24
|
+
/**
|
|
25
|
+
* Lines listing the triggered requests: the first
|
|
26
|
+
* {@link MAX_TRIGGERED_REQUESTS_SHOWN} notable ones (documents, XHR, fetch,
|
|
27
|
+
* WebSocket, failures; see {@link isNotableRequest}), how many more there
|
|
28
|
+
* are and where to find them (JSON, or the network list when JSON left some
|
|
29
|
+
* out too), then one line counting the static assets that loaded.
|
|
30
|
+
*
|
|
31
|
+
* @param requests - Triggered requests, in start order
|
|
32
|
+
* @param omitted - Requests the result already left out
|
|
33
|
+
* @returns Lines (empty when there are none)
|
|
34
|
+
*/
|
|
35
|
+
export declare function formatTriggeredRequestLines(requests: TriggeredRequest[], omitted?: number): string[];
|
|
36
|
+
//# sourceMappingURL=triggeredRequests.d.ts.map
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Human output of the network requests a DOM action triggered.
|
|
3
|
+
*/
|
|
4
|
+
import { assetTypeNames, isNotableRequest } from '../../telemetry/requestKinds.js';
|
|
5
|
+
import { formatRequestStatus } from './requestStatus.js';
|
|
6
|
+
import { formatDuration, truncateUrl } from '../formatting.js';
|
|
7
|
+
import { assetRequestsNote, moreMatchesNote, moreRequestsNote, triggeredRequestsTitle, } from '../messages/commands.js';
|
|
8
|
+
/** Requests listed in human output (JSON lists up to 50) */
|
|
9
|
+
export const MAX_TRIGGERED_REQUESTS_SHOWN = 10;
|
|
10
|
+
/** Longest URL shown before it is shortened */
|
|
11
|
+
const URL_MAX_LENGTH = 60;
|
|
12
|
+
/**
|
|
13
|
+
* Title of the list, with how many requests there were in all (the listed
|
|
14
|
+
* rows, the "... and N more" note and the assets line add up to it).
|
|
15
|
+
*
|
|
16
|
+
* @param requests - Triggered requests in the result
|
|
17
|
+
* @param omitted - Requests the result left out
|
|
18
|
+
* @returns e.g. "Requests during the action (18):"
|
|
19
|
+
*/
|
|
20
|
+
export function formatTriggeredRequestsTitle(requests, omitted = 0) {
|
|
21
|
+
return triggeredRequestsTitle(requests.length + omitted);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* One request as a line, e.g. `POST 127.0.0.1:8080/api/save → 200 (85ms)`,
|
|
25
|
+
* or `GET 127.0.0.1:8080/events → 200 (loading)` while its body still loads.
|
|
26
|
+
*
|
|
27
|
+
* @param request - Triggered request
|
|
28
|
+
* @returns Line text
|
|
29
|
+
*/
|
|
30
|
+
export function formatTriggeredRequest(request) {
|
|
31
|
+
const httpStatus = request.failed ? 0 : request.status;
|
|
32
|
+
const status = formatRequestStatus({
|
|
33
|
+
...(httpStatus !== undefined && { status: httpStatus }),
|
|
34
|
+
...(request.errorText !== undefined && { errorText: request.errorText }),
|
|
35
|
+
});
|
|
36
|
+
const duration = request.loading
|
|
37
|
+
? ' (loading)'
|
|
38
|
+
: request.durationMs === undefined
|
|
39
|
+
? ''
|
|
40
|
+
: ` (${formatDuration(request.durationMs)})`;
|
|
41
|
+
return `${request.method} ${truncateUrl(request.url, URL_MAX_LENGTH)} → ${status}${duration}`;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Lines listing the triggered requests: the first
|
|
45
|
+
* {@link MAX_TRIGGERED_REQUESTS_SHOWN} notable ones (documents, XHR, fetch,
|
|
46
|
+
* WebSocket, failures; see {@link isNotableRequest}), how many more there
|
|
47
|
+
* are and where to find them (JSON, or the network list when JSON left some
|
|
48
|
+
* out too), then one line counting the static assets that loaded.
|
|
49
|
+
*
|
|
50
|
+
* @param requests - Triggered requests, in start order
|
|
51
|
+
* @param omitted - Requests the result already left out
|
|
52
|
+
* @returns Lines (empty when there are none)
|
|
53
|
+
*/
|
|
54
|
+
export function formatTriggeredRequestLines(requests, omitted = 0) {
|
|
55
|
+
const notable = requests.filter(isNotableRequest);
|
|
56
|
+
const assets = requests.filter((request) => !isNotableRequest(request));
|
|
57
|
+
const lines = notable.slice(0, MAX_TRIGGERED_REQUESTS_SHOWN).map(formatTriggeredRequest);
|
|
58
|
+
const hidden = notable.length - lines.length + omitted;
|
|
59
|
+
if (hidden > 0)
|
|
60
|
+
lines.push(omitted > 0 ? moreRequestsNote(hidden) : moreMatchesNote(hidden));
|
|
61
|
+
if (assets.length > 0)
|
|
62
|
+
lines.push(assetRequestsNote(assets.length, assetTypeNames(assets)));
|
|
63
|
+
return lines;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=triggeredRequests.js.map
|
package/dist/ui/formatting.d.ts
CHANGED
|
@@ -61,6 +61,16 @@ export declare function escapeControlChars(text: string): string;
|
|
|
61
61
|
export declare function joinLines(...lines: Array<string | null | undefined | false>): string;
|
|
62
62
|
export declare function section(title: string, content: string[], indent?: number): string;
|
|
63
63
|
export declare function truncateText(text: string, maxLines?: number): string;
|
|
64
|
+
/**
|
|
65
|
+
* A URL for one line: host and path without the scheme (`www.example.com`
|
|
66
|
+
* for the root), cut in the middle when too long, keeping the host, the
|
|
67
|
+
* start of the path and the end of the path and query, where requests to
|
|
68
|
+
* one API differ (`api.example.com/v1/users/…/orders?page=2`).
|
|
69
|
+
*
|
|
70
|
+
* @param url - URL
|
|
71
|
+
* @param maxLength - Maximum length
|
|
72
|
+
* @returns Shortened URL; non-web URLs (data:, blob:) cut at the end
|
|
73
|
+
*/
|
|
64
74
|
export declare function truncateUrl(url: string, maxLength?: number): string;
|
|
65
75
|
export declare function pluralize(count: number, singular: string, plural?: string): string;
|
|
66
76
|
export declare function formatDuration(ms: number): string;
|
package/dist/ui/formatting.js
CHANGED
|
@@ -138,36 +138,45 @@ export function truncateText(text, maxLines = 3) {
|
|
|
138
138
|
const hiddenCount = lines.length - maxLines;
|
|
139
139
|
return `${truncated}\n ... (${hiddenCount} more lines)`;
|
|
140
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* A URL for one line: host and path without the scheme (`www.example.com`
|
|
143
|
+
* for the root), cut in the middle when too long, keeping the host, the
|
|
144
|
+
* start of the path and the end of the path and query, where requests to
|
|
145
|
+
* one API differ (`api.example.com/v1/users/…/orders?page=2`).
|
|
146
|
+
*
|
|
147
|
+
* @param url - URL
|
|
148
|
+
* @param maxLength - Maximum length
|
|
149
|
+
* @returns Shortened URL; non-web URLs (data:, blob:) cut at the end
|
|
150
|
+
*/
|
|
141
151
|
export function truncateUrl(url, maxLength = 60) {
|
|
142
152
|
const parsed = safeParseUrl(url);
|
|
143
153
|
if (!parsed || !WEB_PROTOCOLS.has(parsed.protocol)) {
|
|
144
154
|
return truncateEnd(url, maxLength);
|
|
145
155
|
}
|
|
146
156
|
const host = parsed.host;
|
|
147
|
-
const
|
|
148
|
-
const
|
|
149
|
-
if (
|
|
150
|
-
return
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const query = cutQuery(parsed.search, MIN_QUERY_SHOWN);
|
|
157
|
-
return `${shortenPath(host, path, maxLength - query.length)}${query}`;
|
|
157
|
+
const rest = `${parsed.pathname.substring(1)}${parsed.search}`;
|
|
158
|
+
const shown = parsed.pathname.length > 1 ? `${host}/${rest}` : `${host}${parsed.search}`;
|
|
159
|
+
if (shown.length <= maxLength)
|
|
160
|
+
return shown;
|
|
161
|
+
const room = maxLength - host.length - 2;
|
|
162
|
+
if (room < MIN_URL_END_SHOWN)
|
|
163
|
+
return cutMiddle(shown, maxLength);
|
|
164
|
+
const start = Math.floor(room / 3);
|
|
165
|
+
return `${host}/${rest.substring(0, start)}…${rest.substring(rest.length - (room - start))}`;
|
|
158
166
|
}
|
|
167
|
+
/** Characters of path and query a shortened URL keeps at least besides its host */
|
|
168
|
+
const MIN_URL_END_SHOWN = 12;
|
|
159
169
|
/**
|
|
160
|
-
*
|
|
170
|
+
* Cut text in the middle, marking the cut with "…".
|
|
161
171
|
*
|
|
162
|
-
* @param
|
|
163
|
-
* @param
|
|
164
|
-
* @returns
|
|
172
|
+
* @param text - Text
|
|
173
|
+
* @param maxLength - Maximum length
|
|
174
|
+
* @returns Start and end of the text around "…"
|
|
165
175
|
*/
|
|
166
|
-
function
|
|
167
|
-
|
|
176
|
+
function cutMiddle(text, maxLength) {
|
|
177
|
+
const head = Math.ceil((maxLength - 1) / 2);
|
|
178
|
+
return `${text.substring(0, head)}…${text.substring(text.length - (maxLength - 1 - head))}`;
|
|
168
179
|
}
|
|
169
|
-
/** Characters of a long query string kept, so similar requests stay distinguishable */
|
|
170
|
-
const MIN_QUERY_SHOWN = 12;
|
|
171
180
|
/** Protocols whose URLs are shown as host/path (others, like data: or blob:, verbatim) */
|
|
172
181
|
const WEB_PROTOCOLS = new Set(['http:', 'https:', 'ws:', 'wss:']);
|
|
173
182
|
/**
|
|
@@ -180,23 +189,6 @@ const WEB_PROTOCOLS = new Set(['http:', 'https:', 'ws:', 'wss:']);
|
|
|
180
189
|
function truncateEnd(text, maxLength) {
|
|
181
190
|
return text.length > maxLength ? text.substring(0, maxLength - 3) + '...' : text;
|
|
182
191
|
}
|
|
183
|
-
/**
|
|
184
|
-
* Shorten a long host/path by eliding its middle segments.
|
|
185
|
-
*
|
|
186
|
-
* @param host - Host (with port)
|
|
187
|
-
* @param path - Path without the leading slash
|
|
188
|
-
* @param maxLength - Maximum length
|
|
189
|
-
* @returns e.g. "example.com/docs/.../page"
|
|
190
|
-
*/
|
|
191
|
-
function shortenPath(host, path, maxLength) {
|
|
192
|
-
const parts = path.split('/');
|
|
193
|
-
const first = parts[0];
|
|
194
|
-
const last = parts[parts.length - 1];
|
|
195
|
-
if (parts.length <= 2 || !first || !last)
|
|
196
|
-
return truncateEnd(`${host}/${path}`, maxLength);
|
|
197
|
-
const elided = `${host}/${first}/.../${last}`;
|
|
198
|
-
return elided.length <= maxLength ? elided : `${host}/${first}/.../${last.substring(0, 8)}`;
|
|
199
|
-
}
|
|
200
192
|
export function pluralize(count, singular, plural) {
|
|
201
193
|
const word = count === 1 ? singular : (plural ?? singular + 's');
|
|
202
194
|
return `${count} ${word}`;
|
|
@@ -161,4 +161,13 @@ export declare function chromeBinaryOverrideIsDirectory(path: string, source: st
|
|
|
161
161
|
* @returns Multi-line formatted error message with troubleshooting steps
|
|
162
162
|
*/
|
|
163
163
|
export declare function portInUseError(port: number): string;
|
|
164
|
+
/**
|
|
165
|
+
* Warning when bdg's Chrome preferences (password manager and leak check
|
|
166
|
+
* off, etc.) could not be written into the profile.
|
|
167
|
+
*
|
|
168
|
+
* @param file - Preferences file
|
|
169
|
+
* @param reason - Why
|
|
170
|
+
* @returns Message
|
|
171
|
+
*/
|
|
172
|
+
export declare function chromePrefsNotAppliedMessage(file: string, reason: string): string;
|
|
164
173
|
//# sourceMappingURL=chrome.d.ts.map
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { getChromeDiagnostics } from '../../connection/diagnostics.js';
|
|
7
7
|
import { pluralize, joinLines } from '../formatting.js';
|
|
8
|
+
import { sessionCommand } from './sessionCommand.js';
|
|
8
9
|
/**
|
|
9
10
|
* Format a structured Chrome-related notice into a user-facing log line.
|
|
10
11
|
*
|
|
@@ -52,7 +53,7 @@ export function formatChromeIssue(issue) {
|
|
|
52
53
|
? chromeLaunchFailedError(reason)
|
|
53
54
|
: `Chrome failed to launch`;
|
|
54
55
|
const diagnostics = getFormattedDiagnostics();
|
|
55
|
-
return joinLines(header, '', 'Possible causes:', ` - Port ${port} conflict (check: lsof -ti:${port})`, ` - Chrome binary not found`, ` - Insufficient permissions`, ` - Chrome crashed on startup`, '', ...diagnostics, '', 'Try:', ` - bdg cleanup`, ` - See what uses the port: lsof -i :${port}`, ` - Use different port: bdg <url> --port ${port + 1}`, ` - In a container where Chrome's sandbox fails: BDG_NO_SANDBOX=1 bdg <url
|
|
56
|
+
return joinLines(header, '', 'Possible causes:', ` - Port ${port} conflict (check: lsof -ti:${port})`, ` - Chrome binary not found`, ` - Insufficient permissions`, ` - Chrome crashed on startup`, '', ...diagnostics, '', 'Try:', ` - ${sessionCommand('bdg cleanup')}`, ` - See what uses the port: lsof -i :${port}`, ` - Use different port: ${sessionCommand(`bdg <url> --port ${port + 1}`)}`, ` - In a container where Chrome's sandbox fails: BDG_NO_SANDBOX=1 ${sessionCommand('bdg <url>')}`);
|
|
56
57
|
}
|
|
57
58
|
case 'CHROME_EXITED_DURING_STARTUP':
|
|
58
59
|
return chromeExitedDuringStartupError(ctx['exitCode'], ctx['output'] ?? [], ctx['userDataDir'], ctx['profileInUse'] === true);
|
|
@@ -90,7 +91,7 @@ export function formatChromeIssue(issue) {
|
|
|
90
91
|
*/
|
|
91
92
|
export function chromeExitedDuringStartupError(exitCode, output, userDataDir, profileInUse) {
|
|
92
93
|
if (profileInUse) {
|
|
93
|
-
return joinLines(`The Chrome profile ${userDataDir} is in use by another Chrome`,
|
|
94
|
+
return joinLines(`The Chrome profile ${userDataDir} is in use by another Chrome`, `Close that Chrome, or use another profile directory: ${sessionCommand('bdg <url> -u ./other-profile')}`);
|
|
94
95
|
}
|
|
95
96
|
return joinLines(`Chrome exited during startup (exit code ${exitCode ?? 'none'})`, ...(output.length > 0 ? ['Chrome said:', ...output.map((line) => ` ${line}`)] : []), 'Check --chrome-flags and BDG_CHROME_FLAGS (an unknown flag or value can stop Chrome)');
|
|
96
97
|
}
|
|
@@ -197,8 +198,8 @@ export function chromeExternalSkipTerminationMessage() {
|
|
|
197
198
|
* @returns Formatted error message with diagnostics and troubleshooting steps
|
|
198
199
|
*/
|
|
199
200
|
export function noPageTargetFoundError(port, availableTargets) {
|
|
200
|
-
return joinLines(`Chrome started but opened no page to attach to (port ${port})`,
|
|
201
|
-
`${port}) or a crashed session may be left over: bdg cleanup && bdg <url
|
|
201
|
+
return joinLines(`Chrome started but opened no page to attach to (port ${port})`, `Retry: ${sessionCommand('bdg <url>')}. If it keeps failing, another program may use the port (lsof -i :` +
|
|
202
|
+
`${port}) or a crashed session may be left over: ${sessionCommand('bdg cleanup')} && ${sessionCommand('bdg <url>')}`, ...(availableTargets ? ['', `Chrome targets:\n${availableTargets}`] : []));
|
|
202
203
|
}
|
|
203
204
|
/**
|
|
204
205
|
* Generate preferences file not found error.
|
|
@@ -276,6 +277,17 @@ export function chromeBinaryOverrideIsDirectory(path, source) {
|
|
|
276
277
|
* @returns Multi-line formatted error message with troubleshooting steps
|
|
277
278
|
*/
|
|
278
279
|
export function portInUseError(port) {
|
|
279
|
-
return joinLines(`Port ${port} is already in use.\n`, 'Another program (or a Chrome left from a previous session) is listening on it.\n', 'Try:', ` - Use a different port: bdg <url> --port ${port + 1}`, ` - If a bdg session
|
|
280
|
+
return joinLines(`Port ${port} is already in use.\n`, 'Another program (or a Chrome left from a previous session) is listening on it.\n', 'Try:', ` - Use a different port: ${sessionCommand(`bdg <url> --port ${port + 1}`)}`, ` - If a bdg session holds it: find it with bdg sessions, then end that one: bdg stop --session <name> (bdg cleanup --force --session <name> if it is stuck)`, ` - See what uses the port: lsof -i :${port}`);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Warning when bdg's Chrome preferences (password manager and leak check
|
|
284
|
+
* off, etc.) could not be written into the profile.
|
|
285
|
+
*
|
|
286
|
+
* @param file - Preferences file
|
|
287
|
+
* @param reason - Why
|
|
288
|
+
* @returns Message
|
|
289
|
+
*/
|
|
290
|
+
export function chromePrefsNotAppliedMessage(file, reason) {
|
|
291
|
+
return `Warning: Chrome preferences not applied to ${file} (${reason}); password manager bubbles may capture clicks`;
|
|
280
292
|
}
|
|
281
293
|
//# sourceMappingURL=chrome.js.map
|