@moxxy/cli 0.12.0 → 0.12.2

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/sidecar.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'node:module';
3
3
  import * as readline from 'readline';
4
+ import { fileURLToPath } from 'url';
4
5
  import { isIP } from 'net';
5
6
  import { lookup } from 'dns/promises';
6
7
  import { spawn } from 'child_process';
@@ -77,16 +78,33 @@ async function assertPublicUrl(raw, label = "request") {
77
78
  }
78
79
  return addrs;
79
80
  }
81
+
82
+ // ../plugin-browser/src/sidecar/types.ts
83
+ function errMsg(err) {
84
+ return err instanceof Error ? err.message : String(err);
85
+ }
86
+ var SidecarError = class extends Error {
87
+ constructor(message, kind) {
88
+ super(message);
89
+ this.kind = kind;
90
+ this.name = "SidecarError";
91
+ }
92
+ kind;
93
+ };
94
+ function badParams(msg) {
95
+ return new SidecarError(msg, "runtime");
96
+ }
97
+
98
+ // ../plugin-browser/src/sidecar/install.ts
80
99
  async function importPlaywright() {
81
100
  try {
82
101
  return await import('playwright');
83
102
  } catch (err) {
84
- const e = new Error(
103
+ throw new SidecarError(
85
104
  `Playwright is not installed. Run \`pnpm add playwright\` (or \`npm i playwright\`) and then \`npx playwright install\` in the moxxy install dir.
86
- Underlying: ${err instanceof Error ? err.message : String(err)}`
105
+ Underlying: ${err instanceof Error ? err.message : String(err)}`,
106
+ "init"
87
107
  );
88
- e.kind = "init";
89
- throw e;
90
108
  }
91
109
  }
92
110
  async function launchWithAutoInstall(browserType, which, headless) {
@@ -102,11 +120,10 @@ async function launchWithAutoInstall(browserType, which, headless) {
102
120
  await runPlaywrightInstall(which);
103
121
  } catch (installErr) {
104
122
  const msg = installErr instanceof Error ? installErr.message : String(installErr);
105
- const e = new Error(
106
- `Playwright browser auto-install failed: ${msg}. Run \`npx playwright install ${which}\` manually in the moxxy dir.`
123
+ throw new SidecarError(
124
+ `Playwright browser auto-install failed: ${msg}. Run \`npx playwright install ${which}\` manually in the moxxy dir.`,
125
+ "init"
107
126
  );
108
- e.kind = "init";
109
- throw e;
110
127
  }
111
128
  process.stderr.write(`moxxy-browser: install complete, retrying launch
112
129
  `);
@@ -160,16 +177,6 @@ function runPlaywrightInstall(which) {
160
177
  });
161
178
  }
162
179
 
163
- // ../plugin-browser/src/sidecar/types.ts
164
- function errMsg(err) {
165
- return err instanceof Error ? err.message : String(err);
166
- }
167
- function badParams(msg) {
168
- const e = new Error(msg);
169
- e.kind = "runtime";
170
- return e;
171
- }
172
-
173
180
  // ../plugin-browser/src/sidecar/dispatch.ts
174
181
  async function ensurePlaywright(state2, opts) {
175
182
  if (state2.handle) return state2.handle;
@@ -182,7 +189,6 @@ async function ensurePlaywright(state2, opts) {
182
189
  return state2.handle;
183
190
  }
184
191
  async function teardown(state2) {
185
- await stopScreencast(state2);
186
192
  if (!state2.handle) return;
187
193
  try {
188
194
  await state2.handle.context.close();
@@ -191,27 +197,14 @@ async function teardown(state2) {
191
197
  }
192
198
  state2.handle = null;
193
199
  }
194
- async function stopScreencast(state2) {
195
- if (!state2.cdp) return;
196
- try {
197
- await state2.cdp.send("Page.stopScreencast");
198
- } catch {
199
- }
200
- try {
201
- await state2.cdp.detach();
202
- } catch {
203
- }
204
- state2.cdp = null;
205
- }
206
200
  async function dispatch(state2, req) {
207
201
  try {
208
202
  return await dispatchInner(state2, req);
209
203
  } catch (err) {
210
- const kind = err.kind;
211
204
  return {
212
205
  id: req.id,
213
206
  ok: false,
214
- error: { message: errMsg(err), kind: kind ?? "unknown" }
207
+ error: { message: errMsg(err), kind: err instanceof SidecarError ? err.kind : "unknown" }
215
208
  };
216
209
  }
217
210
  }
@@ -309,37 +302,6 @@ async function dispatchInner(state2, req) {
309
302
  await h.page.mouse.wheel(0, dy ?? 0);
310
303
  return { id: req.id, ok: true };
311
304
  }
312
- case "startScreencast": {
313
- const h = await ensurePlaywright(state2, {});
314
- if (state2.cdp) return { id: req.id, ok: true, result: { url: h.page.url() } };
315
- if (!h.context.newCDPSession) {
316
- return {
317
- id: req.id,
318
- ok: false,
319
- error: { message: "screencast requires Chromium (CDP unavailable)", kind: "runtime" }
320
- };
321
- }
322
- const client = await h.context.newCDPSession(h.page);
323
- state2.cdp = client;
324
- client.on("Page.screencastFrame", (params) => {
325
- const p = params;
326
- state2.emit?.({ event: "screencastFrame", data: p.data, url: h.page.url() });
327
- void client.send("Page.screencastAck", { sessionId: p.sessionId }).catch(() => void 0);
328
- });
329
- const { maxWidth, maxHeight } = req.params ?? {};
330
- await client.send("Page.startScreencast", {
331
- format: "jpeg",
332
- quality: 50,
333
- maxWidth: maxWidth ?? 1280,
334
- maxHeight: maxHeight ?? 800,
335
- everyNthFrame: 1
336
- });
337
- return { id: req.id, ok: true, result: { url: h.page.url() } };
338
- }
339
- case "stopScreencast": {
340
- await stopScreencast(state2);
341
- return { id: req.id, ok: true };
342
- }
343
305
  case "eval": {
344
306
  const h = await ensurePlaywright(state2, {});
345
307
  const { expression } = req.params ?? {};
@@ -404,33 +366,39 @@ function startParentWatchdog() {
404
366
  interval.unref?.();
405
367
  }
406
368
  var queue = Promise.resolve();
369
+ function enqueueLine(line, out) {
370
+ if (!line.trim()) return queue;
371
+ let req;
372
+ try {
373
+ req = JSON.parse(line);
374
+ } catch {
375
+ out({ id: "unknown", ok: false, error: { message: "invalid JSON", kind: "runtime" } });
376
+ return queue;
377
+ }
378
+ if (!req.id || !req.method) {
379
+ out({
380
+ id: req.id ?? "unknown",
381
+ ok: false,
382
+ error: { message: "request requires { id, method }", kind: "runtime" }
383
+ });
384
+ return queue;
385
+ }
386
+ queue = queue.then(async () => {
387
+ const reply = await dispatch(state, req);
388
+ out(reply);
389
+ }).catch((err) => {
390
+ try {
391
+ out({ id: req.id, ok: false, error: { message: errMsg(err), kind: "runtime" } });
392
+ } catch {
393
+ }
394
+ });
395
+ return queue;
396
+ }
407
397
  async function main() {
408
398
  startParentWatchdog();
409
- state.emit = (event) => {
410
- process.stdout.write(JSON.stringify(event) + "\n");
411
- };
412
399
  const rl = readline.createInterface({ input: process.stdin });
413
400
  rl.on("line", (line) => {
414
- if (!line.trim()) return;
415
- let req;
416
- try {
417
- req = JSON.parse(line);
418
- } catch {
419
- write({ id: "unknown", ok: false, error: { message: "invalid JSON", kind: "runtime" } });
420
- return;
421
- }
422
- if (!req.id || !req.method) {
423
- write({
424
- id: req.id ?? "unknown",
425
- ok: false,
426
- error: { message: "request requires { id, method }", kind: "runtime" }
427
- });
428
- return;
429
- }
430
- queue = queue.then(async () => {
431
- const reply = await dispatch(state, req);
432
- write(reply);
433
- });
401
+ void enqueueLine(line, write);
434
402
  });
435
403
  rl.once("close", () => {
436
404
  void shutdownAndExit(0);
@@ -441,10 +409,14 @@ async function main() {
441
409
  }
442
410
  });
443
411
  }
444
- main().catch((err) => {
445
- process.stderr.write(`sidecar fatal: ${errMsg(err)}
412
+ if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
413
+ main().catch((err) => {
414
+ process.stderr.write(`sidecar fatal: ${errMsg(err)}
446
415
  `);
447
- void shutdownAndExit(1);
448
- });
416
+ void shutdownAndExit(1);
417
+ });
418
+ }
419
+
420
+ export { enqueueLine };
449
421
  //# sourceMappingURL=sidecar.js.map
450
422
  //# sourceMappingURL=sidecar.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../plugin-browser/src/ssrf-guard.ts","../../plugin-browser/src/sidecar/install.ts","../../plugin-browser/src/sidecar/types.ts","../../plugin-browser/src/sidecar/dispatch.ts","../../plugin-browser/src/sidecar.ts"],"names":["dnsLookup","state","text"],"mappings":"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","file":"sidecar.js","sourcesContent":["import { isIP } from 'node:net';\nimport { lookup as dnsLookup } from 'node:dns/promises';\n\n/**\n * Shared SSRF guard for every model-drivable navigation/fetch path in this\n * plugin: `web_fetch` (initial URL + every redirect hop), `browser_session`'s\n * goto (parent side), the sidecar's goto dispatch (child-process side), and\n * the sidecar's in-page navigation interceptor.\n *\n * Blocks non-HTTP(S) schemes, loopback (incl. `localhost`/`*.localhost`),\n * 0.0.0.0/8, RFC-1918 private ranges, link-local 169.254/16 (incl. the\n * 169.254.169.254 cloud metadata endpoint), CGNAT 100.64/10, multicast/\n * reserved, and IPv6 loopback/link-local/unique-local (+ v4-mapped). Hostnames\n * are resolved so an internal DNS name (or rebinding) can't smuggle a private\n * target past the literal-IP checks.\n *\n * NOTE: deliberately NO `@moxxy/sdk` import. The Playwright sidecar — a\n * separate child process whose bundle must stay free of non-builtin deps —\n * imports this module too. Parent-side callers wrap `SsrfBlockedError` into\n * `MoxxyError` themselves.\n */\n\n/** Thrown for every guard rejection (bad scheme, private/loopback target, unparseable URL). */\nexport class SsrfBlockedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'SsrfBlockedError';\n }\n}\n\nexport type DnsResolver = (host: string) => Promise<ReadonlyArray<string>>;\nconst defaultResolver: DnsResolver = async (host) =>\n (await dnsLookup(host, { all: true })).map((a) => a.address);\nlet resolver: DnsResolver = defaultResolver;\n\n/** Test seam: override DNS resolution so SSRF tests stay hermetic. Pass null to reset. */\nexport function setSsrfDnsResolver(fn: DnsResolver | null): void {\n resolver = fn ?? defaultResolver;\n}\n\nfunction isBlockedIpv4(ip: string): boolean {\n const parts = ip.split('.').map((p) => Number(p));\n if (parts.length !== 4 || parts.some((p) => !Number.isInteger(p) || p < 0 || p > 255)) return true;\n const [a, b] = parts as [number, number, number, number];\n if (a === 0) return true; // 0.0.0.0/8 \"this host\"\n if (a === 127) return true; // loopback\n if (a === 10) return true; // private\n if (a === 172 && b >= 16 && b <= 31) return true; // private\n if (a === 192 && b === 168) return true; // private\n if (a === 169 && b === 254) return true; // link-local incl. 169.254.169.254 metadata\n if (a === 100 && b >= 64 && b <= 127) return true; // CGNAT 100.64/10\n if (a >= 224) return true; // multicast / reserved\n return false;\n}\n\nfunction isBlockedIpv6(ip: string): boolean {\n const addr = ip.toLowerCase().replace(/^\\[|\\]$/g, '').split('%')[0]!; // strip zone id\n if (addr === '::1' || addr === '::') return true; // loopback / unspecified\n if (addr.startsWith('fe80')) return true; // link-local\n if (addr.startsWith('fc') || addr.startsWith('fd')) return true; // unique-local fc00::/7\n const v4mapped = addr.match(/^::ffff:(\\d+\\.\\d+\\.\\d+\\.\\d+)$/);\n if (v4mapped) return isBlockedIpv4(v4mapped[1]!);\n return false;\n}\n\nexport function isBlockedIp(ip: string): boolean {\n const kind = isIP(ip);\n if (kind === 4) return isBlockedIpv4(ip);\n if (kind === 6) return isBlockedIpv6(ip);\n return true; // not a parseable IP → block\n}\n\n/**\n * Reject `raw` unless it is an http(s) URL whose host is (and resolves to)\n * a public address. `label` prefixes the error message so each caller's\n * rejections stay attributable (e.g. \"web_fetch\", \"browser_session\").\n *\n * Returns the vetted resolved addresses so callers can PIN the subsequent\n * connection to exactly what was checked (closing the DNS-rebinding TOCTOU\n * where the guard resolves one answer and the fetch independently resolves\n * another — see web-fetch's pinned undici dispatcher). Returns `null` when\n * there is nothing to pin: the host is already an IP literal (vetted above,\n * no DNS involved) or resolution failed (fail-open — a name the guard can't\n * resolve, the fetch's identical system resolver can't reach either).\n */\nexport async function assertPublicUrl(\n raw: string,\n label = 'request',\n): Promise<ReadonlyArray<string> | null> {\n let u: URL;\n try {\n u = new URL(raw);\n } catch {\n throw new SsrfBlockedError(`${label}: invalid URL: ${raw}`);\n }\n if (u.protocol !== 'http:' && u.protocol !== 'https:') {\n throw new SsrfBlockedError(`${label}: refusing non-HTTP(S) scheme \"${u.protocol}\"`);\n }\n const host = u.hostname.replace(/^\\[|\\]$/g, '');\n if (host === 'localhost' || host.endsWith('.localhost')) {\n throw new SsrfBlockedError(`${label}: refusing to fetch loopback host \"${host}\"`);\n }\n if (isIP(host)) {\n if (isBlockedIp(host))\n throw new SsrfBlockedError(`${label}: refusing private/loopback address \"${host}\"`);\n return null;\n }\n // Resolve the name and block if it maps to a private range (internal name or\n // DNS rebinding). Fail OPEN on resolution error: a name we can't resolve here\n // the subsequent fetch can't reach either, so it's no SSRF vector.\n let addrs: ReadonlyArray<string>;\n try {\n addrs = await resolver(host);\n } catch {\n return null;\n }\n for (const addr of addrs) {\n if (isBlockedIp(addr)) {\n throw new SsrfBlockedError(\n `${label}: host \"${host}\" resolves to a private/loopback address (${addr})`,\n );\n }\n }\n return addrs;\n}\n","/**\n * Playwright lifecycle: import, launch, and one-shot auto-install of the\n * per-browser binary. Keeps the dispatch layer free of node:child_process\n * + Playwright-import noise.\n */\n\nimport { spawn } from 'node:child_process';\nimport { assertPublicUrl } from '../ssrf-guard.js';\nimport type { BrowserKind, BrowserType, PageHandle, PlaywrightHandle } from './types.js';\n\nexport interface LaunchResult {\n handle: PlaywrightHandle;\n /** Set when the browser binary was auto-downloaded during this launch. */\n installNotice: string | null;\n}\n\nexport async function importPlaywright(): Promise<{\n chromium: BrowserType;\n firefox: BrowserType;\n webkit: BrowserType;\n}> {\n try {\n return (await import('playwright')) as never;\n } catch (err) {\n const e = new Error(\n `Playwright is not installed. Run \\`pnpm add playwright\\` (or \\`npm i playwright\\`) and then \\`npx playwright install\\` in the moxxy install dir.\\n` +\n `Underlying: ${err instanceof Error ? err.message : String(err)}`,\n );\n (e as Error & { kind?: string }).kind = 'init';\n throw e;\n }\n}\n\n/**\n * Try to launch the browser. If the binary isn't downloaded yet\n * (Playwright distinguishes the npm install from the per-browser\n * binary download), run `npx playwright install <which>` once and\n * retry. The install can take 30s–2min on the first run depending on\n * connection; we surface progress on stderr (parent forwards to the\n * logger) and return a one-shot notice for the first tool response.\n */\nexport async function launchWithAutoInstall(\n browserType: BrowserType,\n which: BrowserKind,\n headless: boolean,\n): Promise<LaunchResult> {\n try {\n return { handle: await launchOnce(browserType, headless), installNotice: null };\n } catch (err) {\n if (!isMissingBrowserError(err)) throw err;\n process.stderr.write(\n `moxxy-browser: ${which} binary missing, running \\`npx playwright install ${which}\\` ` +\n `(one-time, ~150MB). This may take a minute…\\n`,\n );\n try {\n await runPlaywrightInstall(which);\n } catch (installErr) {\n const msg = installErr instanceof Error ? installErr.message : String(installErr);\n const e = new Error(\n `Playwright browser auto-install failed: ${msg}. ` +\n `Run \\`npx playwright install ${which}\\` manually in the moxxy dir.`,\n );\n (e as Error & { kind?: string }).kind = 'init';\n throw e;\n }\n process.stderr.write(`moxxy-browser: install complete, retrying launch\\n`);\n return {\n handle: await launchOnce(browserType, headless),\n installNotice: `Auto-installed Playwright ${which} browser (~150MB, one-time).`,\n };\n }\n}\n\nasync function launchOnce(browserType: BrowserType, headless: boolean): Promise<PlaywrightHandle> {\n const browser = await browserType.launch({ headless });\n const context = (await browser.newContext()) as PlaywrightHandle['context'];\n await installNavigationSsrfGuard(context);\n const page = (await context.newPage()) as unknown as PageHandle;\n return { browser, context, page };\n}\n\n/**\n * Block navigations to private/loopback origins for the lifetime of the\n * context. The goto RPC is validated in the parent AND in dispatch, but a\n * page reached via a legitimate public goto can then redirect or\n * script-navigate itself to e.g. http://169.254.169.254/ — those navigations\n * never pass through the RPC layer, so we intercept them here. Navigation\n * requests (top-level + iframes, which covers HTTP redirect hops too) go\n * through the same `assertPublicUrl` guard as web_fetch; everything else is\n * passed through untouched so ordinary page loads don't pay a DNS round-trip\n * per subresource.\n *\n * Residual risk (also stated in the browser_session tool description):\n * SUBRESOURCE requests (img/fetch/script) from a loaded page are NOT\n * filtered. The browser's same-origin policy stops the page reading those\n * responses, but blind request side effects against internal services remain\n * possible. Filtering every request was judged disproportionate for now.\n */\nasync function installNavigationSsrfGuard(context: PlaywrightHandle['context']): Promise<void> {\n if (typeof context.route !== 'function') return; // loose projection: tolerate stubs without route()\n await context.route('**/*', async (route) => {\n const request = route.request();\n if (!request.isNavigationRequest()) return route.continue();\n try {\n await assertPublicUrl(request.url(), 'browser_session navigation');\n } catch {\n return route.abort('blockedbyclient');\n }\n return route.continue();\n });\n}\n\nfunction isMissingBrowserError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n // Playwright's \"Executable doesn't exist at …\" launch error fires\n // when the npm package is installed but the per-browser binary\n // hasn't been downloaded. The message stays stable across versions.\n return /Executable doesn'?t exist at/i.test(err.message);\n}\n\n/**\n * Run `npx playwright install <which>` and stream its output to the\n * sidecar's stderr so the operator can watch progress. Resolves on\n * exit-0; rejects with the tail of stderr otherwise.\n */\nfunction runPlaywrightInstall(which: BrowserKind): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn('npx', ['playwright', 'install', which], {\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let stderrTail = '';\n child.stdout.on('data', (chunk: Buffer) => process.stderr.write(chunk));\n child.stderr.on('data', (chunk: Buffer) => {\n process.stderr.write(chunk);\n stderrTail += chunk.toString('utf8');\n if (stderrTail.length > 4000) stderrTail = stderrTail.slice(-4000);\n });\n child.once('error', (err) => reject(err));\n child.once('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error(`exit ${code}: ${stderrTail.trim() || '(no stderr)'}`));\n });\n });\n}\n","export type BrowserKind = 'chromium' | 'firefox' | 'webkit';\n\nexport type ErrorKind = 'init' | 'navigation' | 'runtime' | 'timeout' | 'unknown';\n\nexport interface Req {\n readonly id: string;\n readonly method: string;\n readonly params?: Record<string, unknown>;\n}\n\nexport interface Ok {\n readonly id: string;\n readonly ok: true;\n readonly result?: unknown;\n /** One-shot human-readable note (e.g. \"Auto-installed Chromium\"). */\n readonly notice?: string;\n}\n\nexport interface Err {\n readonly id: string;\n readonly ok: false;\n readonly error: { message: string; kind: ErrorKind };\n}\n\nexport type Reply = Ok | Err;\n\nexport interface BrowserType {\n launch(opts: {\n headless: boolean;\n }): Promise<{ close(): Promise<void>; newContext(): Promise<unknown> }>;\n}\n\nexport interface PageHandle {\n goto(url: string, opts?: unknown): Promise<unknown>;\n click(selector: string, opts?: unknown): Promise<void>;\n fill(selector: string, value: string, opts?: unknown): Promise<void>;\n textContent(selector: string): Promise<string | null>;\n content(): Promise<string>;\n screenshot(opts?: unknown): Promise<Buffer>;\n evaluate(fn: string): Promise<unknown>;\n url(): string;\n close(): Promise<void>;\n // Coordinate-based input for the live browser surface (loosely typed — the\n // real Playwright Page provides all of these).\n viewportSize(): { width: number; height: number } | null;\n readonly mouse: {\n click(x: number, y: number, opts?: unknown): Promise<void>;\n wheel(dx: number, dy: number): Promise<void>;\n };\n readonly keyboard: {\n press(key: string): Promise<void>;\n type(text: string): Promise<void>;\n };\n}\n\n/** Minimal slice of Playwright's `Request` used by the navigation SSRF guard. */\nexport interface RouteRequest {\n url(): string;\n isNavigationRequest(): boolean;\n}\n\n/** Minimal slice of Playwright's `Route` used by the navigation SSRF guard. */\nexport interface RouteHandle {\n request(): RouteRequest;\n abort(errorCode?: string): Promise<void>;\n continue(): Promise<void>;\n}\n\n/** Minimal slice of a Chrome DevTools Protocol session (Playwright's\n * `CDPSession`) — used for the live browser-surface screencast. */\nexport interface CDPSession {\n send(method: string, params?: Record<string, unknown>): Promise<unknown>;\n on(event: string, handler: (params: unknown) => void): void;\n detach(): Promise<void>;\n}\n\nexport interface PlaywrightHandle {\n // Loosely typed so we can avoid importing the playwright types at compile time —\n // they're an optional peer dependency.\n readonly browser: { close(): Promise<void> };\n readonly context: {\n newPage(): Promise<unknown>;\n close(): Promise<void>;\n /** Optional because the type is a loose projection; real Playwright contexts always have it. */\n route?(pattern: string, handler: (route: RouteHandle) => Promise<void> | void): Promise<void>;\n /** Chromium-only CDP session for screencast (the live browser surface). */\n newCDPSession?(page: PageHandle): Promise<CDPSession>;\n };\n readonly page: PageHandle;\n}\n\nexport function errMsg(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nexport function badParams(msg: string): Error {\n const e = new Error(msg);\n (e as Error & { kind?: string }).kind = 'runtime';\n return e;\n}\n","/**\n * JSON-RPC dispatch table for the sidecar. Each `method` here corresponds\n * one-to-one with the wire-format methods documented in `sidecar.ts`.\n */\n\nimport { assertPublicUrl } from '../ssrf-guard.js';\nimport { importPlaywright, launchWithAutoInstall } from './install.js';\nimport {\n badParams,\n errMsg,\n type BrowserKind,\n type CDPSession,\n type Err,\n type PlaywrightHandle,\n type Reply,\n type Req,\n} from './types.js';\n\nexport interface SidecarState {\n handle: PlaywrightHandle | null;\n /**\n * Set after a successful auto-install of browser binaries so the next\n * tool result can carry a `notice` letting the user/model know the\n * one-time download happened. Cleared once the notice has been\n * delivered (handed to the reply once, then forgotten).\n */\n pendingInstallNotice: string | null;\n /**\n * Emit an unsolicited event line to the parent (no `id`). Set by the sidecar\n * main loop; used to push `screencastFrame` events for the live browser\n * surface. Undefined in unit tests that call `dispatch` directly.\n */\n emit?: (event: Record<string, unknown>) => void;\n /** Active CDP screencast session, when the browser surface is open. */\n cdp?: CDPSession | null;\n}\n\nasync function ensurePlaywright(\n state: SidecarState,\n opts: { browser?: BrowserKind; headless?: boolean },\n): Promise<PlaywrightHandle> {\n if (state.handle) return state.handle;\n const pw = await importPlaywright();\n const which = opts.browser ?? 'chromium';\n const browserType = pw[which];\n const { handle, installNotice } = await launchWithAutoInstall(browserType, which, opts.headless ?? true);\n state.handle = handle;\n if (installNotice) state.pendingInstallNotice = installNotice;\n return state.handle;\n}\n\nexport async function teardown(state: SidecarState): Promise<void> {\n await stopScreencast(state);\n if (!state.handle) return;\n try {\n await state.handle.context.close();\n await state.handle.browser.close();\n } catch {\n /* ignore */\n }\n state.handle = null;\n}\n\nasync function stopScreencast(state: SidecarState): Promise<void> {\n if (!state.cdp) return;\n try {\n await state.cdp.send('Page.stopScreencast');\n } catch {\n /* page may already be gone */\n }\n try {\n await state.cdp.detach();\n } catch {\n /* ignore */\n }\n state.cdp = null;\n}\n\nexport async function dispatch(state: SidecarState, req: Req): Promise<Reply> {\n try {\n return await dispatchInner(state, req);\n } catch (err) {\n const kind = (err as Error & { kind?: string }).kind;\n return {\n id: req.id,\n ok: false,\n error: { message: errMsg(err), kind: (kind as Err['error']['kind']) ?? 'unknown' },\n };\n }\n}\n\nasync function dispatchInner(state: SidecarState, req: Req): Promise<Reply> {\n switch (req.method) {\n case 'init': {\n const opts = (req.params ?? {}) as { browser?: BrowserKind; headless?: boolean };\n await ensurePlaywright(state, opts);\n return { id: req.id, ok: true, result: { ready: true } };\n }\n case 'goto': {\n const { url, waitUntil, timeoutMs } = (req.params ?? {}) as {\n url: string;\n waitUntil?: 'load' | 'domcontentloaded' | 'networkidle';\n timeoutMs?: number;\n };\n if (!url) throw badParams('url is required');\n // Defence-in-depth: the parent already runs the full SSRF guard before\n // sending this RPC, but the sidecar is a distinct process driven over\n // JSON-RPC, so re-check here rather than trust the caller to have\n // validated. Blocks file:// / javascript: schemes AND loopback/private/\n // link-local (incl. 169.254.169.254 metadata)/CGNAT targets, resolving\n // hostnames. Runs BEFORE ensurePlaywright so a blocked URL never\n // launches (or auto-installs) a browser.\n try {\n await assertPublicUrl(url, 'goto');\n } catch (err) {\n return { id: req.id, ok: false, error: { message: errMsg(err), kind: 'navigation' } };\n }\n const h = await ensurePlaywright(state, {});\n try {\n await h.page.goto(url, { waitUntil: waitUntil ?? 'domcontentloaded', timeout: timeoutMs ?? 30_000 });\n } catch (err) {\n return { id: req.id, ok: false, error: { message: errMsg(err), kind: 'navigation' } };\n }\n return { id: req.id, ok: true, result: { url: h.page.url() } };\n }\n case 'click': {\n const h = await ensurePlaywright(state, {});\n const { selector, timeoutMs } = (req.params ?? {}) as { selector: string; timeoutMs?: number };\n if (!selector) throw badParams('selector is required');\n await h.page.click(selector, { timeout: timeoutMs ?? 10_000 });\n return { id: req.id, ok: true };\n }\n case 'fill': {\n const h = await ensurePlaywright(state, {});\n const { selector, value, timeoutMs } = (req.params ?? {}) as {\n selector: string;\n value: string;\n timeoutMs?: number;\n };\n if (!selector) throw badParams('selector is required');\n await h.page.fill(selector, value ?? '', { timeout: timeoutMs ?? 10_000 });\n return { id: req.id, ok: true };\n }\n case 'text': {\n const h = await ensurePlaywright(state, {});\n const { selector } = (req.params ?? {}) as { selector?: string };\n if (selector) {\n const text = await h.page.textContent(selector);\n return { id: req.id, ok: true, result: text ?? '' };\n }\n // Whole-document text via evaluate\n const text = (await h.page.evaluate('document.body ? document.body.innerText : \"\"')) as string;\n return { id: req.id, ok: true, result: text };\n }\n case 'html': {\n const h = await ensurePlaywright(state, {});\n const html = await h.page.content();\n return { id: req.id, ok: true, result: html };\n }\n case 'screenshot': {\n const h = await ensurePlaywright(state, {});\n const { fullPage } = (req.params ?? {}) as { fullPage?: boolean };\n const buf = await h.page.screenshot({ fullPage: fullPage ?? false });\n return { id: req.id, ok: true, result: { mediaType: 'image/png', base64: buf.toString('base64') } };\n }\n case 'frame': {\n // Combined live-view frame for the browser SURFACE: a JPEG screenshot\n // plus the current url + viewport size, so the renderer can map clicks\n // back onto the page. One round-trip per frame.\n const h = await ensurePlaywright(state, {});\n const buf = await h.page.screenshot({ type: 'jpeg', quality: 55 });\n const vp = h.page.viewportSize() ?? { width: 1280, height: 720 };\n return {\n id: req.id,\n ok: true,\n result: {\n mediaType: 'image/jpeg',\n base64: buf.toString('base64'),\n url: h.page.url(),\n width: vp.width,\n height: vp.height,\n },\n };\n }\n case 'mouse': {\n const h = await ensurePlaywright(state, {});\n const { x, y } = (req.params ?? {}) as { x: number; y: number };\n await h.page.mouse.click(x, y);\n return { id: req.id, ok: true, result: { url: h.page.url() } };\n }\n case 'key': {\n const h = await ensurePlaywright(state, {});\n const { key } = (req.params ?? {}) as { key: string };\n if (!key) throw badParams('key is required');\n // A single printable char is typed (inserts it); a named key is pressed.\n if (key.length === 1) await h.page.keyboard.type(key);\n else await h.page.keyboard.press(key);\n return { id: req.id, ok: true };\n }\n case 'scroll': {\n const h = await ensurePlaywright(state, {});\n const { dy } = (req.params ?? {}) as { dy: number };\n await h.page.mouse.wheel(0, dy ?? 0);\n return { id: req.id, ok: true };\n }\n case 'startScreencast': {\n // Push live JPEG frames over CDP (`Page.screencastFrame`) for the browser\n // SURFACE — far smoother than polling screenshots. Chromium-only.\n const h = await ensurePlaywright(state, {});\n if (state.cdp) return { id: req.id, ok: true, result: { url: h.page.url() } };\n if (!h.context.newCDPSession) {\n return {\n id: req.id,\n ok: false,\n error: { message: 'screencast requires Chromium (CDP unavailable)', kind: 'runtime' },\n };\n }\n const client = await h.context.newCDPSession(h.page);\n state.cdp = client;\n client.on('Page.screencastFrame', (params) => {\n const p = params as { data: string; sessionId: number };\n state.emit?.({ event: 'screencastFrame', data: p.data, url: h.page.url() });\n // Ack so Chromium keeps streaming (it pauses without an ack).\n void client.send('Page.screencastAck', { sessionId: p.sessionId }).catch(() => undefined);\n });\n const { maxWidth, maxHeight } = (req.params ?? {}) as { maxWidth?: number; maxHeight?: number };\n await client.send('Page.startScreencast', {\n format: 'jpeg',\n quality: 50,\n maxWidth: maxWidth ?? 1280,\n maxHeight: maxHeight ?? 800,\n everyNthFrame: 1,\n });\n return { id: req.id, ok: true, result: { url: h.page.url() } };\n }\n case 'stopScreencast': {\n await stopScreencast(state);\n return { id: req.id, ok: true };\n }\n case 'eval': {\n const h = await ensurePlaywright(state, {});\n const { expression } = (req.params ?? {}) as { expression: string };\n if (!expression) throw badParams('expression is required');\n const value = await h.page.evaluate(expression);\n return { id: req.id, ok: true, result: value };\n }\n case 'url': {\n const h = await ensurePlaywright(state, {});\n return { id: req.id, ok: true, result: h.page.url() };\n }\n case 'close': {\n await teardown(state);\n return { id: req.id, ok: true };\n }\n default:\n return {\n id: req.id,\n ok: false,\n error: { message: `unknown method: ${req.method}`, kind: 'runtime' },\n };\n }\n}\n","#!/usr/bin/env node\n/**\n * Playwright sidecar — owns a single browser context. Speaks newline-delimited\n * JSON-RPC over stdio so the parent (`browser_session` tool) doesn't load\n * Playwright into its own process. Crash isolation, lazy install: the parent\n * only spawns this when the heavy tier is actually needed.\n *\n * Wire format (one line per message):\n * { \"id\": \"uuid\", \"method\": \"goto\"|\"click\"|\"fill\"|\"text\"|\"html\"|\"screenshot\"|\"eval\"|\"close\", \"params\": {...} }\n * { \"id\": \"uuid\", \"ok\": true, \"result\": ... }\n * { \"id\": \"uuid\", \"ok\": false, \"error\": { \"message\": \"...\", \"kind\": \"init\"|\"navigation\"|\"runtime\"|\"timeout\" } }\n *\n * Run with `node dist/sidecar.js` (the package's `bin` entry is\n * `moxxy-browser-sidecar`). Parent terminates by closing stdin or sending\n * `{method:'close'}`.\n */\n\nimport * as readline from 'node:readline';\nimport { dispatch, teardown, type SidecarState } from './sidecar/dispatch.js';\nimport { errMsg, type Reply, type Req } from './sidecar/types.js';\n\nconst state: SidecarState = { handle: null, pendingInstallNotice: null };\n\nfunction write(reply: Reply): void {\n // Drain the install-notice flag into the first reply that goes out\n // after the install completed, then clear it. Errors get the notice\n // too — sometimes the launch retry surfaces a different problem and\n // the user still wants to know we tried to install.\n if (state.pendingInstallNotice) {\n if (reply.ok) {\n reply = { ...reply, notice: state.pendingInstallNotice };\n } else {\n reply = {\n ...reply,\n error: {\n ...reply.error,\n message: `${state.pendingInstallNotice} Then: ${reply.error.message}`,\n },\n };\n }\n state.pendingInstallNotice = null;\n }\n process.stdout.write(JSON.stringify(reply) + '\\n');\n}\n\n/**\n * Tears down the browser context AND exits the process. Used both by\n * the explicit `close` RPC path and the parent-loss / stdin-close\n * paths so all cleanup goes through one routine.\n */\nasync function shutdownAndExit(code: number): Promise<void> {\n await teardown(state);\n process.exit(code);\n}\n\n/**\n * Parent watchdog: if the moxxy process that spawned this sidecar\n * disappears (crash, SIGKILL, terminal hangup), there's no stdin EOF\n * to rely on — orphan Chromium would keep running and chew CPU/memory\n * until the user notices. Poll the parent PID every few seconds and\n * self-terminate when it goes away.\n *\n * `process.kill(pid, 0)` is the POSIX trick for \"does this PID\n * exist?\" — no signal is actually delivered. Throws ESRCH when the\n * process is gone (or EPERM when it exists but we can't signal it —\n * still alive, so don't treat as gone).\n */\nfunction startParentWatchdog(): void {\n const parentPid = process.ppid;\n if (!parentPid || parentPid <= 1) return; // already orphaned (init), nothing to watch\n const interval = setInterval(() => {\n try {\n process.kill(parentPid, 0);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ESRCH') {\n clearInterval(interval);\n void shutdownAndExit(0);\n }\n // EPERM means the process exists but we can't signal it — still alive.\n }\n }, 2000);\n interval.unref?.(); // never block the event loop from exiting\n}\n\nlet queue: Promise<void> = Promise.resolve();\n\nasync function main(): Promise<void> {\n startParentWatchdog();\n // Lets dispatch handlers push unsolicited event lines (no `id`) — the live\n // browser surface's screencast frames ride this channel.\n state.emit = (event) => {\n process.stdout.write(JSON.stringify(event) + '\\n');\n };\n const rl = readline.createInterface({ input: process.stdin });\n rl.on('line', (line) => {\n if (!line.trim()) return;\n let req: Req;\n try {\n req = JSON.parse(line) as Req;\n } catch {\n write({ id: 'unknown', ok: false, error: { message: 'invalid JSON', kind: 'runtime' } });\n return;\n }\n if (!req.id || !req.method) {\n write({\n id: req.id ?? 'unknown',\n ok: false,\n error: { message: 'request requires { id, method }', kind: 'runtime' },\n });\n return;\n }\n // Sequentially serve requests on the single page. Parent can pipeline by\n // sending more requests; we serialize them inside the sidecar so a goto\n // doesn't race a click.\n queue = queue.then(async () => {\n const reply = await dispatch(state, req);\n write(reply);\n });\n });\n rl.once('close', () => {\n void shutdownAndExit(0);\n });\n // Defensive: if our stdout pipe breaks (parent died mid-write), Node\n // would otherwise throw an uncaught EPIPE on the next write. Treat\n // it as a signal to clean up gracefully instead.\n process.stdout.on('error', (err) => {\n if ((err as NodeJS.ErrnoException).code === 'EPIPE') {\n void shutdownAndExit(0);\n }\n });\n}\n\nmain().catch((err) => {\n process.stderr.write(`sidecar fatal: ${errMsg(err)}\\n`);\n void shutdownAndExit(1);\n});\n"]}
1
+ {"version":3,"sources":["../../plugin-browser/src/ssrf-guard.ts","../../plugin-browser/src/sidecar/types.ts","../../plugin-browser/src/sidecar/install.ts","../../plugin-browser/src/sidecar/dispatch.ts","../../plugin-browser/src/sidecar.ts"],"names":["dnsLookup","state","text"],"mappings":"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","file":"sidecar.js","sourcesContent":["import { isIP } from 'node:net';\nimport { lookup as dnsLookup } from 'node:dns/promises';\n\n/**\n * Shared SSRF guard for every model-drivable navigation/fetch path in this\n * plugin: `web_fetch` (initial URL + every redirect hop), `browser_session`'s\n * goto (parent side), the sidecar's goto dispatch (child-process side), and\n * the sidecar's in-page navigation interceptor.\n *\n * Blocks non-HTTP(S) schemes, loopback (incl. `localhost`/`*.localhost`),\n * 0.0.0.0/8, RFC-1918 private ranges, link-local 169.254/16 (incl. the\n * 169.254.169.254 cloud metadata endpoint), CGNAT 100.64/10, multicast/\n * reserved, and IPv6 loopback/link-local/unique-local (+ v4-mapped). Hostnames\n * are resolved so an internal DNS name (or rebinding) can't smuggle a private\n * target past the literal-IP checks.\n *\n * NOTE: deliberately NO `@moxxy/sdk` import. The Playwright sidecar — a\n * separate child process whose bundle must stay free of non-builtin deps —\n * imports this module too. Parent-side callers wrap `SsrfBlockedError` into\n * `MoxxyError` themselves.\n */\n\n/** Thrown for every guard rejection (bad scheme, private/loopback target, unparseable URL). */\nexport class SsrfBlockedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'SsrfBlockedError';\n }\n}\n\nexport type DnsResolver = (host: string) => Promise<ReadonlyArray<string>>;\nconst defaultResolver: DnsResolver = async (host) =>\n (await dnsLookup(host, { all: true })).map((a) => a.address);\nlet resolver: DnsResolver = defaultResolver;\n\n/** Test seam: override DNS resolution so SSRF tests stay hermetic. Pass null to reset. */\nexport function setSsrfDnsResolver(fn: DnsResolver | null): void {\n resolver = fn ?? defaultResolver;\n}\n\nfunction isBlockedIpv4(ip: string): boolean {\n const parts = ip.split('.').map((p) => Number(p));\n if (parts.length !== 4 || parts.some((p) => !Number.isInteger(p) || p < 0 || p > 255)) return true;\n const [a, b] = parts as [number, number, number, number];\n if (a === 0) return true; // 0.0.0.0/8 \"this host\"\n if (a === 127) return true; // loopback\n if (a === 10) return true; // private\n if (a === 172 && b >= 16 && b <= 31) return true; // private\n if (a === 192 && b === 168) return true; // private\n if (a === 169 && b === 254) return true; // link-local incl. 169.254.169.254 metadata\n if (a === 100 && b >= 64 && b <= 127) return true; // CGNAT 100.64/10\n if (a >= 224) return true; // multicast / reserved\n return false;\n}\n\nfunction isBlockedIpv6(ip: string): boolean {\n const addr = ip.toLowerCase().replace(/^\\[|\\]$/g, '').split('%')[0]!; // strip zone id\n if (addr === '::1' || addr === '::') return true; // loopback / unspecified\n if (addr.startsWith('fe80')) return true; // link-local\n if (addr.startsWith('fc') || addr.startsWith('fd')) return true; // unique-local fc00::/7\n const v4mapped = addr.match(/^::ffff:(\\d+\\.\\d+\\.\\d+\\.\\d+)$/);\n if (v4mapped) return isBlockedIpv4(v4mapped[1]!);\n return false;\n}\n\nexport function isBlockedIp(ip: string): boolean {\n const kind = isIP(ip);\n if (kind === 4) return isBlockedIpv4(ip);\n if (kind === 6) return isBlockedIpv6(ip);\n return true; // not a parseable IP → block\n}\n\n/**\n * Reject `raw` unless it is an http(s) URL whose host is (and resolves to)\n * a public address. `label` prefixes the error message so each caller's\n * rejections stay attributable (e.g. \"web_fetch\", \"browser_session\").\n *\n * Returns the vetted resolved addresses so callers can PIN the subsequent\n * connection to exactly what was checked (closing the DNS-rebinding TOCTOU\n * where the guard resolves one answer and the fetch independently resolves\n * another — see web-fetch's pinned undici dispatcher). Returns `null` when\n * there is nothing to pin: the host is already an IP literal (vetted above,\n * no DNS involved) or resolution failed (fail-open — a name the guard can't\n * resolve, the fetch's identical system resolver can't reach either).\n */\nexport async function assertPublicUrl(\n raw: string,\n label = 'request',\n): Promise<ReadonlyArray<string> | null> {\n let u: URL;\n try {\n u = new URL(raw);\n } catch {\n throw new SsrfBlockedError(`${label}: invalid URL: ${raw}`);\n }\n if (u.protocol !== 'http:' && u.protocol !== 'https:') {\n throw new SsrfBlockedError(`${label}: refusing non-HTTP(S) scheme \"${u.protocol}\"`);\n }\n const host = u.hostname.replace(/^\\[|\\]$/g, '');\n if (host === 'localhost' || host.endsWith('.localhost')) {\n throw new SsrfBlockedError(`${label}: refusing to fetch loopback host \"${host}\"`);\n }\n if (isIP(host)) {\n if (isBlockedIp(host))\n throw new SsrfBlockedError(`${label}: refusing private/loopback address \"${host}\"`);\n return null;\n }\n // Resolve the name and block if it maps to a private range (internal name or\n // DNS rebinding). Fail OPEN on resolution error: a name we can't resolve here\n // the subsequent fetch can't reach either, so it's no SSRF vector.\n let addrs: ReadonlyArray<string>;\n try {\n addrs = await resolver(host);\n } catch {\n return null;\n }\n for (const addr of addrs) {\n if (isBlockedIp(addr)) {\n throw new SsrfBlockedError(\n `${label}: host \"${host}\" resolves to a private/loopback address (${addr})`,\n );\n }\n }\n return addrs;\n}\n","export type BrowserKind = 'chromium' | 'firefox' | 'webkit';\n\nexport type ErrorKind = 'init' | 'navigation' | 'runtime' | 'timeout' | 'unknown';\n\nexport interface Req {\n readonly id: string;\n readonly method: string;\n readonly params?: Record<string, unknown>;\n}\n\nexport interface Ok {\n readonly id: string;\n readonly ok: true;\n readonly result?: unknown;\n /** One-shot human-readable note (e.g. \"Auto-installed Chromium\"). */\n readonly notice?: string;\n}\n\nexport interface Err {\n readonly id: string;\n readonly ok: false;\n readonly error: { message: string; kind: ErrorKind };\n}\n\nexport type Reply = Ok | Err;\n\nexport interface BrowserType {\n launch(opts: {\n headless: boolean;\n }): Promise<{ close(): Promise<void>; newContext(): Promise<unknown> }>;\n}\n\nexport interface PageHandle {\n goto(url: string, opts?: unknown): Promise<unknown>;\n click(selector: string, opts?: unknown): Promise<void>;\n fill(selector: string, value: string, opts?: unknown): Promise<void>;\n textContent(selector: string): Promise<string | null>;\n content(): Promise<string>;\n screenshot(opts?: unknown): Promise<Buffer>;\n evaluate(fn: string): Promise<unknown>;\n url(): string;\n close(): Promise<void>;\n // Coordinate-based input for the live browser surface (loosely typed — the\n // real Playwright Page provides all of these).\n viewportSize(): { width: number; height: number } | null;\n readonly mouse: {\n click(x: number, y: number, opts?: unknown): Promise<void>;\n wheel(dx: number, dy: number): Promise<void>;\n };\n readonly keyboard: {\n press(key: string): Promise<void>;\n type(text: string): Promise<void>;\n };\n}\n\n/** Minimal slice of Playwright's `Request` used by the navigation SSRF guard. */\nexport interface RouteRequest {\n url(): string;\n isNavigationRequest(): boolean;\n}\n\n/** Minimal slice of Playwright's `Route` used by the navigation SSRF guard. */\nexport interface RouteHandle {\n request(): RouteRequest;\n abort(errorCode?: string): Promise<void>;\n continue(): Promise<void>;\n}\n\nexport interface PlaywrightHandle {\n // Loosely typed so we can avoid importing the playwright types at compile time —\n // they're an optional peer dependency.\n readonly browser: { close(): Promise<void> };\n readonly context: {\n newPage(): Promise<unknown>;\n close(): Promise<void>;\n /** Optional because the type is a loose projection; real Playwright contexts always have it. */\n route?(pattern: string, handler: (route: RouteHandle) => Promise<void> | void): Promise<void>;\n };\n readonly page: PageHandle;\n}\n\nexport function errMsg(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * An error carrying a typed {@link ErrorKind} so the dispatch layer can map it\n * onto the wire reply's `error.kind` without poking an untyped `kind` property\n * onto a bare `Error`.\n */\nexport class SidecarError extends Error {\n constructor(\n message: string,\n readonly kind: ErrorKind,\n ) {\n super(message);\n this.name = 'SidecarError';\n }\n}\n\nexport function badParams(msg: string): SidecarError {\n return new SidecarError(msg, 'runtime');\n}\n","/**\n * Playwright lifecycle: import, launch, and one-shot auto-install of the\n * per-browser binary. Keeps the dispatch layer free of node:child_process\n * + Playwright-import noise.\n */\n\nimport { spawn } from 'node:child_process';\nimport { assertPublicUrl } from '../ssrf-guard.js';\nimport { SidecarError } from './types.js';\nimport type { BrowserKind, BrowserType, PageHandle, PlaywrightHandle } from './types.js';\n\nexport interface LaunchResult {\n handle: PlaywrightHandle;\n /** Set when the browser binary was auto-downloaded during this launch. */\n installNotice: string | null;\n}\n\nexport async function importPlaywright(): Promise<{\n chromium: BrowserType;\n firefox: BrowserType;\n webkit: BrowserType;\n}> {\n try {\n return (await import('playwright')) as never;\n } catch (err) {\n throw new SidecarError(\n `Playwright is not installed. Run \\`pnpm add playwright\\` (or \\`npm i playwright\\`) and then \\`npx playwright install\\` in the moxxy install dir.\\n` +\n `Underlying: ${err instanceof Error ? err.message : String(err)}`,\n 'init',\n );\n }\n}\n\n/**\n * Try to launch the browser. If the binary isn't downloaded yet\n * (Playwright distinguishes the npm install from the per-browser\n * binary download), run `npx playwright install <which>` once and\n * retry. The install can take 30s–2min on the first run depending on\n * connection; we surface progress on stderr (parent forwards to the\n * logger) and return a one-shot notice for the first tool response.\n */\nexport async function launchWithAutoInstall(\n browserType: BrowserType,\n which: BrowserKind,\n headless: boolean,\n): Promise<LaunchResult> {\n try {\n return { handle: await launchOnce(browserType, headless), installNotice: null };\n } catch (err) {\n if (!isMissingBrowserError(err)) throw err;\n process.stderr.write(\n `moxxy-browser: ${which} binary missing, running \\`npx playwright install ${which}\\` ` +\n `(one-time, ~150MB). This may take a minute…\\n`,\n );\n try {\n await runPlaywrightInstall(which);\n } catch (installErr) {\n const msg = installErr instanceof Error ? installErr.message : String(installErr);\n throw new SidecarError(\n `Playwright browser auto-install failed: ${msg}. ` +\n `Run \\`npx playwright install ${which}\\` manually in the moxxy dir.`,\n 'init',\n );\n }\n process.stderr.write(`moxxy-browser: install complete, retrying launch\\n`);\n return {\n handle: await launchOnce(browserType, headless),\n installNotice: `Auto-installed Playwright ${which} browser (~150MB, one-time).`,\n };\n }\n}\n\nasync function launchOnce(browserType: BrowserType, headless: boolean): Promise<PlaywrightHandle> {\n const browser = await browserType.launch({ headless });\n const context = (await browser.newContext()) as PlaywrightHandle['context'];\n await installNavigationSsrfGuard(context);\n const page = (await context.newPage()) as unknown as PageHandle;\n return { browser, context, page };\n}\n\n/**\n * Block navigations to private/loopback origins for the lifetime of the\n * context. The goto RPC is validated in the parent AND in dispatch, but a\n * page reached via a legitimate public goto can then redirect or\n * script-navigate itself to e.g. http://169.254.169.254/ — those navigations\n * never pass through the RPC layer, so we intercept them here. Navigation\n * requests (top-level + iframes, which covers HTTP redirect hops too) go\n * through the same `assertPublicUrl` guard as web_fetch; everything else is\n * passed through untouched so ordinary page loads don't pay a DNS round-trip\n * per subresource.\n *\n * Residual risk (also stated in the browser_session tool description):\n * SUBRESOURCE requests (img/fetch/script) from a loaded page are NOT\n * filtered. The browser's same-origin policy stops the page reading those\n * responses, but blind request side effects against internal services remain\n * possible. Filtering every request was judged disproportionate for now.\n */\nasync function installNavigationSsrfGuard(context: PlaywrightHandle['context']): Promise<void> {\n if (typeof context.route !== 'function') return; // loose projection: tolerate stubs without route()\n await context.route('**/*', async (route) => {\n const request = route.request();\n if (!request.isNavigationRequest()) return route.continue();\n try {\n await assertPublicUrl(request.url(), 'browser_session navigation');\n } catch {\n return route.abort('blockedbyclient');\n }\n return route.continue();\n });\n}\n\nfunction isMissingBrowserError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n // Playwright's \"Executable doesn't exist at …\" launch error fires\n // when the npm package is installed but the per-browser binary\n // hasn't been downloaded. The message stays stable across versions.\n return /Executable doesn'?t exist at/i.test(err.message);\n}\n\n/**\n * Run `npx playwright install <which>` and stream its output to the\n * sidecar's stderr so the operator can watch progress. Resolves on\n * exit-0; rejects with the tail of stderr otherwise.\n */\nfunction runPlaywrightInstall(which: BrowserKind): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn('npx', ['playwright', 'install', which], {\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n let stderrTail = '';\n child.stdout.on('data', (chunk: Buffer) => process.stderr.write(chunk));\n child.stderr.on('data', (chunk: Buffer) => {\n process.stderr.write(chunk);\n stderrTail += chunk.toString('utf8');\n if (stderrTail.length > 4000) stderrTail = stderrTail.slice(-4000);\n });\n child.once('error', (err) => reject(err));\n child.once('close', (code) => {\n if (code === 0) resolve();\n else reject(new Error(`exit ${code}: ${stderrTail.trim() || '(no stderr)'}`));\n });\n });\n}\n","/**\n * JSON-RPC dispatch table for the sidecar. Each `method` here corresponds\n * one-to-one with the wire-format methods documented in `sidecar.ts`.\n */\n\nimport { assertPublicUrl } from '../ssrf-guard.js';\nimport { importPlaywright, launchWithAutoInstall } from './install.js';\nimport {\n badParams,\n errMsg,\n SidecarError,\n type BrowserKind,\n type PlaywrightHandle,\n type Reply,\n type Req,\n} from './types.js';\n\nexport interface SidecarState {\n handle: PlaywrightHandle | null;\n /**\n * Set after a successful auto-install of browser binaries so the next\n * tool result can carry a `notice` letting the user/model know the\n * one-time download happened. Cleared once the notice has been\n * delivered (handed to the reply once, then forgotten).\n */\n pendingInstallNotice: string | null;\n}\n\nasync function ensurePlaywright(\n state: SidecarState,\n opts: { browser?: BrowserKind; headless?: boolean },\n): Promise<PlaywrightHandle> {\n if (state.handle) return state.handle;\n const pw = await importPlaywright();\n const which = opts.browser ?? 'chromium';\n const browserType = pw[which];\n const { handle, installNotice } = await launchWithAutoInstall(browserType, which, opts.headless ?? true);\n state.handle = handle;\n if (installNotice) state.pendingInstallNotice = installNotice;\n return state.handle;\n}\n\nexport async function teardown(state: SidecarState): Promise<void> {\n if (!state.handle) return;\n try {\n await state.handle.context.close();\n await state.handle.browser.close();\n } catch {\n /* ignore */\n }\n state.handle = null;\n}\n\nexport async function dispatch(state: SidecarState, req: Req): Promise<Reply> {\n try {\n return await dispatchInner(state, req);\n } catch (err) {\n return {\n id: req.id,\n ok: false,\n error: { message: errMsg(err), kind: err instanceof SidecarError ? err.kind : 'unknown' },\n };\n }\n}\n\nasync function dispatchInner(state: SidecarState, req: Req): Promise<Reply> {\n switch (req.method) {\n case 'init': {\n const opts = (req.params ?? {}) as { browser?: BrowserKind; headless?: boolean };\n await ensurePlaywright(state, opts);\n return { id: req.id, ok: true, result: { ready: true } };\n }\n case 'goto': {\n const { url, waitUntil, timeoutMs } = (req.params ?? {}) as {\n url: string;\n waitUntil?: 'load' | 'domcontentloaded' | 'networkidle';\n timeoutMs?: number;\n };\n if (!url) throw badParams('url is required');\n // Defence-in-depth: the parent already runs the full SSRF guard before\n // sending this RPC, but the sidecar is a distinct process driven over\n // JSON-RPC, so re-check here rather than trust the caller to have\n // validated. Blocks file:// / javascript: schemes AND loopback/private/\n // link-local (incl. 169.254.169.254 metadata)/CGNAT targets, resolving\n // hostnames. Runs BEFORE ensurePlaywright so a blocked URL never\n // launches (or auto-installs) a browser.\n try {\n await assertPublicUrl(url, 'goto');\n } catch (err) {\n return { id: req.id, ok: false, error: { message: errMsg(err), kind: 'navigation' } };\n }\n const h = await ensurePlaywright(state, {});\n try {\n await h.page.goto(url, { waitUntil: waitUntil ?? 'domcontentloaded', timeout: timeoutMs ?? 30_000 });\n } catch (err) {\n return { id: req.id, ok: false, error: { message: errMsg(err), kind: 'navigation' } };\n }\n return { id: req.id, ok: true, result: { url: h.page.url() } };\n }\n case 'click': {\n const h = await ensurePlaywright(state, {});\n const { selector, timeoutMs } = (req.params ?? {}) as { selector: string; timeoutMs?: number };\n if (!selector) throw badParams('selector is required');\n await h.page.click(selector, { timeout: timeoutMs ?? 10_000 });\n return { id: req.id, ok: true };\n }\n case 'fill': {\n const h = await ensurePlaywright(state, {});\n const { selector, value, timeoutMs } = (req.params ?? {}) as {\n selector: string;\n value: string;\n timeoutMs?: number;\n };\n if (!selector) throw badParams('selector is required');\n await h.page.fill(selector, value ?? '', { timeout: timeoutMs ?? 10_000 });\n return { id: req.id, ok: true };\n }\n case 'text': {\n const h = await ensurePlaywright(state, {});\n const { selector } = (req.params ?? {}) as { selector?: string };\n if (selector) {\n const text = await h.page.textContent(selector);\n return { id: req.id, ok: true, result: text ?? '' };\n }\n // Whole-document text via evaluate\n const text = (await h.page.evaluate('document.body ? document.body.innerText : \"\"')) as string;\n return { id: req.id, ok: true, result: text };\n }\n case 'html': {\n const h = await ensurePlaywright(state, {});\n const html = await h.page.content();\n return { id: req.id, ok: true, result: html };\n }\n case 'screenshot': {\n const h = await ensurePlaywright(state, {});\n const { fullPage } = (req.params ?? {}) as { fullPage?: boolean };\n const buf = await h.page.screenshot({ fullPage: fullPage ?? false });\n return { id: req.id, ok: true, result: { mediaType: 'image/png', base64: buf.toString('base64') } };\n }\n case 'frame': {\n // Combined live-view frame for the browser SURFACE: a JPEG screenshot\n // plus the current url + viewport size, so the renderer can map clicks\n // back onto the page. One round-trip per frame.\n const h = await ensurePlaywright(state, {});\n const buf = await h.page.screenshot({ type: 'jpeg', quality: 55 });\n const vp = h.page.viewportSize() ?? { width: 1280, height: 720 };\n return {\n id: req.id,\n ok: true,\n result: {\n mediaType: 'image/jpeg',\n base64: buf.toString('base64'),\n url: h.page.url(),\n width: vp.width,\n height: vp.height,\n },\n };\n }\n case 'mouse': {\n const h = await ensurePlaywright(state, {});\n const { x, y } = (req.params ?? {}) as { x: number; y: number };\n await h.page.mouse.click(x, y);\n return { id: req.id, ok: true, result: { url: h.page.url() } };\n }\n case 'key': {\n const h = await ensurePlaywright(state, {});\n const { key } = (req.params ?? {}) as { key: string };\n if (!key) throw badParams('key is required');\n // A single printable char is typed (inserts it); a named key is pressed.\n if (key.length === 1) await h.page.keyboard.type(key);\n else await h.page.keyboard.press(key);\n return { id: req.id, ok: true };\n }\n case 'scroll': {\n const h = await ensurePlaywright(state, {});\n const { dy } = (req.params ?? {}) as { dy: number };\n await h.page.mouse.wheel(0, dy ?? 0);\n return { id: req.id, ok: true };\n }\n case 'eval': {\n const h = await ensurePlaywright(state, {});\n const { expression } = (req.params ?? {}) as { expression: string };\n if (!expression) throw badParams('expression is required');\n const value = await h.page.evaluate(expression);\n return { id: req.id, ok: true, result: value };\n }\n case 'url': {\n const h = await ensurePlaywright(state, {});\n return { id: req.id, ok: true, result: h.page.url() };\n }\n case 'close': {\n await teardown(state);\n return { id: req.id, ok: true };\n }\n default:\n return {\n id: req.id,\n ok: false,\n error: { message: `unknown method: ${req.method}`, kind: 'runtime' },\n };\n }\n}\n","#!/usr/bin/env node\n/**\n * Playwright sidecar — owns a single browser context. Speaks newline-delimited\n * JSON-RPC over stdio so the parent (`browser_session` tool) doesn't load\n * Playwright into its own process. Crash isolation, lazy install: the parent\n * only spawns this when the heavy tier is actually needed.\n *\n * Wire format (one line per message):\n * { \"id\": \"uuid\", \"method\": \"goto\"|\"click\"|\"fill\"|\"text\"|\"html\"|\"screenshot\"|\"eval\"|\"close\", \"params\": {...} }\n * { \"id\": \"uuid\", \"ok\": true, \"result\": ... }\n * { \"id\": \"uuid\", \"ok\": false, \"error\": { \"message\": \"...\", \"kind\": \"init\"|\"navigation\"|\"runtime\"|\"timeout\" } }\n *\n * Run with `node dist/sidecar.js` (the package's `bin` entry is\n * `moxxy-browser-sidecar`). Parent terminates by closing stdin or sending\n * `{method:'close'}`.\n */\n\nimport * as readline from 'node:readline';\nimport { fileURLToPath } from 'node:url';\nimport { dispatch, teardown, type SidecarState } from './sidecar/dispatch.js';\nimport { errMsg, type Reply, type Req } from './sidecar/types.js';\n\nconst state: SidecarState = { handle: null, pendingInstallNotice: null };\n\nfunction write(reply: Reply): void {\n // Drain the install-notice flag into the first reply that goes out\n // after the install completed, then clear it. Errors get the notice\n // too — sometimes the launch retry surfaces a different problem and\n // the user still wants to know we tried to install.\n if (state.pendingInstallNotice) {\n if (reply.ok) {\n reply = { ...reply, notice: state.pendingInstallNotice };\n } else {\n reply = {\n ...reply,\n error: {\n ...reply.error,\n message: `${state.pendingInstallNotice} Then: ${reply.error.message}`,\n },\n };\n }\n state.pendingInstallNotice = null;\n }\n process.stdout.write(JSON.stringify(reply) + '\\n');\n}\n\n/**\n * Tears down the browser context AND exits the process. Used both by\n * the explicit `close` RPC path and the parent-loss / stdin-close\n * paths so all cleanup goes through one routine.\n */\nasync function shutdownAndExit(code: number): Promise<void> {\n await teardown(state);\n process.exit(code);\n}\n\n/**\n * Parent watchdog: if the moxxy process that spawned this sidecar\n * disappears (crash, SIGKILL, terminal hangup), there's no stdin EOF\n * to rely on — orphan Chromium would keep running and chew CPU/memory\n * until the user notices. Poll the parent PID every few seconds and\n * self-terminate when it goes away.\n *\n * `process.kill(pid, 0)` is the POSIX trick for \"does this PID\n * exist?\" — no signal is actually delivered. Throws ESRCH when the\n * process is gone (or EPERM when it exists but we can't signal it —\n * still alive, so don't treat as gone).\n */\nfunction startParentWatchdog(): void {\n const parentPid = process.ppid;\n if (!parentPid || parentPid <= 1) return; // already orphaned (init), nothing to watch\n const interval = setInterval(() => {\n try {\n process.kill(parentPid, 0);\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ESRCH') {\n clearInterval(interval);\n void shutdownAndExit(0);\n }\n // EPERM means the process exists but we can't signal it — still alive.\n }\n }, 2000);\n interval.unref?.(); // never block the event loop from exiting\n}\n\nlet queue: Promise<void> = Promise.resolve();\n\n/**\n * Parse one input line and chain its dispatch onto the serial request queue.\n * `out` is the sink for replies (real run: {@link write}; tests inject a stub).\n * Exported so a test can drive the queue without spinning up the whole stdio\n * loop. Returns the queue tail so callers can await it.\n *\n * The `.catch` on the chained link is load-bearing: a throw from `out` (e.g. a\n * broken stdout pipe) would otherwise reject `queue` permanently and strand\n * EVERY subsequent request, since each link chains off the previous one.\n * Swallow it here — after emitting a best-effort error reply — so the next\n * request still serves.\n */\nexport function enqueueLine(line: string, out: (reply: Reply) => void): Promise<void> {\n if (!line.trim()) return queue;\n let req: Req;\n try {\n req = JSON.parse(line) as Req;\n } catch {\n out({ id: 'unknown', ok: false, error: { message: 'invalid JSON', kind: 'runtime' } });\n return queue;\n }\n if (!req.id || !req.method) {\n out({\n id: req.id ?? 'unknown',\n ok: false,\n error: { message: 'request requires { id, method }', kind: 'runtime' },\n });\n return queue;\n }\n // Sequentially serve requests on the single page. Parent can pipeline by\n // sending more requests; we serialize them inside the sidecar so a goto\n // doesn't race a click.\n queue = queue\n .then(async () => {\n const reply = await dispatch(state, req);\n out(reply);\n })\n .catch((err) => {\n try {\n out({ id: req.id, ok: false, error: { message: errMsg(err), kind: 'runtime' } });\n } catch {\n /* stdout is gone too — nothing left to do but keep the queue alive */\n }\n });\n return queue;\n}\n\nasync function main(): Promise<void> {\n startParentWatchdog();\n const rl = readline.createInterface({ input: process.stdin });\n rl.on('line', (line) => {\n void enqueueLine(line, write);\n });\n rl.once('close', () => {\n void shutdownAndExit(0);\n });\n // Defensive: if our stdout pipe breaks (parent died mid-write), Node\n // would otherwise throw an uncaught EPIPE on the next write. Treat\n // it as a signal to clean up gracefully instead.\n process.stdout.on('error', (err) => {\n if ((err as NodeJS.ErrnoException).code === 'EPIPE') {\n void shutdownAndExit(0);\n }\n });\n}\n\n// Auto-run only when executed as the bin script — not when imported (tests).\nif (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {\n main().catch((err) => {\n process.stderr.write(`sidecar fatal: ${errMsg(err)}\\n`);\n void shutdownAndExit(1);\n });\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moxxy/cli",
3
- "version": "0.12.0",
3
+ "version": "0.12.2",
4
4
  "description": "moxxy command-line binary. Subcommand dispatcher consuming the moxxy SDK.",
5
5
  "keywords": [
6
6
  "moxxy",
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "dependencies": {
52
52
  "zod": "^3.24.0",
53
- "@moxxy/sdk": "0.12.0"
53
+ "@moxxy/sdk": "0.13.0"
54
54
  },
55
55
  "optionalDependencies": {
56
56
  "@napi-rs/keyring": "^1.3.0",