@browserbridge/bbx 1.7.4 → 1.7.6
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/package.json +6 -6
- package/packages/agent-client/src/atomic-write.js +99 -0
- package/packages/agent-client/src/cli-args.js +152 -0
- package/packages/agent-client/src/cli-batch.js +140 -0
- package/packages/agent-client/src/cli-helpers.js +20 -3
- package/packages/agent-client/src/cli-output.js +57 -0
- package/packages/agent-client/src/cli-proxy-remote.js +350 -0
- package/packages/agent-client/src/cli-setup-commands.js +404 -0
- package/packages/agent-client/src/cli.js +63 -906
- package/packages/agent-client/src/command-registry.js +12 -6
- package/packages/agent-client/src/install.js +39 -4
- package/packages/agent-client/src/mcp-config.js +28 -14
- package/packages/agent-client/src/remotes.js +93 -15
- package/packages/agent-client/src/runtime.js +6 -4
- package/packages/mcp-server/src/bin.js +10 -1
- package/packages/mcp-server/src/guidance.js +1 -1
- package/packages/mcp-server/src/handlers-capture.js +8 -5
- package/packages/mcp-server/src/handlers-dom.js +2 -2
- package/packages/mcp-server/src/handlers-navigation.js +20 -9
- package/packages/mcp-server/src/handlers-page.js +111 -111
- package/packages/mcp-server/src/handlers-utils.js +268 -8
- package/packages/mcp-server/src/handlers.js +31 -10
- package/packages/mcp-server/src/lifecycle.js +413 -0
- package/packages/mcp-server/src/server.js +27 -19
- package/packages/native-host/src/auth-token.js +1 -1
- package/packages/native-host/src/config.js +9 -4
- package/packages/native-host/src/daemon-process.js +8 -1
- package/packages/protocol/src/capabilities.js +33 -110
- package/packages/protocol/src/capability-values.js +45 -0
- package/packages/protocol/src/defaults.js +19 -2
- package/packages/protocol/src/protocol.js +106 -5
- package/packages/protocol/src/registry.js +299 -86
- package/packages/protocol/src/types.ts +19 -1
- package/skills/browser-bridge/SKILL.md +1 -1
|
@@ -1,122 +1,45 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
+
import { CAPABILITIES, DEFAULT_CAPABILITIES } from './capability-values.js';
|
|
4
|
+
import { BRIDGE_METHODS, BRIDGE_METHOD_REGISTRY } from './registry.js';
|
|
5
|
+
|
|
3
6
|
/** @typedef {import('./types.js').BridgeMethod} CapabilityMethod */
|
|
4
7
|
/** @typedef {import('./types.js').Capability} Capability */
|
|
5
8
|
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
TABS_MANAGE: 'tabs.manage',
|
|
23
|
-
PERFORMANCE_READ: 'performance.read',
|
|
24
|
-
NETWORK_READ: 'network.read',
|
|
25
|
-
NETWORK_INTERCEPT: 'network.intercept',
|
|
26
|
-
});
|
|
9
|
+
export { CAPABILITIES, DEFAULT_CAPABILITIES };
|
|
10
|
+
|
|
11
|
+
/** @type {readonly CapabilityMethod[]} */
|
|
12
|
+
const LEGACY_METHOD_CAPABILITY_PREFIX = [
|
|
13
|
+
'access.request',
|
|
14
|
+
'tabs.list',
|
|
15
|
+
'tabs.create',
|
|
16
|
+
'tabs.close',
|
|
17
|
+
'tabs.activate',
|
|
18
|
+
'skill.get_runtime_context',
|
|
19
|
+
'setup.get_status',
|
|
20
|
+
'setup.install',
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
/** @type {readonly CapabilityMethod[]} */
|
|
24
|
+
const LEGACY_METHOD_CAPABILITY_SUFFIX = ['log.tail', 'health.ping', 'daemon.metrics'];
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
CAPABILITIES.DOM_READ,
|
|
32
|
-
CAPABILITIES.STYLES_READ,
|
|
33
|
-
CAPABILITIES.LAYOUT_READ,
|
|
34
|
-
CAPABILITIES.VIEWPORT_CONTROL,
|
|
35
|
-
CAPABILITIES.NAVIGATION_CONTROL,
|
|
36
|
-
CAPABILITIES.SCREENSHOT_PARTIAL,
|
|
37
|
-
CAPABILITIES.PATCH_DOM,
|
|
38
|
-
CAPABILITIES.PATCH_STYLES,
|
|
39
|
-
CAPABILITIES.AUTOMATION_INPUT,
|
|
40
|
-
CAPABILITIES.CDP_DOM_SNAPSHOT,
|
|
41
|
-
CAPABILITIES.CDP_BOX_MODEL,
|
|
42
|
-
CAPABILITIES.CDP_STYLES,
|
|
43
|
-
CAPABILITIES.CDP_INPUT,
|
|
44
|
-
CAPABILITIES.TABS_MANAGE,
|
|
45
|
-
CAPABILITIES.PERFORMANCE_READ,
|
|
46
|
-
CAPABILITIES.NETWORK_READ,
|
|
47
|
-
CAPABILITIES.NETWORK_INTERCEPT,
|
|
26
|
+
const LEGACY_POSITIONED_METHODS = new Set([
|
|
27
|
+
...LEGACY_METHOD_CAPABILITY_PREFIX,
|
|
28
|
+
...LEGACY_METHOD_CAPABILITY_SUFFIX,
|
|
48
29
|
]);
|
|
49
30
|
|
|
50
31
|
/** @type {Readonly<Record<CapabilityMethod, Capability | null>>} */
|
|
51
|
-
export const METHOD_CAPABILITIES = Object.freeze(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
'page.get_console': CAPABILITIES.PAGE_READ,
|
|
63
|
-
'page.wait_for_load_state': CAPABILITIES.PAGE_READ,
|
|
64
|
-
'page.get_storage': CAPABILITIES.PAGE_READ,
|
|
65
|
-
'page.get_text': CAPABILITIES.PAGE_READ,
|
|
66
|
-
'page.get_network': CAPABILITIES.NETWORK_READ,
|
|
67
|
-
// Interception mutates traffic (block/forge responses) - distinct from
|
|
68
|
-
// passive network reads so hosts can gate it independently.
|
|
69
|
-
'network.intercept.add': CAPABILITIES.NETWORK_INTERCEPT,
|
|
70
|
-
'network.intercept.remove': CAPABILITIES.NETWORK_INTERCEPT,
|
|
71
|
-
'network.intercept.list': CAPABILITIES.NETWORK_INTERCEPT,
|
|
72
|
-
'network.intercept.clear': CAPABILITIES.NETWORK_INTERCEPT,
|
|
73
|
-
'navigation.navigate': CAPABILITIES.NAVIGATION_CONTROL,
|
|
74
|
-
'navigation.reload': CAPABILITIES.NAVIGATION_CONTROL,
|
|
75
|
-
'navigation.go_back': CAPABILITIES.NAVIGATION_CONTROL,
|
|
76
|
-
'navigation.go_forward': CAPABILITIES.NAVIGATION_CONTROL,
|
|
77
|
-
'dom.query': CAPABILITIES.DOM_READ,
|
|
78
|
-
'dom.describe': CAPABILITIES.DOM_READ,
|
|
79
|
-
'dom.get_text': CAPABILITIES.DOM_READ,
|
|
80
|
-
'dom.get_attributes': CAPABILITIES.DOM_READ,
|
|
81
|
-
'dom.wait_for': CAPABILITIES.DOM_READ,
|
|
82
|
-
'dom.find_by_text': CAPABILITIES.DOM_READ,
|
|
83
|
-
'dom.find_by_role': CAPABILITIES.DOM_READ,
|
|
84
|
-
'dom.get_html': CAPABILITIES.DOM_READ,
|
|
85
|
-
'dom.get_accessibility_tree': CAPABILITIES.DOM_READ,
|
|
86
|
-
'layout.get_box_model': CAPABILITIES.LAYOUT_READ,
|
|
87
|
-
'layout.hit_test': CAPABILITIES.LAYOUT_READ,
|
|
88
|
-
'styles.get_computed': CAPABILITIES.STYLES_READ,
|
|
89
|
-
'styles.get_matched_rules': CAPABILITIES.STYLES_READ,
|
|
90
|
-
'viewport.scroll': CAPABILITIES.VIEWPORT_CONTROL,
|
|
91
|
-
'viewport.resize': CAPABILITIES.VIEWPORT_CONTROL,
|
|
92
|
-
'input.click': CAPABILITIES.AUTOMATION_INPUT,
|
|
93
|
-
'input.focus': CAPABILITIES.AUTOMATION_INPUT,
|
|
94
|
-
'input.type': CAPABILITIES.AUTOMATION_INPUT,
|
|
95
|
-
'input.fill': CAPABILITIES.AUTOMATION_INPUT,
|
|
96
|
-
'input.press_key': CAPABILITIES.AUTOMATION_INPUT,
|
|
97
|
-
'input.set_checked': CAPABILITIES.AUTOMATION_INPUT,
|
|
98
|
-
'input.select_option': CAPABILITIES.AUTOMATION_INPUT,
|
|
99
|
-
'input.hover': CAPABILITIES.AUTOMATION_INPUT,
|
|
100
|
-
'input.drag': CAPABILITIES.AUTOMATION_INPUT,
|
|
101
|
-
'input.scroll_into_view': CAPABILITIES.AUTOMATION_INPUT,
|
|
102
|
-
'screenshot.capture_region': CAPABILITIES.SCREENSHOT_PARTIAL,
|
|
103
|
-
'screenshot.capture_element': CAPABILITIES.SCREENSHOT_PARTIAL,
|
|
104
|
-
'screenshot.capture_full_page': CAPABILITIES.SCREENSHOT_PARTIAL,
|
|
105
|
-
'patch.apply_styles': CAPABILITIES.PATCH_STYLES,
|
|
106
|
-
'patch.apply_dom': CAPABILITIES.PATCH_DOM,
|
|
107
|
-
'patch.list': CAPABILITIES.PATCH_DOM,
|
|
108
|
-
'patch.rollback': CAPABILITIES.PATCH_DOM,
|
|
109
|
-
'patch.commit_session_baseline': CAPABILITIES.PATCH_DOM,
|
|
110
|
-
'cdp.get_document': CAPABILITIES.CDP_DOM_SNAPSHOT,
|
|
111
|
-
'cdp.get_dom_snapshot': CAPABILITIES.CDP_DOM_SNAPSHOT,
|
|
112
|
-
'cdp.get_box_model': CAPABILITIES.CDP_BOX_MODEL,
|
|
113
|
-
'cdp.get_computed_styles_for_node': CAPABILITIES.CDP_STYLES,
|
|
114
|
-
'cdp.dispatch_key_event': CAPABILITIES.CDP_INPUT,
|
|
115
|
-
'performance.get_metrics': CAPABILITIES.PERFORMANCE_READ,
|
|
116
|
-
'log.tail': null,
|
|
117
|
-
'health.ping': null,
|
|
118
|
-
'daemon.metrics': null,
|
|
119
|
-
});
|
|
32
|
+
export const METHOD_CAPABILITIES = Object.freeze(
|
|
33
|
+
/** @type {Record<CapabilityMethod, Capability | null>} */ (
|
|
34
|
+
Object.fromEntries(
|
|
35
|
+
[
|
|
36
|
+
...LEGACY_METHOD_CAPABILITY_PREFIX,
|
|
37
|
+
...BRIDGE_METHODS.filter((method) => !LEGACY_POSITIONED_METHODS.has(method)),
|
|
38
|
+
...LEGACY_METHOD_CAPABILITY_SUFFIX,
|
|
39
|
+
].map((method) => [method, BRIDGE_METHOD_REGISTRY[method].capability])
|
|
40
|
+
)
|
|
41
|
+
)
|
|
42
|
+
);
|
|
120
43
|
|
|
121
44
|
/**
|
|
122
45
|
* @param {unknown} value
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
export const CAPABILITIES = Object.freeze({
|
|
4
|
+
PAGE_READ: 'page.read',
|
|
5
|
+
PAGE_EVALUATE: 'page.evaluate',
|
|
6
|
+
DOM_READ: 'dom.read',
|
|
7
|
+
STYLES_READ: 'styles.read',
|
|
8
|
+
LAYOUT_READ: 'layout.read',
|
|
9
|
+
VIEWPORT_CONTROL: 'viewport.control',
|
|
10
|
+
NAVIGATION_CONTROL: 'navigation.control',
|
|
11
|
+
SCREENSHOT_PARTIAL: 'screenshot.partial',
|
|
12
|
+
PATCH_DOM: 'patch.dom',
|
|
13
|
+
PATCH_STYLES: 'patch.styles',
|
|
14
|
+
CDP_DOM_SNAPSHOT: 'cdp.dom_snapshot',
|
|
15
|
+
CDP_BOX_MODEL: 'cdp.box_model',
|
|
16
|
+
CDP_STYLES: 'cdp.styles',
|
|
17
|
+
CDP_INPUT: 'cdp.input',
|
|
18
|
+
AUTOMATION_INPUT: 'automation.input',
|
|
19
|
+
TABS_MANAGE: 'tabs.manage',
|
|
20
|
+
PERFORMANCE_READ: 'performance.read',
|
|
21
|
+
NETWORK_READ: 'network.read',
|
|
22
|
+
NETWORK_INTERCEPT: 'network.intercept',
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export const DEFAULT_CAPABILITIES = Object.freeze([
|
|
26
|
+
CAPABILITIES.PAGE_READ,
|
|
27
|
+
CAPABILITIES.PAGE_EVALUATE,
|
|
28
|
+
CAPABILITIES.DOM_READ,
|
|
29
|
+
CAPABILITIES.STYLES_READ,
|
|
30
|
+
CAPABILITIES.LAYOUT_READ,
|
|
31
|
+
CAPABILITIES.VIEWPORT_CONTROL,
|
|
32
|
+
CAPABILITIES.NAVIGATION_CONTROL,
|
|
33
|
+
CAPABILITIES.SCREENSHOT_PARTIAL,
|
|
34
|
+
CAPABILITIES.PATCH_DOM,
|
|
35
|
+
CAPABILITIES.PATCH_STYLES,
|
|
36
|
+
CAPABILITIES.AUTOMATION_INPUT,
|
|
37
|
+
CAPABILITIES.CDP_DOM_SNAPSHOT,
|
|
38
|
+
CAPABILITIES.CDP_BOX_MODEL,
|
|
39
|
+
CAPABILITIES.CDP_STYLES,
|
|
40
|
+
CAPABILITIES.CDP_INPUT,
|
|
41
|
+
CAPABILITIES.TABS_MANAGE,
|
|
42
|
+
CAPABILITIES.PERFORMANCE_READ,
|
|
43
|
+
CAPABILITIES.NETWORK_READ,
|
|
44
|
+
CAPABILITIES.NETWORK_INTERCEPT,
|
|
45
|
+
]);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
+
import { BRIDGE_METHODS, BRIDGE_METHOD_REGISTRY } from './registry.js';
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Shared Browser Bridge defaults used by the protocol, MCP layer, and runtime
|
|
5
7
|
* guidance. Keep this as the source of truth for default limits and presets.
|
|
@@ -20,6 +22,8 @@ export const DEFAULT_CONSOLE_LIMIT = 50;
|
|
|
20
22
|
export const DEFAULT_VIEWPORT_WIDTH = 1280;
|
|
21
23
|
export const DEFAULT_VIEWPORT_HEIGHT = 720;
|
|
22
24
|
export const DEFAULT_DEVICE_SCALE_FACTOR = 0;
|
|
25
|
+
/** @type {'continue'} */
|
|
26
|
+
export const DEFAULT_NETWORK_INTERCEPT_ACTION = 'continue';
|
|
23
27
|
|
|
24
28
|
/** Maximum size of a Chrome native messaging message in bytes. */
|
|
25
29
|
export const MAX_NATIVE_MESSAGE_BYTES = 1_048_576;
|
|
@@ -68,8 +72,8 @@ export const BUDGET_PRESETS = Object.freeze({
|
|
|
68
72
|
deep: { maxNodes: 100, maxDepth: 8, textBudget: 2000, tokenBudget: 4000 },
|
|
69
73
|
});
|
|
70
74
|
|
|
71
|
-
/** @type {
|
|
72
|
-
|
|
75
|
+
/** @type {readonly import('./types.js').BridgeMethod[]} */
|
|
76
|
+
const LEGACY_DEBUGGER_BACKED_METHOD_ORDER = [
|
|
73
77
|
'page.evaluate',
|
|
74
78
|
'dom.get_accessibility_tree',
|
|
75
79
|
'viewport.resize',
|
|
@@ -86,6 +90,19 @@ export const DEBUGGER_BACKED_METHODS = new Set([
|
|
|
86
90
|
'cdp.get_box_model',
|
|
87
91
|
'cdp.get_computed_styles_for_node',
|
|
88
92
|
'cdp.dispatch_key_event',
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
const LEGACY_DEBUGGER_BACKED_METHODS = new Set(LEGACY_DEBUGGER_BACKED_METHOD_ORDER);
|
|
96
|
+
|
|
97
|
+
/** @type {ReadonlySet<string>} */
|
|
98
|
+
export const DEBUGGER_BACKED_METHODS = new Set([
|
|
99
|
+
...LEGACY_DEBUGGER_BACKED_METHOD_ORDER.filter(
|
|
100
|
+
(method) => BRIDGE_METHOD_REGISTRY[method].debuggerBacked
|
|
101
|
+
),
|
|
102
|
+
...BRIDGE_METHODS.filter(
|
|
103
|
+
(method) =>
|
|
104
|
+
BRIDGE_METHOD_REGISTRY[method].debuggerBacked && !LEGACY_DEBUGGER_BACKED_METHODS.has(method)
|
|
105
|
+
),
|
|
89
106
|
]);
|
|
90
107
|
|
|
91
108
|
/**
|
|
@@ -6,12 +6,14 @@ import {
|
|
|
6
6
|
DEFAULT_A11Y_MAX_DEPTH,
|
|
7
7
|
DEFAULT_A11Y_MAX_NODES,
|
|
8
8
|
DEFAULT_CONSOLE_LIMIT,
|
|
9
|
+
DEFAULT_DEVICE_SCALE_FACTOR,
|
|
9
10
|
DEFAULT_EVAL_TIMEOUT_MS,
|
|
10
11
|
DEFAULT_LOG_TAIL_LIMIT,
|
|
11
12
|
DEFAULT_MAX_DEPTH,
|
|
12
13
|
DEFAULT_MAX_HTML_LENGTH,
|
|
13
14
|
DEFAULT_MAX_NODES,
|
|
14
15
|
DEFAULT_NAV_TIMEOUT_MS,
|
|
16
|
+
DEFAULT_NETWORK_INTERCEPT_ACTION,
|
|
15
17
|
DEFAULT_NETWORK_LIMIT,
|
|
16
18
|
DEFAULT_PAGE_TEXT_BUDGET,
|
|
17
19
|
DEFAULT_TEXT_BUDGET,
|
|
@@ -42,6 +44,7 @@ import { BRIDGE_METHODS, METHOD_SET, createBridgeMethodGroups } from './registry
|
|
|
42
44
|
/** @typedef {import('./types.js').InputActionParams} InputActionParams */
|
|
43
45
|
/** @typedef {import('./types.js').LogTailParams} LogTailParams */
|
|
44
46
|
/** @typedef {import('./types.js').NavigationActionParams} NavigationActionParams */
|
|
47
|
+
/** @typedef {import('./types.js').NetworkInterceptAddParams} NetworkInterceptAddParams */
|
|
45
48
|
/** @typedef {import('./types.js').NetworkParams} NetworkParams */
|
|
46
49
|
/** @typedef {import('./types.js').NormalizedAccessibilityTreeParams} NormalizedAccessibilityTreeParams */
|
|
47
50
|
/** @typedef {import('./types.js').NormalizedCheckedAction} NormalizedCheckedAction */
|
|
@@ -58,6 +61,7 @@ import { BRIDGE_METHODS, METHOD_SET, createBridgeMethodGroups } from './registry
|
|
|
58
61
|
/** @typedef {import('./types.js').NormalizedInputAction} NormalizedInputAction */
|
|
59
62
|
/** @typedef {import('./types.js').NormalizedLogTailParams} NormalizedLogTailParams */
|
|
60
63
|
/** @typedef {import('./types.js').NormalizedNavigationAction} NormalizedNavigationAction */
|
|
64
|
+
/** @typedef {import('./types.js').NormalizedNetworkInterceptAddParams} NormalizedNetworkInterceptAddParams */
|
|
61
65
|
/** @typedef {import('./types.js').NormalizedNetworkParams} NormalizedNetworkParams */
|
|
62
66
|
/** @typedef {import('./types.js').NormalizedPageTextParams} NormalizedPageTextParams */
|
|
63
67
|
/** @typedef {import('./types.js').NormalizedPatchOperation} NormalizedPatchOperation */
|
|
@@ -151,6 +155,30 @@ function clampInt(value, min, max, fallback) {
|
|
|
151
155
|
return Math.min(Math.max(integer, min), max);
|
|
152
156
|
}
|
|
153
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Clamp a finite number without discarding its fractional component.
|
|
160
|
+
*
|
|
161
|
+
* @param {unknown} value
|
|
162
|
+
* @param {number} min
|
|
163
|
+
* @param {number} max
|
|
164
|
+
* @param {number} fallback
|
|
165
|
+
* @returns {number}
|
|
166
|
+
*/
|
|
167
|
+
function clampNumber(value, min, max, fallback) {
|
|
168
|
+
const numeric = typeof value === 'number' && Number.isFinite(value) ? value : fallback;
|
|
169
|
+
return Math.min(Math.max(numeric, min), max);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* @param {unknown} value
|
|
174
|
+
* @returns {value is Record<string, unknown>}
|
|
175
|
+
*/
|
|
176
|
+
function isPlainRecord(value) {
|
|
177
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
|
|
178
|
+
const prototype = Object.getPrototypeOf(value);
|
|
179
|
+
return prototype === Object.prototype || prototype === null;
|
|
180
|
+
}
|
|
181
|
+
|
|
154
182
|
/** @type {ReadonlyArray<BridgeMethod>} */
|
|
155
183
|
export const METHODS = BRIDGE_METHODS;
|
|
156
184
|
|
|
@@ -336,6 +364,8 @@ function normalizeRequestParams(method, params) {
|
|
|
336
364
|
return normalizePageTextParams(params);
|
|
337
365
|
case 'page.get_network':
|
|
338
366
|
return normalizeNetworkParams(params);
|
|
367
|
+
case 'network.intercept.add':
|
|
368
|
+
return normalizeNetworkInterceptAddParams(params);
|
|
339
369
|
case 'navigation.navigate':
|
|
340
370
|
case 'navigation.reload':
|
|
341
371
|
case 'navigation.go_back':
|
|
@@ -643,7 +673,7 @@ export function normalizeNavigationAction(params = {}) {
|
|
|
643
673
|
return {
|
|
644
674
|
url,
|
|
645
675
|
waitForLoad: params.waitForLoad !== false,
|
|
646
|
-
timeoutMs: clampInt(params.timeoutMs, 500, 120_000,
|
|
676
|
+
timeoutMs: clampInt(params.timeoutMs, 500, 120_000, DEFAULT_NAV_TIMEOUT_MS),
|
|
647
677
|
};
|
|
648
678
|
}
|
|
649
679
|
|
|
@@ -682,11 +712,17 @@ export function normalizeEvaluateParams(params = {}) {
|
|
|
682
712
|
`Expression too large (${expression.length} chars). Maximum is 100,000.`
|
|
683
713
|
);
|
|
684
714
|
}
|
|
715
|
+
if (params.returnByValue === false) {
|
|
716
|
+
throw new BridgeError(
|
|
717
|
+
ERROR_CODES.INVALID_REQUEST,
|
|
718
|
+
'returnByValue=false is not supported because remote CDP objects cannot be consumed.'
|
|
719
|
+
);
|
|
720
|
+
}
|
|
685
721
|
return {
|
|
686
722
|
expression,
|
|
687
723
|
awaitPromise: Boolean(params.awaitPromise),
|
|
688
|
-
timeoutMs: clampInt(params.timeoutMs, 100, 30_000,
|
|
689
|
-
returnByValue:
|
|
724
|
+
timeoutMs: clampInt(params.timeoutMs, 100, 30_000, DEFAULT_EVAL_TIMEOUT_MS),
|
|
725
|
+
returnByValue: true,
|
|
690
726
|
};
|
|
691
727
|
}
|
|
692
728
|
|
|
@@ -829,7 +865,7 @@ export function normalizeStorageParams(params = {}) {
|
|
|
829
865
|
export function normalizeWaitForLoadStateParams(params = {}) {
|
|
830
866
|
return {
|
|
831
867
|
waitForLoad: params.waitForLoad !== false,
|
|
832
|
-
timeoutMs: clampInt(params.timeoutMs, 500, 120_000,
|
|
868
|
+
timeoutMs: clampInt(params.timeoutMs, 500, 120_000, DEFAULT_NAV_TIMEOUT_MS),
|
|
833
869
|
};
|
|
834
870
|
}
|
|
835
871
|
|
|
@@ -898,6 +934,71 @@ export function normalizeNetworkParams(params = {}) {
|
|
|
898
934
|
};
|
|
899
935
|
}
|
|
900
936
|
|
|
937
|
+
/**
|
|
938
|
+
* @param {NetworkInterceptAddParams} [params={}]
|
|
939
|
+
* @returns {NormalizedNetworkInterceptAddParams}
|
|
940
|
+
*/
|
|
941
|
+
export function normalizeNetworkInterceptAddParams(params = {}) {
|
|
942
|
+
if (typeof params.urlPattern !== 'string' || !params.urlPattern) {
|
|
943
|
+
throw new BridgeError(ERROR_CODES.INVALID_REQUEST, 'urlPattern is required.');
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
const action = params.action ?? DEFAULT_NETWORK_INTERCEPT_ACTION;
|
|
947
|
+
if (action !== 'fulfill' && action !== 'continue' && action !== 'block') {
|
|
948
|
+
throw new BridgeError(
|
|
949
|
+
ERROR_CODES.INVALID_REQUEST,
|
|
950
|
+
'action must be one of fulfill, continue, or block.'
|
|
951
|
+
);
|
|
952
|
+
}
|
|
953
|
+
if (
|
|
954
|
+
params.statusCode !== undefined &&
|
|
955
|
+
(!Number.isInteger(params.statusCode) || params.statusCode < 100 || params.statusCode > 599)
|
|
956
|
+
) {
|
|
957
|
+
throw new BridgeError(
|
|
958
|
+
ERROR_CODES.INVALID_REQUEST,
|
|
959
|
+
'statusCode must be an integer between 100 and 599.'
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
if (params.body !== undefined && typeof params.body !== 'string') {
|
|
963
|
+
throw new BridgeError(ERROR_CODES.INVALID_REQUEST, 'body must be a string.');
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
/** @type {Record<string, string> | undefined} */
|
|
967
|
+
let headers;
|
|
968
|
+
if (params.headers !== undefined) {
|
|
969
|
+
if (!isPlainRecord(params.headers)) {
|
|
970
|
+
throw new BridgeError(
|
|
971
|
+
ERROR_CODES.INVALID_REQUEST,
|
|
972
|
+
'headers must be an object containing string values.'
|
|
973
|
+
);
|
|
974
|
+
}
|
|
975
|
+
headers = {};
|
|
976
|
+
for (const [name, value] of Object.entries(params.headers)) {
|
|
977
|
+
if (!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name)) {
|
|
978
|
+
throw new BridgeError(
|
|
979
|
+
ERROR_CODES.INVALID_REQUEST,
|
|
980
|
+
`Invalid header name: ${name || '(empty)'}.`
|
|
981
|
+
);
|
|
982
|
+
}
|
|
983
|
+
if (typeof value !== 'string' || /[\r\n]/.test(value)) {
|
|
984
|
+
throw new BridgeError(
|
|
985
|
+
ERROR_CODES.INVALID_REQUEST,
|
|
986
|
+
`Header ${name} must have a string value without newlines.`
|
|
987
|
+
);
|
|
988
|
+
}
|
|
989
|
+
headers[name] = value;
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
return {
|
|
994
|
+
urlPattern: params.urlPattern,
|
|
995
|
+
action,
|
|
996
|
+
...(params.statusCode === undefined ? {} : { statusCode: params.statusCode }),
|
|
997
|
+
...(params.body === undefined ? {} : { body: params.body }),
|
|
998
|
+
...(headers === undefined ? {} : { headers }),
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
|
|
901
1002
|
/**
|
|
902
1003
|
* @param {PageTextParams} [params={}]
|
|
903
1004
|
* @returns {NormalizedPageTextParams}
|
|
@@ -926,7 +1027,7 @@ export function normalizeViewportResizeParams(params = {}) {
|
|
|
926
1027
|
return {
|
|
927
1028
|
width: clampInt(params.width, 320, 7680, DEFAULT_VIEWPORT_WIDTH),
|
|
928
1029
|
height: clampInt(params.height, 200, 4320, DEFAULT_VIEWPORT_HEIGHT),
|
|
929
|
-
deviceScaleFactor:
|
|
1030
|
+
deviceScaleFactor: clampNumber(params.deviceScaleFactor, 0, 4, DEFAULT_DEVICE_SCALE_FACTOR),
|
|
930
1031
|
reset: Boolean(params.reset),
|
|
931
1032
|
};
|
|
932
1033
|
}
|