@browserbridge/bbx 1.7.5 → 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.
@@ -433,8 +433,7 @@ export async function getDoctorReport(options = {}) {
433
433
  if (!response.ok) {
434
434
  throw new Error(response.error.message);
435
435
  }
436
- const result =
437
- /** @type {{ daemon?: string, extensionConnected?: boolean, access?: {
436
+ const result = /** @type {{ daemon?: string, extensionConnected?: boolean, access?: {
438
437
  enabled?: boolean,
439
438
  windowId?: number | null,
440
439
  routeTabId?: number | null,
@@ -60,7 +60,7 @@ export async function readBridgeAuthTokenOverride(options = {}) {
60
60
  }
61
61
 
62
62
  /**
63
- * @param {{ tokenPath?: string, readFile?: typeof fs.promises.readFile }} [options={}]
63
+ * @param {{ env?: NodeJS.ProcessEnv, tokenPath?: string, readFile?: typeof fs.promises.readFile }} [options={}]
64
64
  * @returns {Promise<string | null>}
65
65
  */
66
66
  export async function readBridgeAuthToken(options = {}) {
@@ -3,6 +3,7 @@
3
3
  import fs from 'node:fs';
4
4
  import os from 'node:os';
5
5
  import path from 'node:path';
6
+ import { createHash } from 'node:crypto';
6
7
 
7
8
  export const APP_NAME = 'com.browserbridge.browser_bridge';
8
9
  export const BRIDGE_HOME_ENV = 'BROWSER_BRIDGE_HOME';
@@ -62,15 +63,19 @@ export function getBridgeDir(env = process.env) {
62
63
  * connect to. On Windows we use a Named Pipe by default because Node's AF_UNIX
63
64
  * support fails with EACCES on listen() under recent Node + Windows 11
64
65
  * combinations, while Named Pipes are the historical and reliable Windows IPC
65
- * mechanism. An explicit bridge-home override keeps the legacy socket path so
66
- * callers can opt into custom test or compatibility setups.
66
+ * mechanism. Custom bridge homes use a stable suffix so isolated daemon and
67
+ * test setups do not contend for the default pipe.
67
68
  *
68
69
  * @param {NodeJS.ProcessEnv} [env=process.env]
69
70
  * @returns {string}
70
71
  */
71
72
  export function getSocketPath(env = process.env) {
72
- if (os.platform() === 'win32' && !env[BRIDGE_HOME_ENV]) {
73
- return `\\\\.\\pipe\\${APP_NAME}`;
73
+ if (os.platform() === 'win32') {
74
+ const bridgeHome = env[BRIDGE_HOME_ENV];
75
+ const suffix = bridgeHome
76
+ ? `-${createHash('sha256').update(bridgeHome.toLowerCase()).digest('hex').slice(0, 16)}`
77
+ : '';
78
+ return `\\\\.\\pipe\\${APP_NAME}${suffix}`;
74
79
  }
75
80
  return path.join(getBridgeDir(env), 'bridge.sock');
76
81
  }
@@ -407,10 +407,17 @@ async function restartBridgeDaemonAfterStop(stopResult, options = {}) {
407
407
  throw new Error('Timed out waiting for Browser Bridge daemon to start.');
408
408
  }
409
409
 
410
+ let pid = await readPidFn(pidPath);
411
+ if (pid === null) {
412
+ // The daemon starts listening immediately before it persists its PID.
413
+ await sleepFn(pollIntervalMs);
414
+ pid = await readPidFn(pidPath);
415
+ }
416
+
410
417
  return {
411
418
  ...stopResult,
412
419
  pidPath,
413
- pid: await readPidFn(pidPath),
420
+ pid,
414
421
  };
415
422
  }
416
423
 
@@ -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 const CAPABILITIES = Object.freeze({
7
- PAGE_READ: 'page.read',
8
- PAGE_EVALUATE: 'page.evaluate',
9
- DOM_READ: 'dom.read',
10
- STYLES_READ: 'styles.read',
11
- LAYOUT_READ: 'layout.read',
12
- VIEWPORT_CONTROL: 'viewport.control',
13
- NAVIGATION_CONTROL: 'navigation.control',
14
- SCREENSHOT_PARTIAL: 'screenshot.partial',
15
- PATCH_DOM: 'patch.dom',
16
- PATCH_STYLES: 'patch.styles',
17
- CDP_DOM_SNAPSHOT: 'cdp.dom_snapshot',
18
- CDP_BOX_MODEL: 'cdp.box_model',
19
- CDP_STYLES: 'cdp.styles',
20
- CDP_INPUT: 'cdp.input',
21
- AUTOMATION_INPUT: 'automation.input',
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
- export const DEFAULT_CAPABILITIES = Object.freeze([
29
- CAPABILITIES.PAGE_READ,
30
- CAPABILITIES.PAGE_EVALUATE,
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
- 'access.request': null,
53
- 'tabs.list': null,
54
- 'tabs.create': CAPABILITIES.TABS_MANAGE,
55
- 'tabs.close': CAPABILITIES.TABS_MANAGE,
56
- 'tabs.activate': CAPABILITIES.TABS_MANAGE,
57
- 'skill.get_runtime_context': null,
58
- 'setup.get_status': null,
59
- 'setup.install': null,
60
- 'page.get_state': CAPABILITIES.PAGE_READ,
61
- 'page.evaluate': CAPABILITIES.PAGE_EVALUATE,
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.
@@ -70,8 +72,8 @@ export const BUDGET_PRESETS = Object.freeze({
70
72
  deep: { maxNodes: 100, maxDepth: 8, textBudget: 2000, tokenBudget: 4000 },
71
73
  });
72
74
 
73
- /** @type {ReadonlySet<string>} */
74
- export const DEBUGGER_BACKED_METHODS = new Set([
75
+ /** @type {readonly import('./types.js').BridgeMethod[]} */
76
+ const LEGACY_DEBUGGER_BACKED_METHOD_ORDER = [
75
77
  'page.evaluate',
76
78
  'dom.get_accessibility_tree',
77
79
  'viewport.resize',
@@ -88,6 +90,19 @@ export const DEBUGGER_BACKED_METHODS = new Set([
88
90
  'cdp.get_box_model',
89
91
  'cdp.get_computed_styles_for_node',
90
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
+ ),
91
106
  ]);
92
107
 
93
108
  /**