@jaw.id/cli 0.1.26 → 0.2.1

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 (72) hide show
  1. package/dist/base-command.js +3 -1
  2. package/dist/base-command.js.map +1 -1
  3. package/dist/commands/config/set.js +140 -12
  4. package/dist/commands/config/set.js.map +1 -1
  5. package/dist/commands/config/show.js +3 -1
  6. package/dist/commands/config/show.js.map +1 -1
  7. package/dist/commands/config/write.js +6 -4
  8. package/dist/commands/config/write.js.map +1 -1
  9. package/dist/commands/disconnect.js +24 -10
  10. package/dist/commands/disconnect.js.map +1 -1
  11. package/dist/commands/mcp/index.js +2426 -94
  12. package/dist/commands/mcp/index.js.map +1 -1
  13. package/dist/commands/rpc/call.js +197 -45
  14. package/dist/commands/rpc/call.js.map +1 -1
  15. package/dist/commands/session/add.js +1547 -0
  16. package/dist/commands/session/add.js.map +1 -0
  17. package/dist/commands/session/revoke.js +181 -54
  18. package/dist/commands/session/revoke.js.map +1 -1
  19. package/dist/commands/session/setup.js +516 -65
  20. package/dist/commands/session/setup.js.map +1 -1
  21. package/dist/commands/session/status.js +315 -6
  22. package/dist/commands/session/status.js.map +1 -1
  23. package/dist/commands/version.js +3 -1
  24. package/dist/commands/version.js.map +1 -1
  25. package/dist/commands/x402/log.js +344 -0
  26. package/dist/commands/x402/log.js.map +1 -0
  27. package/dist/commands/x402/pay.js +2122 -0
  28. package/dist/commands/x402/pay.js.map +1 -0
  29. package/dist/commands/x402/status.js +1047 -0
  30. package/dist/commands/x402/status.js.map +1 -0
  31. package/dist/index.js +41 -14
  32. package/dist/index.js.map +1 -1
  33. package/dist/lib/bridge-singleton.js +41 -14
  34. package/dist/lib/bridge-singleton.js.map +1 -1
  35. package/dist/lib/config.js +26 -3
  36. package/dist/lib/config.js.map +1 -1
  37. package/dist/lib/keystore.js +13 -2
  38. package/dist/lib/keystore.js.map +1 -1
  39. package/dist/lib/paths.js +3 -1
  40. package/dist/lib/paths.js.map +1 -1
  41. package/dist/lib/payment-lock.js +121 -0
  42. package/dist/lib/payment-lock.js.map +1 -0
  43. package/dist/lib/session-bridge.js +148 -24
  44. package/dist/lib/session-bridge.js.map +1 -1
  45. package/dist/lib/session-config.js +78 -11
  46. package/dist/lib/session-config.js.map +1 -1
  47. package/dist/lib/terminal.js +22 -0
  48. package/dist/lib/terminal.js.map +1 -0
  49. package/dist/lib/validation.js +3 -3
  50. package/dist/lib/validation.js.map +1 -1
  51. package/dist/lib/ws-bridge.js +22 -10
  52. package/dist/lib/ws-bridge.js.map +1 -1
  53. package/dist/mcp/handlers/config.js +73 -6
  54. package/dist/mcp/handlers/config.js.map +1 -1
  55. package/dist/mcp/handlers/daemon.js +43 -12
  56. package/dist/mcp/handlers/daemon.js.map +1 -1
  57. package/dist/mcp/handlers/resources.js +119 -0
  58. package/dist/mcp/handlers/resources.js.map +1 -1
  59. package/dist/mcp/handlers/rpc.js +269 -60
  60. package/dist/mcp/handlers/rpc.js.map +1 -1
  61. package/dist/mcp/helpers.js +50 -3
  62. package/dist/mcp/helpers.js.map +1 -1
  63. package/dist/mcp/server.js +2426 -94
  64. package/dist/mcp/server.js.map +1 -1
  65. package/dist/mcp/tools.js +43 -3
  66. package/dist/mcp/tools.js.map +1 -1
  67. package/dist/x402/log-view.js +160 -0
  68. package/dist/x402/log-view.js.map +1 -0
  69. package/dist/x402/status-report.js +90 -0
  70. package/dist/x402/status-report.js.map +1 -0
  71. package/oclif.manifest.json +405 -11
  72. package/package.json +5 -2
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/paths.ts","../../../src/lib/validation.ts","../../../src/lib/config.ts","../../../src/lib/output.ts","../../../src/base-command.ts","../../../src/lib/crypto.ts","../../../src/lib/ws-bridge.ts","../../../src/lib/relay-session.ts","../../../src/lib/bridge-singleton.ts","../../../src/lib/rpc-classifier.ts","../../../src/lib/keystore.ts","../../../src/lib/session-config.ts","../../../src/lib/session-bridge.ts","../../../src/commands/rpc/call.ts"],"names":["fs2","crypto2","fs4","fs5","Flags"],"mappings":"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","file":"call.js","sourcesContent":["import * as path from 'node:path';\nimport * as os from 'node:os';\n\nconst JAW_DIR = path.join(os.homedir(), '.jaw');\n\nexport const PATHS = {\n root: JAW_DIR,\n config: path.join(JAW_DIR, 'config.json'),\n session: path.join(JAW_DIR, 'session.json'),\n relay: path.join(JAW_DIR, 'relay.json'),\n keystore: path.join(JAW_DIR, 'keystore.json'),\n sessionConfig: path.join(JAW_DIR, 'session-config.json'),\n} as const;\n","import type { PermissionsConfig } from './types.js';\n\nconst ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;\nconst SELECTOR_RE = /^0x[0-9a-fA-F]{8}$/;\nconst HEX_RE = /^0x[0-9a-fA-F]+$/;\nconst VALID_SPEND_UNITS = new Set(['minute', 'hour', 'day', 'week', 'month', 'year', 'forever']);\n\nexport function parsePermissionsConfig(raw: unknown): PermissionsConfig {\n const errors: string[] = [];\n\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw new Error('Invalid permissions:\\n - Must be an object');\n }\n\n const obj = raw as Record<string, unknown>;\n const calls = obj.calls as unknown[] | undefined;\n const spends = obj.spends as unknown[] | undefined;\n\n if (!calls && !spends) {\n throw new Error('Invalid permissions:\\n - Must include at least \"calls\" or \"spends\"');\n }\n\n if (calls !== undefined) {\n if (!Array.isArray(calls) || calls.length === 0) {\n errors.push('calls: Must be a non-empty array');\n } else {\n for (let i = 0; i < calls.length; i++) {\n const c = calls[i] as Record<string, unknown>;\n if (!c || typeof c !== 'object') {\n errors.push(`calls.${i}: Must be an object`);\n continue;\n }\n if (typeof c.target !== 'string' || !ADDRESS_RE.test(c.target)) {\n errors.push(`calls.${i}.target: Must be a valid 0x address (40 hex chars)`);\n }\n if (c.selector !== undefined && (typeof c.selector !== 'string' || !SELECTOR_RE.test(c.selector))) {\n errors.push(`calls.${i}.selector: Must be a 4-byte hex selector (e.g. 0xa9059cbb)`);\n }\n }\n }\n }\n\n if (spends !== undefined) {\n if (!Array.isArray(spends) || spends.length === 0) {\n errors.push('spends: Must be a non-empty array');\n } else {\n for (let i = 0; i < spends.length; i++) {\n const s = spends[i] as Record<string, unknown>;\n if (!s || typeof s !== 'object') {\n errors.push(`spends.${i}: Must be an object`);\n continue;\n }\n if (typeof s.token !== 'string' || !ADDRESS_RE.test(s.token)) {\n errors.push(`spends.${i}.token: Must be a valid 0x address (40 hex chars)`);\n }\n if (typeof s.allowance !== 'string' || !HEX_RE.test(s.allowance)) {\n errors.push(`spends.${i}.allowance: Must be a non-empty 0x hex value`);\n }\n if (typeof s.unit !== 'string' || !VALID_SPEND_UNITS.has(s.unit)) {\n errors.push(`spends.${i}.unit: Must be one of: ${[...VALID_SPEND_UNITS].join(', ')}`);\n }\n if (s.multiplier !== undefined && (!Number.isInteger(s.multiplier) || (s.multiplier as number) < 1)) {\n errors.push(`spends.${i}.multiplier: Must be a positive integer`);\n }\n }\n }\n }\n\n if (errors.length > 0) {\n throw new Error(`Invalid permissions:\\n${errors.map((e) => ` - ${e}`).join('\\n')}`);\n }\n\n return raw as PermissionsConfig;\n}\n\nexport function isValidKeysUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n const isTrustedHost =\n parsed.hostname.endsWith('.jaw.id') ||\n parsed.hostname === 'jaw.id' ||\n parsed.hostname === 'localhost' ||\n parsed.hostname === '127.0.0.1';\n const isSecure = parsed.protocol === 'https:' || parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1';\n return isTrustedHost && isSecure;\n } catch {\n return false;\n }\n}\n\nexport function isValidRelayUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n const isTrustedHost =\n parsed.hostname.endsWith('.jaw.id') ||\n parsed.hostname === 'jaw.id' ||\n parsed.hostname === 'localhost' ||\n parsed.hostname === '127.0.0.1';\n const isSecure = parsed.protocol === 'wss:' || parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1';\n const isWebSocket = parsed.protocol === 'wss:' || parsed.protocol === 'ws:';\n return isTrustedHost && isSecure && isWebSocket;\n } catch {\n return false;\n }\n}\n","import * as fs from 'node:fs';\nimport { PATHS } from './paths.js';\nimport type { JawConfig } from './types.js';\nimport { isValidKeysUrl, isValidRelayUrl } from './validation.js';\n\nexport function ensureDir(dir: string): void {\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n fs.chmodSync(dir, 0o700);\n}\n\nfunction migrateConfig(config: JawConfig): JawConfig {\n if (config.paymasterUrl && !config.paymasters) {\n const chainId = config.defaultChain ?? 1;\n config.paymasters = { [chainId]: { url: config.paymasterUrl } };\n delete config.paymasterUrl;\n saveConfig(config);\n }\n return config;\n}\n\nexport function loadConfig(): JawConfig {\n if (!fs.existsSync(PATHS.config)) {\n return {};\n }\n const raw = fs.readFileSync(PATHS.config, 'utf-8');\n try {\n const config = JSON.parse(raw) as JawConfig;\n return migrateConfig(config);\n } catch {\n throw new Error(\n `Config file at ${PATHS.config} is not valid JSON. Run \\`jaw config set apiKey=<key>\\` to reset it.`\n );\n }\n}\n\nexport function saveConfig(config: JawConfig): void {\n ensureDir(PATHS.root);\n fs.writeFileSync(PATHS.config, JSON.stringify(config, null, 2) + '\\n', {\n encoding: 'utf-8',\n mode: 0o600,\n });\n}\n\n/** Paymaster URLs embed provider API keys as query params (e.g. Pimlico's ?apikey=...). */\nfunction redactUrlSecrets(url: string): string {\n try {\n const parsed = new URL(url);\n for (const key of [...parsed.searchParams.keys()]) {\n parsed.searchParams.set(key, '***');\n }\n return parsed.toString();\n } catch {\n return '***';\n }\n}\n\nexport function redactConfig(config: JawConfig): Record<string, unknown> {\n return {\n ...config,\n apiKey: config.apiKey ? `${config.apiKey.slice(0, 8)}...` : undefined,\n ...(config.paymasters && {\n paymasters: Object.fromEntries(\n Object.entries(config.paymasters).map(([chainId, pm]) => [\n chainId,\n // context is a free-form object (usually just a sponsorshipPolicyId) but a\n // provider could stash a token there, so mask it rather than hand it to the agent.\n { ...pm, url: redactUrlSecrets(pm.url), context: pm.context ? '***' : undefined },\n ])\n ),\n }),\n };\n}\n\nexport function setConfigValue(key: keyof JawConfig, value: string | number): void {\n if (key === 'keysUrl' && typeof value === 'string' && !isValidKeysUrl(value)) {\n throw new Error(`Untrusted keysUrl: ${value}. Must be a *.jaw.id domain (HTTPS) or localhost.`);\n }\n if (key === 'relayUrl' && typeof value === 'string' && !isValidRelayUrl(value)) {\n throw new Error(`Untrusted relayUrl: ${value}. Must be wss://*.jaw.id or ws://localhost.`);\n }\n const config = loadConfig();\n const updated = { ...config, [key]: value };\n saveConfig(updated);\n}\n","import type { OutputFormat } from './types.js';\n\nexport function formatOutput(data: unknown, format: OutputFormat): string {\n if (format === 'json') {\n return JSON.stringify(data, replaceBigInt, 2);\n }\n return formatHuman(data);\n}\n\nfunction replaceBigInt(_key: string, value: unknown): unknown {\n if (typeof value === 'bigint') {\n return value.toString();\n }\n return value;\n}\n\nfunction formatHuman(data: unknown, indent = 0): string {\n if (data === null || data === undefined) {\n return 'null';\n }\n\n if (typeof data === 'string' || typeof data === 'number' || typeof data === 'boolean' || typeof data === 'bigint') {\n return String(data);\n }\n\n if (Array.isArray(data)) {\n if (data.length === 0) return '(empty)';\n return data.map((item, i) => `${i + 1}. ${formatHuman(item, indent + 2)}`).join('\\n');\n }\n\n if (typeof data === 'object') {\n const entries = Object.entries(data as Record<string, unknown>);\n if (entries.length === 0) return '(empty)';\n const pad = ' '.repeat(indent);\n const maxKeyLen = Math.max(...entries.map(([k]) => k.length));\n return entries\n .map(([key, val]) => {\n const paddedKey = key.padEnd(maxKeyLen);\n const valStr = typeof val === 'object' && val !== null ? '\\n' + formatHuman(val, indent + 2) : String(val);\n return `${pad}${paddedKey} ${valStr}`;\n })\n .join('\\n');\n }\n\n return String(data);\n}\n","import { Command, Flags } from '@oclif/core';\nimport type { OutputFormat } from './lib/types.js';\nimport { loadConfig } from './lib/config.js';\nimport { formatOutput } from './lib/output.js';\n\nexport abstract class BaseCommand extends Command {\n static override baseFlags = {\n output: Flags.string({\n char: 'o',\n description: 'Output format',\n options: ['json', 'human'],\n default: 'human',\n env: 'JAW_OUTPUT',\n }),\n chain: Flags.integer({\n char: 'c',\n description: 'Chain ID',\n env: 'JAW_CHAIN_ID',\n }),\n 'api-key': Flags.string({\n description: 'JAW API key',\n env: 'JAW_API_KEY',\n }),\n yes: Flags.boolean({\n char: 'y',\n description: 'Skip confirmations (for AI agents)',\n default: false,\n }),\n quiet: Flags.boolean({\n char: 'q',\n description: 'Suppress non-essential output',\n default: false,\n }),\n };\n\n protected resolveApiKey(flags: { 'api-key'?: string }): string {\n const apiKey = flags['api-key'] ?? loadConfig().apiKey;\n if (!apiKey) {\n this.error('API key required. Set via --api-key, JAW_API_KEY env, or `jaw config set apiKey <key>`');\n }\n return apiKey;\n }\n\n protected resolveChainId(flags: { chain?: number }): number {\n const chainId = flags.chain ?? loadConfig().defaultChain;\n if (!chainId) {\n this.error('Chain ID required. Set via --chain, JAW_CHAIN_ID env, or `jaw config set defaultChain <id>`');\n }\n return chainId;\n }\n\n protected outputResult(data: unknown, format: OutputFormat): void {\n const output = formatOutput(data, format);\n this.log(output);\n }\n}\n","/**\n * E2E encryption primitives for CLI ↔ browser communication.\n *\n * Uses ECDH P-256 for key exchange and AES-256-GCM for message encryption.\n * Mirrors the same crypto operations in @jaw.id/core but uses only\n * Node.js built-in crypto.subtle — no external dependencies.\n */\n\nimport type { webcrypto } from 'node:crypto';\n\ntype CKey = webcrypto.CryptoKey;\ntype CKeyPair = webcrypto.CryptoKeyPair;\n\nconst subtle = globalThis.crypto.subtle;\n\n// ── Key generation ───────────────────────────────────────────────\n\nexport async function generateKeyPair(): Promise<CKeyPair> {\n return subtle.generateKey({ name: 'ECDH', namedCurve: 'P-256' }, true, ['deriveKey']) as Promise<CKeyPair>;\n}\n\nexport async function deriveSharedSecret(privateKey: CKey, peerPublicKey: CKey): Promise<CKey> {\n return subtle.deriveKey(\n { name: 'ECDH', public: peerPublicKey },\n privateKey,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt', 'decrypt']\n );\n}\n\n// ── Encrypt / Decrypt ────────────────────────────────────────────\n\nexport interface EncryptedEnvelope {\n iv: string; // base64\n ciphertext: string; // base64\n}\n\nexport async function encryptMessage(sharedSecret: CKey, payload: Record<string, unknown>): Promise<EncryptedEnvelope> {\n const iv = globalThis.crypto.getRandomValues(new Uint8Array(12));\n const plaintext = new TextEncoder().encode(JSON.stringify(payload));\n const cipherBuf = await subtle.encrypt({ name: 'AES-GCM', iv }, sharedSecret, plaintext);\n return {\n iv: bufferToBase64(iv),\n ciphertext: bufferToBase64(new Uint8Array(cipherBuf)),\n };\n}\n\nexport async function decryptMessage(\n sharedSecret: CKey,\n envelope: EncryptedEnvelope\n): Promise<Record<string, unknown>> {\n const iv = Buffer.from(envelope.iv, 'base64');\n const ciphertext = Buffer.from(envelope.ciphertext, 'base64');\n const plainBuf = await subtle.decrypt({ name: 'AES-GCM', iv }, sharedSecret, ciphertext);\n return JSON.parse(new TextDecoder().decode(plainBuf));\n}\n\n// ── Key import / export (hex) ────────────────────────────────────\n\nexport async function exportKeyToHex(type: 'private' | 'public', key: CKey): Promise<string> {\n const format = type === 'private' ? 'pkcs8' : 'spki';\n const buf = await subtle.exportKey(format, key);\n return bytesToHex(new Uint8Array(buf));\n}\n\nexport async function importKeyFromHex(type: 'private' | 'public', hex: string): Promise<CKey> {\n const format = type === 'private' ? 'pkcs8' : 'spki';\n return subtle.importKey(\n format,\n Buffer.from(hexToBytes(hex)),\n { name: 'ECDH', namedCurve: 'P-256' },\n true,\n type === 'private' ? ['deriveKey'] : []\n );\n}\n\n// ── Encoding helpers ─────────────────────────────────────────────\n\nfunction bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\nfunction hexToBytes(hex: string): Uint8Array {\n if (hex.length % 2 !== 0) throw new Error('Invalid hex: odd length');\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);\n }\n return bytes;\n}\n\nfunction bufferToBase64(buf: Uint8Array): string {\n return Buffer.from(buf).toString('base64');\n}\n","/**\n * WSBridge — CLI-side relay client\n *\n * Connects to the cloud relay (wss://relay.jaw.id) instead of a local daemon.\n * All messages (except key_exchange) are E2E encrypted via ECDH + AES-256-GCM.\n */\n\nimport * as crypto from 'node:crypto';\nimport type { webcrypto } from 'node:crypto';\nimport WebSocket from 'ws';\nimport {\n deriveSharedSecret,\n encryptMessage,\n decryptMessage,\n importKeyFromHex,\n type EncryptedEnvelope,\n} from './crypto.js';\n\ntype CKey = webcrypto.CryptoKey;\n\nexport interface WSBridgeConfig {\n apiKey: string;\n chainId: number;\n ens?: string;\n paymasterUrl?: string;\n}\n\nexport interface WSBridgeOptions {\n relayUrl: string;\n session: string;\n timeout?: number;\n config: WSBridgeConfig;\n /** CLI's ECDH private key (hex). Loaded from relay.json for existing sessions. */\n privateKeyHex: string;\n /** CLI's ECDH public key (hex). Sent to browser for key derivation. */\n publicKeyHex: string;\n /** Browser's ECDH public key (hex). Null if new session (key exchange needed). */\n peerPublicKeyHex: string | null;\n}\n\nconst DEFAULT_TIMEOUT_MS = 120_000;\n\n/**\n * Maximum outbound message size (5 MB).\n *\n * wallet_sendCalls with large batches (50+ calls, complex calldata) can reach\n * hundreds of KB. Base64 encoding of the AES-GCM ciphertext adds ~33% overhead.\n * 5 MB is generous enough for any realistic batch while still preventing\n * accidental memory issues.\n */\nconst MAX_MESSAGE_BYTES = 5 * 1024 * 1024;\n\n/** Minimum time between browser reopen attempts (ms). */\nconst BROWSER_REOPEN_COOLDOWN_MS = 5_000;\n\n/** Maximum reconnection attempts before giving up. */\nconst MAX_RECONNECT_ATTEMPTS = 3;\n\n/** Base delay for exponential backoff (ms). */\nconst RECONNECT_BASE_DELAY_MS = 1_000;\n\nexport class WSBridge {\n private readonly relayUrl: string;\n private readonly session: string;\n private readonly timeout: number;\n private readonly config: WSBridgeConfig;\n private readonly privateKeyHex: string;\n readonly publicKeyHex: string;\n private peerPublicKeyHex: string | null;\n private sharedSecret: CKey | null = null;\n private ws: WebSocket | null = null;\n private disposed = false;\n\n // Auto-reopen browser state\n private onBrowserNeeded: (() => Promise<void>) | undefined;\n private onPeerKeyChanged: ((key: string) => void) | undefined;\n private lastBrowserOpenTime = 0;\n\n // Reconnection state\n private reconnectAttempts = 0;\n\n /** Updated after key exchange — caller should persist this. */\n get peerPublicKey(): string | null {\n return this.peerPublicKeyHex;\n }\n\n constructor(options: WSBridgeOptions) {\n this.relayUrl = options.relayUrl;\n this.session = options.session;\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;\n this.config = options.config;\n this.privateKeyHex = options.privateKeyHex;\n this.publicKeyHex = options.publicKeyHex;\n this.peerPublicKeyHex = options.peerPublicKeyHex;\n }\n\n /**\n * Connect to the relay and wait for the browser to be ready.\n *\n * @param onBrowserNeeded — called when the relay reports no browser connected.\n * @param onPeerKeyChanged — called when a key_exchange updates the peer key.\n */\n async connect(\n onBrowserNeeded?: () => Promise<void>,\n onPeerKeyChanged?: (newPeerPublicKeyHex: string) => void\n ): Promise<void> {\n // Store callbacks for auto-reopen on browser disconnect\n this.onBrowserNeeded = onBrowserNeeded;\n this.onPeerKeyChanged = onPeerKeyChanged;\n\n // Pre-derive shared secret if we already have the peer key\n if (this.peerPublicKeyHex) {\n await this.deriveSecret();\n }\n\n return this.connectInternal(onBrowserNeeded, onPeerKeyChanged);\n }\n\n private async connectInternal(\n onBrowserNeeded?: () => Promise<void>,\n onPeerKeyChanged?: (newPeerPublicKeyHex: string) => void\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n const url = `${this.relayUrl}?session=${encodeURIComponent(this.session)}&role=cli`;\n const ws = new WebSocket(url);\n\n let browserOpened = false;\n let resolved = false;\n let expectingKeyExchange = !this.peerPublicKeyHex;\n\n const timer = setTimeout(() => {\n ws.close();\n reject(new Error('Browser did not connect in time.\\n' + 'Run `jaw disconnect` then try again.'));\n }, 30_000);\n\n const sendEncryptedInit = async () => {\n if (!this.sharedSecret) return;\n const envelope = await encryptMessage(this.sharedSecret, {\n type: 'init',\n apiKey: this.config.apiKey,\n chainId: this.config.chainId,\n ens: this.config.ens,\n paymasterUrl: this.config.paymasterUrl,\n });\n this.sendRaw(ws, JSON.stringify({ type: 'encrypted', ...envelope }));\n };\n\n const waitForReady = () => {\n const readyTimer = setTimeout(() => {\n ws.close();\n reject(new Error('Browser SDK did not become ready in time.'));\n }, 15_000);\n\n const onMsg = async (data: WebSocket.Data) => {\n const msg = safeParse(data);\n if (!msg) return;\n\n if (msg.type === 'encrypted' && this.sharedSecret) {\n try {\n const inner = await decryptMessage(this.sharedSecret, msg as unknown as EncryptedEnvelope);\n if (inner.type === 'ready') {\n clearTimeout(readyTimer);\n ws.off('message', onMsg);\n this.reconnectAttempts = 0; // Reset on successful connect\n resolve();\n }\n } catch {\n // Not a valid encrypted message for us, ignore\n }\n }\n };\n ws.on('message', onMsg);\n };\n\n const onBrowserReady = async () => {\n if (resolved) return;\n resolved = true;\n clearTimeout(timer);\n // Set up listener BEFORE sending init to avoid missing the ready response\n waitForReady();\n await sendEncryptedInit();\n };\n\n ws.on('open', () => {\n this.ws = ws;\n });\n\n ws.on('message', async (data) => {\n const msg = safeParse(data);\n if (!msg) return;\n\n if (msg.type === 'status') {\n if (msg.browserConnected) {\n if (this.sharedSecret) {\n // Already have shared secret — skip key exchange\n await onBrowserReady();\n } else {\n // Browser is connected but we don't have its key yet.\n expectingKeyExchange = true;\n }\n } else if (!browserOpened && onBrowserNeeded) {\n browserOpened = true;\n expectingKeyExchange = true;\n onBrowserNeeded().catch(() => {\n /* best effort */\n });\n } else if (!onBrowserNeeded) {\n // Reuse path (bridge-singleton.ts called connectBridge with\n // openBrowser=false): the relay reports no browser connected and\n // we have no callback to open one. Bail immediately so the\n // caller can fall through to a fresh session, instead of waiting\n // out the 30s connect-timer.\n clearTimeout(timer);\n ws.close();\n reject(new Error('Browser not connected — relay session is stale.'));\n }\n } else if (msg.type === 'browser_connected') {\n expectingKeyExchange = true;\n // Wait for key_exchange from browser\n } else if (msg.type === 'browser_disconnected') {\n // Browser tab closed — attempt to reopen after cooldown\n this.handleBrowserDisconnect();\n } else if (msg.type === 'key_exchange' && expectingKeyExchange) {\n expectingKeyExchange = false;\n const peerKey = msg.publicKey as string;\n this.peerPublicKeyHex = peerKey;\n await this.deriveSecret();\n onPeerKeyChanged?.(peerKey);\n await onBrowserReady();\n }\n });\n\n ws.on('error', (err) => {\n clearTimeout(timer);\n reject(err);\n });\n\n ws.on('close', () => {\n clearTimeout(timer);\n if (!this.disposed) {\n this.handleRelayDisconnect();\n }\n });\n });\n }\n\n /**\n * Send an encrypted RPC request through the relay to the browser SDK.\n */\n async request(method: string, params?: unknown): Promise<unknown> {\n const ws = this.ws;\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n throw new Error('Not connected to relay');\n }\n if (!this.sharedSecret) {\n throw new Error('No shared secret — key exchange not completed');\n }\n\n const id = crypto.randomUUID();\n\n const envelope = await encryptMessage(this.sharedSecret, {\n type: 'rpc_request',\n id,\n method,\n params,\n });\n\n const serialized = JSON.stringify({ type: 'encrypted', ...envelope });\n assertMessageSize(serialized, method);\n\n return new Promise<unknown>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(\n new Error(`Request timed out after ${this.timeout / 1000}s. ` + 'Did you complete the action in the browser?')\n );\n this.close();\n }, this.timeout);\n\n const onMessage = async (data: WebSocket.Data) => {\n const msg = safeParse(data);\n if (!msg || msg.type !== 'encrypted' || !this.sharedSecret) return;\n\n try {\n const inner = await decryptMessage(this.sharedSecret, msg as unknown as EncryptedEnvelope);\n if (inner.type === 'rpc_response' && inner.id === id) {\n clearTimeout(timer);\n ws.off('message', onMessage);\n\n if (inner.success) {\n resolve(inner.data);\n } else {\n const err = inner.error as { code: number; message: string } | undefined;\n reject(new Error(err ? `[${err.code}] ${err.message}` : 'Request failed'));\n }\n }\n } catch {\n // Decryption failed — not our message or tampered, ignore\n }\n };\n\n ws.on('message', onMessage);\n this.sendRaw(ws, serialized);\n });\n }\n\n async shutdown(): Promise<void> {\n this.disposed = true;\n if (this.ws?.readyState === WebSocket.OPEN && this.sharedSecret) {\n try {\n const envelope = await encryptMessage(this.sharedSecret, {\n type: 'shutdown',\n });\n this.sendRaw(this.ws, JSON.stringify({ type: 'encrypted', ...envelope }));\n } catch {\n // Best effort\n }\n }\n this.close();\n }\n\n /**\n * Connect to relay and send shutdown directly — no init/ready handshake.\n * Used by `jaw disconnect` when we just need to tell the browser to close.\n */\n async connectAndShutdown(): Promise<void> {\n if (!this.peerPublicKeyHex) {\n // No peer key means browser never connected — nothing to shut down\n return;\n }\n\n this.disposed = true;\n await this.deriveSecret();\n\n return new Promise<void>((resolve) => {\n const url = `${this.relayUrl}?session=${encodeURIComponent(this.session)}&role=cli`;\n const ws = new WebSocket(url);\n\n const timer = setTimeout(() => {\n try {\n ws.close();\n } catch {\n /* ignore */\n }\n resolve();\n }, 3000);\n\n ws.on('open', async () => {\n this.ws = ws;\n try {\n await this.shutdown();\n } catch {\n // Best effort\n }\n clearTimeout(timer);\n resolve();\n });\n\n ws.on('error', () => {\n clearTimeout(timer);\n resolve();\n });\n });\n }\n\n close(): void {\n this.disposed = true;\n if (this.ws) {\n try {\n this.ws.close();\n } catch {\n // ignore\n }\n this.ws = null;\n }\n }\n\n /**\n * Auto-reopen browser when browser_disconnected is received from relay.\n * Respects a cooldown to prevent rapid re-opening.\n */\n private handleBrowserDisconnect(): void {\n if (this.disposed || !this.onBrowserNeeded) return;\n\n const now = Date.now();\n if (now - this.lastBrowserOpenTime < BROWSER_REOPEN_COOLDOWN_MS) {\n return; // Too soon — skip this reopen\n }\n\n this.lastBrowserOpenTime = now;\n\n // Reset shared secret — the new browser tab will do a fresh key exchange\n this.sharedSecret = null;\n this.peerPublicKeyHex = null;\n\n this.onBrowserNeeded().catch(() => {\n // Best effort — if browser open fails, the next request will error\n });\n }\n\n /**\n * Attempt to reconnect to the relay with exponential backoff\n * when the WebSocket connection drops unexpectedly.\n */\n private handleRelayDisconnect(): void {\n if (this.disposed) return;\n if (this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) return;\n\n const delay = RECONNECT_BASE_DELAY_MS * Math.pow(2, this.reconnectAttempts);\n this.reconnectAttempts++;\n\n setTimeout(() => {\n if (this.disposed) return;\n this.connectInternal(this.onBrowserNeeded, this.onPeerKeyChanged).catch(() => {\n // Reconnection failed — will retry if attempts remain\n });\n }, delay);\n }\n\n /** Send a raw string over the WebSocket, enforcing message size limits. */\n private sendRaw(ws: WebSocket, data: string): void {\n ws.send(data);\n }\n\n private async deriveSecret(): Promise<void> {\n if (!this.peerPublicKeyHex) return;\n const privateKey = await importKeyFromHex('private', this.privateKeyHex);\n const peerPublicKey = await importKeyFromHex('public', this.peerPublicKeyHex);\n this.sharedSecret = await deriveSharedSecret(privateKey, peerPublicKey);\n }\n}\n\n/**\n * Validate message size before sending to the relay.\n * Throws with a descriptive error if the message is too large.\n */\nfunction assertMessageSize(serialized: string, method: string): void {\n const byteLength = Buffer.byteLength(serialized, 'utf-8');\n if (byteLength > MAX_MESSAGE_BYTES) {\n const sizeMB = (byteLength / (1024 * 1024)).toFixed(2);\n throw new Error(\n `Message for ${method} is too large (${sizeMB} MB, limit ${MAX_MESSAGE_BYTES / (1024 * 1024)} MB). ` +\n 'Try reducing the number of calls in your batch.'\n );\n }\n}\n\nfunction safeParse(data: WebSocket.Data): Record<string, unknown> | null {\n try {\n return JSON.parse(data.toString()) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n","/**\n * Relay session persistence (~/.jaw/relay.json).\n * Shared by the bridge lifecycle (bridge-singleton) and status reporting (MCP jaw_status).\n */\n\nimport * as fs from 'node:fs';\nimport { PATHS } from './paths.js';\nimport { ensureDir } from './config.js';\n\nexport interface RelaySession {\n session: string;\n relayUrl: string;\n privateKey: string;\n publicKey: string;\n peerPublicKey: string | null;\n startedAt: string;\n}\n\nexport function loadRelaySession(): RelaySession | null {\n try {\n if (!fs.existsSync(PATHS.relay)) return null;\n const raw = fs.readFileSync(PATHS.relay, 'utf-8');\n const parsed = JSON.parse(raw) as RelaySession;\n // Basic validation\n if (!parsed.session || !parsed.relayUrl || !parsed.privateKey || !parsed.publicKey) {\n return null;\n }\n return parsed;\n } catch {\n return null;\n }\n}\n\nexport function saveRelaySession(info: RelaySession): void {\n ensureDir(PATHS.root);\n fs.writeFileSync(PATHS.relay, JSON.stringify(info, null, 2) + '\\n', {\n encoding: 'utf-8',\n mode: 0o600,\n });\n}\n\nexport function deleteRelaySession(): void {\n try {\n if (fs.existsSync(PATHS.relay)) fs.unlinkSync(PATHS.relay);\n } catch {\n // ignore\n }\n}\n","/**\n * Bridge lifecycle management — relay edition.\n *\n * - Generates a session token + ECDH keypair for new sessions\n * - Opens the browser to keys.jaw.id/cli-bridge\n * - Saves relay state to ~/.jaw/relay.json\n * - Creates a WSBridge client connected to the relay\n */\n\nimport * as fs from 'node:fs';\nimport * as crypto from 'node:crypto';\nimport { PATHS } from './paths.js';\nimport { loadConfig } from './config.js';\nimport { WSBridge } from './ws-bridge.js';\nimport { isValidKeysUrl, isValidRelayUrl } from './validation.js';\nimport { generateKeyPair, exportKeyToHex } from './crypto.js';\nimport { type RelaySession, loadRelaySession, saveRelaySession, deleteRelaySession } from './relay-session.js';\n\nconst DEFAULT_KEYS_URL = 'https://keys.jaw.id';\nconst DEFAULT_RELAY_URL = 'wss://relay.jaw.id';\n\nexport interface BridgeOptions {\n keysUrl?: string;\n relayUrl?: string;\n apiKey: string;\n chainId?: number;\n ens?: string;\n paymasterUrl?: string;\n timeout?: number;\n}\n\n/**\n * Get or create a relay bridge connection.\n */\nexport async function getBridge(options: BridgeOptions): Promise<WSBridge> {\n const config = loadConfig();\n const keysUrl = options.keysUrl ?? config.keysUrl ?? DEFAULT_KEYS_URL;\n const relayUrl = options.relayUrl ?? config.relayUrl ?? DEFAULT_RELAY_URL;\n const chainId = options.chainId ?? config.defaultChain ?? 1;\n if (!isValidKeysUrl(keysUrl)) {\n throw new Error(`Untrusted keysUrl: ${keysUrl}. Must be a *.jaw.id domain (HTTPS) or localhost.`);\n }\n if (!isValidRelayUrl(relayUrl)) {\n throw new Error(`Untrusted relayUrl: ${relayUrl}. Must be wss://*.jaw.id or ws://localhost.`);\n }\n\n // Try existing session first — but never open a browser for a stale session.\n // If the browser is already connected, reuse it. If not, fall through to a new session.\n let relaySession = loadRelaySession();\n if (relaySession && relaySession.relayUrl === relayUrl && relaySession.peerPublicKey) {\n try {\n return await connectBridge(relaySession, options, chainId, keysUrl, relayUrl, false);\n } catch {\n // Connection failed — stale session or relay restarted.\n // Delete and fall through to create a new one.\n deleteRelaySession();\n relaySession = null;\n }\n } else if (relaySession) {\n // Incomplete session (no peer key) — discard\n deleteRelaySession();\n }\n\n // New session — this is the only path that opens a browser\n const session = await createNewSession(relayUrl);\n saveRelaySession(session);\n return await connectBridge(session, options, chainId, keysUrl, relayUrl, true);\n}\n\nasync function createNewSession(relayUrl: string): Promise<RelaySession> {\n const kp = await generateKeyPair();\n const privateKey = await exportKeyToHex('private', kp.privateKey);\n const publicKey = await exportKeyToHex('public', kp.publicKey);\n\n return {\n session: crypto.randomUUID(),\n relayUrl,\n privateKey,\n publicKey,\n peerPublicKey: null,\n startedAt: new Date().toISOString(),\n };\n}\n\nasync function connectBridge(\n relaySession: RelaySession,\n options: BridgeOptions,\n chainId: number,\n keysUrl: string,\n relayUrl: string,\n openBrowser: boolean\n): Promise<WSBridge> {\n const config = loadConfig();\n const bridge = new WSBridge({\n relayUrl,\n session: relaySession.session,\n timeout: options.timeout,\n config: {\n apiKey: options.apiKey,\n chainId,\n ens: options.ens ?? config.ens,\n paymasterUrl: options.paymasterUrl ?? config.paymasters?.[chainId]?.url,\n },\n privateKeyHex: relaySession.privateKey,\n publicKeyHex: relaySession.publicKey,\n peerPublicKeyHex: relaySession.peerPublicKey,\n });\n\n await bridge.connect(\n // onBrowserNeeded — only open a browser for new sessions\n openBrowser\n ? async () => {\n const bridgeUrl = buildBridgeUrl(keysUrl, relaySession.session, relayUrl, relaySession.publicKey);\n const { default: open } = await import('open');\n await open(bridgeUrl);\n }\n : undefined,\n // onPeerKeyChanged\n (newPeerKey) => {\n relaySession.peerPublicKey = newPeerKey;\n saveRelaySession(relaySession);\n }\n );\n\n return bridge;\n}\n\nfunction buildBridgeUrl(keysUrl: string, session: string, relayUrl: string, cliPublicKeyHex: string): string {\n const url = new URL('/cli-bridge', keysUrl);\n url.searchParams.set('session', session);\n url.searchParams.set('relay', relayUrl);\n // CLI public key in fragment — not sent to server\n url.hash = `pk=${cliPublicKeyHex}`;\n return url.toString();\n}\n\n/**\n * Shutdown: close the relay session and clean up.\n */\nexport async function shutdownDaemon(): Promise<void> {\n const session = loadRelaySession();\n if (!session) return;\n\n // Send shutdown directly — no init/ready handshake needed\n try {\n const bridge = new WSBridge({\n relayUrl: session.relayUrl,\n session: session.session,\n timeout: 5000,\n config: { apiKey: '', chainId: 1 },\n privateKeyHex: session.privateKey,\n publicKeyHex: session.publicKey,\n peerPublicKeyHex: session.peerPublicKey,\n });\n await bridge.connectAndShutdown();\n } catch {\n // Best effort — relay or browser may already be gone\n }\n\n deleteRelaySession();\n\n // Legacy cleanup: kill old daemon process and remove files\n const legacyBridge = PATHS.root + '/bridge.json';\n const legacyLog = PATHS.root + '/daemon.log';\n const legacyLock = PATHS.root + '/daemon.lock';\n try {\n if (fs.existsSync(legacyBridge)) {\n const info = JSON.parse(fs.readFileSync(legacyBridge, 'utf-8'));\n if (info.pid && Number.isInteger(info.pid) && info.pid > 0) {\n try {\n process.kill(info.pid, 'SIGTERM');\n } catch {\n /* already dead */\n }\n }\n }\n } catch {\n /* ignore */\n }\n for (const f of [legacyBridge, legacyLog, legacyLock]) {\n try {\n if (fs.existsSync(f)) fs.unlinkSync(f);\n } catch {\n /* ignore */\n }\n }\n}\n","/**\n * Classifies RPC methods to determine if they require browser interaction.\n * Used to show appropriate terminal prompts to the user.\n */\n\nconst BROWSER_REQUIRED_METHODS = new Set([\n // Signing\n 'personal_sign',\n 'eth_signTypedData_v4',\n 'wallet_sign',\n // Transactions\n 'wallet_sendCalls',\n 'eth_sendTransaction',\n // Connection / account\n 'wallet_connect',\n 'eth_requestAccounts',\n // Permissions\n 'wallet_grantPermissions',\n 'wallet_revokePermissions',\n]);\n\nexport function requiresBrowser(method: string): boolean {\n return BROWSER_REQUIRED_METHODS.has(method);\n}\n\nconst SESSION_SUPPORTED_METHODS = new Set([\n 'eth_requestAccounts',\n 'eth_accounts',\n 'wallet_sendCalls',\n 'wallet_getCallsStatus',\n 'personal_sign',\n 'eth_signTypedData_v4',\n]);\n\nexport function supportsSessionMode(method: string): boolean {\n return SESSION_SUPPORTED_METHODS.has(method);\n}\n","import * as crypto from 'node:crypto';\nimport * as fs from 'node:fs';\nimport { PATHS } from './paths.js';\nimport { ensureDir } from './config.js';\n\ninterface KeystoreFile {\n version: 2;\n privateKey: string;\n address: string;\n createdAt: string;\n}\n\n/**\n * Generate a random secp256k1 private key as 0x-prefixed hex.\n */\nexport function generateSessionKey(): `0x${string}` {\n const bytes = crypto.randomBytes(32);\n return `0x${bytes.toString('hex')}` as `0x${string}`;\n}\n\n/**\n * Save private key to keystore.json.\n * On-chain PermissionManager is the real security boundary — the session key\n * can only act within its granted permission scope regardless of local access.\n */\nexport function saveKeystore(privateKeyHex: string, address: string): void {\n const keystore: KeystoreFile = {\n version: 2,\n privateKey: privateKeyHex,\n address,\n createdAt: new Date().toISOString(),\n };\n\n ensureDir(PATHS.root);\n fs.writeFileSync(PATHS.keystore, JSON.stringify(keystore, null, 2) + '\\n', {\n encoding: 'utf-8',\n mode: 0o600,\n });\n // `mode` is only honored on file creation, not overwrite — re-apply explicitly.\n fs.chmodSync(PATHS.keystore, 0o600);\n}\n\n/**\n * Load private key hex from keystore.json.\n */\nexport function loadSessionKey(): string {\n if (!fs.existsSync(PATHS.keystore)) {\n throw new Error('No session configured. Run `jaw session setup` first.');\n }\n\n const contents = fs.readFileSync(PATHS.keystore, 'utf-8');\n let parsed: KeystoreFile;\n try {\n parsed = JSON.parse(contents) as KeystoreFile;\n } catch {\n throw new Error(`Keystore at ${PATHS.keystore} is corrupted. Run \\`jaw session setup\\` to recreate it.`);\n }\n return parsed.privateKey;\n}\n\n/**\n * Delete keystore.json.\n */\nexport function deleteKeystore(): void {\n if (fs.existsSync(PATHS.keystore)) {\n fs.unlinkSync(PATHS.keystore);\n }\n}\n\n/**\n * Check if keystore.json exists.\n */\nexport function keystoreExists(): boolean {\n return fs.existsSync(PATHS.keystore);\n}\n","import * as fs from 'node:fs';\nimport { PATHS } from './paths.js';\nimport { ensureDir } from './config.js';\n\nexport interface SessionConfig {\n ownerAddress: string;\n sessionAddress: string;\n permissionId: string;\n chainId: number;\n expiry: number;\n createdAt: string;\n}\n\nexport function saveSessionConfig(input: Omit<SessionConfig, 'createdAt'>): void {\n const config: SessionConfig = {\n ...input,\n createdAt: new Date().toISOString(),\n };\n ensureDir(PATHS.root);\n fs.writeFileSync(PATHS.sessionConfig, JSON.stringify(config, null, 2) + '\\n', {\n encoding: 'utf-8',\n mode: 0o600,\n });\n fs.chmodSync(PATHS.sessionConfig, 0o600);\n}\n\nexport function loadSessionConfig(): SessionConfig {\n if (!fs.existsSync(PATHS.sessionConfig)) {\n throw new Error('No session configured. Run `jaw session setup` first.');\n }\n const raw = fs.readFileSync(PATHS.sessionConfig, 'utf-8');\n try {\n return JSON.parse(raw) as SessionConfig;\n } catch {\n throw new Error(`Session config at ${PATHS.sessionConfig} is corrupted. Run \\`jaw session setup\\` to recreate it.`);\n }\n}\n\nexport function deleteSessionConfig(): void {\n if (fs.existsSync(PATHS.sessionConfig)) {\n fs.unlinkSync(PATHS.sessionConfig);\n }\n}\n","import { loadSessionKey } from './keystore.js';\nimport { loadSessionConfig, type SessionConfig } from './session-config.js';\nimport { loadConfig } from './config.js';\n\nexport interface SessionBridgeOptions {\n apiKey: string;\n chainId: number;\n paymasterUrl?: string;\n paymasterContext?: Record<string, unknown>;\n}\n\n/** Lazily resolved Account instance + session config */\ninterface InitializedSession {\n account: {\n address: string;\n sendCalls: (...args: unknown[]) => Promise<unknown>;\n getCallStatus: (batchId: `0x${string}`) => Promise<unknown>;\n signMessage: (message: string) => Promise<`0x${string}`>;\n signTypedData: (typedData: unknown) => Promise<`0x${string}`>;\n };\n config: SessionConfig;\n}\n\nexport class SessionBridge {\n private readonly options: SessionBridgeOptions;\n private session: InitializedSession | null = null;\n\n constructor(options: SessionBridgeOptions) {\n this.options = { ...options };\n\n if (!this.options.paymasterUrl) {\n const config = loadConfig();\n const pm = config.paymasters?.[this.options.chainId];\n if (pm) {\n this.options.paymasterUrl = pm.url;\n this.options.paymasterContext = pm.context;\n }\n }\n }\n\n private async getSession(): Promise<InitializedSession> {\n if (this.session) {\n this.checkExpiry(this.session.config);\n return this.session;\n }\n\n const config = loadSessionConfig();\n this.checkExpiry(config);\n\n if (config.chainId !== this.options.chainId) {\n throw new Error(\n `Session was created for chain ${config.chainId}, but --chain ${this.options.chainId} was requested. ` +\n `Run \\`jaw session setup --chain ${this.options.chainId}\\` to create a session for that chain.`\n );\n }\n\n let privateKeyHex: string | null = loadSessionKey();\n\n const { privateKeyToAccount } = await import('viem/accounts');\n const localAccount = privateKeyToAccount(privateKeyHex as `0x${string}`);\n privateKeyHex = null;\n\n const { Account } = await import('@jaw.id/core');\n const account = await Account.fromLocalAccount(\n {\n chainId: this.options.chainId,\n apiKey: this.options.apiKey,\n paymasterUrl: this.options.paymasterUrl,\n paymasterContext: this.options.paymasterContext,\n },\n localAccount\n );\n\n this.session = { account: account as InitializedSession['account'], config };\n return this.session;\n }\n\n private checkExpiry(config: SessionConfig): void {\n if (config.expiry <= Date.now() / 1000) {\n const expiryDate = new Date(config.expiry * 1000).toISOString();\n throw new Error(`Session expired on ${expiryDate}. Run \\`jaw session setup\\` to create a new session.`);\n }\n }\n\n async request(method: string, params?: unknown): Promise<unknown> {\n const { account, config } = await this.getSession();\n\n switch (method) {\n case 'eth_requestAccounts':\n case 'eth_accounts':\n return [config.sessionAddress];\n\n case 'wallet_sendCalls': {\n const payload = Array.isArray(params) ? params[0] : params;\n const { calls } = payload as {\n calls: Array<{ to: string; value?: string; data?: string }>;\n };\n return account.sendCalls(calls, {\n permissionId: config.permissionId as `0x${string}`,\n });\n }\n\n case 'wallet_getCallsStatus': {\n const batchId = Array.isArray(params) ? params[0] : params;\n return account.getCallStatus(batchId as `0x${string}`);\n }\n\n case 'personal_sign': {\n const message = Array.isArray(params) ? params[0] : params;\n return account.signMessage(message as string);\n }\n\n case 'eth_signTypedData_v4': {\n const asArray = Array.isArray(params) ? params : [params];\n const raw = asArray.length > 1 ? asArray[1] : asArray[0];\n const typedData = typeof raw === 'string' ? JSON.parse(raw) : raw;\n return account.signTypedData(typedData);\n }\n\n case 'wallet_grantPermissions':\n throw new Error('Requires browser — run `jaw session setup`.');\n\n case 'wallet_revokePermissions':\n throw new Error('Requires browser — run `jaw session revoke`.');\n\n default:\n throw new Error(`Method ${method} is not supported in auto mode.`);\n }\n }\n\n close(): void {\n // No-op — no WebSocket to close\n }\n}\n","import { Args, Flags } from '@oclif/core';\nimport { BaseCommand } from '../../base-command.js';\nimport { getBridge } from '../../lib/bridge-singleton.js';\nimport { loadConfig } from '../../lib/config.js';\nimport { requiresBrowser, supportsSessionMode } from '../../lib/rpc-classifier.js';\nimport { SessionBridge } from '../../lib/session-bridge.js';\nimport type { OutputFormat } from '../../lib/types.js';\n\nexport default class RpcCall extends BaseCommand {\n static override description = 'Execute any JAW.id RPC method via the browser bridge or local session key.';\n\n static override examples = [\n '<%= config.bin %> rpc call wallet_sendCalls \\'{\"calls\":[{\"to\":\"0x...\",\"value\":\"0x0\"}]}\\'',\n '<%= config.bin %> rpc call personal_sign \\'\"Hello World\"\\'',\n '<%= config.bin %> rpc call wallet_getAssets',\n '<%= config.bin %> rpc call eth_requestAccounts',\n '<%= config.bin %> rpc call wallet_getCallsStatus \\'\"0x...\"\\'',\n '<%= config.bin %> rpc call wallet_sendCalls \\'{\"calls\":[...]}\\' --session',\n ];\n\n static override args = {\n method: Args.string({\n description: 'EIP-1193 RPC method name',\n required: true,\n }),\n params: Args.string({\n description: 'Method parameters as JSON string',\n required: false,\n }),\n };\n\n static override flags = {\n ...BaseCommand.baseFlags,\n timeout: Flags.integer({\n char: 't',\n description: 'Request timeout in seconds',\n default: 120,\n }),\n session: Flags.boolean({\n char: 's',\n description: 'Use local session key (auto mode)',\n default: false,\n env: 'JAW_SESSION',\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(RpcCall);\n const { method } = args;\n\n let params: unknown;\n if (args.params) {\n try {\n params = JSON.parse(args.params);\n } catch {\n this.error(`Invalid JSON params: ${args.params}`);\n }\n }\n\n const format = flags.output as OutputFormat;\n const config = loadConfig();\n const apiKey = this.resolveApiKey(flags);\n const chainId = flags.chain ?? config.defaultChain ?? 1;\n\n let bridge: { request(method: string, params?: unknown): Promise<unknown>; close(): void };\n\n if (flags.session) {\n if (!supportsSessionMode(method)) {\n this.error(\n `Method ${method} is not supported in session mode. ` +\n 'Use without --session to route through the browser bridge.'\n );\n }\n\n bridge = new SessionBridge({ apiKey, chainId });\n\n if (!flags.quiet) {\n this.log(`Sending ${method} (session mode)...`);\n }\n } else {\n const pm = config.paymasters?.[chainId];\n bridge = await getBridge({\n keysUrl: config.keysUrl,\n apiKey,\n chainId,\n ens: config.ens,\n paymasterUrl: pm?.url,\n timeout: flags.timeout * 1000,\n });\n\n if (!flags.quiet) {\n if (requiresBrowser(method)) {\n this.log(`Sending ${method}... Check your browser to approve the request.`);\n } else {\n this.log(`Sending ${method}...`);\n }\n }\n }\n\n try {\n const result = await bridge.request(method, params);\n this.outputResult(result, format);\n } finally {\n bridge.close();\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../../../src/lib/paths.ts","../../../src/lib/validation.ts","../../../src/lib/config.ts","../../../src/lib/output.ts","../../../src/base-command.ts","../../../src/lib/crypto.ts","../../../src/lib/ws-bridge.ts","../../../src/lib/relay-session.ts","../../../src/lib/bridge-singleton.ts","../../../src/lib/rpc-classifier.ts","../../../src/lib/keystore.ts","../../../src/lib/session-config.ts","../../../src/x402/asset-registry.ts","../../../src/x402/permit2.ts","../../../src/lib/session-bridge.ts","../../../src/commands/rpc/call.ts"],"names":["fs2","crypto2","fs4","fs5","Flags"],"mappings":"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","file":"call.js","sourcesContent":["import * as path from 'node:path';\nimport * as os from 'node:os';\n\nconst JAW_DIR = path.join(os.homedir(), '.jaw');\n\nexport const PATHS = {\n root: JAW_DIR,\n config: path.join(JAW_DIR, 'config.json'),\n session: path.join(JAW_DIR, 'session.json'),\n relay: path.join(JAW_DIR, 'relay.json'),\n keystore: path.join(JAW_DIR, 'keystore.json'),\n sessionConfig: path.join(JAW_DIR, 'session-config.json'),\n x402Log: path.join(JAW_DIR, 'x402-log.jsonl'),\n paymentLock: path.join(JAW_DIR, 'x402-payment.lock'),\n} as const;\n","import type { PermissionsConfig } from './types.js';\n\nconst ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;\nconst SELECTOR_RE = /^0x[0-9a-fA-F]{8}$/;\n// The SDK hands `allowance` straight to BigInt(), which takes decimal and hex\n// alike, and the permissions doc shows the decimal form\n// (parseUnits('100', 6).toString()). Accepting only hex here made the CLI\n// stricter than the SDK it wraps, so the documented example failed validation.\nconst ALLOWANCE_RE = /^(0x[0-9a-fA-F]+|[0-9]+)$/;\nconst VALID_SPEND_UNITS = new Set(['minute', 'hour', 'day', 'week', 'month', 'year', 'forever']);\n\nexport function parsePermissionsConfig(raw: unknown): PermissionsConfig {\n const errors: string[] = [];\n\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw new Error('Invalid permissions:\\n - Must be an object');\n }\n\n const obj = raw as Record<string, unknown>;\n const calls = obj.calls as unknown[] | undefined;\n const spends = obj.spends as unknown[] | undefined;\n\n if (!calls && !spends) {\n throw new Error('Invalid permissions:\\n - Must include at least \"calls\" or \"spends\"');\n }\n\n if (calls !== undefined) {\n if (!Array.isArray(calls) || calls.length === 0) {\n errors.push('calls: Must be a non-empty array');\n } else {\n for (let i = 0; i < calls.length; i++) {\n const c = calls[i] as Record<string, unknown>;\n if (!c || typeof c !== 'object') {\n errors.push(`calls.${i}: Must be an object`);\n continue;\n }\n if (typeof c.target !== 'string' || !ADDRESS_RE.test(c.target)) {\n errors.push(`calls.${i}.target: Must be a valid 0x address (40 hex chars)`);\n }\n if (c.selector !== undefined && (typeof c.selector !== 'string' || !SELECTOR_RE.test(c.selector))) {\n errors.push(`calls.${i}.selector: Must be a 4-byte hex selector (e.g. 0xa9059cbb)`);\n }\n }\n }\n }\n\n if (spends !== undefined) {\n if (!Array.isArray(spends) || spends.length === 0) {\n errors.push('spends: Must be a non-empty array');\n } else {\n for (let i = 0; i < spends.length; i++) {\n const s = spends[i] as Record<string, unknown>;\n if (!s || typeof s !== 'object') {\n errors.push(`spends.${i}: Must be an object`);\n continue;\n }\n if (typeof s.token !== 'string' || !ADDRESS_RE.test(s.token)) {\n errors.push(`spends.${i}.token: Must be a valid 0x address (40 hex chars)`);\n }\n if (typeof s.allowance !== 'string' || !ALLOWANCE_RE.test(s.allowance)) {\n errors.push(`spends.${i}.allowance: Must be a decimal or 0x hex integer`);\n }\n if (typeof s.unit !== 'string' || !VALID_SPEND_UNITS.has(s.unit)) {\n errors.push(`spends.${i}.unit: Must be one of: ${[...VALID_SPEND_UNITS].join(', ')}`);\n }\n if (s.multiplier !== undefined && (!Number.isInteger(s.multiplier) || (s.multiplier as number) < 1)) {\n errors.push(`spends.${i}.multiplier: Must be a positive integer`);\n }\n }\n }\n }\n\n if (errors.length > 0) {\n throw new Error(`Invalid permissions:\\n${errors.map((e) => ` - ${e}`).join('\\n')}`);\n }\n\n return raw as PermissionsConfig;\n}\n\nexport function isValidKeysUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n const isTrustedHost =\n parsed.hostname.endsWith('.jaw.id') ||\n parsed.hostname === 'jaw.id' ||\n parsed.hostname === 'localhost' ||\n parsed.hostname === '127.0.0.1';\n const isSecure = parsed.protocol === 'https:' || parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1';\n return isTrustedHost && isSecure;\n } catch {\n return false;\n }\n}\n\nexport function isValidRelayUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n const isTrustedHost =\n parsed.hostname.endsWith('.jaw.id') ||\n parsed.hostname === 'jaw.id' ||\n parsed.hostname === 'localhost' ||\n parsed.hostname === '127.0.0.1';\n const isSecure = parsed.protocol === 'wss:' || parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1';\n const isWebSocket = parsed.protocol === 'wss:' || parsed.protocol === 'ws:';\n return isTrustedHost && isSecure && isWebSocket;\n } catch {\n return false;\n }\n}\n","import * as fs from 'node:fs';\nimport { PATHS } from './paths.js';\nimport type { JawConfig, SettableConfigKey } from './types.js';\nimport type { X402Policy, X402PolicyKey } from '../x402/policy.js';\nimport { isValidKeysUrl, isValidRelayUrl } from './validation.js';\n\nexport function ensureDir(dir: string): void {\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n fs.chmodSync(dir, 0o700);\n}\n\nfunction migrateConfig(config: JawConfig): JawConfig {\n if (config.paymasterUrl && !config.paymasters) {\n const chainId = config.defaultChain ?? 1;\n config.paymasters = { [chainId]: { url: config.paymasterUrl } };\n delete config.paymasterUrl;\n saveConfig(config);\n }\n return config;\n}\n\nexport function loadConfig(): JawConfig {\n if (!fs.existsSync(PATHS.config)) {\n return {};\n }\n const raw = fs.readFileSync(PATHS.config, 'utf-8');\n try {\n const config = JSON.parse(raw) as JawConfig;\n return migrateConfig(config);\n } catch {\n throw new Error(\n `Config file at ${PATHS.config} is not valid JSON. Run \\`jaw config set apiKey=<key>\\` to reset it.`\n );\n }\n}\n\nexport function saveConfig(config: JawConfig): void {\n ensureDir(PATHS.root);\n fs.writeFileSync(PATHS.config, JSON.stringify(config, null, 2) + '\\n', {\n encoding: 'utf-8',\n mode: 0o600,\n });\n}\n\n/** Paymaster URLs embed provider API keys as query params (e.g. Pimlico's ?apikey=...). */\nfunction redactUrlSecrets(url: string): string {\n try {\n const parsed = new URL(url);\n for (const key of [...parsed.searchParams.keys()]) {\n parsed.searchParams.set(key, '***');\n }\n return parsed.toString();\n } catch {\n return '***';\n }\n}\n\nexport function redactConfig(config: JawConfig): Record<string, unknown> {\n return {\n ...config,\n apiKey: config.apiKey ? `${config.apiKey.slice(0, 8)}...` : undefined,\n ...(config.paymasters && {\n paymasters: Object.fromEntries(\n Object.entries(config.paymasters).map(([chainId, pm]) => [\n chainId,\n // context is a free-form object (usually just a sponsorshipPolicyId) but a\n // provider could stash a token there, so mask it rather than hand it to the agent.\n { ...pm, url: redactUrlSecrets(pm.url), context: pm.context ? '***' : undefined },\n ])\n ),\n }),\n };\n}\n\n/**\n * Set one field of the `x402` payment policy. Array fields (allow-lists) are\n * comma-split. Intentionally NOT reachable from the MCP tool surface: an agent\n * must not be able to raise its own spending caps — only a human at the CLI.\n */\nexport function setX402PolicyValue(key: X402PolicyKey, value: string): void {\n const config = loadConfig();\n const x402: X402Policy = { ...(config.x402 ?? {}) };\n if (key === 'maxAmountPerPayment' || key === 'maxTotalPerSession' || key === 'topUpFloat') {\n // These are base-unit amounts read via BigInt() on the hot payment path;\n // reject anything that isn't a non-negative integer here so a bad value\n // can never turn into a per-payment failure later.\n if (!/^\\d+$/.test(value.trim())) {\n throw new Error(`${key} must be a non-negative integer (base units), got: ${value}`);\n }\n x402[key] = value.trim();\n } else {\n x402[key] = value\n .split(',')\n .map((v) => v.trim())\n .filter(Boolean);\n }\n saveConfig({ ...config, x402 });\n}\n\nexport function setConfigValue(key: SettableConfigKey, value: string | number): void {\n if (key === 'keysUrl' && typeof value === 'string' && !isValidKeysUrl(value)) {\n throw new Error(`Untrusted keysUrl: ${value}. Must be a *.jaw.id domain (HTTPS) or localhost.`);\n }\n if (key === 'relayUrl' && typeof value === 'string' && !isValidRelayUrl(value)) {\n throw new Error(`Untrusted relayUrl: ${value}. Must be wss://*.jaw.id or ws://localhost.`);\n }\n // Numeric keys: coerce + validate here so EVERY caller is safe. The MCP tool\n // passes raw strings (its schema types value as a string), so without this a\n // `sessionExpiry: \"abc\"` would land as a string and turn `expiry * 86400`\n // into NaN, and a `defaultChain` string would ride into an RPC URL verbatim.\n let toStore: string | number = value;\n if (key === 'defaultChain' || key === 'sessionExpiry') {\n // Strict: reject anything parseInt would silently truncate ('1.5' -> 1,\n // '0x10' -> 0, '10abc' -> 10). Only a bare positive decimal integer passes.\n const n = typeof value === 'number' ? value : /^\\d+$/.test(value.trim()) ? parseInt(value.trim(), 10) : NaN;\n if (!Number.isInteger(n) || n <= 0) {\n throw new Error(`${key} must be a positive integer, got: ${JSON.stringify(value)}`);\n }\n toStore = n;\n }\n const config = loadConfig();\n const updated = { ...config, [key]: toStore };\n saveConfig(updated);\n}\n","import type { OutputFormat } from './types.js';\n\nexport function formatOutput(data: unknown, format: OutputFormat): string {\n if (format === 'json') {\n return JSON.stringify(data, replaceBigInt, 2);\n }\n return formatHuman(data);\n}\n\nfunction replaceBigInt(_key: string, value: unknown): unknown {\n if (typeof value === 'bigint') {\n return value.toString();\n }\n return value;\n}\n\nfunction formatHuman(data: unknown, indent = 0): string {\n if (data === null || data === undefined) {\n return 'null';\n }\n\n if (typeof data === 'string' || typeof data === 'number' || typeof data === 'boolean' || typeof data === 'bigint') {\n return String(data);\n }\n\n if (Array.isArray(data)) {\n if (data.length === 0) return '(empty)';\n return data.map((item, i) => `${i + 1}. ${formatHuman(item, indent + 2)}`).join('\\n');\n }\n\n if (typeof data === 'object') {\n const entries = Object.entries(data as Record<string, unknown>);\n if (entries.length === 0) return '(empty)';\n const pad = ' '.repeat(indent);\n const maxKeyLen = Math.max(...entries.map(([k]) => k.length));\n return entries\n .map(([key, val]) => {\n const paddedKey = key.padEnd(maxKeyLen);\n const valStr = typeof val === 'object' && val !== null ? '\\n' + formatHuman(val, indent + 2) : String(val);\n return `${pad}${paddedKey} ${valStr}`;\n })\n .join('\\n');\n }\n\n return String(data);\n}\n","import { Command, Flags } from '@oclif/core';\nimport type { OutputFormat } from './lib/types.js';\nimport { loadConfig } from './lib/config.js';\nimport { formatOutput } from './lib/output.js';\n\nexport abstract class BaseCommand extends Command {\n static override baseFlags = {\n output: Flags.string({\n char: 'o',\n description: 'Output format',\n options: ['json', 'human'],\n default: 'human',\n env: 'JAW_OUTPUT',\n }),\n chain: Flags.integer({\n char: 'c',\n description: 'Chain ID',\n env: 'JAW_CHAIN_ID',\n }),\n 'api-key': Flags.string({\n description: 'JAW API key',\n env: 'JAW_API_KEY',\n }),\n yes: Flags.boolean({\n char: 'y',\n description: 'Skip confirmations (for AI agents)',\n default: false,\n }),\n quiet: Flags.boolean({\n char: 'q',\n description: 'Suppress non-essential output',\n default: false,\n }),\n };\n\n protected resolveApiKey(flags: { 'api-key'?: string }): string {\n const apiKey = flags['api-key'] ?? loadConfig().apiKey;\n if (!apiKey) {\n this.error('API key required. Set via --api-key, JAW_API_KEY env, or `jaw config set apiKey <key>`');\n }\n return apiKey;\n }\n\n protected resolveChainId(flags: { chain?: number }): number {\n const chainId = flags.chain ?? loadConfig().defaultChain;\n if (!chainId) {\n this.error('Chain ID required. Set via --chain, JAW_CHAIN_ID env, or `jaw config set defaultChain <id>`');\n }\n return chainId;\n }\n\n protected outputResult(data: unknown, format: OutputFormat): void {\n const output = formatOutput(data, format);\n this.log(output);\n }\n}\n","/**\n * E2E encryption primitives for CLI ↔ browser communication.\n *\n * Uses ECDH P-256 for key exchange and AES-256-GCM for message encryption.\n * Mirrors the same crypto operations in @jaw.id/core but uses only\n * Node.js built-in crypto.subtle — no external dependencies.\n */\n\nimport type { webcrypto } from 'node:crypto';\n\ntype CKey = webcrypto.CryptoKey;\ntype CKeyPair = webcrypto.CryptoKeyPair;\n\nconst subtle = globalThis.crypto.subtle;\n\n// ── Key generation ───────────────────────────────────────────────\n\nexport async function generateKeyPair(): Promise<CKeyPair> {\n return subtle.generateKey({ name: 'ECDH', namedCurve: 'P-256' }, true, ['deriveKey']) as Promise<CKeyPair>;\n}\n\nexport async function deriveSharedSecret(privateKey: CKey, peerPublicKey: CKey): Promise<CKey> {\n return subtle.deriveKey(\n { name: 'ECDH', public: peerPublicKey },\n privateKey,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt', 'decrypt']\n );\n}\n\n// ── Encrypt / Decrypt ────────────────────────────────────────────\n\nexport interface EncryptedEnvelope {\n iv: string; // base64\n ciphertext: string; // base64\n}\n\nexport async function encryptMessage(sharedSecret: CKey, payload: Record<string, unknown>): Promise<EncryptedEnvelope> {\n const iv = globalThis.crypto.getRandomValues(new Uint8Array(12));\n const plaintext = new TextEncoder().encode(JSON.stringify(payload));\n const cipherBuf = await subtle.encrypt({ name: 'AES-GCM', iv }, sharedSecret, plaintext);\n return {\n iv: bufferToBase64(iv),\n ciphertext: bufferToBase64(new Uint8Array(cipherBuf)),\n };\n}\n\nexport async function decryptMessage(\n sharedSecret: CKey,\n envelope: EncryptedEnvelope\n): Promise<Record<string, unknown>> {\n const iv = Buffer.from(envelope.iv, 'base64');\n const ciphertext = Buffer.from(envelope.ciphertext, 'base64');\n const plainBuf = await subtle.decrypt({ name: 'AES-GCM', iv }, sharedSecret, ciphertext);\n return JSON.parse(new TextDecoder().decode(plainBuf));\n}\n\n// ── Key import / export (hex) ────────────────────────────────────\n\nexport async function exportKeyToHex(type: 'private' | 'public', key: CKey): Promise<string> {\n const format = type === 'private' ? 'pkcs8' : 'spki';\n const buf = await subtle.exportKey(format, key);\n return bytesToHex(new Uint8Array(buf));\n}\n\nexport async function importKeyFromHex(type: 'private' | 'public', hex: string): Promise<CKey> {\n const format = type === 'private' ? 'pkcs8' : 'spki';\n return subtle.importKey(\n format,\n Buffer.from(hexToBytes(hex)),\n { name: 'ECDH', namedCurve: 'P-256' },\n true,\n type === 'private' ? ['deriveKey'] : []\n );\n}\n\n// ── Encoding helpers ─────────────────────────────────────────────\n\nfunction bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\nfunction hexToBytes(hex: string): Uint8Array {\n if (hex.length % 2 !== 0) throw new Error('Invalid hex: odd length');\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);\n }\n return bytes;\n}\n\nfunction bufferToBase64(buf: Uint8Array): string {\n return Buffer.from(buf).toString('base64');\n}\n","/**\n * WSBridge — CLI-side relay client\n *\n * Connects to the cloud relay (wss://relay.jaw.id) instead of a local daemon.\n * All messages (except key_exchange) are E2E encrypted via ECDH + AES-256-GCM.\n */\n\nimport * as crypto from 'node:crypto';\nimport type { webcrypto } from 'node:crypto';\nimport WebSocket from 'ws';\nimport {\n deriveSharedSecret,\n encryptMessage,\n decryptMessage,\n importKeyFromHex,\n type EncryptedEnvelope,\n} from './crypto.js';\n\ntype CKey = webcrypto.CryptoKey;\n\nexport interface WSBridgeConfig {\n apiKey: string;\n chainId: number;\n ens?: string;\n paymasterUrl?: string;\n paymasterContext?: Record<string, unknown>;\n}\n\nexport interface WSBridgeOptions {\n relayUrl: string;\n session: string;\n timeout?: number;\n /** How long to wait for the browser to connect. See DEFAULT_CONNECT_TIMEOUT_MS. */\n connectTimeout?: number;\n config: WSBridgeConfig;\n /** CLI's ECDH private key (hex). Loaded from relay.json for existing sessions. */\n privateKeyHex: string;\n /** CLI's ECDH public key (hex). Sent to browser for key derivation. */\n publicKeyHex: string;\n /** Browser's ECDH public key (hex). Null if new session (key exchange needed). */\n peerPublicKeyHex: string | null;\n}\n\n/**\n * The `init` payload the CLI hands the browser once the shared secret exists.\n *\n * A function rather than an object literal inside the handshake so what crosses\n * the bridge can be asserted without standing up a relay and a socket.\n *\n * `paymasterContext` travels with its url or not at all. The two name one\n * paymaster between them, and the browser resolves a url of its own when none\n * arrives — a context sent alone would be applied to whichever paymaster that\n * turns out to be, which is the divergence the SDK-side resolution just closed.\n */\nexport function buildInitPayload(config: WSBridgeConfig): Record<string, unknown> {\n return {\n type: 'init',\n apiKey: config.apiKey,\n chainId: config.chainId,\n ens: config.ens,\n paymasterUrl: config.paymasterUrl,\n ...(config.paymasterUrl && config.paymasterContext ? { paymasterContext: config.paymasterContext } : {}),\n };\n}\n\nconst DEFAULT_TIMEOUT_MS = 120_000;\n/**\n * How long to wait for the browser to reach the relay, which is a different\n * wait from `DEFAULT_TIMEOUT_MS`: that one covers approving a request once the\n * page is there, this one covers the page arriving at all. Thirty seconds fits\n * a browser this process opened itself and nothing else. A URL carried to a\n * phone, a first passkey enrolment, or a machine with no browser to open takes\n * longer than that before anyone has done anything wrong.\n */\nconst DEFAULT_CONNECT_TIMEOUT_MS = 30_000;\n\n/**\n * Maximum outbound message size (5 MB).\n *\n * wallet_sendCalls with large batches (50+ calls, complex calldata) can reach\n * hundreds of KB. Base64 encoding of the AES-GCM ciphertext adds ~33% overhead.\n * 5 MB is generous enough for any realistic batch while still preventing\n * accidental memory issues.\n */\nconst MAX_MESSAGE_BYTES = 5 * 1024 * 1024;\n\n/** Minimum time between browser reopen attempts (ms). */\nconst BROWSER_REOPEN_COOLDOWN_MS = 5_000;\n\n/** Maximum reconnection attempts before giving up. */\nconst MAX_RECONNECT_ATTEMPTS = 3;\n\n/** Base delay for exponential backoff (ms). */\nconst RECONNECT_BASE_DELAY_MS = 1_000;\n\nexport class WSBridge {\n private readonly relayUrl: string;\n private readonly session: string;\n private readonly timeout: number;\n private readonly connectTimeout: number;\n private readonly config: WSBridgeConfig;\n private readonly privateKeyHex: string;\n readonly publicKeyHex: string;\n private peerPublicKeyHex: string | null;\n private sharedSecret: CKey | null = null;\n private ws: WebSocket | null = null;\n private disposed = false;\n\n // Auto-reopen browser state\n private onBrowserNeeded: (() => Promise<void>) | undefined;\n private onPeerKeyChanged: ((key: string) => void) | undefined;\n private lastBrowserOpenTime = 0;\n\n // Reconnection state\n private reconnectAttempts = 0;\n\n /** Updated after key exchange — caller should persist this. */\n get peerPublicKey(): string | null {\n return this.peerPublicKeyHex;\n }\n\n constructor(options: WSBridgeOptions) {\n this.relayUrl = options.relayUrl;\n this.session = options.session;\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;\n this.connectTimeout = options.connectTimeout ?? DEFAULT_CONNECT_TIMEOUT_MS;\n this.config = options.config;\n this.privateKeyHex = options.privateKeyHex;\n this.publicKeyHex = options.publicKeyHex;\n this.peerPublicKeyHex = options.peerPublicKeyHex;\n }\n\n /**\n * Connect to the relay and wait for the browser to be ready.\n *\n * @param onBrowserNeeded — called when the relay reports no browser connected.\n * @param onPeerKeyChanged — called when a key_exchange updates the peer key.\n */\n async connect(\n onBrowserNeeded?: () => Promise<void>,\n onPeerKeyChanged?: (newPeerPublicKeyHex: string) => void\n ): Promise<void> {\n // Store callbacks for auto-reopen on browser disconnect\n this.onBrowserNeeded = onBrowserNeeded;\n this.onPeerKeyChanged = onPeerKeyChanged;\n\n // Pre-derive shared secret if we already have the peer key\n if (this.peerPublicKeyHex) {\n await this.deriveSecret();\n }\n\n return this.connectInternal(onBrowserNeeded, onPeerKeyChanged);\n }\n\n private async connectInternal(\n onBrowserNeeded?: () => Promise<void>,\n onPeerKeyChanged?: (newPeerPublicKeyHex: string) => void\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n const url = `${this.relayUrl}?session=${encodeURIComponent(this.session)}&role=cli`;\n const ws = new WebSocket(url);\n\n let browserOpened = false;\n let resolved = false;\n let expectingKeyExchange = !this.peerPublicKeyHex;\n\n const timer = setTimeout(() => {\n ws.close();\n reject(\n new Error(\n `Browser did not connect within ${Math.round(this.connectTimeout / 1000)}s.\\n` +\n 'Run `jaw disconnect` then try again, or raise JAW_BRIDGE_TIMEOUT_MS.'\n )\n );\n }, this.connectTimeout);\n\n const sendEncryptedInit = async () => {\n if (!this.sharedSecret) return;\n const envelope = await encryptMessage(this.sharedSecret, buildInitPayload(this.config));\n this.sendRaw(ws, JSON.stringify({ type: 'encrypted', ...envelope }));\n };\n\n const waitForReady = () => {\n const readyTimer = setTimeout(() => {\n ws.close();\n reject(new Error('Browser SDK did not become ready in time.'));\n }, 15_000);\n\n const onMsg = async (data: WebSocket.Data) => {\n const msg = safeParse(data);\n if (!msg) return;\n\n if (msg.type === 'encrypted' && this.sharedSecret) {\n try {\n const inner = await decryptMessage(this.sharedSecret, msg as unknown as EncryptedEnvelope);\n if (inner.type === 'ready') {\n clearTimeout(readyTimer);\n ws.off('message', onMsg);\n this.reconnectAttempts = 0; // Reset on successful connect\n resolve();\n }\n } catch {\n // Not a valid encrypted message for us, ignore\n }\n }\n };\n ws.on('message', onMsg);\n };\n\n const onBrowserReady = async () => {\n if (resolved) return;\n resolved = true;\n clearTimeout(timer);\n // Set up listener BEFORE sending init to avoid missing the ready response\n waitForReady();\n await sendEncryptedInit();\n };\n\n ws.on('open', () => {\n this.ws = ws;\n });\n\n ws.on('message', async (data) => {\n const msg = safeParse(data);\n if (!msg) return;\n\n if (msg.type === 'status') {\n if (msg.browserConnected) {\n if (this.sharedSecret) {\n // Already have shared secret — skip key exchange\n await onBrowserReady();\n } else {\n // Browser is connected but we don't have its key yet.\n expectingKeyExchange = true;\n }\n } else if (!browserOpened && onBrowserNeeded) {\n browserOpened = true;\n expectingKeyExchange = true;\n onBrowserNeeded().catch(() => {\n /* best effort */\n });\n } else if (!onBrowserNeeded) {\n // Reuse path (bridge-singleton.ts called connectBridge with\n // openBrowser=false): the relay reports no browser connected and\n // we have no callback to open one. Bail immediately so the\n // caller can fall through to a fresh session, instead of waiting\n // out the 30s connect-timer.\n clearTimeout(timer);\n ws.close();\n reject(new Error('Browser not connected — relay session is stale.'));\n }\n } else if (msg.type === 'browser_connected') {\n expectingKeyExchange = true;\n // Wait for key_exchange from browser\n } else if (msg.type === 'browser_disconnected') {\n // Browser tab closed — attempt to reopen after cooldown\n this.handleBrowserDisconnect();\n } else if (msg.type === 'key_exchange' && expectingKeyExchange) {\n expectingKeyExchange = false;\n const peerKey = msg.publicKey as string;\n this.peerPublicKeyHex = peerKey;\n await this.deriveSecret();\n onPeerKeyChanged?.(peerKey);\n await onBrowserReady();\n }\n });\n\n ws.on('error', (err) => {\n clearTimeout(timer);\n reject(err);\n });\n\n ws.on('close', () => {\n clearTimeout(timer);\n if (!this.disposed) {\n this.handleRelayDisconnect();\n }\n });\n });\n }\n\n /**\n * Send an encrypted RPC request through the relay to the browser SDK.\n */\n async request(method: string, params?: unknown): Promise<unknown> {\n const ws = this.ws;\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n throw new Error('Not connected to relay');\n }\n if (!this.sharedSecret) {\n throw new Error('No shared secret — key exchange not completed');\n }\n\n const id = crypto.randomUUID();\n\n const envelope = await encryptMessage(this.sharedSecret, {\n type: 'rpc_request',\n id,\n method,\n params,\n });\n\n const serialized = JSON.stringify({ type: 'encrypted', ...envelope });\n assertMessageSize(serialized, method);\n\n return new Promise<unknown>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(\n new Error(`Request timed out after ${this.timeout / 1000}s. ` + 'Did you complete the action in the browser?')\n );\n this.close();\n }, this.timeout);\n\n const onMessage = async (data: WebSocket.Data) => {\n const msg = safeParse(data);\n if (!msg || msg.type !== 'encrypted' || !this.sharedSecret) return;\n\n try {\n const inner = await decryptMessage(this.sharedSecret, msg as unknown as EncryptedEnvelope);\n if (inner.type === 'rpc_response' && inner.id === id) {\n clearTimeout(timer);\n ws.off('message', onMessage);\n\n if (inner.success) {\n resolve(inner.data);\n } else {\n const err = inner.error as { code: number; message: string } | undefined;\n reject(new Error(err ? `[${err.code}] ${err.message}` : 'Request failed'));\n }\n }\n } catch {\n // Decryption failed — not our message or tampered, ignore\n }\n };\n\n ws.on('message', onMessage);\n this.sendRaw(ws, serialized);\n });\n }\n\n async shutdown(): Promise<void> {\n this.disposed = true;\n if (this.ws?.readyState === WebSocket.OPEN && this.sharedSecret) {\n try {\n const envelope = await encryptMessage(this.sharedSecret, {\n type: 'shutdown',\n });\n this.sendRaw(this.ws, JSON.stringify({ type: 'encrypted', ...envelope }));\n } catch {\n // Best effort\n }\n }\n this.close();\n }\n\n /**\n * Connect to relay and send shutdown directly — no init/ready handshake.\n * Used by `jaw disconnect` when we just need to tell the browser to close.\n */\n async connectAndShutdown(): Promise<void> {\n if (!this.peerPublicKeyHex) {\n // No peer key means browser never connected — nothing to shut down\n return;\n }\n\n this.disposed = true;\n await this.deriveSecret();\n\n return new Promise<void>((resolve) => {\n const url = `${this.relayUrl}?session=${encodeURIComponent(this.session)}&role=cli`;\n const ws = new WebSocket(url);\n\n const timer = setTimeout(() => {\n try {\n ws.close();\n } catch {\n /* ignore */\n }\n resolve();\n }, 3000);\n\n ws.on('open', async () => {\n this.ws = ws;\n try {\n await this.shutdown();\n } catch {\n // Best effort\n }\n clearTimeout(timer);\n resolve();\n });\n\n ws.on('error', () => {\n clearTimeout(timer);\n resolve();\n });\n });\n }\n\n close(): void {\n this.disposed = true;\n if (this.ws) {\n try {\n this.ws.close();\n } catch {\n // ignore\n }\n this.ws = null;\n }\n }\n\n /**\n * Auto-reopen browser when browser_disconnected is received from relay.\n * Respects a cooldown to prevent rapid re-opening.\n */\n private handleBrowserDisconnect(): void {\n if (this.disposed || !this.onBrowserNeeded) return;\n\n const now = Date.now();\n if (now - this.lastBrowserOpenTime < BROWSER_REOPEN_COOLDOWN_MS) {\n return; // Too soon — skip this reopen\n }\n\n this.lastBrowserOpenTime = now;\n\n // Reset shared secret — the new browser tab will do a fresh key exchange\n this.sharedSecret = null;\n this.peerPublicKeyHex = null;\n\n this.onBrowserNeeded().catch(() => {\n // Best effort — if browser open fails, the next request will error\n });\n }\n\n /**\n * Attempt to reconnect to the relay with exponential backoff\n * when the WebSocket connection drops unexpectedly.\n */\n private handleRelayDisconnect(): void {\n if (this.disposed) return;\n if (this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) return;\n\n const delay = RECONNECT_BASE_DELAY_MS * Math.pow(2, this.reconnectAttempts);\n this.reconnectAttempts++;\n\n setTimeout(() => {\n if (this.disposed) return;\n this.connectInternal(this.onBrowserNeeded, this.onPeerKeyChanged).catch(() => {\n // Reconnection failed — will retry if attempts remain\n });\n }, delay);\n }\n\n /** Send a raw string over the WebSocket, enforcing message size limits. */\n private sendRaw(ws: WebSocket, data: string): void {\n ws.send(data);\n }\n\n private async deriveSecret(): Promise<void> {\n if (!this.peerPublicKeyHex) return;\n const privateKey = await importKeyFromHex('private', this.privateKeyHex);\n const peerPublicKey = await importKeyFromHex('public', this.peerPublicKeyHex);\n this.sharedSecret = await deriveSharedSecret(privateKey, peerPublicKey);\n }\n}\n\n/**\n * Validate message size before sending to the relay.\n * Throws with a descriptive error if the message is too large.\n */\nfunction assertMessageSize(serialized: string, method: string): void {\n const byteLength = Buffer.byteLength(serialized, 'utf-8');\n if (byteLength > MAX_MESSAGE_BYTES) {\n const sizeMB = (byteLength / (1024 * 1024)).toFixed(2);\n throw new Error(\n `Message for ${method} is too large (${sizeMB} MB, limit ${MAX_MESSAGE_BYTES / (1024 * 1024)} MB). ` +\n 'Try reducing the number of calls in your batch.'\n );\n }\n}\n\nfunction safeParse(data: WebSocket.Data): Record<string, unknown> | null {\n try {\n return JSON.parse(data.toString()) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n","/**\n * Relay session persistence (~/.jaw/relay.json).\n * Shared by the bridge lifecycle (bridge-singleton) and status reporting (MCP jaw_status).\n */\n\nimport * as fs from 'node:fs';\nimport { PATHS } from './paths.js';\nimport { ensureDir } from './config.js';\n\nexport interface RelaySession {\n session: string;\n relayUrl: string;\n privateKey: string;\n publicKey: string;\n peerPublicKey: string | null;\n startedAt: string;\n}\n\nexport function loadRelaySession(): RelaySession | null {\n try {\n if (!fs.existsSync(PATHS.relay)) return null;\n const raw = fs.readFileSync(PATHS.relay, 'utf-8');\n const parsed = JSON.parse(raw) as RelaySession;\n // Basic validation\n if (!parsed.session || !parsed.relayUrl || !parsed.privateKey || !parsed.publicKey) {\n return null;\n }\n return parsed;\n } catch {\n return null;\n }\n}\n\nexport function saveRelaySession(info: RelaySession): void {\n ensureDir(PATHS.root);\n fs.writeFileSync(PATHS.relay, JSON.stringify(info, null, 2) + '\\n', {\n encoding: 'utf-8',\n mode: 0o600,\n });\n}\n\nexport function deleteRelaySession(): void {\n try {\n if (fs.existsSync(PATHS.relay)) fs.unlinkSync(PATHS.relay);\n } catch {\n // ignore\n }\n}\n","/**\n * Bridge lifecycle management — relay edition.\n *\n * - Generates a session token + ECDH keypair for new sessions\n * - Opens the browser to keys.jaw.id/cli-bridge\n * - Saves relay state to ~/.jaw/relay.json\n * - Creates a WSBridge client connected to the relay\n */\n\nimport * as fs from 'node:fs';\nimport * as crypto from 'node:crypto';\nimport { PATHS } from './paths.js';\nimport { loadConfig } from './config.js';\nimport { WSBridge } from './ws-bridge.js';\nimport { isValidKeysUrl, isValidRelayUrl } from './validation.js';\nimport { generateKeyPair, exportKeyToHex } from './crypto.js';\nimport { type RelaySession, loadRelaySession, saveRelaySession, deleteRelaySession } from './relay-session.js';\n\nconst DEFAULT_KEYS_URL = 'https://keys.jaw.id';\nconst DEFAULT_RELAY_URL = 'wss://relay.jaw.id';\n\nexport interface BridgeOptions {\n keysUrl?: string;\n relayUrl?: string;\n apiKey: string;\n chainId?: number;\n ens?: string;\n timeout?: number;\n connectTimeout?: number;\n}\n\n/**\n * Get or create a relay bridge connection.\n */\nexport async function getBridge(options: BridgeOptions): Promise<WSBridge> {\n const config = loadConfig();\n // Both waits on a person: thirty seconds for the browser to reach the relay,\n // two minutes to approve once it is there. Those suit a browser this process\n // opened itself and nothing else. A first passkey, a URL carried to a phone,\n // or a machine with no browser to open takes longer than either before\n // anyone has done anything wrong, so one knob raises both.\n const envTimeout = Number(process.env['JAW_BRIDGE_TIMEOUT_MS']);\n const fromEnv = Number.isFinite(envTimeout) && envTimeout > 0 ? envTimeout : undefined;\n const timeout = options.timeout ?? fromEnv;\n // Resolved on its own, never from the caller's request timeout. Deriving it\n // meant `jaw rpc call --timeout 300` silently gave the browser five minutes\n // to connect, and then dropping that flag's default cut the same wait to\n // thirty seconds. Neither followed from anything the caller asked for.\n const connectTimeout = options.connectTimeout ?? fromEnv;\n const keysUrl = options.keysUrl ?? config.keysUrl ?? DEFAULT_KEYS_URL;\n const relayUrl = options.relayUrl ?? config.relayUrl ?? DEFAULT_RELAY_URL;\n const chainId = options.chainId ?? config.defaultChain ?? 1;\n if (!isValidKeysUrl(keysUrl)) {\n throw new Error(`Untrusted keysUrl: ${keysUrl}. Must be a *.jaw.id domain (HTTPS) or localhost.`);\n }\n if (!isValidRelayUrl(relayUrl)) {\n throw new Error(`Untrusted relayUrl: ${relayUrl}. Must be wss://*.jaw.id or ws://localhost.`);\n }\n\n // Try existing session first — but never open a browser for a stale session.\n // If the browser is already connected, reuse it. If not, fall through to a new session.\n let relaySession = loadRelaySession();\n if (relaySession && relaySession.relayUrl === relayUrl && relaySession.peerPublicKey) {\n try {\n // Deliberately not the long wait: nothing is opened here, so this only\n // asks whether the browser from an earlier command is still connected.\n // When it is not, the answer is to give up quickly and fall through to a\n // fresh session that does open one. Waiting the human-sized wait to find\n // that out leaves the command silent for as long as someone will stare at\n // it, having just told them a browser was opening.\n return await connectBridge({ ...options, timeout }, relaySession, chainId, keysUrl, relayUrl, false);\n } catch {\n // Connection failed — stale session or relay restarted.\n // Delete and fall through to create a new one.\n deleteRelaySession();\n relaySession = null;\n }\n } else if (relaySession) {\n // Incomplete session (no peer key) — discard\n deleteRelaySession();\n }\n\n // New session — this is the only path that opens a browser\n const session = await createNewSession(relayUrl);\n saveRelaySession(session);\n return await connectBridge({ ...options, timeout, connectTimeout }, session, chainId, keysUrl, relayUrl, true);\n}\n\nasync function createNewSession(relayUrl: string): Promise<RelaySession> {\n const kp = await generateKeyPair();\n const privateKey = await exportKeyToHex('private', kp.privateKey);\n const publicKey = await exportKeyToHex('public', kp.publicKey);\n\n return {\n session: crypto.randomUUID(),\n relayUrl,\n privateKey,\n publicKey,\n peerPublicKey: null,\n startedAt: new Date().toISOString(),\n };\n}\n\nasync function connectBridge(\n options: BridgeOptions,\n relaySession: RelaySession,\n chainId: number,\n keysUrl: string,\n relayUrl: string,\n openBrowser: boolean\n): Promise<WSBridge> {\n const config = loadConfig();\n // Read as one entry, so the url and the context cannot come from different\n // paymasters. Every caller used to look this up and forward the url alone,\n // which is how a configured `context` was lost before it reached the browser.\n const paymaster = config.paymasters?.[chainId];\n const bridge = new WSBridge({\n relayUrl,\n session: relaySession.session,\n timeout: options.timeout,\n connectTimeout: options.connectTimeout,\n config: {\n apiKey: options.apiKey,\n chainId,\n ens: options.ens ?? config.ens,\n paymasterUrl: paymaster?.url,\n paymasterContext: paymaster?.context,\n },\n privateKeyHex: relaySession.privateKey,\n publicKeyHex: relaySession.publicKey,\n peerPublicKeyHex: relaySession.peerPublicKey,\n });\n\n await bridge.connect(\n // onBrowserNeeded — only open a browser for new sessions\n openBrowser\n ? async () => {\n const bridgeUrl = buildBridgeUrl(keysUrl, relaySession.session, relayUrl, relaySession.publicKey);\n // Over SSH, in a container, or under a test driver, there is no\n // browser worth opening and `open` either does nothing or opens one on\n // the wrong machine, leaving the command waiting on an approval nobody\n // was told how to give. Printing the URL is the way out, and it goes\n // to stderr so it cannot land in the middle of `--output json`.\n if (process.env['JAW_NO_BROWSER']) {\n process.stderr.write(`Open this URL to approve:\\n${bridgeUrl}\\n`);\n return;\n }\n const { default: open } = await import('open');\n await open(bridgeUrl);\n }\n : undefined,\n // onPeerKeyChanged\n (newPeerKey) => {\n relaySession.peerPublicKey = newPeerKey;\n saveRelaySession(relaySession);\n }\n );\n\n return bridge;\n}\n\nfunction buildBridgeUrl(keysUrl: string, session: string, relayUrl: string, cliPublicKeyHex: string): string {\n const url = new URL('/cli-bridge', keysUrl);\n url.searchParams.set('session', session);\n url.searchParams.set('relay', relayUrl);\n // CLI public key in fragment — not sent to server\n url.hash = `pk=${cliPublicKeyHex}`;\n return url.toString();\n}\n\n/**\n * Shutdown: close the relay session and clean up.\n */\nexport async function shutdownDaemon(): Promise<void> {\n const session = loadRelaySession();\n if (!session) return;\n\n // Send shutdown directly — no init/ready handshake needed\n try {\n const bridge = new WSBridge({\n relayUrl: session.relayUrl,\n session: session.session,\n timeout: 5000,\n config: { apiKey: '', chainId: 1 },\n privateKeyHex: session.privateKey,\n publicKeyHex: session.publicKey,\n peerPublicKeyHex: session.peerPublicKey,\n });\n await bridge.connectAndShutdown();\n } catch {\n // Best effort — relay or browser may already be gone\n }\n\n deleteRelaySession();\n\n // Legacy cleanup: kill old daemon process and remove files\n const legacyBridge = PATHS.root + '/bridge.json';\n const legacyLog = PATHS.root + '/daemon.log';\n const legacyLock = PATHS.root + '/daemon.lock';\n try {\n if (fs.existsSync(legacyBridge)) {\n const info = JSON.parse(fs.readFileSync(legacyBridge, 'utf-8'));\n if (info.pid && Number.isInteger(info.pid) && info.pid > 0) {\n try {\n process.kill(info.pid, 'SIGTERM');\n } catch {\n /* already dead */\n }\n }\n }\n } catch {\n /* ignore */\n }\n for (const f of [legacyBridge, legacyLog, legacyLock]) {\n try {\n if (fs.existsSync(f)) fs.unlinkSync(f);\n } catch {\n /* ignore */\n }\n }\n}\n","/**\n * Classifies RPC methods to determine if they require browser interaction.\n * Used to show appropriate terminal prompts to the user.\n */\n\nconst BROWSER_REQUIRED_METHODS = new Set([\n // Signing\n 'personal_sign',\n 'eth_signTypedData_v4',\n 'wallet_sign',\n // Transactions\n 'wallet_sendCalls',\n 'eth_sendTransaction',\n // Connection / account\n 'wallet_connect',\n 'eth_requestAccounts',\n // Permissions\n 'wallet_grantPermissions',\n 'wallet_revokePermissions',\n]);\n\nexport function requiresBrowser(method: string): boolean {\n return BROWSER_REQUIRED_METHODS.has(method);\n}\n\n/**\n * What the session key may do without a human present.\n *\n * Signing is deliberately absent. A session that signs arbitrary typed data can\n * be asked for an EIP-3009 authorization or an EIP-2612 `permit` over its own\n * USDC, and neither is a call, so neither passes the x402 policy, reaches the\n * ledger, or takes the payment lock. A `permit` is the worse of the two: it\n * leaves a standing allowance, so it takes every later top-up as it arrives\n * rather than just the balance of the moment.\n *\n * Being delegated does not help. USDC routes a delegated account through\n * EIP-1271, and ERC-7739 rejects a raw signature over the plain digest, but the\n * envelope is ordinary typed data and the wrapping suffix is public (see\n * `wrappedSigner` in `x402/payer.ts`), so asking for the envelope gets the same\n * result.\n *\n * Nothing here needs it: the payer signs through its own injected signer and\n * top-ups go through `wallet_sendCalls`. A caller that wants a signature can\n * still ask for one through the browser, where a human sees what it is.\n */\nconst SESSION_SUPPORTED_METHODS = new Set([\n 'eth_requestAccounts',\n 'eth_accounts',\n 'wallet_sendCalls',\n 'wallet_getCallsStatus',\n]);\n\nexport function supportsSessionMode(method: string): boolean {\n return SESSION_SUPPORTED_METHODS.has(method);\n}\n","import * as crypto from 'node:crypto';\nimport * as fs from 'node:fs';\nimport { PATHS } from './paths.js';\nimport { ensureDir } from './config.js';\n\ninterface KeystoreFile {\n version: 2;\n privateKey: string;\n address: string;\n createdAt: string;\n}\n\n/**\n * Generate a random secp256k1 private key as 0x-prefixed hex.\n */\nexport function generateSessionKey(): `0x${string}` {\n const bytes = crypto.randomBytes(32);\n return `0x${bytes.toString('hex')}` as `0x${string}`;\n}\n\n/**\n * Save private key to keystore.json.\n * On-chain PermissionManager is the real security boundary — the session key\n * can only act within its granted permission scope regardless of local access.\n */\nexport function saveKeystore(privateKeyHex: string, address: string): void {\n const keystore: KeystoreFile = {\n version: 2,\n privateKey: privateKeyHex,\n address,\n createdAt: new Date().toISOString(),\n };\n\n ensureDir(PATHS.root);\n fs.writeFileSync(PATHS.keystore, JSON.stringify(keystore, null, 2) + '\\n', {\n encoding: 'utf-8',\n mode: 0o600,\n });\n // `mode` is only honored on file creation, not overwrite — re-apply explicitly.\n fs.chmodSync(PATHS.keystore, 0o600);\n}\n\n/**\n * Load private key hex from keystore.json.\n */\nexport function loadSessionKey(): string {\n if (!fs.existsSync(PATHS.keystore)) {\n throw new Error('No session configured. Run `jaw session setup` first.');\n }\n\n const contents = fs.readFileSync(PATHS.keystore, 'utf-8');\n let parsed: KeystoreFile;\n try {\n parsed = JSON.parse(contents) as KeystoreFile;\n } catch {\n throw new Error(`Keystore at ${PATHS.keystore} is corrupted. Run \\`jaw session setup\\` to recreate it.`);\n }\n return parsed.privateKey;\n}\n\n/**\n * Load the session address from keystore.json, or null if it cannot be read.\n * Used to name the key in messages, so a corrupt keystore degrades the message\n * rather than the command.\n */\nexport function tryLoadKeystoreAddress(): string | null {\n try {\n if (!fs.existsSync(PATHS.keystore)) return null;\n const parsed = JSON.parse(fs.readFileSync(PATHS.keystore, 'utf-8')) as KeystoreFile;\n return parsed.address ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * Delete keystore.json.\n */\nexport function deleteKeystore(): void {\n if (fs.existsSync(PATHS.keystore)) {\n fs.unlinkSync(PATHS.keystore);\n }\n}\n\n/**\n * Check if keystore.json exists.\n */\nexport function keystoreExists(): boolean {\n return fs.existsSync(PATHS.keystore);\n}\n","import * as fs from 'node:fs';\nimport { PATHS } from './paths.js';\nimport { ensureDir } from './config.js';\n\n/**\n * How the session account address is derived, as it appears on disk.\n *\n * 'eip7702' is the only one written now: the session key EOA itself, upgraded\n * in place via a delegation attached to its first userOp, so the session\n * account and the x402 payer are one address.\n *\n * 'counterfactual' is what earlier versions wrote, and what a config from\n * before the field existed means: a CREATE2 prediction from the account\n * factory, a second address that holds nothing and so cannot be charged for\n * the gas of the ops it sends. Still in the union because those files exist and\n * `SessionBridge` has to recognise them; `SessionSetup` never writes it.\n */\nexport type SessionMode = 'counterfactual' | 'eip7702';\n\n/**\n * The granted permission as `JustaPermissionManager` stores it.\n *\n * Every view on the manager takes `Permission calldata` and hashes it inside:\n * `isApproved`, `isRevoked` and `getCurrentPeriod` all do, and none of them\n * accept an id. A session holding only `permissionId` therefore holds the one\n * field the chain will not answer about, which is why nothing local could tell\n * that a permission had been revoked from another device.\n *\n * The grant response already carries all of it, so this costs a wider write\n * rather than a network call. Optional on read for two reasons: configs written\n * before this field exist, and a wallet running an older core answers with the\n * id alone. Consumers fall back to the local file, which is what those sessions\n * already meant.\n */\nexport interface GrantedPermission {\n account: string;\n spender: string;\n /**\n * Unix seconds the permission starts at. Also the anchor the contract steps\n * its period windows from, and what the local policy anchors on. A summary\n * field used to hold an approximation of it taken from the local clock.\n */\n start: number;\n /** Unix seconds the permission ends at. */\n end: number;\n /** Hex, as the grant returned it. Widened to a bigint at encode time. */\n salt: string;\n calls: Array<{ target: string; selector: string }>;\n spends: Array<{ token: string; allowance: string; unit: string; multiplier: number }>;\n}\n\nconst ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;\nconst SELECTOR_RE = /^0x[0-9a-fA-F]{8}$/;\nconst HEX_RE = /^0x[0-9a-fA-F]+$/;\n/** Decimal or hex, matching what the SDK hands to `BigInt()`. */\nconst ALLOWANCE_RE = /^(0x[0-9a-fA-F]+|[0-9]+)$/;\n/** The units a grant may carry. `year` has no on-chain enum and is rewritten before encoding. */\nconst SPEND_UNITS = new Set(['minute', 'hour', 'day', 'week', 'month', 'year', 'forever']);\n\nfunction isPositiveInt(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value > 0;\n}\n\n/**\n * The permission struct out of a `wallet_grantPermissions` response, or\n * undefined when the response does not carry a usable one.\n *\n * Undefined rather than a throw, on every malformed field. By the time this\n * runs the grant is already on chain, and refusing to write the session over a\n * field that arrived in an unexpected shape would strand a live permission with\n * no local record of it. A session that skips this keeps behaving the way every\n * session behaved before the field existed.\n *\n * Strict about what it does accept: a struct that is wrong in any part hashes\n * to something other than the granted permission, so every on-chain read made\n * from it would quietly answer about a permission that does not exist.\n */\nexport function parseGrantedPermission(raw: unknown): GrantedPermission | undefined {\n if (typeof raw !== 'object' || raw === null) return undefined;\n const r = raw as Record<string, unknown>;\n\n const { account, spender, salt } = r;\n if (typeof account !== 'string' || !ADDRESS_RE.test(account)) return undefined;\n if (typeof spender !== 'string' || !ADDRESS_RE.test(spender)) return undefined;\n if (typeof salt !== 'string' || !HEX_RE.test(salt)) return undefined;\n if (!isPositiveInt(r.start) || !isPositiveInt(r.end)) return undefined;\n\n if (!Array.isArray(r.calls) || r.calls.length === 0) return undefined;\n const calls: GrantedPermission['calls'] = [];\n for (const entry of r.calls) {\n if (typeof entry !== 'object' || entry === null) return undefined;\n const { target, selector } = entry as Record<string, unknown>;\n if (typeof target !== 'string' || !ADDRESS_RE.test(target)) return undefined;\n // The response builds the selector from the signature, so an entry without\n // one cannot be reconstructed: the signature it came from is not returned.\n if (typeof selector !== 'string' || !SELECTOR_RE.test(selector)) return undefined;\n calls.push({ target, selector });\n }\n\n if (!Array.isArray(r.spends)) return undefined;\n const spends: GrantedPermission['spends'] = [];\n for (const entry of r.spends) {\n if (typeof entry !== 'object' || entry === null) return undefined;\n const { token, allowance, unit, multiplier } = entry as Record<string, unknown>;\n if (typeof token !== 'string' || !ADDRESS_RE.test(token)) return undefined;\n if (typeof allowance !== 'string' || !ALLOWANCE_RE.test(allowance)) return undefined;\n if (typeof unit !== 'string' || !SPEND_UNITS.has(unit)) return undefined;\n // `multiplier` is a uint16 on chain and defaults to 1 in the grant, but the\n // encoded struct has to carry the number the permission was hashed with,\n // so an absent one is a struct we cannot rebuild rather than a 1.\n if (!isPositiveInt(multiplier) || multiplier > 65535) return undefined;\n spends.push({ token, allowance, unit, multiplier });\n }\n\n return { account, spender, start: r.start, end: r.end, salt, calls, spends };\n}\n\n/**\n * Whether this session predates the CLI settling on one account derivation, so\n * its permission belongs to an address separate from the session key and no op\n * it sends can be charged for its own gas.\n *\n * Named rather than compared inline: three callers ask this, and each one\n * spelled as `mode !== 'eip7702'` reads like a check for a variant among\n * several, when the only question is whether the session is still usable.\n */\nexport function isLegacySession(config: Pick<SessionConfig, 'mode'>): boolean {\n return config.mode !== 'eip7702';\n}\n\n/**\n * A permission this CLI granted and then stopped tracking.\n *\n * `session setup` replaces a session rather than adding to it, and it does not\n * always revoke what it replaces: the interactive path takes no for an answer,\n * and `--yes` never revokes at all. The session key is reused by default, so\n * the address the session signs with then holds two live grants while the\n * config names one. Its real authority is the sum of both, `x402 status`\n * reports only the new one, and `session revoke` could not reach the old one\n * at all, because the id lived in the file that was overwritten.\n *\n * Keeping the id is what makes it reachable again. Nothing here revokes on its\n * own: setup already asked.\n */\nexport interface OrphanedPermission {\n id: string;\n chainId: number;\n /** Unix seconds. */\n expiry: number;\n}\n\nexport interface SessionConfig {\n ownerAddress: string;\n sessionAddress: string;\n permissionId: string;\n chainId: number;\n expiry: number;\n createdAt: string;\n mode?: SessionMode;\n /** The struct the on-chain reads need. Absent on older sessions; see the type. */\n permission?: GrantedPermission;\n /** Permissions this key still holds that the session no longer names. */\n orphanedPermissions?: OrphanedPermission[];\n /**\n * Whether the permission this session names has already been revoked, while\n * something else it holds has not.\n *\n * Its own field rather than a rewritten `expiry`, which is what this was\n * first. `expiry` means when the permission ends, and the recovered-struct\n * check compares it against the permission's own `end` to know the relay\n * answered about this session: overwriting it made that comparison fail\n * forever, so a partly revoked session could never recover its struct and\n * went back to reporting \"cannot tell\", which is the state recovery exists to\n * end. A field that says one thing cannot be borrowed to say another.\n */\n permissionRevoked?: boolean;\n}\n\n/**\n * The orphans still worth carrying, newest first.\n *\n * An expired permission authorises nothing, so it is dropped rather than\n * accumulating in the file for the life of the machine. Dropping it is the same\n * decision `session revoke` makes when it skips the browser for an expired\n * session.\n */\nexport function liveOrphans(\n orphans: OrphanedPermission[] | undefined,\n now: number = Date.now() / 1000\n): OrphanedPermission[] {\n return (orphans ?? []).filter((orphan) => orphan.expiry > now);\n}\n\n/**\n * `mode` is required and pinned here, unlike on the read side where it stays\n * optional to describe files earlier versions wrote. Nothing but `SessionSetup`\n * writes a session, and a session written without the mode would be refused by\n * `SessionBridge` as if an old CLI had made it, so the compiler holds the\n * invariant rather than a test having to.\n */\nexport function saveSessionConfig(\n input: Omit<SessionConfig, 'createdAt' | 'mode'> & {\n mode: 'eip7702';\n /**\n * Carried over when a session is being replaced in place rather than\n * started, which `session add` does. `createdAt` is what the session total\n * is counted from (`sumSpentSince(payer, session.createdAt)`), so stamping a\n * fresh one there would hand the session cap a clean slate as a side effect\n * of adding a capability.\n */\n createdAt?: string;\n }\n): void {\n writeSessionConfig({ ...input, createdAt: input.createdAt ?? new Date().toISOString() });\n}\n\n/**\n * Written to a temporary file and renamed over the real one, which is atomic on\n * the same filesystem, so a reader never sees a half-written config.\n *\n * It matters more than it did: recovering the permission struct made two\n * commands that only ever read (`x402 status`, `session status`) into writers,\n * and the MCP server runs alongside a terminal, so two processes writing at\n * once is ordinary rather than exotic. A torn file loses the permission id,\n * which is exactly the stranding the orphan list exists to prevent.\n */\nfunction writeSessionConfig(config: SessionConfig): void {\n ensureDir(PATHS.root);\n const temp = `${PATHS.sessionConfig}.${process.pid}.tmp`;\n fs.writeFileSync(temp, JSON.stringify(config, null, 2) + '\\n', { encoding: 'utf-8', mode: 0o600 });\n fs.chmodSync(temp, 0o600);\n fs.renameSync(temp, PATHS.sessionConfig);\n}\n\n/**\n * Store a permission struct recovered for a session that was written without\n * one, leaving the rest of the file alone. Same reason as below for not going\n * through `saveSessionConfig`: it stamps a fresh `createdAt`.\n */\nexport function saveRecoveredPermission(config: SessionConfig, permission: GrantedPermission): boolean {\n // Merged into the file as it is now, not into the snapshot the caller loaded.\n // Recovery holds its copy across a relay round trip, and in that time a\n // `session revoke` running beside it writes progress between browser\n // approvals: renaming the old copy back over it would restore the expiry and\n // the orphan list that revoke had just cleared, and the next revoke would\n // re-attempt ids that are already gone. Reading immediately before the write\n // does not make this a transaction, it makes the window microseconds instead\n // of the length of a network call.\n //\n // A session that disappeared in the meantime stays gone: the only thing being\n // added here is a cache of something the relay can produce again.\n const current = tryLoadSessionConfig();\n if (!current || current.permissionId !== config.permissionId) return false;\n writeSessionConfig({ ...current, permission });\n return true;\n}\n\n/**\n * Record what a revoke has already done, so the rest of it can be retried.\n *\n * Revoking is not idempotent: core reads the permission from the relay before\n * sending and deletes it from there afterwards, so a second attempt at an id\n * already revoked fails before it sends anything. A session left naming an id\n * that is gone therefore costs a browser round trip that can only fail, which\n * is why what succeeded has to come out of the file as it succeeds.\n *\n * `ownPermissionRevoked` is recorded on its own field. Borrowing `expiry` for\n * it, which is what this did first, made that field mean two things at once and\n * broke the recovered-struct check that compares it against the permission's\n * own `end`. What it is for is unchanged: stopping the next revoke from\n * attempting an id the relay no longer has.\n *\n * Separate from `saveSessionConfig` because that one stamps a fresh\n * `createdAt`, and `createdAt` is what the session total is counted from\n * (`sumSpentSince(payer, session.createdAt)`). Editing a session through it\n * would hand the session cap a clean slate as a side effect of revoking one\n * permission.\n */\nexport function saveRevokeProgress(\n config: SessionConfig,\n progress: { orphans: OrphanedPermission[]; ownPermissionRevoked: boolean }\n): void {\n // Merged into the file as it stands, for the same reason\n // `saveRecoveredPermission` does: this runs between browser round trips, and\n // a recovery finishing beside it would otherwise be dropped by the next\n // progress write.\n const next: SessionConfig = { ...(tryLoadSessionConfig() ?? config) };\n if (progress.orphans.length > 0) next.orphanedPermissions = progress.orphans;\n else delete next.orphanedPermissions;\n if (progress.ownPermissionRevoked) next.permissionRevoked = true;\n writeSessionConfig(next);\n}\n\nexport function sessionConfigExists(): boolean {\n return fs.existsSync(PATHS.sessionConfig);\n}\n\nexport function loadSessionConfig(): SessionConfig {\n if (!fs.existsSync(PATHS.sessionConfig)) {\n throw new Error('No session configured. Run `jaw session setup` first.');\n }\n const raw = fs.readFileSync(PATHS.sessionConfig, 'utf-8');\n try {\n return JSON.parse(raw) as SessionConfig;\n } catch {\n throw new Error(`Session config at ${PATHS.sessionConfig} is corrupted. Run \\`jaw session setup\\` to recreate it.`);\n }\n}\n\n/**\n * Like `loadSessionConfig`, but returns null instead of throwing when the file\n * is missing or unreadable. For callers that can recover from a keystore whose\n * session-config is gone (interrupted setup, manual deletion, partial restore)\n * rather than callers that need an existing session to do their job.\n */\nexport function tryLoadSessionConfig(): SessionConfig | null {\n try {\n return loadSessionConfig();\n } catch {\n return null;\n }\n}\n\nexport function deleteSessionConfig(): void {\n if (fs.existsSync(PATHS.sessionConfig)) {\n fs.unlinkSync(PATHS.sessionConfig);\n }\n}\n","// USDC asset registry, mirrored from the backend's\n// `apps/ens/src/external/payment/asset-registry.ts`. Keep this in sync when the\n// server adds a chain. `wireNetwork` is the CAIP-2 id used on the x402 v2 wire.\n\nexport interface UsdcAsset {\n address: `0x${string}`;\n chainId: number;\n wireNetwork: string;\n /** EIP-712 domain `name` for this deployment's USDC. */\n usdcName: string;\n /** EIP-712 domain `version`. */\n usdcVersion: string;\n /**\n * Token decimals. Every USDC deployment here is 6, but carrying it on the\n * registry entry (rather than a literal `6` at the format site) keeps the\n * source of truth in one place and is ready for a non-6-decimal asset when\n * the registry grows past USDC. Reading it off-chain from the contract is\n * deliberately avoided: the registry is a controlled allowlist, so an extra\n * RPC round-trip and trusting a token's self-reported decimals buy nothing.\n */\n decimals: number;\n}\n\nexport const USDC_BY_NETWORK: Record<string, UsdcAsset> = {\n 'eip155:8453': {\n address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n chainId: 8453,\n wireNetwork: 'eip155:8453',\n usdcName: 'USD Coin',\n usdcVersion: '2',\n decimals: 6,\n },\n 'eip155:84532': {\n address: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n chainId: 84532,\n wireNetwork: 'eip155:84532',\n usdcName: 'USDC',\n usdcVersion: '2',\n decimals: 6,\n },\n 'eip155:137': {\n address: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n chainId: 137,\n wireNetwork: 'eip155:137',\n usdcName: 'USD Coin',\n usdcVersion: '2',\n decimals: 6,\n },\n 'eip155:80002': {\n address: '0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582',\n chainId: 80002,\n wireNetwork: 'eip155:80002',\n usdcName: 'USDC',\n usdcVersion: '2',\n decimals: 6,\n },\n};\n\n/**\n * Look up USDC metadata by CAIP-2 network id, or `undefined` if unsupported.\n *\n * Own keys only. The network reaches here from a 402 challenge and from the\n * Bazaar catalogue, both untrusted, and a plain index answers `constructor` or\n * `toString` with something off the prototype: callers then read `.address` off\n * a function and throw where they expected an unsupported network.\n */\nexport function usdcForNetwork(network: string): UsdcAsset | undefined {\n return Object.hasOwn(USDC_BY_NETWORK, network) ? USDC_BY_NETWORK[network] : undefined;\n}\n","/**\n * Permit2 declarations for the x402 `upto` scheme.\n *\n * `upto` does not settle through EIP-3009 the way `exact` does. The client signs\n * a Permit2 `permitWitnessTransferFrom` authorizing a ceiling, and the\n * facilitator later calls the x402 proxy with the amount the run actually\n * consumed, which the proxy refuses if it exceeds the ceiling. The witness binds\n * both the recipient and the facilitator, so a signature is not useful to anyone\n * else.\n *\n * Everything here is a declaration: the addresses, the structs, and the domain.\n * Hashing them is viem's job. Choosing a nonce, a deadline, a spender or an\n * amount, and deciding whether a challenge may be paid at all, belongs to the\n * scheme module and the policy, not to this file.\n */\n\n/**\n * Canonical Permit2, the same address `JustaPermissionManager` pins as its\n * `PERMIT2` constant. Deployed deterministically, so it does not vary per chain.\n */\nexport const PERMIT2_ADDRESS = '0x000000000022D473030F116dDEE9F6B43aC78BA3' as const;\n\n/**\n * `x402UptoPermit2Proxy`, the spender the payer authorizes and the only contract\n * allowed to settle the permit.\n *\n * Pinned rather than read from the challenge. The spender is what a Permit2\n * signature hands the ability to move funds to, so accepting a server-supplied\n * one would authorize a stranger to pull up to the ceiling. This is the same\n * rule the `exact` scheme already applies to the token address.\n *\n * Verified on chain on 2026-08-28, not just read from a repo: deployed at this\n * address on both Base Mainnet and Base Sepolia with an identical codehash\n * (`0x4662dc27...`), which is what a deterministic CREATE2 deployment should\n * look like. The runtime bytecode contains the witness type string and the\n * typehash below as literals, so the transcription is checked against the\n * contract that will actually run and not only against its source.\n *\n * Two traps live near this address. The x402 README still lists Base Mainnet as\n * having no `upto` deployment, which is stale. And Base Sepolia carries a\n * second, legacy proxy at `0x402039b3d6E6BEC5A02c2C9fd937ac17A6940002` with\n * different bytecode, predating the deterministic build. Nothing refuses a\n * challenge that names it: the spender is not read off the wire at all, this\n * constant is written into every permit, and a challenge advertising the legacy\n * proxy is signed for this one instead. Substituting silently is the safe\n * direction, since the permit stays worth its ceiling only to the address\n * pinned here, but it is a substitution and not a refusal.\n */\nexport const X402_UPTO_PROXY_ADDRESS = '0x4020A4f3b7b90ccA423B9fabCc0CE57C6C240002' as const;\n\n/**\n * The chains the proxy above was verified on, and therefore the only ones an\n * `upto` payment may be signed for.\n *\n * The asset registry is wider than this: it also carries USDC on Polygon and\n * Amoy, and nothing about a deterministic address makes a contract exist on a\n * chain nobody deployed it to. Signing a permit whose spender has no code\n * produces an authorization that can never settle, and by the ledger's own rule\n * a failed attempt reserves its whole ceiling against the cap, so the cost of\n * guessing lands on the user. Allow what was checked, refuse the rest, and widen\n * this when a deployment is confirmed rather than assumed.\n */\nexport const UPTO_VERIFIED_CHAIN_IDS: readonly number[] = [8453, 84532];\n\n/**\n * `WITNESS_TYPE_STRING` from `x402UptoPermit2Proxy.sol`, reproduced verbatim.\n * Permit2 concatenates it onto its own stub to form the full type, so the two\n * halves below must stay exactly as the contracts spell them: the struct order\n * (TokenPermissions before Witness) is the alphabetical order EIP-712 requires,\n * and a single byte out of place produces a signature that no verifier accepts\n * and no error explains.\n */\nconst UPTO_WITNESS_TYPE_STRING =\n 'Witness witness)TokenPermissions(address token,uint256 amount)Witness(address to,address facilitator,uint256 validAfter)';\n\n/** Permit2's `_PERMIT_TRANSFER_FROM_WITNESS_TYPEHASH_STUB`. */\nconst PERMIT_TRANSFER_FROM_WITNESS_STUB =\n 'PermitWitnessTransferFrom(TokenPermissions permitted,address spender,uint256 nonce,uint256 deadline,';\n\n/** The canonical EIP-712 type string for what the payer signs under `upto`. */\nexport const PERMIT2_UPTO_CONTENTS_TYPE = PERMIT_TRANSFER_FROM_WITNESS_STUB + UPTO_WITNESS_TYPE_STRING;\n\n/**\n * The same structs as a viem types object. This is what actually gets signed, on\n * both validation paths: viem derives the canonical type from it, which is what\n * makes the string above a check on this rather than a second copy of it.\n */\nexport const PERMIT_WITNESS_TRANSFER_FROM_TYPES = {\n PermitWitnessTransferFrom: [\n { name: 'permitted', type: 'TokenPermissions' },\n { name: 'spender', type: 'address' },\n { name: 'nonce', type: 'uint256' },\n { name: 'deadline', type: 'uint256' },\n { name: 'witness', type: 'Witness' },\n ],\n TokenPermissions: [\n { name: 'token', type: 'address' },\n { name: 'amount', type: 'uint256' },\n ],\n Witness: [\n { name: 'to', type: 'address' },\n { name: 'facilitator', type: 'address' },\n { name: 'validAfter', type: 'uint256' },\n ],\n} as const;\n\n/** What the payer authorizes: a ceiling, a spender, and the witness binding. */\nexport interface UptoPermitMessage {\n permitted: { token: `0x${string}`; amount: bigint };\n spender: `0x${string}`;\n nonce: bigint;\n deadline: bigint;\n witness: { to: `0x${string}`; facilitator: `0x${string}`; validAfter: bigint };\n}\n\n/**\n * Permit2's EIP-712 domain. It carries no `version`, so passing an empty one\n * would produce a domain separator the contract never computes and a signature\n * it never accepts.\n */\nexport function permit2Domain(chainId: number): { name: string; chainId: number; verifyingContract: `0x${string}` } {\n return { name: 'Permit2', chainId, verifyingContract: PERMIT2_ADDRESS };\n}\n","import { loadSessionKey } from './keystore.js';\nimport { isLegacySession, loadSessionConfig, type SessionConfig } from './session-config.js';\nimport { loadConfig } from './config.js';\nimport { encodeFunctionData, erc20Abi, maxUint256 } from 'viem';\nimport { usdcForNetwork } from '../x402/asset-registry.js';\nimport { PERMIT2_ADDRESS } from '../x402/permit2.js';\n\n// JAW's ERC-20 paymaster, mirrored from core's JAW_PAYMASTER_URL. Kept as a\n// local literal rather than an import because `@jaw.id/core` is lazy-loaded in\n// the CLI (a static import would pull it into startup); keep in sync if core's\n// URL moves. The core SDK recognises this exact base URL and adds the USDC\n// approval the paymaster needs, so the path must match byte for byte.\nconst JAW_ERC20_PAYMASTER_URL = 'https://api.justaname.id/proxy/v1/rpc/erc20-paymaster';\n\n/**\n * The paymaster an auto-mode userOp goes out with, in precedence order: an\n * explicit url, then `config.paymasters` for the chain, then JAW's own.\n *\n * Falling through to JAW's is what makes the default path need no configuration.\n * Without it a fresh setup could not top up at all: the account has to prefund\n * the EntryPoint for the worst-case gas, which fails on an account holding only\n * USDC, and the error names none of this. Asking the user for a paymaster url\n * put the ERC-7677 app-developer role on someone who is just using the wallet,\n * and it asked them to sign up with the provider we already proxy and pay for.\n *\n * It takes its fee in USDC rather than sponsoring anything, so the account never\n * needs a native token, which is the point: gas comes out of the same balance\n * the payments do. `config.paymasters` still wins, so anyone bringing their own\n * keeps it.\n */\nfunction resolvePaymaster(\n options: SessionBridgeOptions\n): Pick<SessionBridgeOptions, 'paymasterUrl' | 'paymasterContext'> {\n if (options.paymasterUrl) {\n return { paymasterUrl: options.paymasterUrl, paymasterContext: options.paymasterContext };\n }\n\n const configured = loadConfig().paymasters?.[options.chainId];\n if (configured) {\n return { paymasterUrl: configured.url, paymasterContext: configured.context };\n }\n\n // No api key means nothing to authenticate the proxy with, so there is no\n // paymaster to engage and the account pays its gas in the native token.\n if (!options.apiKey) return {};\n\n // The ERC-20 paymaster has to be told which token it is being paid in: the SDK\n // sizes and emits the `approve` it needs from this address, and without it the\n // userOp reaches the paymaster with no allowance behind it and cannot settle.\n // A chain the registry does not cover has no token to name, so fall back to\n // sending with no paymaster rather than engaging one that must fail.\n const asset = usdcForNetwork(`eip155:${options.chainId}`);\n if (!asset) {\n // Say so rather than falling through quietly: the userOp goes out with no\n // paymaster, and the failure the user eventually sees is about native funds\n // and mentions none of this. stderr, so stdio MCP framing is untouched.\n console.warn(\n `[jaw] No USDC in the x402 asset registry for chain ${options.chainId}, so no ERC-20 paymaster ` +\n 'can be engaged. Gas will come out of the account\\u2019s native balance. ' +\n 'Set `paymasters` in your config to sponsor this chain.'\n );\n return {};\n }\n\n const url = new URL(JAW_ERC20_PAYMASTER_URL);\n url.searchParams.set('chainId', String(options.chainId));\n url.searchParams.set('api-key', options.apiKey);\n return { paymasterUrl: url.toString(), paymasterContext: { token: asset.address } };\n}\n\n/**\n * The one way the send still breaks once nothing is sponsored: the ERC-20\n * paymaster charges the account the userOp is sent from, and an account with no\n * USDC cannot be charged, so sizing its approval fails. Core's error names the\n * token and the chain and nothing about the account, which is what made this\n * hard to read the first time it happened.\n *\n * A session normally receives its gas in the grant, so an empty one means that\n * transfer did not happen: the wallet that approved the permission does not\n * carry it yet. Say the address and the amount rather than leaving the user to\n * work backwards from a paymaster error.\n */\nfunction explainUnchargeableSender(err: unknown, sessionAddress: string): unknown {\n const message = err instanceof Error ? err.message : String(err);\n if (!message.includes('Could not size the ERC-20 paymaster approval')) return err;\n return new Error(\n `${message}\\n\\nIf ${sessionAddress} holds no USDC, that is why: it pays for its own gas and ` +\n 'cannot be charged with an empty balance. Send it 0.1 USDC, or run `jaw session setup` again.',\n { cause: err }\n );\n}\n\nexport interface SessionBridgeOptions {\n apiKey: string;\n chainId: number;\n paymasterUrl?: string;\n paymasterContext?: Record<string, unknown>;\n}\n\n/** Lazily resolved Account instance + session config */\ninterface InitializedSession {\n account: {\n address: string;\n sendCalls: (...args: unknown[]) => Promise<unknown>;\n getCallStatus: (batchId: `0x${string}`) => Promise<unknown>;\n };\n config: SessionConfig;\n}\n\nexport class SessionBridge {\n private readonly options: SessionBridgeOptions;\n private session: InitializedSession | null = null;\n\n constructor(options: SessionBridgeOptions) {\n this.options = { ...options, ...resolvePaymaster(options) };\n }\n\n private async getSession(): Promise<InitializedSession> {\n if (this.session) {\n this.checkExpiry(this.session.config);\n return this.session;\n }\n\n const config = loadSessionConfig();\n this.checkExpiry(config);\n\n // Sessions from before the CLI settled on EIP-7702 granted their permission\n // to a counterfactual second address, which holds nothing and so cannot be\n // charged the gas of the ops it sends. Re-deriving one of those here would\n // produce a different address and fail at the mismatch guard below, which\n // blames the keystore. Say what it actually is, and how to fix it.\n if (isLegacySession(config)) {\n throw new Error(\n 'This session was created by an older CLI and uses a session address separate from the session key. ' +\n 'Run `jaw session setup` to recreate it, which offers to revoke the old permission first. ' +\n '`jaw session status` still shows the old session, and `jaw session revoke` still revokes it.'\n );\n }\n\n if (config.chainId !== this.options.chainId) {\n throw new Error(\n `Session was created for chain ${config.chainId}, but --chain ${this.options.chainId} was requested. ` +\n `Run \\`jaw session setup --chain ${this.options.chainId}\\` to create a session for that chain.`\n );\n }\n\n let privateKeyHex: string | null = loadSessionKey();\n\n const { privateKeyToAccount } = await import('viem/accounts');\n const localAccount = privateKeyToAccount(privateKeyHex as `0x${string}`);\n privateKeyHex = null;\n\n const { Account } = await import('@jaw.id/core');\n // Every session is EIP-7702, so the account re-derives to the session key\n // EOA and the delegation rides its userOps. Deriving any other way would\n // produce an address the permission was never granted to.\n const account = await Account.fromLocalAccount(\n {\n chainId: this.options.chainId,\n apiKey: this.options.apiKey,\n paymasterUrl: this.options.paymasterUrl,\n paymasterContext: this.options.paymasterContext,\n },\n localAccount,\n { eip7702: true }\n );\n\n // The stored sessionAddress is the on-chain permission's spender. If the\n // key or mode drifted since setup (hand-edited keystore, config from\n // another machine), signing would come from an account the permission was\n // never granted to — fail clearly instead of sending doomed userOps.\n if (account.address.toLowerCase() !== config.sessionAddress.toLowerCase()) {\n throw new Error(\n `Session key derives ${account.address}, but the stored session address is ${config.sessionAddress}. ` +\n 'The keystore and session config are out of sync. Run `jaw session setup` to recreate the session.'\n );\n }\n\n this.session = { account: account as InitializedSession['account'], config };\n return this.session;\n }\n\n private checkExpiry(config: SessionConfig): void {\n if (config.expiry <= Date.now() / 1000) {\n const expiryDate = new Date(config.expiry * 1000).toISOString();\n throw new Error(`Session expired on ${expiryDate}. Run \\`jaw session setup\\` to create a new session.`);\n }\n }\n\n /**\n * Approve Permit2 to move one of the payer's tokens, and return the batch id.\n *\n * The only call this session sends outside its permission, and the only one\n * that can be: `JustaPermissionManager` checks every call's selector against\n * the grant, and the x402 grant permits `transfer` alone, so an approval\n * routed through the permission reverts before anything else happens. Sent by\n * the session on its own balance it never reaches the manager at all, whose\n * approval revocation and Permit2 lockdown act on the granting account and\n * only within their own execution.\n *\n * Being outside the permission is exactly why it is not a general send. It\n * takes a token and nothing else: the spender is Permit2 and the amount is\n * the maximum, neither reachable by a caller, and the token has to be the\n * registry's USDC for this session's chain. There is no shape of argument\n * that turns this into an arbitrary transfer, which matters because an agent\n * reaches the tools that reach this.\n */\n async approvePermit2(token: `0x${string}`): Promise<string> {\n const { account, config } = await this.getSession();\n const usdc = usdcForNetwork(`eip155:${config.chainId}`);\n if (!usdc || token.toLowerCase() !== usdc.address.toLowerCase()) {\n throw new Error(\n `Refusing to approve Permit2 for ${token}: only the registry USDC on chain ${config.chainId} is allowed.`\n );\n }\n\n const data = encodeFunctionData({\n abi: erc20Abi,\n functionName: 'approve',\n args: [PERMIT2_ADDRESS, maxUint256],\n });\n\n try {\n // No permissionId: this is the session acting for itself.\n // Same shape tolerance the funder applies: `{ id, chainId }` from\n // Account.sendCalls, or a bare id from an older bridge.\n const sent: unknown = await account.sendCalls([{ to: usdc.address, data }]);\n const id = typeof sent === 'string' ? sent : (sent as { id?: string } | null)?.id;\n if (!id) throw new Error('approval submitted but no call id was returned');\n return id;\n } catch (err) {\n throw explainUnchargeableSender(err, config.sessionAddress);\n }\n }\n\n async request(method: string, params?: unknown): Promise<unknown> {\n const { account, config } = await this.getSession();\n\n switch (method) {\n case 'eth_requestAccounts':\n case 'eth_accounts':\n return [config.sessionAddress];\n\n case 'wallet_sendCalls': {\n const payload = Array.isArray(params) ? params[0] : params;\n const { calls } = payload as {\n calls: Array<{ to: string; value?: string; data?: string }>;\n };\n const sendOptions = { permissionId: config.permissionId as `0x${string}` };\n\n // Always charged, never sponsored. The grant leaves the session enough\n // to pay for its first op and every refill leaves `gasReserve` behind\n // for the next one, so the sender can be charged.\n try {\n return await account.sendCalls(calls, sendOptions);\n } catch (err) {\n throw explainUnchargeableSender(err, config.sessionAddress);\n }\n }\n\n case 'wallet_getCallsStatus': {\n const batchId = Array.isArray(params) ? params[0] : params;\n return account.getCallStatus(batchId as `0x${string}`);\n }\n\n // Refused rather than absent, so the reason is on screen instead of a\n // caller reading \"not supported in auto mode\" and looking for a flag. See\n // `supportsSessionMode` in rpc-classifier.ts for why.\n case 'personal_sign':\n case 'eth_signTypedData_v4':\n throw new Error(\n `${method} is not available in auto mode: a signature the session makes is not a call, so it never reaches the spend caps or the ledger. Run it through the browser instead.`\n );\n\n case 'wallet_grantPermissions':\n throw new Error('Requires browser — run `jaw session setup`.');\n\n case 'wallet_revokePermissions':\n throw new Error('Requires browser — run `jaw session revoke`.');\n\n default:\n throw new Error(`Method ${method} is not supported in auto mode.`);\n }\n }\n\n close(): void {\n // No-op — no WebSocket to close\n }\n}\n","import { Args, Flags } from '@oclif/core';\nimport { BaseCommand } from '../../base-command.js';\nimport { getBridge } from '../../lib/bridge-singleton.js';\nimport { loadConfig } from '../../lib/config.js';\nimport { requiresBrowser, supportsSessionMode } from '../../lib/rpc-classifier.js';\nimport { SessionBridge } from '../../lib/session-bridge.js';\nimport type { OutputFormat } from '../../lib/types.js';\n\nexport default class RpcCall extends BaseCommand {\n static override description = 'Execute any JAW.id RPC method via the browser bridge or local session key.';\n\n static override examples = [\n '<%= config.bin %> rpc call wallet_sendCalls \\'{\"calls\":[{\"to\":\"0x...\",\"value\":\"0x0\"}]}\\'',\n '<%= config.bin %> rpc call personal_sign \\'\"Hello World\"\\'',\n '<%= config.bin %> rpc call wallet_getAssets',\n '<%= config.bin %> rpc call eth_requestAccounts',\n '<%= config.bin %> rpc call wallet_getCallsStatus \\'\"0x...\"\\'',\n '<%= config.bin %> rpc call wallet_sendCalls \\'{\"calls\":[...]}\\' --session',\n ];\n\n static override args = {\n method: Args.string({\n description: 'EIP-1193 RPC method name',\n required: true,\n }),\n params: Args.string({\n description: 'Method parameters as JSON string',\n required: false,\n }),\n };\n\n static override flags = {\n ...BaseCommand.baseFlags,\n timeout: Flags.integer({\n char: 't',\n // No default. A default is indistinguishable from an explicit value, and\n // this one was passed to getBridge on every run, which made\n // JAW_BRIDGE_TIMEOUT_MS dead here: the env only applies when no caller\n // named a timeout. The error text tells people to raise that knob, so it\n // has to work in the command most likely to hit it. Unset falls through\n // to the env, then to the built-in 120 seconds.\n description: 'Request timeout in seconds (default 120, or JAW_BRIDGE_TIMEOUT_MS)',\n }),\n session: Flags.boolean({\n char: 's',\n description: 'Use local session key (auto mode)',\n default: false,\n env: 'JAW_SESSION',\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(RpcCall);\n const { method } = args;\n\n let params: unknown;\n if (args.params) {\n try {\n params = JSON.parse(args.params);\n } catch {\n this.error(`Invalid JSON params: ${args.params}`);\n }\n }\n\n const format = flags.output as OutputFormat;\n const config = loadConfig();\n const apiKey = this.resolveApiKey(flags);\n const chainId = flags.chain ?? config.defaultChain ?? 1;\n\n let bridge: { request(method: string, params?: unknown): Promise<unknown>; close(): void };\n\n if (flags.session) {\n if (!supportsSessionMode(method)) {\n this.error(\n `Method ${method} is not supported in session mode. ` +\n 'Use without --session to route through the browser bridge.'\n );\n }\n\n bridge = new SessionBridge({ apiKey, chainId });\n\n if (!flags.quiet) {\n this.log(`Sending ${method} (session mode)...`);\n }\n } else {\n bridge = await getBridge({\n keysUrl: config.keysUrl,\n apiKey,\n chainId,\n ens: config.ens,\n // Undefined when the flag was not given, so getBridge falls through to\n // the env knob and then to its own default.\n timeout: flags.timeout === undefined ? undefined : flags.timeout * 1000,\n });\n\n if (!flags.quiet) {\n if (requiresBrowser(method)) {\n this.log(`Sending ${method}... Check your browser to approve the request.`);\n } else {\n this.log(`Sending ${method}...`);\n }\n }\n }\n\n try {\n const result = await bridge.request(method, params);\n this.outputResult(result, format);\n } finally {\n bridge.close();\n }\n }\n}\n"]}