@midscene/web 1.9.8 → 1.10.1-beta-20260624112700.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/dist/es/{mcp-agent-init-args.mjs → agent-init-args.mjs} +2 -2
- package/dist/es/{mcp-agent-init-args.mjs.map → agent-init-args.mjs.map} +1 -1
- package/dist/es/{mcp-tools-cdp.mjs → agent-tools-cdp.mjs} +5 -5
- package/dist/es/agent-tools-cdp.mjs.map +1 -0
- package/dist/es/{mcp-tools-puppeteer.mjs → agent-tools-puppeteer.mjs} +7 -7
- package/dist/es/agent-tools-puppeteer.mjs.map +1 -0
- package/dist/es/{mcp-tools.mjs → agent-tools.mjs} +4 -4
- package/dist/es/agent-tools.mjs.map +1 -0
- package/dist/es/bridge-mode/io-client.mjs +1 -1
- package/dist/es/bridge-mode/io-server.mjs +2 -2
- package/dist/es/bridge-mode/io-server.mjs.map +1 -1
- package/dist/es/bridge-mode/page-browser-side.mjs +1 -1
- package/dist/es/bridge-mode/page-browser-side.mjs.map +1 -1
- package/dist/es/cdp-proxy-constants.mjs.map +1 -1
- package/dist/es/cdp-proxy-manager.mjs +1 -1
- package/dist/es/cdp-proxy-manager.mjs.map +1 -1
- package/dist/es/cdp-proxy.mjs.map +1 -1
- package/dist/es/cdp-target-store.mjs +1 -1
- package/dist/es/cdp-target-store.mjs.map +1 -1
- package/dist/es/cli.mjs +4 -4
- package/dist/es/cli.mjs.map +1 -1
- package/dist/es/index.mjs +2 -2
- package/dist/es/playwright/index.mjs +5 -3
- package/dist/es/playwright/index.mjs.map +1 -1
- package/dist/es/puppeteer/base-page.mjs +43 -44
- package/dist/es/puppeteer/base-page.mjs.map +1 -1
- package/dist/es/puppeteer/index.mjs +5 -3
- package/dist/es/puppeteer/index.mjs.map +1 -1
- package/dist/es/static/static-page.mjs +8 -3
- package/dist/es/static/static-page.mjs.map +1 -1
- package/dist/es/web-element.mjs.map +1 -1
- package/dist/lib/{mcp-agent-init-args.js → agent-init-args.js} +2 -2
- package/dist/lib/{mcp-agent-init-args.js.map → agent-init-args.js.map} +1 -1
- package/dist/lib/{mcp-tools-cdp.js → agent-tools-cdp.js} +7 -7
- package/dist/lib/agent-tools-cdp.js.map +1 -0
- package/dist/lib/{mcp-tools-puppeteer.js → agent-tools-puppeteer.js} +9 -9
- package/dist/lib/agent-tools-puppeteer.js.map +1 -0
- package/dist/lib/{mcp-tools.js → agent-tools.js} +6 -6
- package/dist/lib/agent-tools.js.map +1 -0
- package/dist/lib/bridge-mode/io-client.js +1 -1
- package/dist/lib/bridge-mode/io-server.js +2 -2
- package/dist/lib/bridge-mode/io-server.js.map +1 -1
- package/dist/lib/bridge-mode/page-browser-side.js +1 -1
- package/dist/lib/bridge-mode/page-browser-side.js.map +1 -1
- package/dist/lib/cdp-proxy-constants.js.map +1 -1
- package/dist/lib/cdp-proxy-manager.js +1 -1
- package/dist/lib/cdp-proxy-manager.js.map +1 -1
- package/dist/lib/cdp-proxy.js.map +1 -1
- package/dist/lib/cdp-target-store.js +1 -1
- package/dist/lib/cdp-target-store.js.map +1 -1
- package/dist/lib/cli.js +5 -5
- package/dist/lib/cli.js.map +1 -1
- package/dist/lib/index.js +4 -4
- package/dist/lib/playwright/index.js +5 -3
- package/dist/lib/playwright/index.js.map +1 -1
- package/dist/lib/puppeteer/base-page.js +43 -44
- package/dist/lib/puppeteer/base-page.js.map +1 -1
- package/dist/lib/puppeteer/index.js +5 -3
- package/dist/lib/puppeteer/index.js.map +1 -1
- package/dist/lib/static/static-page.js +8 -3
- package/dist/lib/static/static-page.js.map +1 -1
- package/dist/lib/web-element.js.map +1 -1
- package/dist/types/{mcp-agent-init-args.d.ts → agent-init-args.d.ts} +1 -1
- package/dist/types/{mcp-tools-cdp.d.ts → agent-tools-cdp.d.ts} +4 -4
- package/dist/types/{mcp-tools-puppeteer.d.ts → agent-tools-puppeteer.d.ts} +4 -4
- package/dist/types/{mcp-tools.d.ts → agent-tools.d.ts} +4 -4
- package/dist/types/cdp-proxy-manager.d.ts +1 -1
- package/dist/types/cdp-proxy.d.ts +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/puppeteer/base-page.d.ts +2 -9
- package/dist/types/static/static-page.d.ts +9 -2
- package/dist/types/web-element.d.ts +3 -0
- package/package.json +4 -9
- package/dist/es/mcp-server.mjs +0 -35
- package/dist/es/mcp-server.mjs.map +0 -1
- package/dist/es/mcp-tools-cdp.mjs.map +0 -1
- package/dist/es/mcp-tools-puppeteer.mjs.map +0 -1
- package/dist/es/mcp-tools.mjs.map +0 -1
- package/dist/lib/mcp-server.js +0 -75
- package/dist/lib/mcp-server.js.map +0 -1
- package/dist/lib/mcp-tools-cdp.js.map +0 -1
- package/dist/lib/mcp-tools-puppeteer.js.map +0 -1
- package/dist/lib/mcp-tools.js.map +0 -1
- package/dist/types/mcp-server.d.ts +0 -26
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cdp-proxy.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","../../src/cdp-proxy.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","/**\n * CDP WebSocket Proxy — standalone process.\n *\n * Holds a persistent WebSocket connection to Chrome's CDP endpoint and\n * exposes a local WebSocket server. Midscene CLI processes connect to the\n * proxy instead of Chrome directly, so Chrome's \"Allow remote debugging\"\n * permission popup only fires once (when the proxy connects).\n *\n * Lifecycle notes:\n * - When all downstream clients disconnect the proxy stays running but\n * marks the upstream as needing reconnection. The actual reconnect is\n * deferred to the moment the next client connects, so Chrome's CDP\n * state (notably Target.setDiscoverTargets) is reset and the new\n * client receives all targetCreated events.\n * - On startup, if another proxy is already alive the new instance\n * announces \"duplicate proxy detected\" on stderr and exits 0 without\n * touching the existing metadata files.\n *\n * Exit conditions:\n * 1. Upstream Chrome connection closes or errors.\n * 2. No downstream client message for IDLE_TIMEOUT_MS (default 5 min).\n * 3. SIGTERM / SIGINT.\n * 4. Duplicate proxy detected on startup (exits 0 with stderr notice).\n *\n * Usage (spawned by mcp-tools-cdp.ts):\n * node cdp-proxy.js <chrome-ws-endpoint>\n *\n * On startup, prints the proxy endpoint to stdout as a single JSON line:\n * {\"endpoint\":\"ws://127.0.0.1:<port>/devtools/browser\"}\n * and writes:\n * - PROXY_ENDPOINT_FILE — the local proxy URL above\n * - PROXY_PID_FILE — this process's pid\n * - PROXY_UPSTREAM_FILE — the Chrome endpoint the proxy is connected to,\n * so callers can detect when the requested\n * upstream has changed and replace the proxy.\n */\n\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { createServer } from 'node:http';\nimport WebSocket, { WebSocketServer } from 'ws';\nimport {\n PROXY_ENDPOINT_FILE,\n PROXY_PID_FILE,\n PROXY_UPSTREAM_FILE,\n} from './cdp-proxy-constants';\n\n// ---------------------------------------------------------------------------\n// Config\n// ---------------------------------------------------------------------------\n\nconst IDLE_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\n\nconst chromeEndpoint = process.argv[2];\nif (!chromeEndpoint) {\n process.stderr.write('Usage: node cdp-proxy.js <chrome-ws-endpoint>\\n');\n process.exit(1);\n}\n\n// ---------------------------------------------------------------------------\n// Cleanup\n// ---------------------------------------------------------------------------\n\nfunction cleanupIfOwned() {\n // Only clean up if the PID file exists and records *our* PID.\n // If the file is missing (e.g. already deleted by killProxy()) or\n // unreadable, skip cleanup — another process may have taken over.\n try {\n if (!existsSync(PROXY_PID_FILE)) return;\n const pid = Number(readFileSync(PROXY_PID_FILE, 'utf-8').trim());\n if (pid !== process.pid) return;\n } catch {\n return;\n }\n try {\n if (existsSync(PROXY_ENDPOINT_FILE)) unlinkSync(PROXY_ENDPOINT_FILE);\n } catch {}\n try {\n if (existsSync(PROXY_PID_FILE)) unlinkSync(PROXY_PID_FILE);\n } catch {}\n try {\n if (existsSync(PROXY_UPSTREAM_FILE)) unlinkSync(PROXY_UPSTREAM_FILE);\n } catch {}\n}\n\n/**\n * Maximum time to wait for the stderr drain callback before forcing exit.\n * The callback should normally fire within microseconds, but if the pipe\n * has been closed by the parent it may never run. 500ms is generous\n * enough to be effectively unreachable in the happy path while still\n * keeping the process from hanging if something goes wrong.\n */\nconst STDERR_FLUSH_FALLBACK_MS = 500;\n\n/**\n * Exit after the stderr diagnostic has been flushed.\n *\n * When the proxy's stderr is a pipe (parent uses stdio 'pipe'), Node's\n * process.stderr.write() is asynchronous on POSIX. Calling process.exit()\n * immediately afterwards can drop the pending write, which would silently\n * lose the very diagnostic the caller is relying on. Wait for the drain\n * callback before exiting, with a short fallback timer in case the\n * callback never fires (e.g. the pipe is already closed).\n */\nfunction exitWithStderr(message: string, code = 0): void {\n let exited = false;\n const doExit = () => {\n if (exited) return;\n exited = true;\n process.exit(code);\n };\n const fallback = setTimeout(doExit, STDERR_FLUSH_FALLBACK_MS);\n fallback.unref?.();\n try {\n process.stderr.write(message, () => doExit());\n } catch {\n doExit();\n }\n}\n\nfunction shutdown(reason: string): void {\n cleanupIfOwned();\n exitWithStderr(`[cdp-proxy] shutting down: ${reason}\\n`, 0);\n}\n\nprocess.on('SIGTERM', () => shutdown('SIGTERM'));\nprocess.on('SIGINT', () => shutdown('SIGINT'));\nprocess.on('uncaughtException', (e) => shutdown(`uncaught: ${e.message}`));\n\n// ---------------------------------------------------------------------------\n// Idle timer\n// ---------------------------------------------------------------------------\n\nlet idleTimer: ReturnType<typeof setTimeout> | null = null;\n\nfunction resetIdleTimer() {\n if (idleTimer) clearTimeout(idleTimer);\n idleTimer = setTimeout(\n () => shutdown('idle timeout (5min)'),\n IDLE_TIMEOUT_MS,\n );\n}\n\nresetIdleTimer();\n\n// ---------------------------------------------------------------------------\n// Upstream: connect to Chrome\n// ---------------------------------------------------------------------------\n\nconst clients = new Set<WebSocket>();\n\n/**\n * Whether we are intentionally reconnecting the upstream WebSocket.\n * When true, the old upstream's close/error events should not trigger shutdown.\n */\nlet reconnecting = false;\n\n/**\n * Whether the upstream WebSocket needs to be reconnected before the next\n * client can use it. Set to true when all downstream clients disconnect;\n * the actual reconnect is deferred until a new client connects so that\n * Chrome's permission popup only fires when someone actually needs it.\n */\nlet needsUpstreamReconnect = false;\n\n/**\n * Messages from downstream clients that arrived while the upstream WebSocket\n * was not yet open (e.g. during a reconnect). Flushed once upstream opens.\n */\nconst pendingUpstreamMessages: {\n data: WebSocket.RawData;\n isBinary: boolean;\n}[] = [];\n\n/**\n * Create a new upstream WebSocket to Chrome and bind its event handlers.\n * Used for both initial connection and reconnection.\n */\nfunction createUpstream(endpoint: string): WebSocket {\n const ws = new WebSocket(endpoint);\n\n ws.on('error', (err) => {\n // A failed reconnect must not leave the flag stuck on.\n reconnecting = false;\n shutdown(`upstream error: ${err.message}`);\n });\n\n ws.on('close', (code, reasonBuf) => {\n if (reconnecting) return;\n const reason = reasonBuf?.toString?.() || '';\n const detail = reason\n ? ` (code=${code}, reason=${reason})`\n : ` (code=${code})`;\n shutdown(`upstream closed${detail}`);\n });\n\n // Forward upstream messages to all downstream clients\n ws.on('message', (data, isBinary) => {\n resetIdleTimer();\n for (const client of clients) {\n if (client.readyState === WebSocket.OPEN) {\n client.send(data, { binary: isBinary });\n }\n }\n });\n\n ws.on('open', () => {\n reconnecting = false;\n for (const msg of pendingUpstreamMessages) {\n ws.send(msg.data, { binary: msg.isBinary });\n }\n pendingUpstreamMessages.length = 0;\n });\n\n return ws;\n}\n\nlet upstream = createUpstream(chromeEndpoint);\n\n/**\n * Reconnect the upstream WebSocket to Chrome.\n *\n * Called when all downstream clients have disconnected. This resets the CDP\n * protocol state on Chrome's side — critically, the Target.setDiscoverTargets\n * subscription — so the next client that connects gets a fresh session and\n * receives all targetCreated events.\n *\n * `reconnecting` is cleared by the new upstream's `open` (or `error`) handler,\n * not here — the new socket is still CONNECTING when this returns.\n */\nfunction reconnectUpstream() {\n reconnecting = true;\n upstream.removeAllListeners();\n upstream.close();\n upstream = createUpstream(chromeEndpoint);\n resetIdleTimer();\n}\n\n// ---------------------------------------------------------------------------\n// Downstream: local WebSocket server\n// ---------------------------------------------------------------------------\n\nconst httpServer = createServer((_req, res) => {\n res.writeHead(404);\n res.end();\n});\n\nconst wss = new WebSocketServer({ server: httpServer });\n\nwss.on('connection', (clientWs) => {\n // Reconnect the upstream WebSocket if the previous session ended.\n // This resets Chrome's CDP protocol state (Target.setDiscoverTargets, etc.)\n // so the new client receives all targetCreated events.\n if (needsUpstreamReconnect && upstream.readyState === WebSocket.OPEN) {\n reconnectUpstream();\n needsUpstreamReconnect = false;\n }\n\n clients.add(clientWs);\n resetIdleTimer();\n\n // Forward downstream messages to upstream (buffer if upstream is reconnecting)\n clientWs.on('message', (data, isBinary) => {\n resetIdleTimer();\n if (upstream.readyState === WebSocket.OPEN) {\n upstream.send(data, { binary: isBinary });\n } else {\n pendingUpstreamMessages.push({ data, isBinary });\n }\n });\n\n const removeClient = () => {\n clients.delete(clientWs);\n // When all downstream clients disconnect, mark that the upstream needs\n // reconnecting to reset Chrome's CDP protocol state. The actual\n // reconnect is deferred until the next client connects so we don't\n // trigger Chrome's permission popup while nobody is using the proxy.\n if (clients.size === 0) {\n pendingUpstreamMessages.length = 0;\n needsUpstreamReconnect = true;\n }\n };\n\n clientWs.on('close', removeClient);\n clientWs.on('error', removeClient);\n});\n\n// ---------------------------------------------------------------------------\n// Start\n// ---------------------------------------------------------------------------\n\n// Start the HTTP/WebSocket server once the initial upstream connection opens.\n// This listener is added *after* createUpstream() already bound its own 'open'\n// handler (which flushes pendingUpstreamMessages), so both will fire.\nupstream.once('open', () => {\n // Check for duplicate proxy\n if (existsSync(PROXY_PID_FILE)) {\n try {\n const existingPid = Number(readFileSync(PROXY_PID_FILE, 'utf-8').trim());\n if (existingPid !== process.pid) {\n try {\n process.kill(existingPid, 0);\n // Another proxy is alive — exit without cleanupIfOwned() (we don't\n // own the metadata files). Announce the reason on stderr so the\n // parent process can distinguish this path from upstream failures,\n // then bail out of this open handler so we don't proceed to listen().\n exitWithStderr(\n `[cdp-proxy] duplicate proxy detected (existing pid=${existingPid})\\n`,\n 0,\n );\n return;\n } catch {\n // dead — we take over\n }\n }\n } catch {}\n }\n\n httpServer.listen(0, '127.0.0.1', () => {\n const addr = httpServer.address();\n if (!addr || typeof addr === 'string') {\n shutdown('failed to get server address');\n return;\n }\n\n const proxyEndpoint = `ws://127.0.0.1:${addr.port}/devtools/browser`;\n\n writeFileSync(PROXY_ENDPOINT_FILE, proxyEndpoint);\n writeFileSync(PROXY_PID_FILE, String(process.pid));\n writeFileSync(PROXY_UPSTREAM_FILE, chromeEndpoint);\n\n process.stdout.write(`${JSON.stringify({ endpoint: proxyEndpoint })}\\n`);\n });\n});\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","IDLE_TIMEOUT_MS","chromeEndpoint","process","cleanupIfOwned","existsSync","PROXY_PID_FILE","pid","Number","readFileSync","PROXY_ENDPOINT_FILE","unlinkSync","PROXY_UPSTREAM_FILE","STDERR_FLUSH_FALLBACK_MS","exitWithStderr","message","code","exited","doExit","fallback","setTimeout","shutdown","reason","e","idleTimer","resetIdleTimer","clearTimeout","clients","Set","reconnecting","needsUpstreamReconnect","pendingUpstreamMessages","createUpstream","endpoint","ws","WebSocket","err","reasonBuf","detail","data","isBinary","client","msg","upstream","reconnectUpstream","httpServer","createServer","_req","res","wss","WebSocketServer","clientWs","removeClient","existingPid","addr","proxyEndpoint","writeFileSync","String","JSON"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cdp-proxy.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","../../src/cdp-proxy.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","/**\n * CDP WebSocket Proxy — standalone process.\n *\n * Holds a persistent WebSocket connection to Chrome's CDP endpoint and\n * exposes a local WebSocket server. Midscene CLI processes connect to the\n * proxy instead of Chrome directly, so Chrome's \"Allow remote debugging\"\n * permission popup only fires once (when the proxy connects).\n *\n * Lifecycle notes:\n * - When all downstream clients disconnect the proxy stays running but\n * marks the upstream as needing reconnection. The actual reconnect is\n * deferred to the moment the next client connects, so Chrome's CDP\n * state (notably Target.setDiscoverTargets) is reset and the new\n * client receives all targetCreated events.\n * - On startup, if another proxy is already alive the new instance\n * announces \"duplicate proxy detected\" on stderr and exits 0 without\n * touching the existing metadata files.\n *\n * Exit conditions:\n * 1. Upstream Chrome connection closes or errors.\n * 2. No downstream client message for IDLE_TIMEOUT_MS (default 5 min).\n * 3. SIGTERM / SIGINT.\n * 4. Duplicate proxy detected on startup (exits 0 with stderr notice).\n *\n * Usage (spawned by agent-tools-cdp.ts):\n * node cdp-proxy.js <chrome-ws-endpoint>\n *\n * On startup, prints the proxy endpoint to stdout as a single JSON line:\n * {\"endpoint\":\"ws://127.0.0.1:<port>/devtools/browser\"}\n * and writes:\n * - PROXY_ENDPOINT_FILE — the local proxy URL above\n * - PROXY_PID_FILE — this process's pid\n * - PROXY_UPSTREAM_FILE — the Chrome endpoint the proxy is connected to,\n * so callers can detect when the requested\n * upstream has changed and replace the proxy.\n */\n\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { createServer } from 'node:http';\nimport WebSocket, { WebSocketServer } from 'ws';\nimport {\n PROXY_ENDPOINT_FILE,\n PROXY_PID_FILE,\n PROXY_UPSTREAM_FILE,\n} from './cdp-proxy-constants';\n\n// ---------------------------------------------------------------------------\n// Config\n// ---------------------------------------------------------------------------\n\nconst IDLE_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\n\nconst chromeEndpoint = process.argv[2];\nif (!chromeEndpoint) {\n process.stderr.write('Usage: node cdp-proxy.js <chrome-ws-endpoint>\\n');\n process.exit(1);\n}\n\n// ---------------------------------------------------------------------------\n// Cleanup\n// ---------------------------------------------------------------------------\n\nfunction cleanupIfOwned() {\n // Only clean up if the PID file exists and records *our* PID.\n // If the file is missing (e.g. already deleted by killProxy()) or\n // unreadable, skip cleanup — another process may have taken over.\n try {\n if (!existsSync(PROXY_PID_FILE)) return;\n const pid = Number(readFileSync(PROXY_PID_FILE, 'utf-8').trim());\n if (pid !== process.pid) return;\n } catch {\n return;\n }\n try {\n if (existsSync(PROXY_ENDPOINT_FILE)) unlinkSync(PROXY_ENDPOINT_FILE);\n } catch {}\n try {\n if (existsSync(PROXY_PID_FILE)) unlinkSync(PROXY_PID_FILE);\n } catch {}\n try {\n if (existsSync(PROXY_UPSTREAM_FILE)) unlinkSync(PROXY_UPSTREAM_FILE);\n } catch {}\n}\n\n/**\n * Maximum time to wait for the stderr drain callback before forcing exit.\n * The callback should normally fire within microseconds, but if the pipe\n * has been closed by the parent it may never run. 500ms is generous\n * enough to be effectively unreachable in the happy path while still\n * keeping the process from hanging if something goes wrong.\n */\nconst STDERR_FLUSH_FALLBACK_MS = 500;\n\n/**\n * Exit after the stderr diagnostic has been flushed.\n *\n * When the proxy's stderr is a pipe (parent uses stdio 'pipe'), Node's\n * process.stderr.write() is asynchronous on POSIX. Calling process.exit()\n * immediately afterwards can drop the pending write, which would silently\n * lose the very diagnostic the caller is relying on. Wait for the drain\n * callback before exiting, with a short fallback timer in case the\n * callback never fires (e.g. the pipe is already closed).\n */\nfunction exitWithStderr(message: string, code = 0): void {\n let exited = false;\n const doExit = () => {\n if (exited) return;\n exited = true;\n process.exit(code);\n };\n const fallback = setTimeout(doExit, STDERR_FLUSH_FALLBACK_MS);\n fallback.unref?.();\n try {\n process.stderr.write(message, () => doExit());\n } catch {\n doExit();\n }\n}\n\nfunction shutdown(reason: string): void {\n cleanupIfOwned();\n exitWithStderr(`[cdp-proxy] shutting down: ${reason}\\n`, 0);\n}\n\nprocess.on('SIGTERM', () => shutdown('SIGTERM'));\nprocess.on('SIGINT', () => shutdown('SIGINT'));\nprocess.on('uncaughtException', (e) => shutdown(`uncaught: ${e.message}`));\n\n// ---------------------------------------------------------------------------\n// Idle timer\n// ---------------------------------------------------------------------------\n\nlet idleTimer: ReturnType<typeof setTimeout> | null = null;\n\nfunction resetIdleTimer() {\n if (idleTimer) clearTimeout(idleTimer);\n idleTimer = setTimeout(\n () => shutdown('idle timeout (5min)'),\n IDLE_TIMEOUT_MS,\n );\n}\n\nresetIdleTimer();\n\n// ---------------------------------------------------------------------------\n// Upstream: connect to Chrome\n// ---------------------------------------------------------------------------\n\nconst clients = new Set<WebSocket>();\n\n/**\n * Whether we are intentionally reconnecting the upstream WebSocket.\n * When true, the old upstream's close/error events should not trigger shutdown.\n */\nlet reconnecting = false;\n\n/**\n * Whether the upstream WebSocket needs to be reconnected before the next\n * client can use it. Set to true when all downstream clients disconnect;\n * the actual reconnect is deferred until a new client connects so that\n * Chrome's permission popup only fires when someone actually needs it.\n */\nlet needsUpstreamReconnect = false;\n\n/**\n * Messages from downstream clients that arrived while the upstream WebSocket\n * was not yet open (e.g. during a reconnect). Flushed once upstream opens.\n */\nconst pendingUpstreamMessages: {\n data: WebSocket.RawData;\n isBinary: boolean;\n}[] = [];\n\n/**\n * Create a new upstream WebSocket to Chrome and bind its event handlers.\n * Used for both initial connection and reconnection.\n */\nfunction createUpstream(endpoint: string): WebSocket {\n const ws = new WebSocket(endpoint);\n\n ws.on('error', (err) => {\n // A failed reconnect must not leave the flag stuck on.\n reconnecting = false;\n shutdown(`upstream error: ${err.message}`);\n });\n\n ws.on('close', (code, reasonBuf) => {\n if (reconnecting) return;\n const reason = reasonBuf?.toString?.() || '';\n const detail = reason\n ? ` (code=${code}, reason=${reason})`\n : ` (code=${code})`;\n shutdown(`upstream closed${detail}`);\n });\n\n // Forward upstream messages to all downstream clients\n ws.on('message', (data, isBinary) => {\n resetIdleTimer();\n for (const client of clients) {\n if (client.readyState === WebSocket.OPEN) {\n client.send(data, { binary: isBinary });\n }\n }\n });\n\n ws.on('open', () => {\n reconnecting = false;\n for (const msg of pendingUpstreamMessages) {\n ws.send(msg.data, { binary: msg.isBinary });\n }\n pendingUpstreamMessages.length = 0;\n });\n\n return ws;\n}\n\nlet upstream = createUpstream(chromeEndpoint);\n\n/**\n * Reconnect the upstream WebSocket to Chrome.\n *\n * Called when all downstream clients have disconnected. This resets the CDP\n * protocol state on Chrome's side — critically, the Target.setDiscoverTargets\n * subscription — so the next client that connects gets a fresh session and\n * receives all targetCreated events.\n *\n * `reconnecting` is cleared by the new upstream's `open` (or `error`) handler,\n * not here — the new socket is still CONNECTING when this returns.\n */\nfunction reconnectUpstream() {\n reconnecting = true;\n upstream.removeAllListeners();\n upstream.close();\n upstream = createUpstream(chromeEndpoint);\n resetIdleTimer();\n}\n\n// ---------------------------------------------------------------------------\n// Downstream: local WebSocket server\n// ---------------------------------------------------------------------------\n\nconst httpServer = createServer((_req, res) => {\n res.writeHead(404);\n res.end();\n});\n\nconst wss = new WebSocketServer({ server: httpServer });\n\nwss.on('connection', (clientWs) => {\n // Reconnect the upstream WebSocket if the previous session ended.\n // This resets Chrome's CDP protocol state (Target.setDiscoverTargets, etc.)\n // so the new client receives all targetCreated events.\n if (needsUpstreamReconnect && upstream.readyState === WebSocket.OPEN) {\n reconnectUpstream();\n needsUpstreamReconnect = false;\n }\n\n clients.add(clientWs);\n resetIdleTimer();\n\n // Forward downstream messages to upstream (buffer if upstream is reconnecting)\n clientWs.on('message', (data, isBinary) => {\n resetIdleTimer();\n if (upstream.readyState === WebSocket.OPEN) {\n upstream.send(data, { binary: isBinary });\n } else {\n pendingUpstreamMessages.push({ data, isBinary });\n }\n });\n\n const removeClient = () => {\n clients.delete(clientWs);\n // When all downstream clients disconnect, mark that the upstream needs\n // reconnecting to reset Chrome's CDP protocol state. The actual\n // reconnect is deferred until the next client connects so we don't\n // trigger Chrome's permission popup while nobody is using the proxy.\n if (clients.size === 0) {\n pendingUpstreamMessages.length = 0;\n needsUpstreamReconnect = true;\n }\n };\n\n clientWs.on('close', removeClient);\n clientWs.on('error', removeClient);\n});\n\n// ---------------------------------------------------------------------------\n// Start\n// ---------------------------------------------------------------------------\n\n// Start the HTTP/WebSocket server once the initial upstream connection opens.\n// This listener is added *after* createUpstream() already bound its own 'open'\n// handler (which flushes pendingUpstreamMessages), so both will fire.\nupstream.once('open', () => {\n // Check for duplicate proxy\n if (existsSync(PROXY_PID_FILE)) {\n try {\n const existingPid = Number(readFileSync(PROXY_PID_FILE, 'utf-8').trim());\n if (existingPid !== process.pid) {\n try {\n process.kill(existingPid, 0);\n // Another proxy is alive — exit without cleanupIfOwned() (we don't\n // own the metadata files). Announce the reason on stderr so the\n // parent process can distinguish this path from upstream failures,\n // then bail out of this open handler so we don't proceed to listen().\n exitWithStderr(\n `[cdp-proxy] duplicate proxy detected (existing pid=${existingPid})\\n`,\n 0,\n );\n return;\n } catch {\n // dead — we take over\n }\n }\n } catch {}\n }\n\n httpServer.listen(0, '127.0.0.1', () => {\n const addr = httpServer.address();\n if (!addr || typeof addr === 'string') {\n shutdown('failed to get server address');\n return;\n }\n\n const proxyEndpoint = `ws://127.0.0.1:${addr.port}/devtools/browser`;\n\n writeFileSync(PROXY_ENDPOINT_FILE, proxyEndpoint);\n writeFileSync(PROXY_PID_FILE, String(process.pid));\n writeFileSync(PROXY_UPSTREAM_FILE, chromeEndpoint);\n\n process.stdout.write(`${JSON.stringify({ endpoint: proxyEndpoint })}\\n`);\n });\n});\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","IDLE_TIMEOUT_MS","chromeEndpoint","process","cleanupIfOwned","existsSync","PROXY_PID_FILE","pid","Number","readFileSync","PROXY_ENDPOINT_FILE","unlinkSync","PROXY_UPSTREAM_FILE","STDERR_FLUSH_FALLBACK_MS","exitWithStderr","message","code","exited","doExit","fallback","setTimeout","shutdown","reason","e","idleTimer","resetIdleTimer","clearTimeout","clients","Set","reconnecting","needsUpstreamReconnect","pendingUpstreamMessages","createUpstream","endpoint","ws","WebSocket","err","reasonBuf","detail","data","isBinary","client","msg","upstream","reconnectUpstream","httpServer","createServer","_req","res","wss","WebSocketServer","clientWs","removeClient","existingPid","addr","proxyEndpoint","writeFileSync","String","JSON"],"mappings":"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"}
|
|
@@ -31,7 +31,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
31
31
|
const external_node_fs_namespaceObject = require("node:fs");
|
|
32
32
|
const logger_namespaceObject = require("@midscene/shared/logger");
|
|
33
33
|
const external_cdp_proxy_constants_js_namespaceObject = require("./cdp-proxy-constants.js");
|
|
34
|
-
const debug = (0, logger_namespaceObject.getDebug)('
|
|
34
|
+
const debug = (0, logger_namespaceObject.getDebug)('agent-tools:cdp:target-store');
|
|
35
35
|
function readSavedTargetId() {
|
|
36
36
|
if (!(0, external_node_fs_namespaceObject.existsSync)(external_cdp_proxy_constants_js_namespaceObject.TARGET_ID_FILE)) return null;
|
|
37
37
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cdp-target-store.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/cdp-target-store.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/**\n * Persistent store for the CDP-mode \"current tab\" targetId.\n *\n * The Midscene CLI runs each command as a fresh Node process, so anything\n * the previous command knew about which tab was being driven must survive\n * across processes. This store writes the chosen targetId to a temp file\n * after `connect`/`act`/etc. succeed, and the next command reads it back\n * to bind to the exact same tab — even when Chrome holds 14 of them.\n *\n * Owns nothing else. The CDP proxy lifecycle and its own metadata files\n * live in `cdp-proxy-manager.ts`.\n */\n\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { getDebug } from '@midscene/shared/logger';\nimport { TARGET_ID_FILE } from './cdp-proxy-constants';\n\nconst debug = getDebug('
|
|
1
|
+
{"version":3,"file":"cdp-target-store.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../src/cdp-target-store.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","/**\n * Persistent store for the CDP-mode \"current tab\" targetId.\n *\n * The Midscene CLI runs each command as a fresh Node process, so anything\n * the previous command knew about which tab was being driven must survive\n * across processes. This store writes the chosen targetId to a temp file\n * after `connect`/`act`/etc. succeed, and the next command reads it back\n * to bind to the exact same tab — even when Chrome holds 14 of them.\n *\n * Owns nothing else. The CDP proxy lifecycle and its own metadata files\n * live in `cdp-proxy-manager.ts`.\n */\n\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { getDebug } from '@midscene/shared/logger';\nimport { TARGET_ID_FILE } from './cdp-proxy-constants';\n\nconst debug = getDebug('agent-tools:cdp:target-store');\n\n/**\n * Read the saved targetId, or null if no command has stored one yet.\n */\nexport function readSavedTargetId(): string | null {\n if (!existsSync(TARGET_ID_FILE)) return null;\n try {\n return readFileSync(TARGET_ID_FILE, 'utf-8').trim() || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Save a targetId so the next CLI command can rebind to the same tab.\n */\nexport function saveTargetId(targetId: string): void {\n try {\n writeFileSync(TARGET_ID_FILE, targetId, 'utf-8');\n debug('Saved targetId: %s', targetId);\n } catch (err) {\n debug('Failed to save targetId: %s', err);\n }\n}\n\n/**\n * Discard the saved targetId — call when disconnecting or when the\n * upstream Chrome changes (the targetId would point into the old\n * browser's tab list).\n */\nexport function cleanupTargetIdFile(): void {\n try {\n if (existsSync(TARGET_ID_FILE)) unlinkSync(TARGET_ID_FILE);\n } catch {}\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","debug","getDebug","readSavedTargetId","existsSync","TARGET_ID_FILE","readFileSync","saveTargetId","targetId","writeFileSync","err","cleanupTargetIdFile","unlinkSync"],"mappings":";;;IAAAA,oBAAoB,CAAC,GAAG,CAAC,UAASC;QACjC,IAAI,IAAIC,OAAOD,WACR,IAAGD,oBAAoB,CAAC,CAACC,YAAYC,QAAQ,CAACF,oBAAoB,CAAC,CAAC,UAASE,MACzEC,OAAO,cAAc,CAAC,UAASD,KAAK;YAAE,YAAY;YAAM,KAAKD,UAAU,CAACC,IAAI;QAAC;IAGzF;;;ICNAF,oBAAoB,CAAC,GAAG,CAACI,KAAKC,OAAUF,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAACC,KAAKC;;;ICClFL,oBAAoB,CAAC,GAAG,CAAC;QACxB,IAAG,AAAkB,eAAlB,OAAOM,UAA0BA,OAAO,WAAW,EACrDH,OAAO,cAAc,CAAC,UAASG,OAAO,WAAW,EAAE;YAAE,OAAO;QAAS;QAEtEH,OAAO,cAAc,CAAC,UAAS,cAAc;YAAE,OAAO;QAAK;IAC5D;;;;;;;;;;;;ACWA,MAAMI,QAAQC,AAAAA,IAAAA,uBAAAA,QAAAA,AAAAA,EAAS;AAKhB,SAASC;IACd,IAAI,CAACC,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWC,gDAAAA,cAAcA,GAAG,OAAO;IACxC,IAAI;QACF,OAAOC,AAAAA,IAAAA,iCAAAA,YAAAA,AAAAA,EAAaD,gDAAAA,cAAcA,EAAE,SAAS,IAAI,MAAM;IACzD,EAAE,OAAM;QACN,OAAO;IACT;AACF;AAKO,SAASE,aAAaC,QAAgB;IAC3C,IAAI;QACFC,IAAAA,iCAAAA,aAAAA,AAAAA,EAAcJ,gDAAAA,cAAcA,EAAEG,UAAU;QACxCP,MAAM,sBAAsBO;IAC9B,EAAE,OAAOE,KAAK;QACZT,MAAM,+BAA+BS;IACvC;AACF;AAOO,SAASC;IACd,IAAI;QACF,IAAIP,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWC,gDAAAA,cAAcA,GAAGO,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWP,gDAAAA,cAAcA;IAC3D,EAAE,OAAM,CAAC;AACX"}
|
package/dist/lib/cli.js
CHANGED
|
@@ -27,10 +27,10 @@ const core_namespaceObject = require("@midscene/core");
|
|
|
27
27
|
const cli_namespaceObject = require("@midscene/shared/cli");
|
|
28
28
|
const external_dotenv_namespaceObject = require("dotenv");
|
|
29
29
|
var external_dotenv_default = /*#__PURE__*/ __webpack_require__.n(external_dotenv_namespaceObject);
|
|
30
|
+
const external_agent_tools_js_namespaceObject = require("./agent-tools.js");
|
|
31
|
+
const external_agent_tools_cdp_js_namespaceObject = require("./agent-tools-cdp.js");
|
|
32
|
+
const external_agent_tools_puppeteer_js_namespaceObject = require("./agent-tools-puppeteer.js");
|
|
30
33
|
const external_cli_options_js_namespaceObject = require("./cli-options.js");
|
|
31
|
-
const external_mcp_tools_js_namespaceObject = require("./mcp-tools.js");
|
|
32
|
-
const external_mcp_tools_cdp_js_namespaceObject = require("./mcp-tools-cdp.js");
|
|
33
|
-
const external_mcp_tools_puppeteer_js_namespaceObject = require("./mcp-tools-puppeteer.js");
|
|
34
34
|
const envFile = (0, external_node_path_namespaceObject.join)(process.cwd(), '.env');
|
|
35
35
|
if ((0, external_node_fs_namespaceObject.existsSync)(envFile)) external_dotenv_default().config({
|
|
36
36
|
path: envFile
|
|
@@ -38,11 +38,11 @@ if ((0, external_node_fs_namespaceObject.existsSync)(envFile)) external_dotenv_d
|
|
|
38
38
|
Promise.resolve().then(()=>{
|
|
39
39
|
const parsedOptions = (0, external_cli_options_js_namespaceObject.parseWebCliOptions)(process.argv.slice(2));
|
|
40
40
|
let tools;
|
|
41
|
-
tools = 'bridge' === parsedOptions.mode ? new
|
|
41
|
+
tools = 'bridge' === parsedOptions.mode ? new external_agent_tools_js_namespaceObject.WebMidsceneTools() : 'cdp' === parsedOptions.mode ? new external_agent_tools_cdp_js_namespaceObject.WebCdpMidsceneTools(parsedOptions.cdpEndpoint) : new external_agent_tools_puppeteer_js_namespaceObject.WebPuppeteerMidsceneTools(parsedOptions.viewport);
|
|
42
42
|
return (0, cli_namespaceObject.runToolsCLI)(tools, 'midscene-web', {
|
|
43
43
|
stripPrefix: 'web_',
|
|
44
44
|
argv: parsedOptions.argv,
|
|
45
|
-
version: "1.
|
|
45
|
+
version: "1.10.1-beta-20260624112700.0",
|
|
46
46
|
extraCommands: (0, core_namespaceObject.createReportCliCommands)()
|
|
47
47
|
});
|
|
48
48
|
}).catch((e)=>{
|
package/dist/lib/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","../../src/cli.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createReportCliCommands } from '@midscene/core';\nimport { reportCLIError, runToolsCLI } from '@midscene/shared/cli';\nimport dotenv from 'dotenv';\nimport {
|
|
1
|
+
{"version":3,"file":"cli.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","../../src/cli.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createReportCliCommands } from '@midscene/core';\nimport { reportCLIError, runToolsCLI } from '@midscene/shared/cli';\nimport dotenv from 'dotenv';\nimport { WebMidsceneTools } from './agent-tools';\nimport { WebCdpMidsceneTools } from './agent-tools-cdp';\nimport { WebPuppeteerMidsceneTools } from './agent-tools-puppeteer';\nimport { parseWebCliOptions } from './cli-options';\n\n// Load .env early so MIDSCENE_CDP_ENDPOINT is available during arg parsing\nconst envFile = join(process.cwd(), '.env');\nif (existsSync(envFile)) {\n dotenv.config({ path: envFile });\n}\n\ndeclare const __VERSION__: string;\n\nPromise.resolve()\n .then(() => {\n const parsedOptions = parseWebCliOptions(process.argv.slice(2));\n\n let tools:\n | WebMidsceneTools\n | WebPuppeteerMidsceneTools\n | WebCdpMidsceneTools;\n if (parsedOptions.mode === 'bridge') {\n tools = new WebMidsceneTools();\n } else if (parsedOptions.mode === 'cdp') {\n tools = new WebCdpMidsceneTools(parsedOptions.cdpEndpoint!);\n } else {\n tools = new WebPuppeteerMidsceneTools(parsedOptions.viewport);\n }\n\n return runToolsCLI(tools, 'midscene-web', {\n stripPrefix: 'web_',\n argv: parsedOptions.argv,\n version: __VERSION__,\n extraCommands: createReportCliCommands(),\n });\n })\n .catch((e) => {\n process.exit(reportCLIError(e));\n });\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","envFile","join","process","existsSync","dotenv","Promise","parsedOptions","parseWebCliOptions","tools","WebMidsceneTools","WebCdpMidsceneTools","WebPuppeteerMidsceneTools","runToolsCLI","__VERSION__","createReportCliCommands","e","reportCLIError"],"mappings":";;;IACAA,oBAAoB,CAAC,GAAG,CAACC;QACxB,IAAIC,SAASD,UAAUA,OAAO,UAAU,GACvC,IAAOA,MAAM,CAAC,UAAU,GACxB,IAAOA;QACRD,oBAAoB,CAAC,CAACE,QAAQ;YAAE,GAAGA;QAAO;QAC1C,OAAOA;IACR;;;ICPAF,oBAAoB,CAAC,GAAG,CAAC,UAASG;QACjC,IAAI,IAAIC,OAAOD,WACR,IAAGH,oBAAoB,CAAC,CAACG,YAAYC,QAAQ,CAACJ,oBAAoB,CAAC,CAAC,UAASI,MACzEC,OAAO,cAAc,CAAC,UAASD,KAAK;YAAE,YAAY;YAAM,KAAKD,UAAU,CAACC,IAAI;QAAC;IAGzF;;;ICNAJ,oBAAoB,CAAC,GAAG,CAACM,KAAKC,OAAUF,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAACC,KAAKC;;;;;;;;;;;;;ACWlF,MAAMC,UAAUC,AAAAA,IAAAA,mCAAAA,IAAAA,AAAAA,EAAKC,QAAQ,GAAG,IAAI;AACpC,IAAIC,AAAAA,IAAAA,iCAAAA,UAAAA,AAAAA,EAAWH,UACbI,0BAAAA,MAAa,CAAC;IAAE,MAAMJ;AAAQ;AAKhCK,QAAQ,OAAO,GACZ,IAAI,CAAC;IACJ,MAAMC,gBAAgBC,AAAAA,IAAAA,wCAAAA,kBAAAA,AAAAA,EAAmBL,QAAQ,IAAI,CAAC,KAAK,CAAC;IAE5D,IAAIM;IAKFA,QADEF,AAAuB,aAAvBA,cAAc,IAAI,GACZ,IAAIG,wCAAAA,gBAAgBA,KACnBH,AAAuB,UAAvBA,cAAc,IAAI,GACnB,IAAII,4CAAAA,mBAAmBA,CAACJ,cAAc,WAAW,IAEjD,IAAIK,kDAAAA,yBAAyBA,CAACL,cAAc,QAAQ;IAG9D,OAAOM,AAAAA,IAAAA,oBAAAA,WAAAA,AAAAA,EAAYJ,OAAO,gBAAgB;QACxC,aAAa;QACb,MAAMF,cAAc,IAAI;QACxB,SAASO;QACT,eAAeC,AAAAA,IAAAA,qBAAAA,uBAAAA,AAAAA;IACjB;AACF,GACC,KAAK,CAAC,CAACC;IACNb,QAAQ,IAAI,CAACc,AAAAA,IAAAA,oBAAAA,cAAAA,AAAAA,EAAeD;AAC9B"}
|
package/dist/lib/index.js
CHANGED
|
@@ -31,16 +31,16 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
31
31
|
StaticPage: ()=>external_static_index_js_namespaceObject.StaticPage,
|
|
32
32
|
PageAgent: ()=>agent_namespaceObject.Agent,
|
|
33
33
|
webPlaygroundPlatform: ()=>external_platform_js_namespaceObject.webPlaygroundPlatform,
|
|
34
|
-
WebCdpMidsceneTools: ()=>
|
|
35
|
-
WebMidsceneTools: ()=>
|
|
34
|
+
WebCdpMidsceneTools: ()=>external_agent_tools_cdp_js_namespaceObject.WebCdpMidsceneTools,
|
|
35
|
+
WebMidsceneTools: ()=>external_agent_tools_js_namespaceObject.WebMidsceneTools
|
|
36
36
|
});
|
|
37
37
|
const index_js_namespaceObject = require("./playwright/index.js");
|
|
38
38
|
const agent_namespaceObject = require("@midscene/core/agent");
|
|
39
39
|
const external_puppeteer_index_js_namespaceObject = require("./puppeteer/index.js");
|
|
40
40
|
const external_static_index_js_namespaceObject = require("./static/index.js");
|
|
41
|
-
const
|
|
41
|
+
const external_agent_tools_js_namespaceObject = require("./agent-tools.js");
|
|
42
42
|
const external_platform_js_namespaceObject = require("./platform.js");
|
|
43
|
-
const
|
|
43
|
+
const external_agent_tools_cdp_js_namespaceObject = require("./agent-tools-cdp.js");
|
|
44
44
|
exports.PageAgent = __webpack_exports__.PageAgent;
|
|
45
45
|
exports.PlaywrightAgent = __webpack_exports__.PlaywrightAgent;
|
|
46
46
|
exports.PlaywrightAiFixture = __webpack_exports__.PlaywrightAiFixture;
|
|
@@ -65,11 +65,13 @@ class PlaywrightAgent extends agent_namespaceObject.Agent {
|
|
|
65
65
|
if (!page) throw new Error('[midscene] PlaywrightAgent requires a valid Playwright page instance. Please make sure to pass a valid page object.');
|
|
66
66
|
const webPage = new external_page_js_namespaceObject.WebPage(page, opts);
|
|
67
67
|
super(webPage, opts);
|
|
68
|
-
const { forceSameTabNavigation = true, forceChromeSelectRendering } = opts ?? {};
|
|
68
|
+
const { forceSameTabNavigation = true, forceChromeSelectRendering = true } = opts ?? {};
|
|
69
69
|
if (forceSameTabNavigation) (0, base_page_js_namespaceObject.forceClosePopup)(page, debug);
|
|
70
70
|
if (forceChromeSelectRendering) {
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
if (opts?.forceChromeSelectRendering === true) {
|
|
72
|
+
const playwrightVersion = getPlaywrightVersion();
|
|
73
|
+
if (playwrightVersion && !external_semver_default().gte(playwrightVersion, '1.52.0')) console.warn(`[midscene:error] forceChromeSelectRendering requires Playwright >= 1.52.0, but current version is ${playwrightVersion}. This feature may not work correctly.`);
|
|
74
|
+
}
|
|
73
75
|
(0, base_page_js_namespaceObject.forceChromeSelectRendering)(page);
|
|
74
76
|
}
|
|
75
77
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playwright/index.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/playwright/index.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { Agent as PageAgent } from '@midscene/core/agent';\nimport type { Page as PlaywrightPage } from 'playwright';\nimport { WebPage as PlaywrightWebPage } from './page';\n\nexport type {\n PlayWrightAiFixtureType,\n PlaywrightAiFixtureOptions,\n} from './ai-fixture';\nexport { PlaywrightAiFixture } from './ai-fixture';\nexport { overrideAIConfig } from '@midscene/shared/env';\nexport { WebPage as PlaywrightWebPage } from './page';\nexport type { WebPageAgentOpt } from '@/web-element';\nimport type { WebPageAgentOpt } from '@/web-element';\nimport { getDebug } from '@midscene/shared/logger';\nimport semver from 'semver';\nimport {\n BROWSER_NAVIGATION_ERROR_PATTERN,\n forceChromeSelectRendering as applyChromeSelectRendering,\n forceClosePopup,\n} from '../puppeteer/base-page';\nimport { getWebpackRequire } from '../utils';\n\nconst debug = getDebug('playwright:agent');\n\n/**\n * Get Playwright version from package.json\n */\nfunction getPlaywrightVersion(): string | null {\n try {\n const playwrightPkg = getWebpackRequire()('playwright/package.json');\n return playwrightPkg.version || null;\n } catch (error) {\n console.error('[midscene:error] Failed to get Playwright version', error);\n return null;\n }\n}\n\nexport class PlaywrightAgent extends PageAgent<PlaywrightWebPage> {\n protected isRetryableContextError(error: unknown): boolean {\n return (\n error instanceof Error &&\n BROWSER_NAVIGATION_ERROR_PATTERN.test(error.message)\n );\n }\n\n constructor(page: PlaywrightPage, opts?: WebPageAgentOpt) {\n if (!page) {\n throw new Error(\n '[midscene] PlaywrightAgent requires a valid Playwright page instance. Please make sure to pass a valid page object.',\n );\n }\n const webPage = new PlaywrightWebPage(page, opts);\n super(webPage, opts);\n\n const { forceSameTabNavigation = true, forceChromeSelectRendering } =\n opts ?? {};\n\n if (forceSameTabNavigation) {\n forceClosePopup(page, debug);\n }\n\n if (forceChromeSelectRendering) {\n //
|
|
1
|
+
{"version":3,"file":"playwright/index.js","sources":["webpack/runtime/compat_get_default_export","webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/playwright/index.ts"],"sourcesContent":["// getDefaultExport function for compatibility with non-ESM modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};\n","__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { Agent as PageAgent } from '@midscene/core/agent';\nimport type { Page as PlaywrightPage } from 'playwright';\nimport { WebPage as PlaywrightWebPage } from './page';\n\nexport type {\n PlayWrightAiFixtureType,\n PlaywrightAiFixtureOptions,\n} from './ai-fixture';\nexport { PlaywrightAiFixture } from './ai-fixture';\nexport { overrideAIConfig } from '@midscene/shared/env';\nexport { WebPage as PlaywrightWebPage } from './page';\nexport type { WebPageAgentOpt } from '@/web-element';\nimport type { WebPageAgentOpt } from '@/web-element';\nimport { getDebug } from '@midscene/shared/logger';\nimport semver from 'semver';\nimport {\n BROWSER_NAVIGATION_ERROR_PATTERN,\n forceChromeSelectRendering as applyChromeSelectRendering,\n forceClosePopup,\n} from '../puppeteer/base-page';\nimport { getWebpackRequire } from '../utils';\n\nconst debug = getDebug('playwright:agent');\n\n/**\n * Get Playwright version from package.json\n */\nfunction getPlaywrightVersion(): string | null {\n try {\n const playwrightPkg = getWebpackRequire()('playwright/package.json');\n return playwrightPkg.version || null;\n } catch (error) {\n console.error('[midscene:error] Failed to get Playwright version', error);\n return null;\n }\n}\n\nexport class PlaywrightAgent extends PageAgent<PlaywrightWebPage> {\n protected isRetryableContextError(error: unknown): boolean {\n return (\n error instanceof Error &&\n BROWSER_NAVIGATION_ERROR_PATTERN.test(error.message)\n );\n }\n\n constructor(page: PlaywrightPage, opts?: WebPageAgentOpt) {\n if (!page) {\n throw new Error(\n '[midscene] PlaywrightAgent requires a valid Playwright page instance. Please make sure to pass a valid page object.',\n );\n }\n const webPage = new PlaywrightWebPage(page, opts);\n super(webPage, opts);\n\n const { forceSameTabNavigation = true, forceChromeSelectRendering = true } =\n opts ?? {};\n\n if (forceSameTabNavigation) {\n forceClosePopup(page, debug);\n }\n\n if (forceChromeSelectRendering) {\n // Only warn about version requirements when the user explicitly opted in;\n // it is on by default, so we should not nag users on older Playwright.\n if (opts?.forceChromeSelectRendering === true) {\n const playwrightVersion = getPlaywrightVersion();\n if (playwrightVersion && !semver.gte(playwrightVersion, '1.52.0')) {\n console.warn(\n `[midscene:error] forceChromeSelectRendering requires Playwright >= 1.52.0, but current version is ${playwrightVersion}. This feature may not work correctly.`,\n );\n }\n }\n applyChromeSelectRendering(page);\n }\n }\n}\n"],"names":["__webpack_require__","module","getter","definition","key","Object","obj","prop","Symbol","debug","getDebug","getPlaywrightVersion","playwrightPkg","getWebpackRequire","error","console","PlaywrightAgent","PageAgent","Error","BROWSER_NAVIGATION_ERROR_PATTERN","page","opts","webPage","PlaywrightWebPage","forceSameTabNavigation","forceChromeSelectRendering","forceClosePopup","playwrightVersion","semver","applyChromeSelectRendering"],"mappings":";;;IACAA,oBAAoB,CAAC,GAAG,CAACC;QACxB,IAAIC,SAASD,UAAUA,OAAO,UAAU,GACvC,IAAOA,MAAM,CAAC,UAAU,GACxB,IAAOA;QACRD,oBAAoB,CAAC,CAACE,QAAQ;YAAE,GAAGA;QAAO;QAC1C,OAAOA;IACR;;;ICPAF,oBAAoB,CAAC,GAAG,CAAC,UAASG;QACjC,IAAI,IAAIC,OAAOD,WACR,IAAGH,oBAAoB,CAAC,CAACG,YAAYC,QAAQ,CAACJ,oBAAoB,CAAC,CAAC,UAASI,MACzEC,OAAO,cAAc,CAAC,UAASD,KAAK;YAAE,YAAY;YAAM,KAAKD,UAAU,CAACC,IAAI;QAAC;IAGzF;;;ICNAJ,oBAAoB,CAAC,GAAG,CAACM,KAAKC,OAAUF,OAAO,SAAS,CAAC,cAAc,CAAC,IAAI,CAACC,KAAKC;;;ICClFP,oBAAoB,CAAC,GAAG,CAAC;QACxB,IAAG,AAAkB,eAAlB,OAAOQ,UAA0BA,OAAO,WAAW,EACrDH,OAAO,cAAc,CAAC,UAASG,OAAO,WAAW,EAAE;YAAE,OAAO;QAAS;QAEtEH,OAAO,cAAc,CAAC,UAAS,cAAc;YAAE,OAAO;QAAK;IAC5D;;;;;;;;;;;;;;;;;;;ACgBA,MAAMI,QAAQC,AAAAA,IAAAA,uBAAAA,QAAAA,AAAAA,EAAS;AAKvB,SAASC;IACP,IAAI;QACF,MAAMC,gBAAgBC,AAAAA,IAAAA,kCAAAA,iBAAAA,AAAAA,IAAoB;QAC1C,OAAOD,cAAc,OAAO,IAAI;IAClC,EAAE,OAAOE,OAAO;QACdC,QAAQ,KAAK,CAAC,qDAAqDD;QACnE,OAAO;IACT;AACF;AAEO,MAAME,wBAAwBC,sBAAAA,KAASA;IAClC,wBAAwBH,KAAc,EAAW;QACzD,OACEA,iBAAiBI,SACjBC,6BAAAA,gCAAAA,CAAAA,IAAqC,CAACL,MAAM,OAAO;IAEvD;IAEA,YAAYM,IAAoB,EAAEC,IAAsB,CAAE;QACxD,IAAI,CAACD,MACH,MAAM,IAAIF,MACR;QAGJ,MAAMI,UAAU,IAAIC,iCAAAA,OAAiBA,CAACH,MAAMC;QAC5C,KAAK,CAACC,SAASD;QAEf,MAAM,EAAEG,yBAAyB,IAAI,EAAEC,6BAA6B,IAAI,EAAE,GACxEJ,QAAQ,CAAC;QAEX,IAAIG,wBACFE,AAAAA,IAAAA,6BAAAA,eAAAA,AAAAA,EAAgBN,MAAMX;QAGxB,IAAIgB,4BAA4B;YAG9B,IAAIJ,MAAM,+BAA+B,MAAM;gBAC7C,MAAMM,oBAAoBhB;gBAC1B,IAAIgB,qBAAqB,CAACC,0BAAAA,GAAU,CAACD,mBAAmB,WACtDZ,QAAQ,IAAI,CACV,CAAC,kGAAkG,EAAEY,kBAAkB,sCAAsC,CAAC;YAGpK;YACAE,IAAAA,6BAAAA,0BAAAA,AAAAA,EAA2BT;QAC7B;IACF;AACF"}
|
|
@@ -211,17 +211,15 @@ class Page {
|
|
|
211
211
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
212
212
|
console.warn(`[Midscene] Playwright screenshot failed: ${errorMsg}. Falling back to CDP screenshot.`);
|
|
213
213
|
debugPage('playwright screenshot failed, trying CDP fallback: %s', error);
|
|
214
|
-
base64 = await this.screenshotBase64ByPlaywrightCdp(
|
|
214
|
+
base64 = await this.screenshotBase64ByPlaywrightCdp(imgType, quality);
|
|
215
215
|
}
|
|
216
216
|
} else throw new Error('Unsupported page type for screenshot');
|
|
217
217
|
const endTime = Date.now();
|
|
218
218
|
debugPage(`screenshotBase64 end, cost: ${endTime - startTime}ms`);
|
|
219
219
|
return base64;
|
|
220
220
|
}
|
|
221
|
-
async screenshotBase64ByPlaywrightCdp(
|
|
222
|
-
const
|
|
223
|
-
if (browserName && 'chromium' !== browserName) throw new Error(`CDP screenshot fallback requires Chromium-based browser, but current browser is "${browserName}".`);
|
|
224
|
-
const client = await page.context().newCDPSession(page);
|
|
221
|
+
async screenshotBase64ByPlaywrightCdp(imgType, quality) {
|
|
222
|
+
const client = await this.createPageCdpSession('CDP screenshot fallback');
|
|
225
223
|
try {
|
|
226
224
|
const result = await new Promise((resolve, reject)=>{
|
|
227
225
|
const timeoutId = setTimeout(()=>{
|
|
@@ -247,14 +245,18 @@ class Page {
|
|
|
247
245
|
});
|
|
248
246
|
}
|
|
249
247
|
}
|
|
250
|
-
async
|
|
248
|
+
async createPageCdpSession(featureName) {
|
|
251
249
|
if ('puppeteer' === this.interfaceType) {
|
|
252
250
|
const page = this.underlyingPage;
|
|
253
|
-
|
|
251
|
+
const pageWithCdp = page;
|
|
252
|
+
if ('function' == typeof pageWithCdp.createCDPSession) return await pageWithCdp.createCDPSession();
|
|
253
|
+
const target = page.target?.();
|
|
254
|
+
if ('function' == typeof target?.createCDPSession) return await target.createCDPSession();
|
|
255
|
+
throw new Error(`${featureName} requires a browser page with CDP session support.`);
|
|
254
256
|
}
|
|
255
257
|
const page = this.underlyingPage;
|
|
256
258
|
const browserName = page.context().browser()?.browserType().name();
|
|
257
|
-
if (browserName && 'chromium' !== browserName) throw new Error(
|
|
259
|
+
if (browserName && 'chromium' !== browserName) throw new Error(`${featureName} requires Chromium-based browser, but current browser is "${browserName}".`);
|
|
258
260
|
return await page.context().newCDPSession(page);
|
|
259
261
|
}
|
|
260
262
|
async waitForDomQuiet(opts) {
|
|
@@ -339,7 +341,7 @@ class Page {
|
|
|
339
341
|
async startMjpegStream(options) {
|
|
340
342
|
const { signal, onFrame, onError } = options;
|
|
341
343
|
if ('function' == typeof this.underlyingPage.bringToFront) await this.underlyingPage.bringToFront();
|
|
342
|
-
const client = await this.
|
|
344
|
+
const client = await this.createPageCdpSession('CDP screencast');
|
|
343
345
|
let stopped = false;
|
|
344
346
|
const streamToken = Symbol('mjpeg-stream');
|
|
345
347
|
const reportStreamError = (error)=>{
|
|
@@ -522,6 +524,22 @@ class Page {
|
|
|
522
524
|
}
|
|
523
525
|
};
|
|
524
526
|
}
|
|
527
|
+
async selectAllByCdp() {
|
|
528
|
+
const client = await this.createPageCdpSession('clearInput');
|
|
529
|
+
try {
|
|
530
|
+
await client.send('Input.dispatchKeyEvent', {
|
|
531
|
+
type: 'rawKeyDown',
|
|
532
|
+
commands: [
|
|
533
|
+
'selectAll'
|
|
534
|
+
]
|
|
535
|
+
});
|
|
536
|
+
await client.send('Input.dispatchKeyEvent', {
|
|
537
|
+
type: 'keyUp'
|
|
538
|
+
});
|
|
539
|
+
} finally{
|
|
540
|
+
await client.detach().catch(()=>void 0);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
525
543
|
async clearInput(element) {
|
|
526
544
|
const backspace = async ()=>{
|
|
527
545
|
await (0, utils_namespaceObject.sleep)(100);
|
|
@@ -531,28 +549,17 @@ class Page {
|
|
|
531
549
|
}
|
|
532
550
|
]);
|
|
533
551
|
};
|
|
534
|
-
const isMac = 'darwin' === process.platform;
|
|
535
552
|
debugPage('clearInput begin');
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
count: 3
|
|
540
|
-
});
|
|
541
|
-
await backspace();
|
|
542
|
-
}
|
|
543
|
-
element && await this.mouse.click(element.center[0], element.center[1]);
|
|
544
|
-
await this.underlyingPage.keyboard.down('Meta');
|
|
545
|
-
await this.underlyingPage.keyboard.press('a');
|
|
546
|
-
await this.underlyingPage.keyboard.up('Meta');
|
|
547
|
-
await backspace();
|
|
548
|
-
} else {
|
|
549
|
-
element && await this.mouse.click(element.center[0], element.center[1]);
|
|
550
|
-
await this.underlyingPage.keyboard.down('Control');
|
|
551
|
-
await this.underlyingPage.keyboard.press('a');
|
|
552
|
-
await this.underlyingPage.keyboard.up('Control');
|
|
553
|
+
element && await this.mouse.click(element.center[0], element.center[1]);
|
|
554
|
+
try {
|
|
555
|
+
await this.selectAllByCdp();
|
|
553
556
|
await backspace();
|
|
557
|
+
} catch (error) {
|
|
558
|
+
debugPage('clearInput cdp selectAll failed', error);
|
|
559
|
+
throw error;
|
|
560
|
+
} finally{
|
|
561
|
+
debugPage('clearInput end');
|
|
554
562
|
}
|
|
555
|
-
debugPage('clearInput end');
|
|
556
563
|
}
|
|
557
564
|
async moveToPointBeforeScroll(point) {
|
|
558
565
|
if (point) await this.mouse.move(point.left, point.top);
|
|
@@ -630,7 +637,7 @@ class Page {
|
|
|
630
637
|
async stopLoading() {
|
|
631
638
|
debugPage('stop loading');
|
|
632
639
|
if ('puppeteer' === this.interfaceType) {
|
|
633
|
-
const client = await this.
|
|
640
|
+
const client = await this.createPageCdpSession('stopLoading');
|
|
634
641
|
try {
|
|
635
642
|
await client.send('Page.stopLoading');
|
|
636
643
|
} finally{
|
|
@@ -736,17 +743,7 @@ class Page {
|
|
|
736
743
|
const delay = duration / steps;
|
|
737
744
|
const halfStart = startDistance / 2;
|
|
738
745
|
const halfEnd = endDistance / 2;
|
|
739
|
-
|
|
740
|
-
if ('puppeteer' === this.interfaceType) {
|
|
741
|
-
const page = this.underlyingPage;
|
|
742
|
-
client = await page.target().createCDPSession();
|
|
743
|
-
} else {
|
|
744
|
-
if ('playwright' !== this.interfaceType) return;
|
|
745
|
-
const page = this.underlyingPage;
|
|
746
|
-
const browserName = page.context().browser()?.browserType().name();
|
|
747
|
-
if (browserName && 'chromium' !== browserName) throw new Error(`Pinch gesture requires Chromium-based browser, but current browser is "${browserName}". CDP touch events are not supported in Firefox/WebKit.`);
|
|
748
|
-
client = await page.context().newCDPSession(page);
|
|
749
|
-
}
|
|
746
|
+
const client = await this.createPageCdpSession('Pinch gesture');
|
|
750
747
|
try {
|
|
751
748
|
await client.send('Input.dispatchTouchEvent', {
|
|
752
749
|
type: 'touchStart',
|
|
@@ -790,9 +787,9 @@ class Page {
|
|
|
790
787
|
await client.detach();
|
|
791
788
|
}
|
|
792
789
|
}
|
|
793
|
-
async ensurePuppeteerFileChooserSession(
|
|
790
|
+
async ensurePuppeteerFileChooserSession() {
|
|
794
791
|
if (this.puppeteerFileChooserSession) return this.puppeteerFileChooserSession;
|
|
795
|
-
const session = await
|
|
792
|
+
const session = await this.createPageCdpSession('Puppeteer file chooser');
|
|
796
793
|
await session.send('Page.enable');
|
|
797
794
|
await session.send('DOM.enable');
|
|
798
795
|
await session.send('Page.setInterceptFileChooserDialog', {
|
|
@@ -803,8 +800,7 @@ class Page {
|
|
|
803
800
|
}
|
|
804
801
|
async registerFileChooserListener(handler) {
|
|
805
802
|
if ('puppeteer' !== this.interfaceType) throw new Error('registerFileChooserListener is only supported in Puppeteer');
|
|
806
|
-
const
|
|
807
|
-
const session = await this.ensurePuppeteerFileChooserSession(page);
|
|
803
|
+
const session = await this.ensurePuppeteerFileChooserSession();
|
|
808
804
|
if (this.puppeteerFileChooserHandler) session.off('Page.fileChooserOpened', this.puppeteerFileChooserHandler);
|
|
809
805
|
let capturedError;
|
|
810
806
|
this.puppeteerFileChooserHandler = async (event)=>{
|
|
@@ -890,7 +886,10 @@ function forceClosePopup(page, debugProfile) {
|
|
|
890
886
|
}
|
|
891
887
|
});
|
|
892
888
|
}
|
|
889
|
+
const forceSelectRenderingPages = new WeakSet();
|
|
893
890
|
function forceChromeSelectRendering(page) {
|
|
891
|
+
if (forceSelectRenderingPages.has(page)) return;
|
|
892
|
+
forceSelectRenderingPages.add(page);
|
|
894
893
|
const styleContent = `
|
|
895
894
|
/* Add by Midscene because of forceChromeSelectRendering is enabled*/
|
|
896
895
|
select {
|