browser-debugger-cli 0.11.0 → 0.12.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 +142 -79
- package/dist/commands/css.d.ts +13 -0
- package/dist/commands/css.js +53 -0
- package/dist/commands/dom/audit.d.ts +14 -0
- package/dist/commands/dom/audit.js +87 -0
- package/dist/commands/dom/formInteraction.js +36 -6
- package/dist/commands/dom/helpers/keyAttributes.d.ts +3 -2
- package/dist/commands/dom/helpers/keyAttributes.js +6 -4
- package/dist/commands/dom/helpers/screenshot.d.ts +1 -0
- package/dist/commands/dom/helpers/screenshot.js +158 -38
- package/dist/commands/dom/index.js +4 -1
- package/dist/commands/dom/screenshot.js +10 -6
- package/dist/commands/dom/wait.js +5 -3
- package/dist/commands/helpJson.js +1 -1
- package/dist/commands/optionBehaviors.js +21 -6
- package/dist/commands/page.js +7 -4
- package/dist/commands/peek.d.ts +7 -0
- package/dist/commands/peek.js +65 -23
- package/dist/commands/shared/optionTypes.d.ts +5 -1
- package/dist/commands/start.d.ts +13 -0
- package/dist/commands/start.js +19 -2
- package/dist/commands/tail.d.ts +7 -1
- package/dist/commands/tail.js +13 -62
- package/dist/commands.js +2 -0
- package/dist/daemon/session/commandRegistry.js +7 -1
- package/dist/daemon/session/plugins.js +4 -52
- package/dist/daemon.js +7986 -6848
- package/dist/errors/messages.d.ts +34 -4
- package/dist/errors/messages.js +68 -5
- package/dist/index.js +610 -186
- package/dist/ipc/client.d.ts +4 -0
- package/dist/ipc/client.js +8 -0
- package/dist/ipc/protocol/auditTypes.d.ts +129 -0
- package/dist/ipc/protocol/auditTypes.js +6 -0
- package/dist/ipc/protocol/commands.d.ts +23 -0
- package/dist/ipc/protocol/commands.js +2 -0
- package/dist/ipc/protocol/domTypes.d.ts +4 -0
- package/dist/ipc/protocol/inspectTypes.d.ts +71 -8
- package/dist/runtime/css/search.d.ts +39 -0
- package/dist/runtime/css/search.js +122 -0
- package/dist/runtime/dom/actionEffects.d.ts +4 -1
- package/dist/runtime/dom/actionEffects.js +8 -4
- package/dist/runtime/dom/audit.d.ts +19 -0
- package/dist/runtime/dom/audit.js +36 -0
- package/dist/runtime/dom/auditModel.d.ts +45 -0
- package/dist/runtime/dom/auditModel.js +215 -0
- package/dist/runtime/dom/auditScripts.d.ts +107 -0
- package/dist/runtime/dom/auditScripts.js +112 -0
- package/dist/runtime/dom/elementGeometry.d.ts +8 -2
- package/dist/runtime/dom/elementGeometry.js +24 -8
- package/dist/runtime/dom/elementInfo.d.ts +3 -2
- package/dist/runtime/dom/elementInfo.js +8 -2
- package/dist/runtime/dom/formFillHelpers/fill.js +2 -2
- package/dist/runtime/dom/inspect.d.ts +7 -0
- package/dist/runtime/dom/inspect.js +88 -23
- package/dist/runtime/dom/inspectAllStyles.d.ts +16 -4
- package/dist/runtime/dom/inspectAllStyles.js +89 -7
- package/dist/runtime/dom/inspectCascade.d.ts +19 -2
- package/dist/runtime/dom/inspectCascade.js +214 -44
- package/dist/runtime/dom/inspectCascadeModel.d.ts +8 -0
- package/dist/runtime/dom/inspectCascadeModel.js +108 -34
- package/dist/runtime/dom/inspectHints.d.ts +26 -3
- package/dist/runtime/dom/inspectHints.js +125 -9
- package/dist/runtime/dom/inspectModel.d.ts +3 -0
- package/dist/runtime/dom/inspectModel.js +30 -7
- package/dist/runtime/dom/inspectPaintModel.d.ts +48 -22
- package/dist/runtime/dom/inspectPaintModel.js +180 -68
- package/dist/runtime/dom/inspectRules.d.ts +19 -0
- package/dist/runtime/dom/inspectRules.js +21 -5
- package/dist/runtime/dom/inspectScripts.d.ts +85 -12
- package/dist/runtime/dom/inspectScripts.js +314 -28
- package/dist/runtime/dom/inspectTree.js +10 -2
- package/dist/runtime/dom/inspectWhyModel.d.ts +2 -1
- package/dist/runtime/dom/inspectWhyModel.js +52 -10
- package/dist/runtime/dom/layout.js +31 -9
- package/dist/runtime/dom/reactEventHelpers.d.ts +7 -0
- package/dist/runtime/dom/reactEventHelpers.js +27 -9
- package/dist/runtime/page/emulation.d.ts +13 -4
- package/dist/runtime/page/emulation.js +69 -4
- package/dist/runtime/page/userAgent.d.ts +17 -0
- package/dist/runtime/page/userAgent.js +57 -0
- package/dist/types.d.ts +4 -0
- package/dist/ui/formatters/audit.d.ts +19 -0
- package/dist/ui/formatters/audit.js +106 -0
- package/dist/ui/formatters/dom.d.ts +1 -1
- package/dist/ui/formatters/dom.js +6 -3
- package/dist/ui/formatters/inspect.js +42 -15
- package/dist/ui/formatters/status.js +1 -1
- package/dist/ui/messages/commands.d.ts +44 -7
- package/dist/ui/messages/commands.js +83 -11
- package/dist/ui/messages/preview.d.ts +6 -0
- package/dist/ui/messages/preview.js +9 -1
- package/dist/utils/cssValues.js +36 -4
- package/dist/utils/decisionTrees.js +0 -5
- package/dist/utils/suggestions.d.ts +4 -2
- package/dist/utils/suggestions.js +7 -5
- package/dist/utils/taskMappings.js +1 -1
- package/package.json +3 -2
package/dist/commands/peek.js
CHANGED
|
@@ -8,9 +8,12 @@ import { fetchPreviewOutput, createErrorResult, } from './shared/dataFetcher.js'
|
|
|
8
8
|
import { followFetchFailure, setupFollowMode, } from './shared/followMode.js';
|
|
9
9
|
import { handleValidationError } from './shared/handleValidationError.js';
|
|
10
10
|
import { MAX_LAST_ITEMS, positiveIntRule, resourceTypeRule } from './shared/validation.js';
|
|
11
|
+
import { CommandError } from '../errors/index.js';
|
|
12
|
+
import { intervalWithoutFollowError } from '../errors/messages.js';
|
|
11
13
|
import { filterByResourceType } from '../telemetry/filters.js';
|
|
12
14
|
import { buildPreviewJsonData, formatPreview, } from '../ui/formatters/preview.js';
|
|
13
15
|
import { followingPreviewMessage, stoppedFollowingPreviewMessage } from '../ui/messages/preview.js';
|
|
16
|
+
import { EXIT_CODES } from '../utils/exitCodes.js';
|
|
14
17
|
function parseOptions(options) {
|
|
15
18
|
const lastN = positiveIntRule({
|
|
16
19
|
name: '--last',
|
|
@@ -20,7 +23,17 @@ function parseOptions(options) {
|
|
|
20
23
|
allowZeroForAll: true,
|
|
21
24
|
}).validate(options.last);
|
|
22
25
|
const resourceTypes = resourceTypeRule().validate(options.type);
|
|
23
|
-
|
|
26
|
+
if (options.interval !== undefined && !options.follow) {
|
|
27
|
+
const err = intervalWithoutFollowError();
|
|
28
|
+
throw new CommandError(err.message, { suggestion: err.suggestion }, EXIT_CODES.INVALID_ARGUMENTS);
|
|
29
|
+
}
|
|
30
|
+
const interval = positiveIntRule({
|
|
31
|
+
name: '--interval',
|
|
32
|
+
min: 100,
|
|
33
|
+
max: 60000,
|
|
34
|
+
default: 1000,
|
|
35
|
+
}).validate(options.interval);
|
|
36
|
+
return { lastN, resourceTypes, interval };
|
|
24
37
|
}
|
|
25
38
|
/**
|
|
26
39
|
* Data section selected by `--network` / `--console`, if any.
|
|
@@ -75,11 +88,12 @@ function createPreviewOptions(base, resourceTypes, unfilteredCount) {
|
|
|
75
88
|
}
|
|
76
89
|
return options;
|
|
77
90
|
}
|
|
78
|
-
async function runFollowMode(options,
|
|
91
|
+
async function runFollowMode(options, parsed, baseOptions) {
|
|
92
|
+
const { lastN, resourceTypes, interval } = parsed;
|
|
79
93
|
const showPreview = async () => {
|
|
80
94
|
const result = await fetchAndFilterPreview(lastN, resourceTypes, peekSection(options));
|
|
81
95
|
if (!result.success) {
|
|
82
|
-
return followFetchFailure(result, { json: options.json, retryIntervalMs:
|
|
96
|
+
return followFetchFailure(result, { json: options.json, retryIntervalMs: interval });
|
|
83
97
|
}
|
|
84
98
|
noteFollowConnected();
|
|
85
99
|
if (!options.json)
|
|
@@ -91,9 +105,51 @@ async function runFollowMode(options, lastN, resourceTypes, baseOptions) {
|
|
|
91
105
|
await setupFollowMode(showPreview, {
|
|
92
106
|
startMessage: followingPreviewMessage,
|
|
93
107
|
stopMessage: stoppedFollowingPreviewMessage,
|
|
94
|
-
intervalMs:
|
|
108
|
+
intervalMs: interval,
|
|
95
109
|
});
|
|
96
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Parse the options, reporting an invalid one and exiting.
|
|
113
|
+
*
|
|
114
|
+
* @param options - Peek options
|
|
115
|
+
* @returns Parsed options
|
|
116
|
+
*/
|
|
117
|
+
function parsePeekOptions(options) {
|
|
118
|
+
try {
|
|
119
|
+
return parseOptions(options);
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
handleValidationError(error, options.json ?? false);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* How the preview is shown.
|
|
127
|
+
*
|
|
128
|
+
* @param options - Peek options
|
|
129
|
+
* @param lastN - Items to show
|
|
130
|
+
* @returns Preview options
|
|
131
|
+
*/
|
|
132
|
+
function previewDisplayOptions(options, lastN) {
|
|
133
|
+
return {
|
|
134
|
+
json: options.json,
|
|
135
|
+
network: options.network,
|
|
136
|
+
console: options.console,
|
|
137
|
+
last: lastN,
|
|
138
|
+
verbose: options.verbose,
|
|
139
|
+
follow: options.follow,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Watch the session data (`peek --follow`, and the deprecated `tail`).
|
|
144
|
+
*
|
|
145
|
+
* @param options - Peek options (follow implied)
|
|
146
|
+
*/
|
|
147
|
+
export async function followPreview(options) {
|
|
148
|
+
const following = { ...options, follow: true };
|
|
149
|
+
showBothSectionsWhenBothRequested(following);
|
|
150
|
+
const parsed = parsePeekOptions(following);
|
|
151
|
+
await runFollowMode(following, parsed, previewDisplayOptions(following, parsed.lastN));
|
|
152
|
+
}
|
|
97
153
|
export function registerPeekCommand(program) {
|
|
98
154
|
program
|
|
99
155
|
.command('peek')
|
|
@@ -103,6 +159,7 @@ export function registerPeekCommand(program) {
|
|
|
103
159
|
.option('-n, --network', 'Show only network requests', false)
|
|
104
160
|
.option('-c, --console', 'Show only console messages', false)
|
|
105
161
|
.option('-f, --follow', 'Watch for updates (like tail -f)', false)
|
|
162
|
+
.option('--interval <ms>', 'Refresh interval of --follow in ms, 100-60000 (default: 1000)')
|
|
106
163
|
.option('--last <count>', 'Show last N items, 0 for all', '10')
|
|
107
164
|
.option('--type <types>', 'Filter network requests by resource type (comma-separated: Document,XHR,Fetch,etc.)')
|
|
108
165
|
.action(async (options) => {
|
|
@@ -110,26 +167,11 @@ export function registerPeekCommand(program) {
|
|
|
110
167
|
if (options.network && !options.json) {
|
|
111
168
|
console.error('Note: "bdg peek --network" is deprecated. Use "bdg network list" for enhanced filtering.');
|
|
112
169
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const parsed = parseOptions(options);
|
|
117
|
-
lastN = parsed.lastN;
|
|
118
|
-
resourceTypes = parsed.resourceTypes;
|
|
119
|
-
}
|
|
120
|
-
catch (error) {
|
|
121
|
-
handleValidationError(error, options.json ?? false);
|
|
122
|
-
}
|
|
123
|
-
const baseOptions = {
|
|
124
|
-
json: options.json,
|
|
125
|
-
network: options.network,
|
|
126
|
-
console: options.console,
|
|
127
|
-
last: lastN,
|
|
128
|
-
verbose: options.verbose,
|
|
129
|
-
follow: options.follow,
|
|
130
|
-
};
|
|
170
|
+
const parsed = parsePeekOptions(options);
|
|
171
|
+
const { lastN, resourceTypes } = parsed;
|
|
172
|
+
const baseOptions = previewDisplayOptions(options, lastN);
|
|
131
173
|
if (options.follow) {
|
|
132
|
-
await runFollowMode(options,
|
|
174
|
+
await runFollowMode(options, parsed, baseOptions);
|
|
133
175
|
return;
|
|
134
176
|
}
|
|
135
177
|
await runCommand(async () => {
|
|
@@ -93,8 +93,10 @@ export interface ScreenshotOptions {
|
|
|
93
93
|
fullPage?: boolean;
|
|
94
94
|
/** CSS selector for element capture */
|
|
95
95
|
selector?: string;
|
|
96
|
-
/** Cached element index (0-based) from previous query */
|
|
96
|
+
/** Cached element index (0-based) from previous query, or with `selector`, which of its matches */
|
|
97
97
|
index?: number;
|
|
98
|
+
/** Extra space (CSS px) around an element capture */
|
|
99
|
+
padding?: number;
|
|
98
100
|
/** Continuous capture mode to directory */
|
|
99
101
|
follow?: boolean;
|
|
100
102
|
/** Capture interval in ms for follow mode (string from CLI) */
|
|
@@ -373,6 +375,8 @@ export interface PeekCommandOptions extends BaseOptions, PreviewDisplayOptions {
|
|
|
373
375
|
last?: string;
|
|
374
376
|
/** Filter network requests by resource type (comma-separated) */
|
|
375
377
|
type?: string;
|
|
378
|
+
/** Refresh interval of --follow in ms (string from CLI, default: 1000) */
|
|
379
|
+
interval?: string;
|
|
376
380
|
}
|
|
377
381
|
/**
|
|
378
382
|
* Options for tail command.
|
package/dist/commands/start.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ export interface CollectorOptions {
|
|
|
26
26
|
chromeFlags?: string;
|
|
27
27
|
/** Viewport size, e.g. `1280x800`. */
|
|
28
28
|
viewport?: string;
|
|
29
|
+
/** Emulate a phone (`--mobile`) */
|
|
30
|
+
mobile?: boolean;
|
|
29
31
|
/** `prefers-color-scheme` to emulate: light or dark. */
|
|
30
32
|
colorScheme?: string;
|
|
31
33
|
}
|
|
@@ -53,6 +55,17 @@ export declare function extractUserDataDirFromFlags(flags: string[]): {
|
|
|
53
55
|
* @returns The modified Command instance with all telemetry options applied
|
|
54
56
|
*/
|
|
55
57
|
export declare function applyCollectorOptions(command: Command): Command;
|
|
58
|
+
/** Viewport of `--mobile` without `--viewport` (a common phone, CSS px) */
|
|
59
|
+
export declare const MOBILE_VIEWPORT: ViewportSize;
|
|
60
|
+
/**
|
|
61
|
+
* The viewport to emulate from `--viewport` and `--mobile`.
|
|
62
|
+
*
|
|
63
|
+
* @param viewport - `--viewport` value
|
|
64
|
+
* @param mobile - `--mobile` was given
|
|
65
|
+
* @returns Viewport (a phone's with `--mobile`), or undefined for neither
|
|
66
|
+
* @throws CommandError (81) for an invalid size
|
|
67
|
+
*/
|
|
68
|
+
export declare function requestedViewport(viewport: string | undefined, mobile: boolean | undefined): ViewportSize | undefined;
|
|
56
69
|
/**
|
|
57
70
|
* Parse a `--viewport` value: width and height in CSS px joined by `x`
|
|
58
71
|
* (`1280x800`; `X`, `×` and `,` work too).
|
package/dist/commands/start.js
CHANGED
|
@@ -81,7 +81,24 @@ export function applyCollectorOptions(command) {
|
|
|
81
81
|
.addOption(jsonOption())
|
|
82
82
|
.option('--chrome-flags <flags>', 'Custom Chrome flags (space-separated, e.g., --chrome-flags="--ignore-certificate-errors --disable-web-security")')
|
|
83
83
|
.option('--viewport <WxH>', 'Viewport size in CSS px for the whole session, e.g. 1280x800 (default: 1920x1080 window)')
|
|
84
|
-
.option('--color-scheme <scheme>', 'Emulate prefers-color-scheme for the session: light or dark (default: the system setting)')
|
|
84
|
+
.option('--color-scheme <scheme>', 'Emulate prefers-color-scheme for the session: light or dark (default: the system setting)')
|
|
85
|
+
.option('--mobile', `Emulate a phone for the session: mobile viewport (${MOBILE_VIEWPORT.width}x${MOBILE_VIEWPORT.height} unless --viewport), touch, mobile user agent`);
|
|
86
|
+
}
|
|
87
|
+
/** Viewport of `--mobile` without `--viewport` (a common phone, CSS px) */
|
|
88
|
+
export const MOBILE_VIEWPORT = { width: 390, height: 844 };
|
|
89
|
+
/**
|
|
90
|
+
* The viewport to emulate from `--viewport` and `--mobile`.
|
|
91
|
+
*
|
|
92
|
+
* @param viewport - `--viewport` value
|
|
93
|
+
* @param mobile - `--mobile` was given
|
|
94
|
+
* @returns Viewport (a phone's with `--mobile`), or undefined for neither
|
|
95
|
+
* @throws CommandError (81) for an invalid size
|
|
96
|
+
*/
|
|
97
|
+
export function requestedViewport(viewport, mobile) {
|
|
98
|
+
const size = viewport !== undefined ? parseViewport(viewport) : undefined;
|
|
99
|
+
if (!mobile)
|
|
100
|
+
return size;
|
|
101
|
+
return { ...(size ?? MOBILE_VIEWPORT), mobile: true };
|
|
85
102
|
}
|
|
86
103
|
/** Largest viewport side accepted by `--viewport` (CSS px) */
|
|
87
104
|
const MAX_VIEWPORT_SIDE = 10000;
|
|
@@ -157,7 +174,7 @@ function buildSessionOptions(options) {
|
|
|
157
174
|
quiet: options.quiet ?? false,
|
|
158
175
|
json: options.json ?? false,
|
|
159
176
|
chromeFlags,
|
|
160
|
-
viewport: options.viewport
|
|
177
|
+
viewport: requestedViewport(options.viewport, options.mobile),
|
|
161
178
|
colorScheme: options.colorScheme !== undefined ? parseColorScheme(options.colorScheme) : undefined,
|
|
162
179
|
};
|
|
163
180
|
}
|
package/dist/commands/tail.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* `bdg tail`: deprecated alias of `bdg peek --follow` (#115). It keeps its
|
|
3
|
+
* options and says to use `peek --follow` instead.
|
|
3
4
|
*/
|
|
4
5
|
import type { Command } from 'commander';
|
|
6
|
+
/**
|
|
7
|
+
* Register the deprecated `tail` command.
|
|
8
|
+
*
|
|
9
|
+
* @param program - Root command
|
|
10
|
+
*/
|
|
5
11
|
export declare function registerTailCommand(program: Command): void;
|
|
6
12
|
//# sourceMappingURL=tail.d.ts.map
|
package/dist/commands/tail.js
CHANGED
|
@@ -1,43 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* `bdg tail`: deprecated alias of `bdg peek --follow` (#115). It keeps its
|
|
3
|
+
* options and says to use `peek --follow` instead.
|
|
4
|
+
*/
|
|
5
|
+
import { followPreview } from './peek.js';
|
|
6
|
+
import { jsonOption } from './shared/commonOptions.js';
|
|
7
|
+
import { tailDeprecatedNotice } from '../ui/messages/preview.js';
|
|
8
|
+
/**
|
|
9
|
+
* Register the deprecated `tail` command.
|
|
10
|
+
*
|
|
11
|
+
* @param program - Root command
|
|
3
12
|
*/
|
|
4
|
-
import { jsonOption, showBothSectionsWhenBothRequested } from './shared/commonOptions.js';
|
|
5
|
-
import { noteFollowConnected } from './shared/daemonErrorHandler.js';
|
|
6
|
-
import { fetchPreviewOutput } from './shared/dataFetcher.js';
|
|
7
|
-
import { followFetchFailure, setupFollowMode, } from './shared/followMode.js';
|
|
8
|
-
import { handleValidationError } from './shared/handleValidationError.js';
|
|
9
|
-
import { MAX_LAST_ITEMS, positiveIntRule } from './shared/validation.js';
|
|
10
|
-
import { formatPreview } from '../ui/formatters/preview.js';
|
|
11
|
-
import { followingPreviewMessage, stoppedFollowingPreviewMessage } from '../ui/messages/preview.js';
|
|
12
|
-
function parseOptions(options) {
|
|
13
|
-
const lastRule = positiveIntRule({
|
|
14
|
-
name: '--last',
|
|
15
|
-
min: 1,
|
|
16
|
-
max: MAX_LAST_ITEMS,
|
|
17
|
-
default: 10,
|
|
18
|
-
allowZeroForAll: true,
|
|
19
|
-
});
|
|
20
|
-
const intervalRule = positiveIntRule({ name: '--interval', min: 100, max: 60000, default: 1000 });
|
|
21
|
-
return {
|
|
22
|
-
lastN: lastRule.validate(options.last),
|
|
23
|
-
interval: intervalRule.validate(options.interval),
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
function createPreviewOptions(options, lastN) {
|
|
27
|
-
return {
|
|
28
|
-
json: options.json,
|
|
29
|
-
network: options.network,
|
|
30
|
-
console: options.console,
|
|
31
|
-
last: lastN,
|
|
32
|
-
verbose: options.verbose,
|
|
33
|
-
follow: true,
|
|
34
|
-
viewedAt: new Date(),
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
13
|
export function registerTailCommand(program) {
|
|
38
14
|
program
|
|
39
15
|
.command('tail')
|
|
40
|
-
.description('
|
|
16
|
+
.description('Deprecated: use "bdg peek --follow" (same options)')
|
|
41
17
|
.addOption(jsonOption())
|
|
42
18
|
.option('-v, --verbose', 'Use verbose output with full URLs and formatting', false)
|
|
43
19
|
.option('-n, --network', 'Show only network requests', false)
|
|
@@ -45,33 +21,8 @@ export function registerTailCommand(program) {
|
|
|
45
21
|
.option('--last <count>', 'Show last N items (network requests + console messages), 0 for all', '10')
|
|
46
22
|
.option('--interval <ms>', 'Update interval in milliseconds', '1000')
|
|
47
23
|
.action(async (options) => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
let interval;
|
|
51
|
-
try {
|
|
52
|
-
const parsed = parseOptions(options);
|
|
53
|
-
lastN = parsed.lastN;
|
|
54
|
-
interval = parsed.interval;
|
|
55
|
-
}
|
|
56
|
-
catch (error) {
|
|
57
|
-
handleValidationError(error, options.json ?? false);
|
|
58
|
-
}
|
|
59
|
-
const showPreview = async () => {
|
|
60
|
-
const result = await fetchPreviewOutput({ lastN });
|
|
61
|
-
if (!result.success) {
|
|
62
|
-
return followFetchFailure(result, { json: options.json, retryIntervalMs: interval });
|
|
63
|
-
}
|
|
64
|
-
noteFollowConnected();
|
|
65
|
-
if (!options.json)
|
|
66
|
-
console.clear();
|
|
67
|
-
console.log(formatPreview(result.data, createPreviewOptions(options, lastN)));
|
|
68
|
-
return undefined;
|
|
69
|
-
};
|
|
70
|
-
await setupFollowMode(showPreview, {
|
|
71
|
-
startMessage: followingPreviewMessage,
|
|
72
|
-
stopMessage: stoppedFollowingPreviewMessage,
|
|
73
|
-
intervalMs: interval,
|
|
74
|
-
});
|
|
24
|
+
console.error(tailDeprecatedNotice());
|
|
25
|
+
await followPreview({ ...options, follow: true });
|
|
75
26
|
});
|
|
76
27
|
}
|
|
77
28
|
//# sourceMappingURL=tail.js.map
|
package/dist/commands.js
CHANGED
|
@@ -6,6 +6,7 @@ import { registerFormInteractionCommands } from './commands/dom/formInteraction.
|
|
|
6
6
|
import { registerDomCommands } from './commands/dom/index.js';
|
|
7
7
|
import { registerInstallSkillCommand } from './commands/installSkill.js';
|
|
8
8
|
import { registerNetworkCommands } from './commands/network/index.js';
|
|
9
|
+
import { registerCssCommands } from './commands/css.js';
|
|
9
10
|
import { registerPageCommands } from './commands/page.js';
|
|
10
11
|
import { registerPeekCommand } from './commands/peek.js';
|
|
11
12
|
import { registerSessionsCommand } from './commands/sessions.js';
|
|
@@ -39,6 +40,7 @@ export const commandRegistry = [
|
|
|
39
40
|
registerDomCommands,
|
|
40
41
|
registerFormInteractionCommands,
|
|
41
42
|
registerPageCommands,
|
|
43
|
+
registerCssCommands,
|
|
42
44
|
addCommandGroup('CDP Commands:'),
|
|
43
45
|
registerCdpCommand,
|
|
44
46
|
addCommandGroup('Network Commands:'),
|
|
@@ -4,6 +4,8 @@ import { createInteractionRunner } from './interactions.js';
|
|
|
4
4
|
import { withTriggeredRequestCount } from './triggeredRequests.js';
|
|
5
5
|
import { CommandError } from '../../errors/index.js';
|
|
6
6
|
import { cdpCallError, formDiscoveryFailedError } from '../../errors/messages.js';
|
|
7
|
+
import { searchStyleSheets } from '../../runtime/css/search.js';
|
|
8
|
+
import { auditPage } from '../../runtime/dom/audit.js';
|
|
7
9
|
import { evaluateScript, withBusyPageRecovery } from '../../runtime/dom/evalHelpers.js';
|
|
8
10
|
import { inspectEventListeners } from '../../runtime/dom/eventListeners.js';
|
|
9
11
|
import { FORM_DISCOVERY_SCRIPT, isRawFormData } from '../../runtime/dom/formDiscovery.js';
|
|
@@ -458,7 +460,11 @@ export function createCommandRegistry(store, emulation) {
|
|
|
458
460
|
})), params.wait !== false))),
|
|
459
461
|
dom_listeners: async (cdp, params) => withBusyPageRecovery(cdp, inspectEventListeners(cdp, params)),
|
|
460
462
|
dom_layout: async (cdp, params) => withBusyPageRecovery(cdp, inspectLayout(cdp, params)),
|
|
461
|
-
|
|
463
|
+
dom_audit: async (cdp, params) => withBusyPageRecovery(cdp, auditPage(cdp, params)),
|
|
464
|
+
css_search: async (cdp, params) => searchStyleSheets(cdp, params),
|
|
465
|
+
dom_inspect: async (cdp, params) => withBusyPageRecovery(cdp, inspectElement(cdp, params).then((result) => result.theme === 'dark' && emulation.get().colorScheme === 'dark'
|
|
466
|
+
? { ...result, themeFrom: 'emulation' }
|
|
467
|
+
: result)),
|
|
462
468
|
dom_wait: async (cdp, params) => waitForCondition(cdp, params),
|
|
463
469
|
page_navigate: async (cdp, params) => interact(cdp, () => navigatePage(cdp, params.action, {
|
|
464
470
|
...filterDefined({ url: params.url, wait: params.wait }),
|
|
@@ -4,6 +4,7 @@ import { prepareDOMCollection } from '../../telemetry/dom.js';
|
|
|
4
4
|
import { startNavigationTracking } from '../../telemetry/navigation.js';
|
|
5
5
|
import { startNetworkCollection, startWebSocketCollection } from '../../telemetry/network.js';
|
|
6
6
|
import { getErrorMessage } from '../../utils/errors.js';
|
|
7
|
+
import { hideHeadlessUserAgent } from '../../runtime/page/userAgent.js';
|
|
7
8
|
import { filterDefined } from '../../utils/objects.js';
|
|
8
9
|
/** Delay before reading the title after a same-document navigation */
|
|
9
10
|
const TITLE_REFRESH_DELAY_MS = 300;
|
|
@@ -83,56 +84,6 @@ async function emulatePageFocus(cdp, logger) {
|
|
|
83
84
|
.send('Emulation.setFocusEmulationEnabled', { enabled: true })
|
|
84
85
|
.catch((error) => logger.debug(`No focus emulation: ${getErrorMessage(error)}`));
|
|
85
86
|
}
|
|
86
|
-
/** Reads the client hints Chrome reports, renaming the HeadlessChrome brand */
|
|
87
|
-
const USER_AGENT_METADATA_SCRIPT = `(async () => {
|
|
88
|
-
const data = navigator.userAgentData;
|
|
89
|
-
if (!data) return null;
|
|
90
|
-
const values = await data.getHighEntropyValues(
|
|
91
|
-
['architecture', 'bitness', 'model', 'platformVersion', 'fullVersionList', 'wow64']
|
|
92
|
-
);
|
|
93
|
-
const rename = (list) => (list || []).map((entry) => ({
|
|
94
|
-
brand: entry.brand.replace('HeadlessChrome', 'Google Chrome'),
|
|
95
|
-
version: entry.version,
|
|
96
|
-
}));
|
|
97
|
-
return {
|
|
98
|
-
brands: rename(values.brands),
|
|
99
|
-
fullVersionList: rename(values.fullVersionList),
|
|
100
|
-
platform: values.platform,
|
|
101
|
-
platformVersion: values.platformVersion,
|
|
102
|
-
architecture: values.architecture,
|
|
103
|
-
model: values.model,
|
|
104
|
-
mobile: values.mobile,
|
|
105
|
-
bitness: values.bitness,
|
|
106
|
-
wow64: values.wow64,
|
|
107
|
-
};
|
|
108
|
-
})()`;
|
|
109
|
-
/**
|
|
110
|
-
* Send the user agent and client hints of regular Chrome from headless
|
|
111
|
-
* Chrome: sites serve "HeadlessChrome" a different page (or a bot
|
|
112
|
-
* challenge), so the page would not be the one a user sees.
|
|
113
|
-
*
|
|
114
|
-
* @param cdp - CDP connection
|
|
115
|
-
* @param logger - Logger for failures (the session works without it)
|
|
116
|
-
*/
|
|
117
|
-
async function hideHeadlessUserAgent(cdp, logger) {
|
|
118
|
-
try {
|
|
119
|
-
const { userAgent } = (await cdp.send('Browser.getVersion'));
|
|
120
|
-
if (!userAgent.includes('HeadlessChrome'))
|
|
121
|
-
return;
|
|
122
|
-
const metadata = (await cdp.send('Runtime.evaluate', {
|
|
123
|
-
expression: USER_AGENT_METADATA_SCRIPT,
|
|
124
|
-
awaitPromise: true,
|
|
125
|
-
returnByValue: true,
|
|
126
|
-
}));
|
|
127
|
-
await cdp.send('Emulation.setUserAgentOverride', {
|
|
128
|
-
userAgent: userAgent.replace('HeadlessChrome', 'Chrome'),
|
|
129
|
-
...(metadata.result?.value ? { userAgentMetadata: metadata.result.value } : {}),
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
catch (error) {
|
|
133
|
-
logger.debug(`User agent left as is: ${getErrorMessage(error)}`);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
87
|
export function createDefaultTelemetryPlugins() {
|
|
137
88
|
return [
|
|
138
89
|
{
|
|
@@ -145,9 +96,10 @@ export function createDefaultTelemetryPlugins() {
|
|
|
145
96
|
{
|
|
146
97
|
name: 'page-identity',
|
|
147
98
|
runAlways: true,
|
|
148
|
-
async start({ cdp, logger }) {
|
|
99
|
+
async start({ cdp, logger, config }) {
|
|
149
100
|
await emulatePageFocus(cdp, logger);
|
|
150
|
-
|
|
101
|
+
if (!config.viewport?.mobile)
|
|
102
|
+
await hideHeadlessUserAgent(cdp, logger);
|
|
151
103
|
return () => undefined;
|
|
152
104
|
},
|
|
153
105
|
},
|