🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@mtop-devtools/client

Package Overview
Dependencies
Maintainers
2
Versions
39
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@mtop-devtools/client - npm Package Compare versions

Comparing version
1.40.0
to
1.40.1
+1
-1
dist/browserRegistry.d.ts

@@ -27,3 +27,3 @@ /**

* left to the native-hosts (they overwrite their own record on reconnect and
* reconcile on browser_list_browsers). Otherwise many concurrent clients pruning at once
* reconcile when serving browser_list). Otherwise many concurrent clients pruning at once
* could, in a narrow window, delete a record a browser just re-published on

@@ -30,0 +30,0 @@ * reconnect — making a live browser briefly vanish from the registry.

@@ -32,3 +32,3 @@ /**

* left to the native-hosts (they overwrite their own record on reconnect and
* reconcile on browser_list_browsers). Otherwise many concurrent clients pruning at once
* reconcile when serving browser_list). Otherwise many concurrent clients pruning at once
* could, in a narrow window, delete a record a browser just re-published on

@@ -35,0 +35,0 @@ * reconnect — making a live browser briefly vanish from the registry.

@@ -16,3 +16,2 @@ #!/usr/bin/env node

import { invoke, CLIENT_VERSION } from './socket.js';
import { listLiveBrowsers, findBrowser, describeBrowser } from './browserRegistry.js';
import { COMMAND_MAP } from './commands.js';

@@ -51,4 +50,4 @@ import { runCheck } from './check.js';

{
title: '托管浏览器',
names: ['browser_launch', 'browser_list_managed', 'browser_close'],
title: '浏览器',
names: ['browser_list', 'browser_launch', 'browser_close'],
},

@@ -79,3 +78,2 @@ ];

' check 检测环境配置,排查连接问题',
' browsers 列出当前已连接的浏览器(多浏览器寻址)',
];

@@ -248,29 +246,2 @@ for (const cat of CATEGORIES) {

}
function runBrowsers() {
const browsers = listLiveBrowsers();
if (browsers.length === 0) {
console.error('当前没有已连接的浏览器。');
console.error('确认浏览器已安装 Mtop DevTools 插件并打开过面板,或已运行 CDP daemon。');
console.error('若插件已安装且面板已打开,多半是 native-host 过旧(浏览器列表由 native-host 发布):');
console.error(' npm install -g @mtop-devtools/native-host@latest 然后重新打开面板');
return;
}
// Default target mirrors socket.ts resolution: explicit env selector wins,
// otherwise the most-recently-focused browser (index 0).
const envSelector = process.env.MTOP_DEVTOOLS_BROWSER;
const defaultTarget = envSelector
? (findBrowser(browsers, envSelector) ?? browsers[0])
: browsers[0];
console.error(`已连接 ${browsers.length} 个浏览器(默认目标标 ★):\n`);
for (const b of browsers) {
const marker = b.browserId === defaultTarget.browserId ? '★' : ' ';
const via = b.transport === 'cdp' ? ' [CDP]' : '';
const ext = b.extensionVersion ? ` ext v${b.extensionVersion}` : '';
console.error(` ${marker} ${describeBrowser(b)}${via}${ext}`);
console.error(` id: ${b.browserId}`);
console.error(` socket: ${b.socketPath}`);
}
console.error('\n用 `mtop-devtools <action> --browser <id|名称>` 指定目标;');
console.error('或设置环境变量 MTOP_DEVTOOLS_BROWSER 固定默认目标。');
}
async function main() {

@@ -282,6 +253,2 @@ // Handle built-in subcommands before normal arg parsing

}
if (process.argv[2] === 'browsers') {
runBrowsers();
return;
}
let args;

@@ -288,0 +255,0 @@ try {

@@ -17,3 +17,3 @@ export interface ParamDef {

export declare const COMMANDS: CommandDef[];
export type KnownAction = 'get_requests' | 'get_logs' | 'get_events' | 'get_api_schema' | 'set_mock' | 'get_mocks' | 'add_rule' | 'proxy_request' | 'send_mtop_request' | 'tab_open' | 'tab_close' | 'tab_list' | 'page_click' | 'page_type' | 'page_hover' | 'page_scroll' | 'page_eval' | 'page_press' | 'page_wait' | 'page_navigate' | 'page_upload' | 'page_snapshot' | 'get_screenshot' | 'get_selected_element' | 'page_frames' | 'set_device_emulation' | 'set_timezone' | 'record_start' | 'record_stop' | 'record_get' | 'request_domain_permission' | 'get_user_info' | 'page_act' | 'run_actions';
export type KnownAction = 'get_requests' | 'get_logs' | 'get_events' | 'get_api_schema' | 'set_mock' | 'get_mocks' | 'add_rule' | 'proxy_request' | 'send_mtop_request' | 'tab_open' | 'tab_close' | 'tab_list' | 'page_click' | 'page_type' | 'page_hover' | 'page_scroll' | 'page_eval' | 'page_press' | 'page_wait' | 'page_navigate' | 'page_upload' | 'page_snapshot' | 'get_screenshot' | 'get_selected_element' | 'page_frames' | 'set_device_emulation' | 'set_timezone' | 'record_start' | 'record_stop' | 'record_get' | 'request_domain_permission' | 'get_user_info' | 'browser_list' | 'browser_launch' | 'browser_close' | 'page_act' | 'run_actions';
export declare const COMMAND_MAP: Map<string, CommandDef>;

@@ -149,4 +149,9 @@ export const COMMANDS = [

},
// ── 托管浏览器 ────────────────────────────────────────────────────────────
// ── 浏览器 ────────────────────────────────────────────────────────────────
{
name: 'browser_list',
description: '列出所有浏览器及其连接状态、类型和托管实例信息',
examples: ['browser_list'],
},
{
name: 'browser_launch',

@@ -190,7 +195,2 @@ description: '启动独立 Chrome,可在新实例中通过 TDBank 登录指定账号',

{
name: 'browser_list_managed',
description: '列出由 Mtop DevTools 启动的托管浏览器',
examples: ['browser_list_managed'],
},
{
name: 'browser_close',

@@ -197,0 +197,0 @@ description: '关闭指定托管浏览器并按策略清理独立 Profile',

@@ -105,16 +105,40 @@ /**

export declare function tdbankAccount(params?: TdbankAccountParams): Promise<any>;
export interface BrowserInfo {
export type BrowserStatus = 'connected' | 'running_disconnected' | 'stopped';
export interface BrowserInfoBase {
browserId: string;
name: string;
status: BrowserStatus;
extensionVersion?: string;
nativeHostVersion?: string;
transport?: 'extension' | 'cdp';
isDefaultTarget: boolean;
}
export interface ListBrowsersResult {
export interface RegularBrowserInfo extends BrowserInfoBase {
type: 'regular';
status: 'connected';
}
export interface ManagedBrowserAccount {
accountId?: string;
loginId?: string;
nickname: string;
}
export interface ManagedBrowserInfo extends BrowserInfoBase {
type: 'managed';
headless: boolean;
persistent: boolean;
cdpPort: number;
createdAt: string;
account?: ManagedBrowserAccount;
copiedCookies?: {
domains: string[];
count: number;
};
}
export type BrowserInfo = RegularBrowserInfo | ManagedBrowserInfo;
export interface BrowserListResult {
count: number;
default: string;
connectedCount: number;
defaultBrowserId: string | null;
browsers: BrowserInfo[];
}
export declare function listBrowsers(): Promise<ListBrowsersResult>;
export declare function browserList(): Promise<BrowserListResult>;
export interface SelectBrowserParams {

@@ -145,3 +169,2 @@ browser?: string;

export declare function browserLaunch(params: BrowserLaunchParams): Promise<any>;
export declare function browserListManaged(): Promise<any>;
export interface BrowserCloseParams {

@@ -148,0 +171,0 @@ browser: string;

@@ -47,4 +47,4 @@ /**

}
export function listBrowsers() {
return invoke('browser_list_browsers', {});
export function browserList() {
return invoke('browser_list', {});
}

@@ -57,5 +57,2 @@ export function selectBrowser(params = {}) {

}
export function browserListManaged() {
return invoke('browser_list_managed', {});
}
export function browserClose(params) {

@@ -62,0 +59,0 @@ return invoke('browser_close', params);

@@ -27,2 +27,3 @@ /**

export declare function getDefaultBrowser(): string | undefined;
export declare function decorateBrowserListResult(result: Record<string, any>): Record<string, any>;
/**

@@ -29,0 +30,0 @@ * 向 native host 发送一个 action 请求并等待响应。

@@ -39,16 +39,20 @@ /**

}
function listBrowsersResult() {
const browsers = listLiveBrowsers();
const current = getDefaultBrowser();
function findConnectedBrowser(items, selector) {
const normalized = selector.trim().toLowerCase();
const connected = items.filter(item => item.status === 'connected');
return (connected.find(item => String(item.browserId).toLowerCase() === normalized) ??
connected.find(item => String(item.name).toLowerCase() === normalized) ??
connected.find(item => String(item.browserId).toLowerCase().includes(normalized) ||
String(item.name).toLowerCase().includes(normalized)) ??
null);
}
export function decorateBrowserListResult(result) {
const browsers = Array.isArray(result?.browsers) ? result.browsers : [];
const selector = getDefaultBrowser() ?? process.env.MTOP_DEVTOOLS_BROWSER;
const selected = selector
? findConnectedBrowser(browsers, selector)
: (browsers.find(browser => browser.status === 'connected') ?? null);
return {
count: browsers.length,
default: current ?? '(auto: most-recently focused browser)',
browsers: browsers.map((browser, index) => ({
browserId: browser.browserId,
name: browser.browserName,
extensionVersion: browser.extensionVersion,
nativeHostVersion: browser.nativeHostVersion,
transport: browser.transport,
isDefaultTarget: current ? browser.browserId === current : index === 0,
})),
...result,
defaultBrowserId: selected?.browserId ?? null,
};

@@ -72,16 +76,19 @@ }

}
/** Whether we have already attempted to auto-spawn native-host in this process. */
/** Whether this process has already attempted to auto-spawn a persistent native-host. */
let spawnAttempted = false;
/**
* Attempt to spawn `mtop-devtools-native-host` in the background (detached).
* Inventory-only hosts serve one browser_list request without publishing a fake CDP target.
* Returns true if a spawn was attempted (regardless of success).
*/
async function trySpawnNativeHost() {
if (spawnAttempted)
async function trySpawnNativeHost(registerBrowser = true) {
if (registerBrowser && spawnAttempted)
return false;
spawnAttempted = true;
if (registerBrowser)
spawnAttempted = true;
try {
const { spawn } = await import('node:child_process');
return await new Promise(resolve => {
const child = spawn('mtop-devtools-native-host', ['--daemon'], {
const args = registerBrowser ? ['--daemon'] : ['--daemon', '--skip-browser-registration'];
const child = spawn('mtop-devtools-native-host', args, {
detached: true,

@@ -118,4 +125,2 @@ stdio: 'ignore',

export function invoke(action, data = {}, options = {}) {
if (action === 'browser_list_browsers')
return Promise.resolve(listBrowsersResult());
if (action === 'browser_select_browser') {

@@ -132,2 +137,5 @@ try {

const resolvedData = resolveFileRefs(data);
if (action === 'browser_list') {
return dispatchInvoke(action, resolvedData, timeoutSec, undefined, undefined).then(decorateBrowserListResult);
}
const selector = browser ?? defaultBrowser ?? process.env.MTOP_DEVTOOLS_BROWSER ?? undefined;

@@ -181,5 +189,5 @@ return dispatchInvoke(action, resolvedData, timeoutSec, transport, selector);

if (err.code === 'ENOENT' && !isRetry) {
const spawned = await trySpawnNativeHost();
const spawned = await trySpawnNativeHost(action !== 'browser_list');
if (spawned) {
// Wait for the native host to start listening and register itself.
// Wait for the native host to start listening; persistent hosts also publish their registry record.
await new Promise(r => setTimeout(r, 1200));

@@ -301,4 +309,4 @@ const browsers = listLiveBrowsers();

'',
'用 `mtop-devtools browsers` 查看完整列表;可用 browserId 或名称匹配。',
'用 `mtop-devtools browser_list` 查看完整列表;可用 browserId 或名称匹配。',
].join('\n');
}
{
"name": "@mtop-devtools/client",
"version": "1.40.0",
"version": "1.40.1",
"description": "Client SDK & CLI for Mtop DevTools — communicate with Chrome Extension via Unix Socket",

@@ -5,0 +5,0 @@ "type": "module",

@@ -59,3 +59,3 @@ # @mtop-devtools/client

mtop-devtools browser_launch --payload '{"name":"cookie-copy","copyCookieDomains":["example.com"]}'
mtop-devtools browsers
mtop-devtools browser_list
```

@@ -87,3 +87,3 @@

| TDBank | `tdbank_account` |
| 托管浏览器 | `browser_launch` `browser_list_managed` `browser_close` |
| 浏览器 | `browser_list` `browser_launch` `browser_close` |

@@ -94,2 +94,4 @@ `page_act` 将一次点击、输入、滚动等动作与动作后的异步稳定判断合并为一个调用。它不替代完整页面理解:`mode: "delta"` 只返回主文档中的 `effects.notifications`、`effects.interactives` 和 `effects.focus` 等高置信度信号,并明确携带 `scope: "main-document"`;`mode: "navigation"` 且 `ready: true` 时,页面已通过网络静默、骨架状态或保守的内容稳定判定,可在新页面重建快照。仅在 `fullSnapshotRecommended` 为 true 时根据 `snapshotReasons` 回退到完整快照或截图。

`browser_list` 统一列出普通浏览器和托管浏览器。`type` 区分 `regular` / `managed`,`status` 区分 `connected` / `running_disconnected` / `stopped`;只有 `connected` 的浏览器可作为操作目标。
托管浏览器使用独立 Profile 和动态 CDP 端口。控制浏览器需先登录 TDBank;生成的 SSO 地址在本地内部传递,新实例可以使用 `headless: true`(默认)完成测试账号登录。`copyCookieDomains` 可把控制浏览器指定域的 Cookie 复制到新实例,Cookie 值不会出现在命令结果或日志中。完整设计见 [托管浏览器与 TDBank 多账号设计](../../docs/managed-browsers.md)。

@@ -96,0 +98,0 @@