@browserbridge/bbx 1.1.0 → 1.3.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 +6 -5
- package/package.json +1 -1
- package/packages/agent-client/src/cli.js +30 -20
- package/packages/agent-client/src/client.js +105 -42
- package/packages/agent-client/src/command-registry.js +4 -14
- package/packages/agent-client/src/detect.js +3 -3
- package/packages/agent-client/src/install.js +3 -7
- package/packages/agent-client/src/mcp-config.js +1 -3
- package/packages/agent-client/src/runtime.js +7 -41
- package/packages/agent-client/src/setup-status.js +3 -13
- package/packages/agent-client/src/types.ts +131 -0
- package/packages/mcp-server/src/handlers-capture.js +291 -0
- package/packages/mcp-server/src/handlers-dom.js +203 -0
- package/packages/mcp-server/src/handlers-navigation.js +79 -0
- package/packages/mcp-server/src/handlers-page.js +365 -0
- package/packages/mcp-server/src/handlers-utils.js +318 -0
- package/packages/mcp-server/src/handlers.js +59 -1176
- package/packages/mcp-server/src/server.js +2 -1
- package/packages/native-host/bin/bridge-daemon.js +2 -1
- package/packages/native-host/bin/install-manifest.js +8 -0
- package/packages/native-host/bin/postinstall.js +46 -9
- package/packages/native-host/src/daemon-logger.js +157 -0
- package/packages/native-host/src/daemon-process.js +43 -18
- package/packages/native-host/src/daemon.js +133 -12
- package/packages/native-host/src/framing.js +13 -0
- package/packages/native-host/src/native-host.js +7 -5
- package/packages/protocol/src/capabilities.js +1 -0
- package/packages/protocol/src/protocol.js +40 -0
- package/packages/protocol/src/registry.js +5 -9
- package/packages/protocol/src/types.ts +572 -0
- package/packages/protocol/src/types.js +0 -626
|
@@ -24,6 +24,19 @@ export async function writeNativeMessage(stream, message) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* @param {NodeJS.WritableStream} stream
|
|
29
|
+
* @returns {(message: unknown) => Promise<void>}
|
|
30
|
+
*/
|
|
31
|
+
export function createNativeMessageWriter(stream) {
|
|
32
|
+
let queue = Promise.resolve();
|
|
33
|
+
return (message) => {
|
|
34
|
+
const writePromise = queue.then(() => writeNativeMessage(stream, message));
|
|
35
|
+
queue = writePromise.catch(() => {});
|
|
36
|
+
return writePromise;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
27
40
|
/**
|
|
28
41
|
* @param {NodeJS.ReadableStream} stream
|
|
29
42
|
* @param {(message: unknown) => void} onMessage
|
|
@@ -5,7 +5,7 @@ import net from 'node:net';
|
|
|
5
5
|
import { createFailure, ERROR_CODES } from '../../protocol/src/index.js';
|
|
6
6
|
import { createSocketBridgeTransport, getBridgeTransport } from './config.js';
|
|
7
7
|
import { spawnBridgeDaemonProcess } from './daemon-process.js';
|
|
8
|
-
import { createNativeMessageReader,
|
|
8
|
+
import { createNativeMessageReader, createNativeMessageWriter, writeJsonLine } from './framing.js';
|
|
9
9
|
|
|
10
10
|
/** @typedef {import('./config.js').BridgeTransport} BridgeTransport */
|
|
11
11
|
|
|
@@ -117,11 +117,13 @@ export async function runNativeHost({
|
|
|
117
117
|
socketPath = undefined,
|
|
118
118
|
} = {}) {
|
|
119
119
|
const resolvedTransport = socketPath ? createSocketBridgeTransport(socketPath) : transport;
|
|
120
|
+
const writeNativeMessageQueued = createNativeMessageWriter(process.stdout);
|
|
121
|
+
|
|
120
122
|
let socket;
|
|
121
123
|
try {
|
|
122
124
|
socket = await connectWithBootstrap(resolvedTransport);
|
|
123
125
|
} catch (error) {
|
|
124
|
-
await
|
|
126
|
+
await writeNativeMessageQueued({
|
|
125
127
|
type: 'agent.response',
|
|
126
128
|
response: createFailure(
|
|
127
129
|
'native_bootstrap',
|
|
@@ -164,11 +166,11 @@ export async function runNativeHost({
|
|
|
164
166
|
}
|
|
165
167
|
void (async () => {
|
|
166
168
|
if (message.type === 'extension.request') {
|
|
167
|
-
await
|
|
169
|
+
await writeNativeMessageQueued(message.request);
|
|
168
170
|
return;
|
|
169
171
|
}
|
|
170
172
|
if (message.type === 'agent.response') {
|
|
171
|
-
await
|
|
173
|
+
await writeNativeMessageQueued({
|
|
172
174
|
type: 'host.bridge_response',
|
|
173
175
|
response: message.response,
|
|
174
176
|
});
|
|
@@ -178,7 +180,7 @@ export async function runNativeHost({
|
|
|
178
180
|
message.type === 'extension.setup_status.response' ||
|
|
179
181
|
message.type === 'extension.setup_status.error'
|
|
180
182
|
) {
|
|
181
|
-
await
|
|
183
|
+
await writeNativeMessageQueued({
|
|
182
184
|
type:
|
|
183
185
|
message.type === 'extension.setup_status.response'
|
|
184
186
|
? 'host.setup_status.response'
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
DEFAULT_A11Y_MAX_NODES,
|
|
8
8
|
DEFAULT_CONSOLE_LIMIT,
|
|
9
9
|
DEFAULT_EVAL_TIMEOUT_MS,
|
|
10
|
+
DEFAULT_LOG_TAIL_LIMIT,
|
|
10
11
|
DEFAULT_MAX_DEPTH,
|
|
11
12
|
DEFAULT_MAX_HTML_LENGTH,
|
|
12
13
|
DEFAULT_MAX_NODES,
|
|
@@ -29,6 +30,7 @@ import { BRIDGE_METHODS, METHOD_SET, createBridgeMethodGroups } from './registry
|
|
|
29
30
|
/** @typedef {import('./types.js').BridgeSuccessResponse} BridgeSuccessResponse */
|
|
30
31
|
/** @typedef {import('./types.js').CheckedActionParams} CheckedActionParams */
|
|
31
32
|
/** @typedef {import('./types.js').CdpDispatchKeyEventParams} CdpDispatchKeyEventParams */
|
|
33
|
+
/** @typedef {import('./types.js').CdpNodeIdParams} CdpNodeIdParams */
|
|
32
34
|
/** @typedef {import('./types.js').ConsoleParams} ConsoleParams */
|
|
33
35
|
/** @typedef {import('./types.js').DomQueryParams} DomQueryParams */
|
|
34
36
|
/** @typedef {import('./types.js').DragParams} DragParams */
|
|
@@ -38,11 +40,13 @@ import { BRIDGE_METHODS, METHOD_SET, createBridgeMethodGroups } from './registry
|
|
|
38
40
|
/** @typedef {import('./types.js').GetHtmlParams} GetHtmlParams */
|
|
39
41
|
/** @typedef {import('./types.js').HoverParams} HoverParams */
|
|
40
42
|
/** @typedef {import('./types.js').InputActionParams} InputActionParams */
|
|
43
|
+
/** @typedef {import('./types.js').LogTailParams} LogTailParams */
|
|
41
44
|
/** @typedef {import('./types.js').NavigationActionParams} NavigationActionParams */
|
|
42
45
|
/** @typedef {import('./types.js').NetworkParams} NetworkParams */
|
|
43
46
|
/** @typedef {import('./types.js').NormalizedAccessibilityTreeParams} NormalizedAccessibilityTreeParams */
|
|
44
47
|
/** @typedef {import('./types.js').NormalizedCheckedAction} NormalizedCheckedAction */
|
|
45
48
|
/** @typedef {import('./types.js').NormalizedCdpDispatchKeyEventParams} NormalizedCdpDispatchKeyEventParams */
|
|
49
|
+
/** @typedef {import('./types.js').NormalizedCdpNodeIdParams} NormalizedCdpNodeIdParams */
|
|
46
50
|
/** @typedef {import('./types.js').NormalizedConsoleParams} NormalizedConsoleParams */
|
|
47
51
|
/** @typedef {import('./types.js').NormalizedDomQuery} NormalizedDomQuery */
|
|
48
52
|
/** @typedef {import('./types.js').NormalizedDragParams} NormalizedDragParams */
|
|
@@ -52,6 +56,7 @@ import { BRIDGE_METHODS, METHOD_SET, createBridgeMethodGroups } from './registry
|
|
|
52
56
|
/** @typedef {import('./types.js').NormalizedGetHtmlParams} NormalizedGetHtmlParams */
|
|
53
57
|
/** @typedef {import('./types.js').NormalizedHoverParams} NormalizedHoverParams */
|
|
54
58
|
/** @typedef {import('./types.js').NormalizedInputAction} NormalizedInputAction */
|
|
59
|
+
/** @typedef {import('./types.js').NormalizedLogTailParams} NormalizedLogTailParams */
|
|
55
60
|
/** @typedef {import('./types.js').NormalizedNavigationAction} NormalizedNavigationAction */
|
|
56
61
|
/** @typedef {import('./types.js').NormalizedNetworkParams} NormalizedNetworkParams */
|
|
57
62
|
/** @typedef {import('./types.js').NormalizedPageTextParams} NormalizedPageTextParams */
|
|
@@ -209,6 +214,12 @@ export function validateBridgeRequest(request) {
|
|
|
209
214
|
'session_id is no longer supported. Use tab_id or window-scoped default routing.'
|
|
210
215
|
);
|
|
211
216
|
}
|
|
217
|
+
if (
|
|
218
|
+
candidate.params != null &&
|
|
219
|
+
(typeof candidate.params !== 'object' || Array.isArray(candidate.params))
|
|
220
|
+
) {
|
|
221
|
+
throw new BridgeError(ERROR_CODES.INVALID_REQUEST, 'Request params must be an object.');
|
|
222
|
+
}
|
|
212
223
|
const parsedTabId = Number(candidate.tab_id);
|
|
213
224
|
|
|
214
225
|
const method = /** @type {BridgeMethod} */ (candidate.method);
|
|
@@ -242,6 +253,8 @@ export function validateBridgeRequest(request) {
|
|
|
242
253
|
*/
|
|
243
254
|
function normalizeRequestParams(method, params) {
|
|
244
255
|
switch (method) {
|
|
256
|
+
case 'log.tail':
|
|
257
|
+
return normalizeLogTailParams(params);
|
|
245
258
|
case 'dom.query':
|
|
246
259
|
return normalizeDomQuery(params);
|
|
247
260
|
case 'page.evaluate':
|
|
@@ -285,6 +298,9 @@ function normalizeRequestParams(method, params) {
|
|
|
285
298
|
return normalizeInputAction(params);
|
|
286
299
|
case 'cdp.dispatch_key_event':
|
|
287
300
|
return normalizeCdpDispatchKeyEventParams(params);
|
|
301
|
+
case 'cdp.get_box_model':
|
|
302
|
+
case 'cdp.get_computed_styles_for_node':
|
|
303
|
+
return normalizeCdpNodeIdParams(params);
|
|
288
304
|
case 'input.set_checked':
|
|
289
305
|
return normalizeCheckedAction(params);
|
|
290
306
|
case 'input.select_option':
|
|
@@ -429,6 +445,20 @@ export function normalizeCdpDispatchKeyEventParams(params = {}) {
|
|
|
429
445
|
};
|
|
430
446
|
}
|
|
431
447
|
|
|
448
|
+
/**
|
|
449
|
+
* @param {CdpNodeIdParams} [params={}]
|
|
450
|
+
* @returns {NormalizedCdpNodeIdParams}
|
|
451
|
+
*/
|
|
452
|
+
export function normalizeCdpNodeIdParams(params = {}) {
|
|
453
|
+
if (typeof params.nodeId !== 'number' || !Number.isFinite(params.nodeId)) {
|
|
454
|
+
throw new BridgeError(ERROR_CODES.INVALID_REQUEST, 'nodeId must be a finite number.');
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
return {
|
|
458
|
+
nodeId: params.nodeId,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
|
|
432
462
|
/**
|
|
433
463
|
* @param {CheckedActionParams} [params={}]
|
|
434
464
|
* @returns {NormalizedCheckedAction}
|
|
@@ -763,6 +793,16 @@ export function normalizePageTextParams(params = {}) {
|
|
|
763
793
|
};
|
|
764
794
|
}
|
|
765
795
|
|
|
796
|
+
/**
|
|
797
|
+
* @param {LogTailParams} [params={}]
|
|
798
|
+
* @returns {NormalizedLogTailParams}
|
|
799
|
+
*/
|
|
800
|
+
export function normalizeLogTailParams(params = {}) {
|
|
801
|
+
return {
|
|
802
|
+
limit: clampInt(params.limit, 1, 200, DEFAULT_LOG_TAIL_LIMIT),
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
|
|
766
806
|
/**
|
|
767
807
|
* @param {ViewportResizeParams} [params={}]
|
|
768
808
|
* @returns {NormalizedViewportResizeParams}
|
|
@@ -82,6 +82,7 @@ const BRIDGE_METHOD_DESCRIPTIONS = Object.freeze({
|
|
|
82
82
|
'performance.get_metrics': 'Read browser performance metrics.',
|
|
83
83
|
'log.tail': 'Tail recent bridge log entries.',
|
|
84
84
|
'health.ping': 'Check daemon, extension, and access-routing health.',
|
|
85
|
+
'daemon.metrics': 'Daemon health and performance metrics.',
|
|
85
86
|
});
|
|
86
87
|
|
|
87
88
|
/**
|
|
@@ -122,8 +123,9 @@ export const BRIDGE_METHOD_REGISTRY = Object.freeze({
|
|
|
122
123
|
['kind', 'target'],
|
|
123
124
|
'trivial'
|
|
124
125
|
),
|
|
125
|
-
'log.tail': createRegistryEntry('log.tail', 'system', false, [], 'trivial'),
|
|
126
|
+
'log.tail': createRegistryEntry('log.tail', 'system', false, ['limit'], 'trivial'),
|
|
126
127
|
'health.ping': createRegistryEntry('health.ping', 'system', false, [], 'trivial'),
|
|
128
|
+
'daemon.metrics': createRegistryEntry('daemon.metrics', 'system', false, [], 'trivial'),
|
|
127
129
|
// tabs — trivial
|
|
128
130
|
'tabs.list': createRegistryEntry('tabs.list', 'tabs', false, [], 'trivial'),
|
|
129
131
|
'tabs.create': createRegistryEntry('tabs.create', 'tabs', false, ['url', 'active'], 'trivial'),
|
|
@@ -411,18 +413,12 @@ export const BRIDGE_METHOD_REGISTRY = Object.freeze({
|
|
|
411
413
|
// cdp — high (raw protocol, large payloads)
|
|
412
414
|
'cdp.get_document': createRegistryEntry('cdp.get_document', 'cdp', true, [], 'high'),
|
|
413
415
|
'cdp.get_dom_snapshot': createRegistryEntry('cdp.get_dom_snapshot', 'cdp', true, [], 'high'),
|
|
414
|
-
'cdp.get_box_model': createRegistryEntry(
|
|
415
|
-
'cdp.get_box_model',
|
|
416
|
-
'cdp',
|
|
417
|
-
true,
|
|
418
|
-
['elementRef'],
|
|
419
|
-
'high'
|
|
420
|
-
),
|
|
416
|
+
'cdp.get_box_model': createRegistryEntry('cdp.get_box_model', 'cdp', true, ['nodeId'], 'high'),
|
|
421
417
|
'cdp.get_computed_styles_for_node': createRegistryEntry(
|
|
422
418
|
'cdp.get_computed_styles_for_node',
|
|
423
419
|
'cdp',
|
|
424
420
|
true,
|
|
425
|
-
['
|
|
421
|
+
['nodeId'],
|
|
426
422
|
'high'
|
|
427
423
|
),
|
|
428
424
|
'cdp.dispatch_key_event': createRegistryEntry(
|