@metamask/device-mcp 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/CHANGELOG.md +21 -1
  2. package/README.md +55 -2
  3. package/dist/backends/adb-backend.cjs +12 -5
  4. package/dist/backends/adb-backend.cjs.map +1 -1
  5. package/dist/backends/adb-backend.d.cts +8 -2
  6. package/dist/backends/adb-backend.d.cts.map +1 -1
  7. package/dist/backends/adb-backend.d.mts +8 -2
  8. package/dist/backends/adb-backend.d.mts.map +1 -1
  9. package/dist/backends/adb-backend.mjs +12 -5
  10. package/dist/backends/adb-backend.mjs.map +1 -1
  11. package/dist/backends/appium-backend.cjs +16 -7
  12. package/dist/backends/appium-backend.cjs.map +1 -1
  13. package/dist/backends/appium-backend.d.cts +8 -2
  14. package/dist/backends/appium-backend.d.cts.map +1 -1
  15. package/dist/backends/appium-backend.d.mts +8 -2
  16. package/dist/backends/appium-backend.d.mts.map +1 -1
  17. package/dist/backends/appium-backend.mjs +16 -7
  18. package/dist/backends/appium-backend.mjs.map +1 -1
  19. package/dist/backends/idb-backend.cjs +12 -5
  20. package/dist/backends/idb-backend.cjs.map +1 -1
  21. package/dist/backends/idb-backend.d.cts +8 -2
  22. package/dist/backends/idb-backend.d.cts.map +1 -1
  23. package/dist/backends/idb-backend.d.mts +8 -2
  24. package/dist/backends/idb-backend.d.mts.map +1 -1
  25. package/dist/backends/idb-backend.mjs +12 -5
  26. package/dist/backends/idb-backend.mjs.map +1 -1
  27. package/dist/backends/index.cjs +4 -3
  28. package/dist/backends/index.cjs.map +1 -1
  29. package/dist/backends/index.d.cts.map +1 -1
  30. package/dist/backends/index.d.mts.map +1 -1
  31. package/dist/backends/index.mjs +4 -3
  32. package/dist/backends/index.mjs.map +1 -1
  33. package/dist/backends/types.cjs.map +1 -1
  34. package/dist/backends/types.d.cts +19 -1
  35. package/dist/backends/types.d.cts.map +1 -1
  36. package/dist/backends/types.d.mts +19 -1
  37. package/dist/backends/types.d.mts.map +1 -1
  38. package/dist/backends/types.mjs.map +1 -1
  39. package/dist/hermes/hermes-cdp.cjs +674 -0
  40. package/dist/hermes/hermes-cdp.cjs.map +1 -0
  41. package/dist/hermes/hermes-cdp.d.cts +248 -0
  42. package/dist/hermes/hermes-cdp.d.cts.map +1 -0
  43. package/dist/hermes/hermes-cdp.d.mts +248 -0
  44. package/dist/hermes/hermes-cdp.d.mts.map +1 -0
  45. package/dist/hermes/hermes-cdp.mjs +665 -0
  46. package/dist/hermes/hermes-cdp.mjs.map +1 -0
  47. package/dist/hermes/session.cjs +196 -0
  48. package/dist/hermes/session.cjs.map +1 -0
  49. package/dist/hermes/session.d.cts +163 -0
  50. package/dist/hermes/session.d.cts.map +1 -0
  51. package/dist/hermes/session.d.mts +163 -0
  52. package/dist/hermes/session.d.mts.map +1 -0
  53. package/dist/hermes/session.mjs +189 -0
  54. package/dist/hermes/session.mjs.map +1 -0
  55. package/dist/index.cjs +16 -1
  56. package/dist/index.cjs.map +1 -1
  57. package/dist/index.d.cts +5 -1
  58. package/dist/index.d.cts.map +1 -1
  59. package/dist/index.d.mts +5 -1
  60. package/dist/index.d.mts.map +1 -1
  61. package/dist/index.mjs +2 -0
  62. package/dist/index.mjs.map +1 -1
  63. package/dist/server.cjs +3 -0
  64. package/dist/server.cjs.map +1 -1
  65. package/dist/server.d.cts.map +1 -1
  66. package/dist/server.d.mts.map +1 -1
  67. package/dist/server.mjs +4 -1
  68. package/dist/server.mjs.map +1 -1
  69. package/dist/tools/hermes-cdp.cjs +102 -0
  70. package/dist/tools/hermes-cdp.cjs.map +1 -0
  71. package/dist/tools/hermes-cdp.d.cts +18 -0
  72. package/dist/tools/hermes-cdp.d.cts.map +1 -0
  73. package/dist/tools/hermes-cdp.d.mts +18 -0
  74. package/dist/tools/hermes-cdp.d.mts.map +1 -0
  75. package/dist/tools/hermes-cdp.mjs +99 -0
  76. package/dist/tools/hermes-cdp.mjs.map +1 -0
  77. package/dist/tools/hermes-targets.cjs +127 -0
  78. package/dist/tools/hermes-targets.cjs.map +1 -0
  79. package/dist/tools/hermes-targets.d.cts +20 -0
  80. package/dist/tools/hermes-targets.d.cts.map +1 -0
  81. package/dist/tools/hermes-targets.d.mts +20 -0
  82. package/dist/tools/hermes-targets.d.mts.map +1 -0
  83. package/dist/tools/hermes-targets.mjs +124 -0
  84. package/dist/tools/hermes-targets.mjs.map +1 -0
  85. package/dist/tools/index.cjs +5 -1
  86. package/dist/tools/index.cjs.map +1 -1
  87. package/dist/tools/index.d.cts +2 -0
  88. package/dist/tools/index.d.cts.map +1 -1
  89. package/dist/tools/index.d.mts +2 -0
  90. package/dist/tools/index.d.mts.map +1 -1
  91. package/dist/tools/index.mjs +2 -0
  92. package/dist/tools/index.mjs.map +1 -1
  93. package/dist/tools/screenshot.cjs +8 -3
  94. package/dist/tools/screenshot.cjs.map +1 -1
  95. package/dist/tools/screenshot.d.cts.map +1 -1
  96. package/dist/tools/screenshot.d.mts.map +1 -1
  97. package/dist/tools/screenshot.mjs +8 -3
  98. package/dist/tools/screenshot.mjs.map +1 -1
  99. package/dist/utils/output-path.cjs +128 -0
  100. package/dist/utils/output-path.cjs.map +1 -0
  101. package/dist/utils/output-path.d.cts +41 -0
  102. package/dist/utils/output-path.d.cts.map +1 -0
  103. package/dist/utils/output-path.d.mts +41 -0
  104. package/dist/utils/output-path.d.mts.map +1 -0
  105. package/dist/utils/output-path.mjs +123 -0
  106. package/dist/utils/output-path.mjs.map +1 -0
  107. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hermes-cdp.cjs","sourceRoot":"","sources":["../../src/hermes/hermes-cdp.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure Hermes Chrome DevTools Protocol (CDP) core for `@metamask/device-mcp`.\n *\n * Ported from `@metamask/client-mcp-core`'s `src/tools/hermes-cdp.ts`, decoupled\n * from that repo's `ToolContext`/`ErrorCodes`/`createToolError|Success`. Every\n * function here takes EXPLICIT parameters (port, appId, pin) and returns a\n * discriminated {@link HermesCdpResult} so this module is MCP-free and\n * unit-testable. The tools layer is responsible for resolving session state and\n * for PERSISTING the device pin — this file never imports `HermesSession`.\n *\n * Mechanism: the React Native Hermes runtime connects out to Metro's inspector\n * proxy; Metro exposes debuggable targets over `http://localhost:<metroPort>/json`\n * and a per-target `webSocketDebuggerUrl`. We speak real CDP over that WebSocket\n * using the GLOBAL `WebSocket` (no library) and the global `fetch` for discovery.\n *\n * Five fail-closed safety checks are preserved VERBATIM from the reference:\n * 1. Strict `appId` match (`===`, no substring, no `targets[0]` fallback).\n * 2. `HermesInternal.getRuntimeProperties()` identity probe before the user method.\n * 3. Device pin on `reactNative.logicalDeviceId` (set on first success).\n * 4. Multi-device fail-closed (missing or >1 distinct `logicalDeviceId`).\n * 5. WebSocket URL validation (protocol/hostname/port).\n */\n\n/**\n * Reported capability flags on a Metro Hermes target.\n */\ntype HermesCapabilities = {\n /** Whether the target supports native page reloads (newer RN registrations). */\n nativePageReloads?: boolean;\n /** Whether the target supports native source-code fetching. */\n nativeSourceCodeFetching?: boolean;\n /** Whether the target supports multiple concurrent debuggers. */\n supportsMultipleDebuggers?: boolean;\n};\n\n/**\n * React Native-specific metadata attached to a Metro Hermes target.\n */\ntype HermesReactNative = {\n /** Stable logical device identifier used for session pinning. */\n logicalDeviceId?: string;\n /** Reported capability flags for this target. */\n capabilities?: HermesCapabilities;\n};\n\n/**\n * A debuggable Hermes target as reported by Metro's `/json` (or `/json/list`)\n * discovery endpoint. Shape matches the reference implementation exactly.\n */\nexport type HermesTarget = {\n /** Metro's per-target identifier. */\n id?: string;\n /** Human-readable target title (used to filter the legacy synthetic page). */\n title?: string;\n /** Human-readable target description. */\n description?: string;\n /** The app bundle identifier this target belongs to (strict-matched). */\n appId?: string;\n /** The `ws://` URL used to speak CDP with this target. */\n webSocketDebuggerUrl?: string;\n /** React Native-specific metadata (logical device id + capabilities). */\n reactNative?: HermesReactNative;\n};\n\n/**\n * Discriminated result of a Hermes CDP operation.\n *\n * On success `result` carries the raw CDP `result` payload. On failure `code`\n * is a STABLE string error code (see the `HERMES_*` constants) and `message`\n * is a human-readable diagnostic preserving the reference's wording.\n */\nexport type HermesCdpResult =\n | { ok: true; result: unknown }\n | { ok: false; code: string; message: string };\n\n/**\n * Parameters for {@link runHermesCdp}.\n */\nexport type RunHermesCdpInput = {\n /** The CDP method to invoke (e.g. `Runtime.evaluate`). */\n method: string;\n /** Optional CDP method parameters. */\n params?: Record<string, unknown>;\n /** Per-call timeout in milliseconds for discovery and each CDP round-trip. */\n timeoutMs: number;\n /** The resolved Metro inspector proxy port. */\n metroPort: number;\n /** The expected app bundle identifier (strict-matched against targets). */\n appId: string;\n /** The pinned `logicalDeviceId` for this session, if one has been set. */\n pinnedDeviceId?: string;\n /**\n * Callback invoked with the resolved `logicalDeviceId` on the FIRST\n * successful identity probe so the caller can persist the pin. This file\n * stays pure: it never imports or mutates session state itself.\n */\n onPin?: (logicalDeviceId: string) => void;\n};\n\ntype CdpSuccessResponse = {\n id: number;\n result?: unknown;\n};\n\ntype CdpErrorResponse = {\n id: number;\n error: {\n message?: string;\n code?: number;\n data?: unknown;\n };\n};\n\ntype TargetSelection =\n | { ok: true; target: HermesTarget }\n | { ok: false; code: string; message: string };\n\ntype ProbeResult = { ok: true } | { ok: false; code: string; message: string };\n\n/**\n * No Hermes debug target matched the expected appId (after synthetic-title and\n * pin filtering). Often means Metro is up but the app is not registered.\n */\nexport const HERMES_TARGET_NOT_FOUND = 'HERMES_TARGET_NOT_FOUND';\n\n/**\n * A target was found but could not be verified as the expected Hermes runtime\n * (identity probe failed, missing `logicalDeviceId`, or non-JSON probe payload).\n */\nexport const HERMES_NOT_VERIFIED = 'HERMES_NOT_VERIFIED';\n\n/**\n * Multiple distinct logical devices are registered without a session pin (or a\n * candidate is missing its `logicalDeviceId`); routing would be a guess, so we\n * fail closed.\n */\nexport const HERMES_MULTIPLE_DEVICES = 'HERMES_MULTIPLE_DEVICES';\n\n/**\n * The resolved target's `logicalDeviceId` does not match the session pin.\n */\nexport const HERMES_DEVICE_PIN_MISMATCH = 'HERMES_DEVICE_PIN_MISMATCH';\n\n/**\n * The requested CDP method is in the destructive blocked set.\n */\nexport const HERMES_BLOCKED_METHOD = 'HERMES_BLOCKED_METHOD';\n\n/**\n * The target's `webSocketDebuggerUrl` failed protocol/hostname/port validation.\n */\nexport const HERMES_INVALID_WS_URL = 'HERMES_INVALID_WS_URL';\n\n/**\n * The underlying connection (discovery fetch or WebSocket) failed.\n */\nexport const HERMES_CONNECTION_FAILED = 'HERMES_CONNECTION_FAILED';\n\n/**\n * A discovery, socket-open, or CDP round-trip exceeded the configured timeout.\n */\nexport const HERMES_TIMEOUT = 'HERMES_TIMEOUT';\n\n/**\n * The user's CDP method returned a CDP-level error.\n */\nexport const HERMES_CDP_FAILED = 'HERMES_CDP_FAILED';\n\n/**\n * The global `WebSocket` constructor is unavailable in this Node runtime.\n */\nexport const HERMES_WEBSOCKET_UNAVAILABLE = 'HERMES_WEBSOCKET_UNAVAILABLE';\n\n/**\n * CDP methods blocked for safety. Ported VERBATIM from the reference — do not\n * weaken.\n */\nconst HERMES_BLOCKED_METHODS = new Set([\n 'Runtime.terminateExecution',\n 'Inspector.detached',\n]);\n\nconst DISCOVERY_PATHS = ['/json', '/json/list'];\nconst ALLOWED_HOSTNAMES = new Set(['localhost', '127.0.0.1', '::1', '[::1]']);\n\n/**\n * Title of the synthetic legacy \"Improved Chrome Reloads\" page that Metro\n * registers alongside the real Hermes target. Filtered out during selection.\n * Ported VERBATIM from the reference.\n */\nexport const LEGACY_SYNTHETIC_TITLE =\n 'React Native Experimental (Improved Chrome Reloads)';\n\n/**\n * JavaScript expression evaluated against a candidate target BEFORE the user's\n * method, to verify it is a genuine Hermes runtime. Copied VERBATIM from the\n * reference — do not alter the verification semantics.\n */\nexport const IDENTITY_PROBE_EXPR = `(function () {\n try {\n var hi = typeof HermesInternal !== 'undefined' ? HermesInternal : null;\n var p =\n hi && typeof hi.getRuntimeProperties === 'function'\n ? hi.getRuntimeProperties()\n : null;\n return JSON.stringify({\n isHermes: !!hi,\n ossVersion: p ? p['OSS Release Version'] : null,\n debuggerEnabled: p ? p['Debugger Enabled'] : null,\n });\n } catch (e) {\n return JSON.stringify({ error: String(e) });\n }\n})();`;\n\n/**\n * Orchestrates a single verified Hermes CDP command end to end.\n *\n * Resolves a target from Metro discovery, enforces all five fail-closed safety\n * checks, runs the identity probe, persists the device pin via `onPin` on first\n * success, sends the user's method, and returns the raw CDP `result`. The caller\n * supplies the resolved port/appId/pin and persists the pin — this function is\n * pure with respect to session state.\n *\n * @param input - Method, params, timeout, resolved port/appId/pin, and the pin\n * persistence callback. See {@link RunHermesCdpInput}.\n * @returns A discriminated {@link HermesCdpResult}.\n */\nexport async function runHermesCdp(\n input: RunHermesCdpInput,\n): Promise<HermesCdpResult> {\n if (HERMES_BLOCKED_METHODS.has(input.method)) {\n return {\n ok: false,\n code: HERMES_BLOCKED_METHOD,\n message:\n `CDP method \"${input.method}\" is blocked for safety. ` +\n `Blocked methods: ${[...HERMES_BLOCKED_METHODS].join(', ')}`,\n };\n }\n\n if (typeof WebSocket !== 'function') {\n return {\n ok: false,\n code: HERMES_WEBSOCKET_UNAVAILABLE,\n message:\n 'Global WebSocket is unavailable. On Node 20 launch device-mcp with ' +\n 'NODE_OPTIONS=\"--experimental-websocket\" (or use Node 22+).',\n };\n }\n\n try {\n const targets = await fetchDiscoveryTargets(\n input.metroPort,\n input.timeoutMs,\n );\n const selection = selectHermesTarget(\n targets,\n input.appId,\n input.pinnedDeviceId,\n );\n if (!selection.ok) {\n return { ok: false, code: selection.code, message: selection.message };\n }\n\n const validation = validateWebSocketUrl(\n selection.target.webSocketDebuggerUrl,\n input.metroPort,\n );\n if (!validation.ok) {\n return {\n ok: false,\n code: HERMES_INVALID_WS_URL,\n message: validation.message,\n };\n }\n\n return await executeVerifiedCdpCommand(\n selection.target,\n input,\n input.pinnedDeviceId,\n input.onPin,\n );\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n ok: false,\n code: HERMES_CONNECTION_FAILED,\n message: `Hermes CDP connection failed: ${message}`,\n };\n }\n}\n\n/**\n * Fetches debuggable Hermes targets from Metro, trying `/json` then falling\n * back to `/json/list`. Each attempt is bounded by an `AbortController`\n * timeout. The payload must be an array; non-object entries are filtered out.\n *\n * @param metroPort - The Metro inspector proxy port.\n * @param timeoutMs - Per-attempt timeout in milliseconds.\n * @returns The discovered targets (objects only).\n * @throws The last error encountered if all discovery paths fail.\n */\nexport async function fetchDiscoveryTargets(\n metroPort: number,\n timeoutMs: number,\n): Promise<HermesTarget[]> {\n let lastError: unknown;\n\n for (const path of DISCOVERY_PATHS) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(`http://localhost:${metroPort}${path}`, {\n signal: controller.signal,\n });\n if (!response.ok) {\n throw new Error(`Metro ${path} returned HTTP ${response.status}`);\n }\n\n const payload: unknown = await response.json();\n if (!Array.isArray(payload)) {\n throw new Error(`Metro ${path} returned a non-array response`);\n }\n\n return payload.filter(isHermesTarget);\n } catch (error) {\n lastError = error;\n } finally {\n clearTimeout(timer);\n }\n }\n\n throw lastError instanceof Error ? lastError : new Error(String(lastError));\n}\n\n/**\n * Narrows an unknown discovery entry to a {@link HermesTarget} (object guard).\n *\n * @param value - A raw entry from the Metro discovery payload.\n * @returns True when `value` is a non-null object.\n */\nfunction isHermesTarget(value: unknown): value is HermesTarget {\n return typeof value === 'object' && value !== null;\n}\n\n/**\n * Selects the single safe Hermes target for the expected app, applying the\n * fail-closed selection algorithm VERBATIM from the reference:\n *\n * `webSocketDebuggerUrl` present → drop the synthetic legacy title → strict\n * `appId` match (`===`) → pin filter → ambiguity check ({@link hasAmbiguousTarget})\n * → `nativePageReloads` tiebreak → last-in-array.\n *\n * @param targets - All discovered targets.\n * @param expectedAppId - The strict app bundle identifier to match.\n * @param pinnedDeviceId - The session pin, if set, used to filter candidates.\n * @returns The selected target or a classified failure.\n */\nexport function selectHermesTarget(\n targets: HermesTarget[],\n expectedAppId: string,\n pinnedDeviceId: string | undefined,\n): TargetSelection {\n const seenAppIds = [...new Set(targets.map((target) => target.appId))].filter(\n (appId): appId is string => typeof appId === 'string',\n );\n\n let candidates = targets\n .filter((target) => Boolean(target.webSocketDebuggerUrl))\n .filter((target) => target.title !== LEGACY_SYNTHETIC_TITLE)\n .filter((target) => target.appId === expectedAppId);\n\n if (pinnedDeviceId) {\n candidates = candidates.filter(\n (target) => target.reactNative?.logicalDeviceId === pinnedDeviceId,\n );\n }\n\n if (candidates.length === 0) {\n return {\n ok: false,\n code: HERMES_TARGET_NOT_FOUND,\n message: `No Hermes debug target found for appId ${expectedAppId}. Saw appIds: ${JSON.stringify(\n seenAppIds,\n )}`,\n };\n }\n\n if (hasAmbiguousTarget(candidates)) {\n return {\n ok: false,\n code: HERMES_MULTIPLE_DEVICES,\n message: `Ambiguous Hermes target after pin filtering. Candidates: ${candidates\n .map(\n (target) =>\n `${target.id ?? '<unknown>'} (device=${\n target.reactNative?.logicalDeviceId ?? '<missing>'\n })`,\n )\n .join(', ')}`,\n };\n }\n\n // Same-device tiebreak: prefer pages with nativePageReloads (newer RN page\n // registrations) over stale entries left behind after in-app reloads.\n const nativeReloadTargets = candidates.filter(\n (target) => target.reactNative?.capabilities?.nativePageReloads === true,\n );\n if (nativeReloadTargets.length > 0) {\n candidates = nativeReloadTargets;\n }\n\n return { ok: true, target: candidates[candidates.length - 1] };\n}\n\n/**\n * Determines whether a multi-candidate target list is too ambiguous to choose\n * from safely. Returns true when:\n * - any candidate is missing a `reactNative.logicalDeviceId` (we can't route safely), or\n * - candidates resolve to more than one distinct `logicalDeviceId` (multi-device\n * without a session pin — picking any one would silently bind the wrong device).\n *\n * Returns false when all candidates share the same logical device ID. In that\n * case the caller falls through to the \"last-in-array\" tiebreak, matching the\n * React Native convention that the most recent page registration wins (e.g.,\n * stale + fresh page after an in-app reload).\n *\n * @param candidates - Targets remaining after appId/pin/capability filtering.\n * @returns True when the caller must fail closed; false when tiebreak is safe.\n */\nexport function hasAmbiguousTarget(candidates: HermesTarget[]): boolean {\n if (candidates.length <= 1) {\n return false;\n }\n const deviceIds = candidates.map(\n (target) => target.reactNative?.logicalDeviceId,\n );\n // Any candidate missing a logicalDeviceId → can't safely route.\n if (deviceIds.some((id) => !id)) {\n return true;\n }\n // Multiple distinct device IDs → multi-device without pin.\n return new Set(deviceIds).size > 1;\n}\n\n/**\n * Validates a target's `webSocketDebuggerUrl` before connecting. The protocol\n * must be `ws:`, the hostname must be loopback (`localhost`, `127.0.0.1`, `::1`,\n * or `[::1]`), and the port must equal the resolved Metro port. Ported VERBATIM\n * from the reference.\n *\n * @param rawUrl - The candidate `webSocketDebuggerUrl`.\n * @param expectedPort - The resolved Metro port the URL must point at.\n * @returns `{ ok: true }` when valid, otherwise a failure with a message.\n */\nexport function validateWebSocketUrl(\n rawUrl: string | undefined,\n expectedPort: number,\n): { ok: true } | { ok: false; message: string } {\n if (!rawUrl) {\n return { ok: false, message: 'webSocketDebuggerUrl is missing' };\n }\n\n let parsed: URL;\n try {\n parsed = new URL(rawUrl);\n } catch {\n return {\n ok: false,\n message: `webSocketDebuggerUrl is not a valid URL: ${rawUrl}`,\n };\n }\n\n if (parsed.protocol !== 'ws:') {\n return { ok: false, message: `Unexpected protocol '${parsed.protocol}'` };\n }\n if (!ALLOWED_HOSTNAMES.has(parsed.hostname)) {\n return { ok: false, message: `Unexpected hostname '${parsed.hostname}'` };\n }\n if (Number(parsed.port) !== expectedPort) {\n return {\n ok: false,\n message: `Port mismatch: target=${parsed.port} expected=${expectedPort}`,\n };\n }\n\n return { ok: true };\n}\n\n/**\n * Opens the target WebSocket, runs the identity probe, enforces the device pin\n * (persisting it via `onPin` on first success, failing closed on mismatch),\n * sends the user's method, matches the response by `id`, and always closes the\n * socket in a `finally`. Ported faithfully from the reference.\n *\n * @param target - The validated, selected target.\n * @param input - The original {@link RunHermesCdpInput} (method/params/timeout).\n * @param pinnedDeviceId - The session pin, if set.\n * @param onPin - Callback to persist the resolved pin on first success.\n * @returns A discriminated {@link HermesCdpResult}.\n */\nexport async function executeVerifiedCdpCommand(\n target: HermesTarget,\n input: RunHermesCdpInput,\n pinnedDeviceId: string | undefined,\n onPin: ((logicalDeviceId: string) => void) | undefined,\n): Promise<HermesCdpResult> {\n if (!target.webSocketDebuggerUrl) {\n return {\n ok: false,\n code: HERMES_INVALID_WS_URL,\n message: 'Target is missing webSocketDebuggerUrl',\n };\n }\n if (typeof WebSocket !== 'function') {\n return {\n ok: false,\n code: HERMES_WEBSOCKET_UNAVAILABLE,\n message:\n 'Global WebSocket is unavailable. On Node 20 launch device-mcp with ' +\n 'NODE_OPTIONS=\"--experimental-websocket\" (or use Node 22+).',\n };\n }\n\n const socket = new WebSocket(target.webSocketDebuggerUrl);\n let nextId = 1;\n\n try {\n await waitForSocketOpen(socket, input.timeoutMs);\n\n const probe = await runIdentityProbe(socket, input.timeoutMs, nextId);\n nextId += 1;\n if (!probe.ok) {\n return { ok: false, code: probe.code, message: probe.message };\n }\n\n const targetDeviceId = target.reactNative?.logicalDeviceId;\n if (!targetDeviceId) {\n return {\n ok: false,\n code: HERMES_NOT_VERIFIED,\n message: 'Target is missing reactNative.logicalDeviceId',\n };\n }\n if (!pinnedDeviceId) {\n onPin?.(targetDeviceId);\n } else if (pinnedDeviceId !== targetDeviceId) {\n return {\n ok: false,\n code: HERMES_DEVICE_PIN_MISMATCH,\n message: `Hermes target device ${targetDeviceId} does not match session pin ${pinnedDeviceId}`,\n };\n }\n\n const response = await sendUserMethod(socket, input, nextId);\n nextId += 1;\n if (isCdpErrorResponse(response)) {\n return {\n ok: false,\n code: HERMES_CDP_FAILED,\n message: `Hermes CDP \"${input.method}\" failed: ${formatCdpError(\n response,\n )}`,\n };\n }\n\n return { ok: true, result: response.result };\n } finally {\n closeSocket(socket);\n }\n}\n\n/**\n * Runs the {@link IDENTITY_PROBE_EXPR} against an open socket and verifies the\n * response confirms a Hermes runtime. Distinguishes timeout from connection\n * failure and unverified payloads.\n *\n * @param socket - The open target WebSocket.\n * @param timeoutMs - Round-trip timeout in milliseconds.\n * @param id - The CDP message id to use for this probe.\n * @returns A {@link ProbeResult}.\n */\nasync function runIdentityProbe(\n socket: WebSocket,\n timeoutMs: number,\n id: number,\n): Promise<ProbeResult> {\n socket.send(\n JSON.stringify({\n id,\n method: 'Runtime.evaluate',\n params: { expression: IDENTITY_PROBE_EXPR, returnByValue: true },\n }),\n );\n\n let response: CdpSuccessResponse | CdpErrorResponse;\n try {\n response = await waitForCdpResponse(socket, id, timeoutMs);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n if (message.includes('timed out')) {\n return {\n ok: false,\n code: HERMES_TIMEOUT,\n message: `Identity probe timed out after ${timeoutMs}ms`,\n };\n }\n return {\n ok: false,\n code: HERMES_CONNECTION_FAILED,\n message: `Hermes CDP connection failed: ${message}`,\n };\n }\n\n if (isCdpErrorResponse(response)) {\n return {\n ok: false,\n code: HERMES_NOT_VERIFIED,\n message: `Identity probe failed: ${formatCdpError(response)}`,\n };\n }\n\n const remoteResult = getProbeRemoteResult(response);\n if (remoteResult.subtype === 'error') {\n return {\n ok: false,\n code: HERMES_NOT_VERIFIED,\n message: 'Identity probe evaluation returned an error subtype',\n };\n }\n if (remoteResult.value === undefined || remoteResult.value === null) {\n return {\n ok: false,\n code: HERMES_NOT_VERIFIED,\n message: 'Identity probe response missing result.value',\n };\n }\n\n const raw =\n typeof remoteResult.value === 'string'\n ? remoteResult.value\n : JSON.stringify(remoteResult.value);\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return {\n ok: false,\n code: HERMES_NOT_VERIFIED,\n message: `Identity probe returned non-JSON: ${raw}`,\n };\n }\n\n if (!isHermesProbePayload(parsed)) {\n return {\n ok: false,\n code: HERMES_NOT_VERIFIED,\n message: `Identity probe did not verify Hermes runtime: ${raw}`,\n };\n }\n\n return { ok: true };\n}\n\n/**\n * Safely extracts the nested CDP `result.result` (the remote object) from a\n * `Runtime.evaluate` success response.\n *\n * @param response - A CDP success response.\n * @returns The remote object's `subtype`/`value`, or an empty object.\n */\nfunction getProbeRemoteResult(response: CdpSuccessResponse): {\n subtype?: unknown;\n value?: unknown;\n} {\n if (typeof response.result !== 'object' || response.result === null) {\n return {};\n }\n const outer = response.result as Record<string, unknown>;\n if (typeof outer.result !== 'object' || outer.result === null) {\n return {};\n }\n return outer.result;\n}\n\n/**\n * Narrows a parsed probe payload to one confirming a Hermes runtime.\n *\n * @param value - The parsed probe JSON payload.\n * @returns True when `isHermes === true`.\n */\nfunction isHermesProbePayload(value: unknown): value is { isHermes: true } {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as Record<string, unknown>).isHermes === true\n );\n}\n\n/**\n * Sends the user's CDP method over an open, verified socket and awaits the\n * matching response by id.\n *\n * @param socket - The open, verified target WebSocket.\n * @param input - The original input carrying method/params/timeout.\n * @param id - The CDP message id to use.\n * @returns The matching CDP success or error response.\n */\nasync function sendUserMethod(\n socket: WebSocket,\n input: RunHermesCdpInput,\n id: number,\n): Promise<CdpSuccessResponse | CdpErrorResponse> {\n socket.send(\n JSON.stringify({\n id,\n method: input.method,\n params: input.params ?? {},\n }),\n );\n return await waitForCdpResponse(socket, id, input.timeoutMs);\n}\n\n/**\n * Resolves once the socket reaches the OPEN state, rejecting on error or\n * timeout. Listeners are always cleaned up.\n *\n * @param socket - The connecting target WebSocket.\n * @param timeoutMs - Connection timeout in milliseconds.\n * @returns A promise that resolves when the socket is open.\n */\nasync function waitForSocketOpen(\n socket: WebSocket,\n timeoutMs: number,\n): Promise<void> {\n if (socket.readyState === WebSocket.OPEN) {\n return Promise.resolve();\n }\n\n return new Promise((resolve, reject) => {\n let cleanup = (): void => undefined;\n const handleOpen = (): void => {\n cleanup();\n resolve();\n };\n const handleError = (): void => {\n cleanup();\n reject(new Error('WebSocket connection error'));\n };\n const timer = setTimeout(() => {\n cleanup();\n reject(new Error(`WebSocket connection timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n cleanup = (): void => {\n clearTimeout(timer);\n socket.removeEventListener('open', handleOpen);\n socket.removeEventListener('error', handleError);\n };\n\n socket.addEventListener('open', handleOpen);\n socket.addEventListener('error', handleError);\n });\n}\n\n/**\n * Resolves with the CDP response whose `id` matches, rejecting on socket error,\n * premature close, or timeout. Listeners are always cleaned up.\n *\n * @param socket - The open target WebSocket.\n * @param id - The CDP message id to match.\n * @param timeoutMs - Round-trip timeout in milliseconds.\n * @returns The matching CDP success or error response.\n */\nasync function waitForCdpResponse(\n socket: WebSocket,\n id: number,\n timeoutMs: number,\n): Promise<CdpSuccessResponse | CdpErrorResponse> {\n return new Promise((resolve, reject) => {\n let cleanup = (): void => undefined;\n const handleMessage = (event: MessageEvent): void => {\n try {\n const parsed = parseCdpResponse(event.data);\n if (parsed?.id !== id) {\n return;\n }\n cleanup();\n resolve(parsed);\n } catch (error) {\n cleanup();\n reject(error);\n }\n };\n const handleError = (): void => {\n cleanup();\n reject(new Error('WebSocket message error'));\n };\n const handleClose = (): void => {\n cleanup();\n reject(new Error('WebSocket closed before CDP response'));\n };\n const timer = setTimeout(() => {\n cleanup();\n reject(new Error(`Hermes CDP call timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n cleanup = (): void => {\n clearTimeout(timer);\n socket.removeEventListener('message', handleMessage);\n socket.removeEventListener('error', handleError);\n socket.removeEventListener('close', handleClose);\n };\n\n socket.addEventListener('message', handleMessage);\n socket.addEventListener('error', handleError);\n socket.addEventListener('close', handleClose);\n });\n}\n\n/**\n * Parses a raw WebSocket frame into a CDP response, returning undefined when it\n * is not an addressable (`id`-bearing) message.\n *\n * @param data - The raw `MessageEvent.data`.\n * @returns A CDP success/error response, or undefined when not addressable.\n * @throws When the frame is not a text frame.\n */\nfunction parseCdpResponse(\n data: MessageEvent['data'],\n): CdpSuccessResponse | CdpErrorResponse | undefined {\n if (typeof data !== 'string') {\n throw new Error('Hermes CDP returned a non-text WebSocket frame');\n }\n\n const parsed: unknown = JSON.parse(data);\n if (typeof parsed !== 'object' || parsed === null) {\n return undefined;\n }\n const candidate = parsed as Record<string, unknown>;\n if (typeof candidate.id !== 'number') {\n return undefined;\n }\n if (isCdpError(candidate.error)) {\n return { id: candidate.id, error: candidate.error };\n }\n return { id: candidate.id, result: candidate.result };\n}\n\n/**\n * Narrows an unknown value to a CDP error object.\n *\n * @param value - The candidate `error` field.\n * @returns True when `value` is a non-null object.\n */\nfunction isCdpError(value: unknown): value is CdpErrorResponse['error'] {\n return typeof value === 'object' && value !== null;\n}\n\n/**\n * Discriminates a CDP response as an error response.\n *\n * @param response - A CDP success or error response.\n * @returns True when the response carries an `error` field.\n */\nfunction isCdpErrorResponse(\n response: CdpSuccessResponse | CdpErrorResponse,\n): response is CdpErrorResponse {\n return 'error' in response;\n}\n\n/**\n * Formats a CDP error response into a single human-readable line.\n *\n * @param response - The CDP error response.\n * @returns A combined message including code and data when present.\n */\nfunction formatCdpError(response: CdpErrorResponse): string {\n const parts = [response.error.message ?? 'Unknown CDP error'];\n if (typeof response.error.code === 'number') {\n parts.push(`code ${response.error.code}`);\n }\n if (response.error.data !== undefined) {\n parts.push(JSON.stringify(response.error.data));\n }\n return parts.join(' - ');\n}\n\n/**\n * Closes the socket if it is still connecting or open.\n *\n * @param socket - The target WebSocket.\n */\nfunction closeSocket(socket: WebSocket): void {\n if (\n socket.readyState === WebSocket.CONNECTING ||\n socket.readyState === WebSocket.OPEN\n ) {\n socket.close();\n }\n}\n"]}
@@ -0,0 +1,248 @@
1
+ /**
2
+ * Pure Hermes Chrome DevTools Protocol (CDP) core for `@metamask/device-mcp`.
3
+ *
4
+ * Ported from `@metamask/client-mcp-core`'s `src/tools/hermes-cdp.ts`, decoupled
5
+ * from that repo's `ToolContext`/`ErrorCodes`/`createToolError|Success`. Every
6
+ * function here takes EXPLICIT parameters (port, appId, pin) and returns a
7
+ * discriminated {@link HermesCdpResult} so this module is MCP-free and
8
+ * unit-testable. The tools layer is responsible for resolving session state and
9
+ * for PERSISTING the device pin — this file never imports `HermesSession`.
10
+ *
11
+ * Mechanism: the React Native Hermes runtime connects out to Metro's inspector
12
+ * proxy; Metro exposes debuggable targets over `http://localhost:<metroPort>/json`
13
+ * and a per-target `webSocketDebuggerUrl`. We speak real CDP over that WebSocket
14
+ * using the GLOBAL `WebSocket` (no library) and the global `fetch` for discovery.
15
+ *
16
+ * Five fail-closed safety checks are preserved VERBATIM from the reference:
17
+ * 1. Strict `appId` match (`===`, no substring, no `targets[0]` fallback).
18
+ * 2. `HermesInternal.getRuntimeProperties()` identity probe before the user method.
19
+ * 3. Device pin on `reactNative.logicalDeviceId` (set on first success).
20
+ * 4. Multi-device fail-closed (missing or >1 distinct `logicalDeviceId`).
21
+ * 5. WebSocket URL validation (protocol/hostname/port).
22
+ */
23
+ /**
24
+ * Reported capability flags on a Metro Hermes target.
25
+ */
26
+ type HermesCapabilities = {
27
+ /** Whether the target supports native page reloads (newer RN registrations). */
28
+ nativePageReloads?: boolean;
29
+ /** Whether the target supports native source-code fetching. */
30
+ nativeSourceCodeFetching?: boolean;
31
+ /** Whether the target supports multiple concurrent debuggers. */
32
+ supportsMultipleDebuggers?: boolean;
33
+ };
34
+ /**
35
+ * React Native-specific metadata attached to a Metro Hermes target.
36
+ */
37
+ type HermesReactNative = {
38
+ /** Stable logical device identifier used for session pinning. */
39
+ logicalDeviceId?: string;
40
+ /** Reported capability flags for this target. */
41
+ capabilities?: HermesCapabilities;
42
+ };
43
+ /**
44
+ * A debuggable Hermes target as reported by Metro's `/json` (or `/json/list`)
45
+ * discovery endpoint. Shape matches the reference implementation exactly.
46
+ */
47
+ export type HermesTarget = {
48
+ /** Metro's per-target identifier. */
49
+ id?: string;
50
+ /** Human-readable target title (used to filter the legacy synthetic page). */
51
+ title?: string;
52
+ /** Human-readable target description. */
53
+ description?: string;
54
+ /** The app bundle identifier this target belongs to (strict-matched). */
55
+ appId?: string;
56
+ /** The `ws://` URL used to speak CDP with this target. */
57
+ webSocketDebuggerUrl?: string;
58
+ /** React Native-specific metadata (logical device id + capabilities). */
59
+ reactNative?: HermesReactNative;
60
+ };
61
+ /**
62
+ * Discriminated result of a Hermes CDP operation.
63
+ *
64
+ * On success `result` carries the raw CDP `result` payload. On failure `code`
65
+ * is a STABLE string error code (see the `HERMES_*` constants) and `message`
66
+ * is a human-readable diagnostic preserving the reference's wording.
67
+ */
68
+ export type HermesCdpResult = {
69
+ ok: true;
70
+ result: unknown;
71
+ } | {
72
+ ok: false;
73
+ code: string;
74
+ message: string;
75
+ };
76
+ /**
77
+ * Parameters for {@link runHermesCdp}.
78
+ */
79
+ export type RunHermesCdpInput = {
80
+ /** The CDP method to invoke (e.g. `Runtime.evaluate`). */
81
+ method: string;
82
+ /** Optional CDP method parameters. */
83
+ params?: Record<string, unknown>;
84
+ /** Per-call timeout in milliseconds for discovery and each CDP round-trip. */
85
+ timeoutMs: number;
86
+ /** The resolved Metro inspector proxy port. */
87
+ metroPort: number;
88
+ /** The expected app bundle identifier (strict-matched against targets). */
89
+ appId: string;
90
+ /** The pinned `logicalDeviceId` for this session, if one has been set. */
91
+ pinnedDeviceId?: string;
92
+ /**
93
+ * Callback invoked with the resolved `logicalDeviceId` on the FIRST
94
+ * successful identity probe so the caller can persist the pin. This file
95
+ * stays pure: it never imports or mutates session state itself.
96
+ */
97
+ onPin?: (logicalDeviceId: string) => void;
98
+ };
99
+ type TargetSelection = {
100
+ ok: true;
101
+ target: HermesTarget;
102
+ } | {
103
+ ok: false;
104
+ code: string;
105
+ message: string;
106
+ };
107
+ /**
108
+ * No Hermes debug target matched the expected appId (after synthetic-title and
109
+ * pin filtering). Often means Metro is up but the app is not registered.
110
+ */
111
+ export declare const HERMES_TARGET_NOT_FOUND = "HERMES_TARGET_NOT_FOUND";
112
+ /**
113
+ * A target was found but could not be verified as the expected Hermes runtime
114
+ * (identity probe failed, missing `logicalDeviceId`, or non-JSON probe payload).
115
+ */
116
+ export declare const HERMES_NOT_VERIFIED = "HERMES_NOT_VERIFIED";
117
+ /**
118
+ * Multiple distinct logical devices are registered without a session pin (or a
119
+ * candidate is missing its `logicalDeviceId`); routing would be a guess, so we
120
+ * fail closed.
121
+ */
122
+ export declare const HERMES_MULTIPLE_DEVICES = "HERMES_MULTIPLE_DEVICES";
123
+ /**
124
+ * The resolved target's `logicalDeviceId` does not match the session pin.
125
+ */
126
+ export declare const HERMES_DEVICE_PIN_MISMATCH = "HERMES_DEVICE_PIN_MISMATCH";
127
+ /**
128
+ * The requested CDP method is in the destructive blocked set.
129
+ */
130
+ export declare const HERMES_BLOCKED_METHOD = "HERMES_BLOCKED_METHOD";
131
+ /**
132
+ * The target's `webSocketDebuggerUrl` failed protocol/hostname/port validation.
133
+ */
134
+ export declare const HERMES_INVALID_WS_URL = "HERMES_INVALID_WS_URL";
135
+ /**
136
+ * The underlying connection (discovery fetch or WebSocket) failed.
137
+ */
138
+ export declare const HERMES_CONNECTION_FAILED = "HERMES_CONNECTION_FAILED";
139
+ /**
140
+ * A discovery, socket-open, or CDP round-trip exceeded the configured timeout.
141
+ */
142
+ export declare const HERMES_TIMEOUT = "HERMES_TIMEOUT";
143
+ /**
144
+ * The user's CDP method returned a CDP-level error.
145
+ */
146
+ export declare const HERMES_CDP_FAILED = "HERMES_CDP_FAILED";
147
+ /**
148
+ * The global `WebSocket` constructor is unavailable in this Node runtime.
149
+ */
150
+ export declare const HERMES_WEBSOCKET_UNAVAILABLE = "HERMES_WEBSOCKET_UNAVAILABLE";
151
+ /**
152
+ * Title of the synthetic legacy "Improved Chrome Reloads" page that Metro
153
+ * registers alongside the real Hermes target. Filtered out during selection.
154
+ * Ported VERBATIM from the reference.
155
+ */
156
+ export declare const LEGACY_SYNTHETIC_TITLE = "React Native Experimental (Improved Chrome Reloads)";
157
+ /**
158
+ * JavaScript expression evaluated against a candidate target BEFORE the user's
159
+ * method, to verify it is a genuine Hermes runtime. Copied VERBATIM from the
160
+ * reference — do not alter the verification semantics.
161
+ */
162
+ export declare const IDENTITY_PROBE_EXPR = "(function () {\n try {\n var hi = typeof HermesInternal !== 'undefined' ? HermesInternal : null;\n var p =\n hi && typeof hi.getRuntimeProperties === 'function'\n ? hi.getRuntimeProperties()\n : null;\n return JSON.stringify({\n isHermes: !!hi,\n ossVersion: p ? p['OSS Release Version'] : null,\n debuggerEnabled: p ? p['Debugger Enabled'] : null,\n });\n } catch (e) {\n return JSON.stringify({ error: String(e) });\n }\n})();";
163
+ /**
164
+ * Orchestrates a single verified Hermes CDP command end to end.
165
+ *
166
+ * Resolves a target from Metro discovery, enforces all five fail-closed safety
167
+ * checks, runs the identity probe, persists the device pin via `onPin` on first
168
+ * success, sends the user's method, and returns the raw CDP `result`. The caller
169
+ * supplies the resolved port/appId/pin and persists the pin — this function is
170
+ * pure with respect to session state.
171
+ *
172
+ * @param input - Method, params, timeout, resolved port/appId/pin, and the pin
173
+ * persistence callback. See {@link RunHermesCdpInput}.
174
+ * @returns A discriminated {@link HermesCdpResult}.
175
+ */
176
+ export declare function runHermesCdp(input: RunHermesCdpInput): Promise<HermesCdpResult>;
177
+ /**
178
+ * Fetches debuggable Hermes targets from Metro, trying `/json` then falling
179
+ * back to `/json/list`. Each attempt is bounded by an `AbortController`
180
+ * timeout. The payload must be an array; non-object entries are filtered out.
181
+ *
182
+ * @param metroPort - The Metro inspector proxy port.
183
+ * @param timeoutMs - Per-attempt timeout in milliseconds.
184
+ * @returns The discovered targets (objects only).
185
+ * @throws The last error encountered if all discovery paths fail.
186
+ */
187
+ export declare function fetchDiscoveryTargets(metroPort: number, timeoutMs: number): Promise<HermesTarget[]>;
188
+ /**
189
+ * Selects the single safe Hermes target for the expected app, applying the
190
+ * fail-closed selection algorithm VERBATIM from the reference:
191
+ *
192
+ * `webSocketDebuggerUrl` present → drop the synthetic legacy title → strict
193
+ * `appId` match (`===`) → pin filter → ambiguity check ({@link hasAmbiguousTarget})
194
+ * → `nativePageReloads` tiebreak → last-in-array.
195
+ *
196
+ * @param targets - All discovered targets.
197
+ * @param expectedAppId - The strict app bundle identifier to match.
198
+ * @param pinnedDeviceId - The session pin, if set, used to filter candidates.
199
+ * @returns The selected target or a classified failure.
200
+ */
201
+ export declare function selectHermesTarget(targets: HermesTarget[], expectedAppId: string, pinnedDeviceId: string | undefined): TargetSelection;
202
+ /**
203
+ * Determines whether a multi-candidate target list is too ambiguous to choose
204
+ * from safely. Returns true when:
205
+ * - any candidate is missing a `reactNative.logicalDeviceId` (we can't route safely), or
206
+ * - candidates resolve to more than one distinct `logicalDeviceId` (multi-device
207
+ * without a session pin — picking any one would silently bind the wrong device).
208
+ *
209
+ * Returns false when all candidates share the same logical device ID. In that
210
+ * case the caller falls through to the "last-in-array" tiebreak, matching the
211
+ * React Native convention that the most recent page registration wins (e.g.,
212
+ * stale + fresh page after an in-app reload).
213
+ *
214
+ * @param candidates - Targets remaining after appId/pin/capability filtering.
215
+ * @returns True when the caller must fail closed; false when tiebreak is safe.
216
+ */
217
+ export declare function hasAmbiguousTarget(candidates: HermesTarget[]): boolean;
218
+ /**
219
+ * Validates a target's `webSocketDebuggerUrl` before connecting. The protocol
220
+ * must be `ws:`, the hostname must be loopback (`localhost`, `127.0.0.1`, `::1`,
221
+ * or `[::1]`), and the port must equal the resolved Metro port. Ported VERBATIM
222
+ * from the reference.
223
+ *
224
+ * @param rawUrl - The candidate `webSocketDebuggerUrl`.
225
+ * @param expectedPort - The resolved Metro port the URL must point at.
226
+ * @returns `{ ok: true }` when valid, otherwise a failure with a message.
227
+ */
228
+ export declare function validateWebSocketUrl(rawUrl: string | undefined, expectedPort: number): {
229
+ ok: true;
230
+ } | {
231
+ ok: false;
232
+ message: string;
233
+ };
234
+ /**
235
+ * Opens the target WebSocket, runs the identity probe, enforces the device pin
236
+ * (persisting it via `onPin` on first success, failing closed on mismatch),
237
+ * sends the user's method, matches the response by `id`, and always closes the
238
+ * socket in a `finally`. Ported faithfully from the reference.
239
+ *
240
+ * @param target - The validated, selected target.
241
+ * @param input - The original {@link RunHermesCdpInput} (method/params/timeout).
242
+ * @param pinnedDeviceId - The session pin, if set.
243
+ * @param onPin - Callback to persist the resolved pin on first success.
244
+ * @returns A discriminated {@link HermesCdpResult}.
245
+ */
246
+ export declare function executeVerifiedCdpCommand(target: HermesTarget, input: RunHermesCdpInput, pinnedDeviceId: string | undefined, onPin: ((logicalDeviceId: string) => void) | undefined): Promise<HermesCdpResult>;
247
+ export {};
248
+ //# sourceMappingURL=hermes-cdp.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hermes-cdp.d.cts","sourceRoot":"","sources":["../../src/hermes/hermes-cdp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH;;GAEG;AACH,KAAK,kBAAkB,GAAG;IACxB,gFAAgF;IAChF,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,+DAA+D;IAC/D,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,iEAAiE;IACjE,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC,CAAC;AAEF;;GAEG;AACH,KAAK,iBAAiB,GAAG;IACvB,iEAAiE;IACjE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iDAAiD;IACjD,YAAY,CAAC,EAAE,kBAAkB,CAAC;CACnC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,qCAAqC;IACrC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,yEAAyE;IACzE,WAAW,CAAC,EAAE,iBAAiB,CAAC;CACjC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAC7B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjD;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,0DAA0D;IAC1D,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,8EAA8E;IAC9E,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,KAAK,CAAC,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C,CAAC;AAgBF,KAAK,eAAe,GAChB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,GAClC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAIjD;;;GAGG;AACH,eAAO,MAAM,uBAAuB,4BAA4B,CAAC;AAEjE;;;GAGG;AACH,eAAO,MAAM,mBAAmB,wBAAwB,CAAC;AAEzD;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,4BAA4B,CAAC;AAEjE;;GAEG;AACH,eAAO,MAAM,0BAA0B,+BAA+B,CAAC;AAEvE;;GAEG;AACH,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAE7D;;GAEG;AACH,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAE7D;;GAEG;AACH,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AAEnE;;GAEG;AACH,eAAO,MAAM,cAAc,mBAAmB,CAAC;AAE/C;;GAEG;AACH,eAAO,MAAM,iBAAiB,sBAAsB,CAAC;AAErD;;GAEG;AACH,eAAO,MAAM,4BAA4B,iCAAiC,CAAC;AAc3E;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,wDACoB,CAAC;AAExD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,qeAe1B,CAAC;AAEP;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC,eAAe,CAAC,CA6D1B;AAED;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,YAAY,EAAE,CAAC,CA4BzB;AAYD;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,YAAY,EAAE,EACvB,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,GAAG,SAAS,GACjC,eAAe,CAmDjB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,YAAY,EAAE,GAAG,OAAO,CAatE;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,YAAY,EAAE,MAAM,GACnB;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CA6B/C;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,iBAAiB,EACxB,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,KAAK,EAAE,CAAC,CAAC,eAAe,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,GACrD,OAAO,CAAC,eAAe,CAAC,CAgE1B"}
@@ -0,0 +1,248 @@
1
+ /**
2
+ * Pure Hermes Chrome DevTools Protocol (CDP) core for `@metamask/device-mcp`.
3
+ *
4
+ * Ported from `@metamask/client-mcp-core`'s `src/tools/hermes-cdp.ts`, decoupled
5
+ * from that repo's `ToolContext`/`ErrorCodes`/`createToolError|Success`. Every
6
+ * function here takes EXPLICIT parameters (port, appId, pin) and returns a
7
+ * discriminated {@link HermesCdpResult} so this module is MCP-free and
8
+ * unit-testable. The tools layer is responsible for resolving session state and
9
+ * for PERSISTING the device pin — this file never imports `HermesSession`.
10
+ *
11
+ * Mechanism: the React Native Hermes runtime connects out to Metro's inspector
12
+ * proxy; Metro exposes debuggable targets over `http://localhost:<metroPort>/json`
13
+ * and a per-target `webSocketDebuggerUrl`. We speak real CDP over that WebSocket
14
+ * using the GLOBAL `WebSocket` (no library) and the global `fetch` for discovery.
15
+ *
16
+ * Five fail-closed safety checks are preserved VERBATIM from the reference:
17
+ * 1. Strict `appId` match (`===`, no substring, no `targets[0]` fallback).
18
+ * 2. `HermesInternal.getRuntimeProperties()` identity probe before the user method.
19
+ * 3. Device pin on `reactNative.logicalDeviceId` (set on first success).
20
+ * 4. Multi-device fail-closed (missing or >1 distinct `logicalDeviceId`).
21
+ * 5. WebSocket URL validation (protocol/hostname/port).
22
+ */
23
+ /**
24
+ * Reported capability flags on a Metro Hermes target.
25
+ */
26
+ type HermesCapabilities = {
27
+ /** Whether the target supports native page reloads (newer RN registrations). */
28
+ nativePageReloads?: boolean;
29
+ /** Whether the target supports native source-code fetching. */
30
+ nativeSourceCodeFetching?: boolean;
31
+ /** Whether the target supports multiple concurrent debuggers. */
32
+ supportsMultipleDebuggers?: boolean;
33
+ };
34
+ /**
35
+ * React Native-specific metadata attached to a Metro Hermes target.
36
+ */
37
+ type HermesReactNative = {
38
+ /** Stable logical device identifier used for session pinning. */
39
+ logicalDeviceId?: string;
40
+ /** Reported capability flags for this target. */
41
+ capabilities?: HermesCapabilities;
42
+ };
43
+ /**
44
+ * A debuggable Hermes target as reported by Metro's `/json` (or `/json/list`)
45
+ * discovery endpoint. Shape matches the reference implementation exactly.
46
+ */
47
+ export type HermesTarget = {
48
+ /** Metro's per-target identifier. */
49
+ id?: string;
50
+ /** Human-readable target title (used to filter the legacy synthetic page). */
51
+ title?: string;
52
+ /** Human-readable target description. */
53
+ description?: string;
54
+ /** The app bundle identifier this target belongs to (strict-matched). */
55
+ appId?: string;
56
+ /** The `ws://` URL used to speak CDP with this target. */
57
+ webSocketDebuggerUrl?: string;
58
+ /** React Native-specific metadata (logical device id + capabilities). */
59
+ reactNative?: HermesReactNative;
60
+ };
61
+ /**
62
+ * Discriminated result of a Hermes CDP operation.
63
+ *
64
+ * On success `result` carries the raw CDP `result` payload. On failure `code`
65
+ * is a STABLE string error code (see the `HERMES_*` constants) and `message`
66
+ * is a human-readable diagnostic preserving the reference's wording.
67
+ */
68
+ export type HermesCdpResult = {
69
+ ok: true;
70
+ result: unknown;
71
+ } | {
72
+ ok: false;
73
+ code: string;
74
+ message: string;
75
+ };
76
+ /**
77
+ * Parameters for {@link runHermesCdp}.
78
+ */
79
+ export type RunHermesCdpInput = {
80
+ /** The CDP method to invoke (e.g. `Runtime.evaluate`). */
81
+ method: string;
82
+ /** Optional CDP method parameters. */
83
+ params?: Record<string, unknown>;
84
+ /** Per-call timeout in milliseconds for discovery and each CDP round-trip. */
85
+ timeoutMs: number;
86
+ /** The resolved Metro inspector proxy port. */
87
+ metroPort: number;
88
+ /** The expected app bundle identifier (strict-matched against targets). */
89
+ appId: string;
90
+ /** The pinned `logicalDeviceId` for this session, if one has been set. */
91
+ pinnedDeviceId?: string;
92
+ /**
93
+ * Callback invoked with the resolved `logicalDeviceId` on the FIRST
94
+ * successful identity probe so the caller can persist the pin. This file
95
+ * stays pure: it never imports or mutates session state itself.
96
+ */
97
+ onPin?: (logicalDeviceId: string) => void;
98
+ };
99
+ type TargetSelection = {
100
+ ok: true;
101
+ target: HermesTarget;
102
+ } | {
103
+ ok: false;
104
+ code: string;
105
+ message: string;
106
+ };
107
+ /**
108
+ * No Hermes debug target matched the expected appId (after synthetic-title and
109
+ * pin filtering). Often means Metro is up but the app is not registered.
110
+ */
111
+ export declare const HERMES_TARGET_NOT_FOUND = "HERMES_TARGET_NOT_FOUND";
112
+ /**
113
+ * A target was found but could not be verified as the expected Hermes runtime
114
+ * (identity probe failed, missing `logicalDeviceId`, or non-JSON probe payload).
115
+ */
116
+ export declare const HERMES_NOT_VERIFIED = "HERMES_NOT_VERIFIED";
117
+ /**
118
+ * Multiple distinct logical devices are registered without a session pin (or a
119
+ * candidate is missing its `logicalDeviceId`); routing would be a guess, so we
120
+ * fail closed.
121
+ */
122
+ export declare const HERMES_MULTIPLE_DEVICES = "HERMES_MULTIPLE_DEVICES";
123
+ /**
124
+ * The resolved target's `logicalDeviceId` does not match the session pin.
125
+ */
126
+ export declare const HERMES_DEVICE_PIN_MISMATCH = "HERMES_DEVICE_PIN_MISMATCH";
127
+ /**
128
+ * The requested CDP method is in the destructive blocked set.
129
+ */
130
+ export declare const HERMES_BLOCKED_METHOD = "HERMES_BLOCKED_METHOD";
131
+ /**
132
+ * The target's `webSocketDebuggerUrl` failed protocol/hostname/port validation.
133
+ */
134
+ export declare const HERMES_INVALID_WS_URL = "HERMES_INVALID_WS_URL";
135
+ /**
136
+ * The underlying connection (discovery fetch or WebSocket) failed.
137
+ */
138
+ export declare const HERMES_CONNECTION_FAILED = "HERMES_CONNECTION_FAILED";
139
+ /**
140
+ * A discovery, socket-open, or CDP round-trip exceeded the configured timeout.
141
+ */
142
+ export declare const HERMES_TIMEOUT = "HERMES_TIMEOUT";
143
+ /**
144
+ * The user's CDP method returned a CDP-level error.
145
+ */
146
+ export declare const HERMES_CDP_FAILED = "HERMES_CDP_FAILED";
147
+ /**
148
+ * The global `WebSocket` constructor is unavailable in this Node runtime.
149
+ */
150
+ export declare const HERMES_WEBSOCKET_UNAVAILABLE = "HERMES_WEBSOCKET_UNAVAILABLE";
151
+ /**
152
+ * Title of the synthetic legacy "Improved Chrome Reloads" page that Metro
153
+ * registers alongside the real Hermes target. Filtered out during selection.
154
+ * Ported VERBATIM from the reference.
155
+ */
156
+ export declare const LEGACY_SYNTHETIC_TITLE = "React Native Experimental (Improved Chrome Reloads)";
157
+ /**
158
+ * JavaScript expression evaluated against a candidate target BEFORE the user's
159
+ * method, to verify it is a genuine Hermes runtime. Copied VERBATIM from the
160
+ * reference — do not alter the verification semantics.
161
+ */
162
+ export declare const IDENTITY_PROBE_EXPR = "(function () {\n try {\n var hi = typeof HermesInternal !== 'undefined' ? HermesInternal : null;\n var p =\n hi && typeof hi.getRuntimeProperties === 'function'\n ? hi.getRuntimeProperties()\n : null;\n return JSON.stringify({\n isHermes: !!hi,\n ossVersion: p ? p['OSS Release Version'] : null,\n debuggerEnabled: p ? p['Debugger Enabled'] : null,\n });\n } catch (e) {\n return JSON.stringify({ error: String(e) });\n }\n})();";
163
+ /**
164
+ * Orchestrates a single verified Hermes CDP command end to end.
165
+ *
166
+ * Resolves a target from Metro discovery, enforces all five fail-closed safety
167
+ * checks, runs the identity probe, persists the device pin via `onPin` on first
168
+ * success, sends the user's method, and returns the raw CDP `result`. The caller
169
+ * supplies the resolved port/appId/pin and persists the pin — this function is
170
+ * pure with respect to session state.
171
+ *
172
+ * @param input - Method, params, timeout, resolved port/appId/pin, and the pin
173
+ * persistence callback. See {@link RunHermesCdpInput}.
174
+ * @returns A discriminated {@link HermesCdpResult}.
175
+ */
176
+ export declare function runHermesCdp(input: RunHermesCdpInput): Promise<HermesCdpResult>;
177
+ /**
178
+ * Fetches debuggable Hermes targets from Metro, trying `/json` then falling
179
+ * back to `/json/list`. Each attempt is bounded by an `AbortController`
180
+ * timeout. The payload must be an array; non-object entries are filtered out.
181
+ *
182
+ * @param metroPort - The Metro inspector proxy port.
183
+ * @param timeoutMs - Per-attempt timeout in milliseconds.
184
+ * @returns The discovered targets (objects only).
185
+ * @throws The last error encountered if all discovery paths fail.
186
+ */
187
+ export declare function fetchDiscoveryTargets(metroPort: number, timeoutMs: number): Promise<HermesTarget[]>;
188
+ /**
189
+ * Selects the single safe Hermes target for the expected app, applying the
190
+ * fail-closed selection algorithm VERBATIM from the reference:
191
+ *
192
+ * `webSocketDebuggerUrl` present → drop the synthetic legacy title → strict
193
+ * `appId` match (`===`) → pin filter → ambiguity check ({@link hasAmbiguousTarget})
194
+ * → `nativePageReloads` tiebreak → last-in-array.
195
+ *
196
+ * @param targets - All discovered targets.
197
+ * @param expectedAppId - The strict app bundle identifier to match.
198
+ * @param pinnedDeviceId - The session pin, if set, used to filter candidates.
199
+ * @returns The selected target or a classified failure.
200
+ */
201
+ export declare function selectHermesTarget(targets: HermesTarget[], expectedAppId: string, pinnedDeviceId: string | undefined): TargetSelection;
202
+ /**
203
+ * Determines whether a multi-candidate target list is too ambiguous to choose
204
+ * from safely. Returns true when:
205
+ * - any candidate is missing a `reactNative.logicalDeviceId` (we can't route safely), or
206
+ * - candidates resolve to more than one distinct `logicalDeviceId` (multi-device
207
+ * without a session pin — picking any one would silently bind the wrong device).
208
+ *
209
+ * Returns false when all candidates share the same logical device ID. In that
210
+ * case the caller falls through to the "last-in-array" tiebreak, matching the
211
+ * React Native convention that the most recent page registration wins (e.g.,
212
+ * stale + fresh page after an in-app reload).
213
+ *
214
+ * @param candidates - Targets remaining after appId/pin/capability filtering.
215
+ * @returns True when the caller must fail closed; false when tiebreak is safe.
216
+ */
217
+ export declare function hasAmbiguousTarget(candidates: HermesTarget[]): boolean;
218
+ /**
219
+ * Validates a target's `webSocketDebuggerUrl` before connecting. The protocol
220
+ * must be `ws:`, the hostname must be loopback (`localhost`, `127.0.0.1`, `::1`,
221
+ * or `[::1]`), and the port must equal the resolved Metro port. Ported VERBATIM
222
+ * from the reference.
223
+ *
224
+ * @param rawUrl - The candidate `webSocketDebuggerUrl`.
225
+ * @param expectedPort - The resolved Metro port the URL must point at.
226
+ * @returns `{ ok: true }` when valid, otherwise a failure with a message.
227
+ */
228
+ export declare function validateWebSocketUrl(rawUrl: string | undefined, expectedPort: number): {
229
+ ok: true;
230
+ } | {
231
+ ok: false;
232
+ message: string;
233
+ };
234
+ /**
235
+ * Opens the target WebSocket, runs the identity probe, enforces the device pin
236
+ * (persisting it via `onPin` on first success, failing closed on mismatch),
237
+ * sends the user's method, matches the response by `id`, and always closes the
238
+ * socket in a `finally`. Ported faithfully from the reference.
239
+ *
240
+ * @param target - The validated, selected target.
241
+ * @param input - The original {@link RunHermesCdpInput} (method/params/timeout).
242
+ * @param pinnedDeviceId - The session pin, if set.
243
+ * @param onPin - Callback to persist the resolved pin on first success.
244
+ * @returns A discriminated {@link HermesCdpResult}.
245
+ */
246
+ export declare function executeVerifiedCdpCommand(target: HermesTarget, input: RunHermesCdpInput, pinnedDeviceId: string | undefined, onPin: ((logicalDeviceId: string) => void) | undefined): Promise<HermesCdpResult>;
247
+ export {};
248
+ //# sourceMappingURL=hermes-cdp.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hermes-cdp.d.mts","sourceRoot":"","sources":["../../src/hermes/hermes-cdp.ts"],"names":[],"mappings":"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"}