@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.
- package/dist/base-command.js +3 -1
- package/dist/base-command.js.map +1 -1
- package/dist/commands/config/set.js +140 -12
- package/dist/commands/config/set.js.map +1 -1
- package/dist/commands/config/show.js +3 -1
- package/dist/commands/config/show.js.map +1 -1
- package/dist/commands/config/write.js +6 -4
- package/dist/commands/config/write.js.map +1 -1
- package/dist/commands/disconnect.js +24 -10
- package/dist/commands/disconnect.js.map +1 -1
- package/dist/commands/mcp/index.js +2426 -94
- package/dist/commands/mcp/index.js.map +1 -1
- package/dist/commands/rpc/call.js +197 -45
- package/dist/commands/rpc/call.js.map +1 -1
- package/dist/commands/session/add.js +1547 -0
- package/dist/commands/session/add.js.map +1 -0
- package/dist/commands/session/revoke.js +181 -54
- package/dist/commands/session/revoke.js.map +1 -1
- package/dist/commands/session/setup.js +516 -65
- package/dist/commands/session/setup.js.map +1 -1
- package/dist/commands/session/status.js +315 -6
- package/dist/commands/session/status.js.map +1 -1
- package/dist/commands/version.js +3 -1
- package/dist/commands/version.js.map +1 -1
- package/dist/commands/x402/log.js +344 -0
- package/dist/commands/x402/log.js.map +1 -0
- package/dist/commands/x402/pay.js +2122 -0
- package/dist/commands/x402/pay.js.map +1 -0
- package/dist/commands/x402/status.js +1047 -0
- package/dist/commands/x402/status.js.map +1 -0
- package/dist/index.js +41 -14
- package/dist/index.js.map +1 -1
- package/dist/lib/bridge-singleton.js +41 -14
- package/dist/lib/bridge-singleton.js.map +1 -1
- package/dist/lib/config.js +26 -3
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/keystore.js +13 -2
- package/dist/lib/keystore.js.map +1 -1
- package/dist/lib/paths.js +3 -1
- package/dist/lib/paths.js.map +1 -1
- package/dist/lib/payment-lock.js +121 -0
- package/dist/lib/payment-lock.js.map +1 -0
- package/dist/lib/session-bridge.js +148 -24
- package/dist/lib/session-bridge.js.map +1 -1
- package/dist/lib/session-config.js +78 -11
- package/dist/lib/session-config.js.map +1 -1
- package/dist/lib/terminal.js +22 -0
- package/dist/lib/terminal.js.map +1 -0
- package/dist/lib/validation.js +3 -3
- package/dist/lib/validation.js.map +1 -1
- package/dist/lib/ws-bridge.js +22 -10
- package/dist/lib/ws-bridge.js.map +1 -1
- package/dist/mcp/handlers/config.js +73 -6
- package/dist/mcp/handlers/config.js.map +1 -1
- package/dist/mcp/handlers/daemon.js +43 -12
- package/dist/mcp/handlers/daemon.js.map +1 -1
- package/dist/mcp/handlers/resources.js +119 -0
- package/dist/mcp/handlers/resources.js.map +1 -1
- package/dist/mcp/handlers/rpc.js +269 -60
- package/dist/mcp/handlers/rpc.js.map +1 -1
- package/dist/mcp/helpers.js +50 -3
- package/dist/mcp/helpers.js.map +1 -1
- package/dist/mcp/server.js +2426 -94
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.js +43 -3
- package/dist/mcp/tools.js.map +1 -1
- package/dist/x402/log-view.js +160 -0
- package/dist/x402/log-view.js.map +1 -0
- package/dist/x402/status-report.js +90 -0
- package/dist/x402/status-report.js.map +1 -0
- package/oclif.manifest.json +405 -11
- package/package.json +5 -2
|
@@ -0,0 +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/keystore.ts","../../../src/lib/session-config.ts","../../../src/x402/asset-registry.ts","../../../src/x402/grant-preset.ts","../../../src/x402/period.ts","../../../src/x402/amount.ts","../../../src/lib/terminal.ts","../../../src/x402/status-report.ts","../../../src/x402/grant-ceiling.ts","../../../src/x402/balance.ts","../../../src/x402/gas-reserve.ts","../../../src/x402/funded-owner.ts","../../../src/x402/permission-onchain.ts","../../../src/x402/permission-recovery.ts","../../../src/x402/merge-permissions.ts","../../../src/commands/session/add.ts"],"names":["fs2","crypto2","fs4","ADDRESS_RE","SELECTOR_RE","ALLOWANCE_RE","fs5","bound","base","parseUnits","DEFAULT_TIMEOUT_MS","Flags","fs6"],"mappings":"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","file":"add.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","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","import { parseUnits } from 'viem';\nimport { USDC_BY_NETWORK } from './asset-registry.js';\nimport type { PermissionsConfig } from '../lib/types.js';\n\n/**\n * Build the permission an x402 payer actually needs, so nobody has to hand-write\n * it.\n *\n * Paying an x402 challenge, and refilling the payer through the permission when\n * it falls short, only ever needs one thing: a USDC `transfer` on the session's\n * chain, capped per period. Spelling that out by hand means knowing the USDC\n * address for your chain and the exact `transfer(address,uint256)` signature,\n * which is a lot to ask before a first payment. The registry already knows the\n * address and the decimals, so derive it.\n */\n\nconst TRANSFER_SIGNATURE = 'transfer(address,uint256)';\n\n/** SpendLimit.allowance is uint160 in JustaPermissionManager. */\nconst MAX_ALLOWANCE = 2n ** 160n - 1n;\n\n/** Spend periods accepted on a limit, matching the units the grant validator takes. */\nexport const LIMIT_PERIODS = ['minute', 'hour', 'day', 'week', 'month', 'year', 'forever'] as const;\nexport type LimitPeriod = (typeof LIMIT_PERIODS)[number];\n\n/** Applied when `--x402` is given with no explicit limit. Matches the default x402 session cap. */\nexport const DEFAULT_X402_LIMIT = '10/day';\n\nexport interface ParsedLimit {\n /** Human amount as written, e.g. \"10\" or \"2.5\". */\n amount: string;\n period: LimitPeriod;\n}\n\n/**\n * Parse a `<amount>[/<period>]` limit, e.g. `10/day`, `2.5/week`, or a bare `10`\n * which means per day. The amount stays a decimal string here; scaling to base\n * units needs the token's decimals and happens in `buildX402Permissions`.\n */\nexport function parseLimit(input: string): ParsedLimit {\n const trimmed = input.trim();\n if (!trimmed) throw new Error('Limit is empty. Use --limit <amount>/<period>, for example 10/day.');\n\n const [rawAmount, rawPeriod = 'day', ...rest] = trimmed.split('/');\n if (rest.length > 0) {\n throw new Error(`Invalid limit \"${input}\". Expected <amount>/<period>, for example 10/day.`);\n }\n\n const amount = rawAmount.trim();\n // Reject exponent and sign forms up front: parseUnits would either throw a\n // less helpful error or silently accept something the user did not mean.\n if (!/^\\d+(\\.\\d+)?$/.test(amount)) {\n throw new Error(`Invalid limit amount \"${rawAmount}\". Expected a positive number, for example 10 or 2.5.`);\n }\n\n const period = rawPeriod.trim().toLowerCase() as LimitPeriod;\n if (!(LIMIT_PERIODS as readonly string[]).includes(period)) {\n throw new Error(`Invalid limit period \"${rawPeriod}\". Expected one of: ${LIMIT_PERIODS.join(', ')}.`);\n }\n\n return { amount, period };\n}\n\n/**\n * The USDC-transfer permission for `chainId`, capped at `limit` per period.\n * Throws when the chain has no USDC in the registry, since there is nothing\n * meaningful to grant for x402 there.\n */\nexport function buildX402Permissions(chainId: number, limit: string = DEFAULT_X402_LIMIT): PermissionsConfig {\n const usdc = Object.values(USDC_BY_NETWORK).find((asset) => asset.chainId === chainId);\n if (!usdc) {\n const supported = Object.values(USDC_BY_NETWORK)\n .map((a) => a.chainId)\n .sort((a, b) => a - b)\n .join(', ');\n throw new Error(`No USDC configured for chain ${chainId}. x402 payments are supported on: ${supported}.`);\n }\n\n const { amount, period } = parseLimit(limit);\n let allowance: bigint;\n try {\n allowance = parseUnits(amount, usdc.decimals);\n } catch {\n throw new Error(`Invalid limit amount \"${amount}\" for a token with ${usdc.decimals} decimals.`);\n }\n if (allowance <= 0n) {\n throw new Error(`Limit \"${limit}\" resolves to zero, which would refuse every payment.`);\n }\n // SpendLimit.allowance is a uint160 on chain. Past that the grant fails deep\n // in ABI encoding with an opaque range error, so refuse here where the number\n // the user typed is still in hand.\n if (allowance > MAX_ALLOWANCE) {\n throw new Error(`Limit \"${limit}\" is larger than a spend allowance can hold (max ${MAX_ALLOWANCE}).`);\n }\n\n return {\n calls: [{ target: usdc.address, functionSignature: TRANSFER_SIGNATURE }],\n spends: [{ token: usdc.address, allowance: allowance.toString(), unit: period, multiplier: 1 }],\n };\n}\n\n/** One-line summary of what an --x402 grant permits, for the setup output. */\nexport function describeX402Grant(limit: string = DEFAULT_X402_LIMIT): string {\n const { amount, period } = parseLimit(limit);\n const per = period === 'forever' ? 'in total' : `per ${period}`;\n return `${amount} USDC ${per}, transfers only`;\n}\n","/**\n * Spend-limit period windows, mirroring `JustaPermissionManager._getCurrentPeriod`.\n *\n * A granted allowance is per period, not per session: the contract rebuilds a\n * fresh window once the previous one elapses, so the allowance resets. The local\n * policy has to compute the same window to refuse for the same reason the chain\n * would, before a signature is produced.\n */\n\n/** Period units the contract's `PeriodUnit` enum accepts. */\nexport const PERIOD_UNITS = ['minute', 'hour', 'day', 'week', 'month', 'forever'] as const;\nexport type PeriodUnit = (typeof PERIOD_UNITS)[number];\n\nexport function isPeriodUnit(value: unknown): value is PeriodUnit {\n return typeof value === 'string' && (PERIOD_UNITS as readonly string[]).includes(value);\n}\n\n/**\n * Normalise a granted spend's unit and multiplier to what the contract stores.\n *\n * The CLI and the SDK both accept `year`, which has no `PeriodUnit` on chain:\n * `permissionToContractFormat` rewrites it to `month` with the multiplier times\n * twelve before encoding. This mirrors that, so a yearly grant lands on the same\n * window locally as the one the permission actually enforces. Returns undefined\n * for a unit with no on-chain meaning, which callers treat as \"no period\n * recorded\" rather than guessing a window.\n */\nexport function normalizePeriod(\n unit: string | undefined,\n multiplier?: number\n): { unit: PeriodUnit; multiplier: number } | undefined {\n const m = Math.max(1, Math.floor(multiplier ?? 1));\n if (unit === 'year') return { unit: 'month', multiplier: m * 12 };\n if (isPeriodUnit(unit)) return { unit, multiplier: m };\n return undefined;\n}\n\n/** Seconds per fixed-duration unit. `month` is calendar-based, `forever` unbounded. */\nconst FIXED_UNIT_SECONDS: Record<Exclude<PeriodUnit, 'month' | 'forever'>, number> = {\n minute: 60,\n hour: 3600,\n day: 86400,\n week: 604800,\n};\n\nexport interface PeriodWindow {\n /** Unix seconds, inclusive. */\n start: number;\n /** Unix seconds, exclusive, clamped at the permission's expiry. */\n end: number;\n}\n\nexport interface PeriodWindowInput {\n /** Unix seconds the periods are anchored at (the permission's start). */\n anchor: number;\n unit: PeriodUnit;\n /** Period multiplier, >= 1. Values below 1 are treated as 1, matching the grant default. */\n multiplier?: number;\n /** Unix seconds to locate the window around. */\n now: number;\n /** Unix seconds the permission expires. The window never extends past it. */\n permissionEnd: number;\n}\n\n/**\n * Add `months` calendar months to a unix timestamp, clamping the day-of-month to\n * the target month's length. Mirrors Solady's `DateTimeLib.addMonths`, which the\n * contract uses: Jan 31 plus one month is Feb 28, not Mar 3.\n */\nfunction addMonths(unixSeconds: number, months: number): number {\n const d = new Date(unixSeconds * 1000);\n const day = d.getUTCDate();\n const target = new Date(\n Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + months, 1, d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds())\n );\n // Day 0 of the following month is the last day of the target month.\n const daysInTarget = new Date(Date.UTC(target.getUTCFullYear(), target.getUTCMonth() + 1, 0)).getUTCDate();\n target.setUTCDate(Math.min(day, daysInTarget));\n return Math.floor(target.getTime() / 1000);\n}\n\n/**\n * The period window containing `now`, anchored at the permission start.\n *\n * `forever` is a single window spanning the whole permission, which is why a\n * `forever` grant behaves like a plain session-wide cap. Fixed units step in\n * whole durations from the anchor. `month` steps in calendar months.\n *\n * `now` before the anchor yields the first window rather than a negative index,\n * so a small clock skew between the grant and the local machine cannot produce a\n * window in the past.\n */\nexport function currentPeriodWindow(input: PeriodWindowInput): PeriodWindow {\n const { anchor, unit, now, permissionEnd } = input;\n const multiplier = Math.max(1, Math.floor(input.multiplier ?? 1));\n\n if (unit === 'forever') {\n return { start: anchor, end: permissionEnd };\n }\n\n let start: number;\n let end: number;\n\n if (unit === 'month') {\n // Walk calendar months from the anchor. Month lengths vary, so stepping is\n // the honest way to find the index; grants run for a bounded number of\n // periods, and the loop is cheap next to the network call it guards.\n let index = 0;\n let cursor = anchor;\n let next = addMonths(anchor, multiplier);\n while (next <= now) {\n index += 1;\n cursor = next;\n next = addMonths(anchor, (index + 1) * multiplier);\n }\n start = cursor;\n end = next;\n } else {\n const duration = FIXED_UNIT_SECONDS[unit] * multiplier;\n const elapsed = Math.max(0, now - anchor);\n const index = Math.floor(elapsed / duration);\n start = anchor + index * duration;\n end = start + duration;\n }\n\n // The contract caps the window at the permission end; past expiry nothing is\n // spendable anyway, so a degenerate window is the correct answer.\n return { start, end: Math.min(end, permissionEnd) };\n}\n\n/** Human-readable period label for refusal messages, e.g. \"day\" or \"3 days\". */\nexport function describePeriod(unit: PeriodUnit, multiplier?: number): string {\n // 'the whole permission' reads right inside a refusal about an allowance and\n // wrong after 'per', which is why the plain form below is its own function\n // rather than a flag on this one.\n if (unit === 'forever') return 'the whole permission';\n return describeSpendPeriod(unit, multiplier);\n}\n\n/**\n * A spend limit's window, as it reads after \"per\".\n *\n * Takes a plain string because a grant may say `year`, which is not a\n * `PeriodUnit`: the contract has no such unit and the SDK rewrites it to months\n * before encoding, but the document the user wrote still says it.\n *\n * Here rather than beside each caller. Two byte-identical copies of this had\n * grown in `grant-ceiling` and `merge-permissions`, the second one added while\n * fixing a review comment about the first.\n */\nexport function describeSpendPeriod(unit: string, multiplier?: number): string {\n const n = Math.max(1, Math.floor(multiplier ?? 1));\n return n === 1 ? unit : `${n} ${unit}s`;\n}\n\n/**\n * How long one period lasts in seconds, at its shortest or its longest.\n *\n * Two bounds because a calendar month is 28 to 31 days and a year 365 or 366,\n * and which end to take depends on which side of a comparison the period is on:\n * measuring a grant at its shortest and a ceiling at its longest keeps the\n * rounding from opening either one up. `year` is here even though the contract\n * has no such unit, because a grant may be written with it and the SDK rewrites\n * it to months before encoding.\n *\n * Returns null for a unit with no meaning, which callers treat as \"cannot be\n * compared\" rather than guessing a length.\n */\nexport function periodLengthSeconds(unit: string, multiplier: number, bound: 'min' | 'max'): number | null {\n const lengths: Record<string, number> = {\n minute: 60,\n hour: 3600,\n day: 86400,\n week: 604800,\n month: (bound === 'min' ? 28 : 31) * 86400,\n year: (bound === 'min' ? 365 : 366) * 86400,\n forever: Number.POSITIVE_INFINITY,\n };\n if (!Object.hasOwn(lengths, unit)) return null;\n return lengths[unit] * Math.max(1, Math.floor(multiplier));\n}\n","/**\n * Canonical base-unit amount parser. Every place that turns an amount string\n * (from an untrusted 402 challenge or from hand-edited config) into a bigint\n * goes through here, so the failure surface is uniform and a malformed value\n * can never crash a hot path. Sign policy is left to the caller: this returns\n * the parsed value (which may be negative) or null when it is not an integer.\n */\nexport function parseBigInt(value: string | undefined | null): bigint | null {\n // Empty string is \"unset\", not zero: BigInt('') is 0n, but an absent config\n // value must read as null so callers treat it as \"no bound\", not \"cap of 0\".\n if (value === undefined || value === null || value === '') return null;\n try {\n return BigInt(value);\n } catch {\n return null;\n }\n}\n\n/** Parse a non-negative base-unit amount; undefined when absent, invalid, or negative. */\nexport function parseNonNegativeBigInt(value: string | undefined | null): bigint | undefined {\n const parsed = parseBigInt(value);\n return parsed !== null && parsed >= 0n ? parsed : undefined;\n}\n","/**\n * Make server-controlled text safe to print.\n *\n * A paid endpoint controls its response body, and parts of its 402 challenge\n * reach our refusal messages, which are stored in the payment ledger and\n * reprinted by `jaw x402 log`. Printed raw, an escape sequence lets that server\n * erase the line the CLI just wrote and paint its own in place: a resource that\n * was never paid for can render a convincing green \"Paid. 5 USDC\" the CLI never\n * emitted, and once in the ledger it does so on every later read.\n *\n * Two shapes, because the danger differs. A newline inside a one-line field\n * forges an extra row that reads as a genuine record, while inside a response\n * body it is just a newline. Only the human renderers need any of this: JSON\n * output escapes control characters on its own.\n */\n\n/**\n * Characters that are invisible or reorder what follows them, in any context.\n *\n * Bidi overrides (U+202A-U+202E, U+2066-U+2069) are the Trojan Source trick:\n * they flip rendering direction, so an address can display as something other\n * than the bytes that were signed. The zero-width family hides text outright,\n * splitting an address to the eye while leaving it intact to a copy. Neither is\n * a control character in the C0 or C1 sense, so stripping those alone misses\n * both. U+2028 and U+2029 break lines the way a newline does.\n */\nconst INVISIBLE_AND_BIDI = /[\\u200B-\\u200F\\u2028\\u2029\\u202A-\\u202E\\u2066-\\u2069\\uFEFF]/g;\n\n/** C0 except tab and newline, DEL, and the C1 block. For multi-line text. */\n// eslint-disable-next-line no-control-regex\nconst BLOCK_CONTROLS = /[\\u0000-\\u0008\\u000B-\\u001F\\u007F-\\u009F]/g;\n\n/** Every C0 control, DEL and C1. For text that must stay on one line. */\n// eslint-disable-next-line no-control-regex\nconst LINE_CONTROLS = /[\\u0000-\\u001F\\u007F-\\u009F]/g;\n\n/** Left in place of a stripped character, so tampering shows rather than vanishing. */\nconst REPLACEMENT = '\\uFFFD';\n\nexport const DEFAULT_LINE_LENGTH = 200;\n\nfunction bound(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n // Say it was cut. A silently truncated error message reads as a complete one.\n return `${text.slice(0, maxLength)}\\u2026 (${text.length - maxLength} more characters)`;\n}\n\n/**\n * Disarm a value that has to render as a single line: a refusal reason, a\n * network id, a host, a transaction hash.\n *\n * Newlines go with everything else here. A reason carrying one would otherwise\n * open a second line under a log entry, indistinguishable from the real row\n * above it, which is the same forgery the escape sequences allow.\n */\nexport function sanitizeLine(value: unknown, maxLength: number = DEFAULT_LINE_LENGTH): string {\n const text = typeof value === 'string' ? value : String(value);\n return bound(text.replace(LINE_CONTROLS, REPLACEMENT).replace(INVISIBLE_AND_BIDI, REPLACEMENT), maxLength);\n}\n\n/**\n * Disarm a response body, keeping its shape.\n *\n * Newlines and tabs survive, since a body is legitimately multi-line and\n * neither can move the cursor back over text already written. Nothing is\n * truncated: the caller asked for this resource and may well have paid for it,\n * and the read is already bounded upstream by MAX_BODY_BYTES.\n */\nexport function sanitizeBlock(value: unknown): string {\n const text = typeof value === 'string' ? value : String(value);\n return text.replace(BLOCK_CONTROLS, REPLACEMENT).replace(INVISIBLE_AND_BIDI, REPLACEMENT);\n}\n","import { parseBigInt } from './amount.js';\nimport { sanitizeLine } from '../lib/terminal.js';\nimport type { PermissionLiveness } from './permission-onchain.js';\n\n/**\n * Presentation and diagnosis for `jaw x402 status`, kept apart from the command\n * so the rules can be tested without a session, a keystore or a network.\n */\n\n/** Base units to a readable amount, trailing zeros trimmed. */\nexport function formatUsdc(base: string | undefined, decimals: number): string {\n if (base === undefined) return 'unlimited';\n const value = parseBigInt(base);\n // Echoing the raw value put an unvalidated string on screen: amounts reach\n // here from the ledger and from config, both files that can be edited.\n if (value === null) return `${sanitizeLine(base, 32)} (invalid)`;\n const scale = 10n ** BigInt(decimals);\n const whole = value / scale;\n const frac = (value % scale).toString().padStart(decimals, '0').replace(/0+$/, '');\n return `${whole}${frac ? `.${frac}` : ''} USDC`;\n}\n\nexport function formatRemaining(seconds: number): string {\n const days = Math.floor(seconds / 86400);\n if (days > 0) return `${days} day${days === 1 ? '' : 's'} left`;\n const hours = Math.max(0, Math.floor(seconds / 3600));\n return `${hours}h left`;\n}\n\nexport interface StatusFacts {\n expired: boolean;\n /**\n * Defaults to `unknown`, which reports exactly what every session reported\n * before this could be read: the local file, and nothing more.\n */\n liveness?: PermissionLiveness;\n /**\n * True for a session an older CLI created, whose permission was granted to an\n * address separate from the session key. Auto mode refuses those, so a report\n * that stayed quiet about it would call a setup ready that cannot pay.\n */\n outdated?: boolean;\n ownerAddress: string;\n /** Formatted balance, or null when the read failed. */\n ownerBalance: string | null;\n payerBalance: string | null;\n /** False when the session's chain has no USDC in the registry. */\n hasAsset: boolean;\n spent: bigint;\n sessionCap: bigint | null;\n /**\n * The granted per-period cap and what has gone against it in the current\n * window: top-ups pulled through the permission, not payments, because the\n * cap mirrors the on-chain allowance and payments lag it by whatever float\n * the payer holds. Null when no grant seeded one. Reported separately from\n * the session cap because a grant-seeded policy usually has no session cap\n * at all, and checking only that one stayed quiet while the cap that\n * actually binds was exhausted.\n */\n periodCap?: bigint | null;\n periodSpent?: bigint | null;\n /** How the window reads in a sentence, e.g. \"day\" or \"2 weeks\". */\n periodLabel?: string | null;\n /**\n * The gas reserve refills leave in the payer, in the same formatted units as\n * the balances. A payer holding no more than this is holding what the CLI put\n * there to pay userOp fees, so it is not the misdirected-funds case below.\n */\n payerReserve?: number;\n}\n\n/**\n * What is stopping a payment, most likely cause first. Empty when nothing is.\n *\n * The interesting case is an empty owner next to a funded payer: payments still\n * succeed, so nothing looks wrong, but they are spending the payer's own balance\n * instead of pulling through the permission, which means the cap the user\n * granted is not being applied to anything.\n */\nexport function diagnose(facts: StatusFacts): string[] {\n const problems: string[] = [];\n\n if (facts.expired) {\n problems.push('The session expired. Run `jaw session setup --x402`.');\n }\n\n // Only the chain knows this one. Expiry is the same number the local file\n // carries, so it needs no read; a revoke made from keys.jaw.id or from\n // another machine leaves that file saying the session is fine.\n if (facts.liveness === 'revoked') {\n problems.push(\n 'The permission was revoked on chain, so nothing can be pulled through it any more. ' +\n 'Run `jaw session setup --x402` to grant a new one.'\n );\n }\n\n if (facts.liveness === 'unapproved') {\n problems.push(\n 'The chain has no record of this permission being approved. If the session was just created, ' +\n 'the grant may not have been mined yet; otherwise run `jaw session setup --x402`.'\n );\n }\n\n // `mismatch` is deliberately not here. It says the struct on disk does not\n // hash to the granted id, so the chain cannot be asked about this permission,\n // and nothing about the permission itself is wrong: the caps still apply and\n // payments still go through. Putting it in `problems` flipped `ready` to\n // false, which stops a script or an agent paying against a healthy session\n // over a local serialisation problem. It is reported on the permission line\n // instead.\n\n if (facts.outdated) {\n problems.push(\n 'This session was created by an older CLI and cannot pay: its permission belongs to an address ' +\n 'separate from the session key. Run `jaw session setup --x402` to recreate it.'\n );\n }\n\n if (!facts.hasAsset) {\n problems.push('This chain has no USDC configured, so x402 payments cannot be made on it.');\n }\n\n if (facts.hasAsset && facts.ownerBalance === null) {\n // Blaming the connection while the other balance rendered fine reads as a\n // contradiction, so only do it when both reads failed.\n problems.push(\n facts.payerBalance === null\n ? 'Could not read balances. Check the API key and network.'\n : `Could not read the owner balance for ${facts.ownerAddress}. The address may be malformed.`\n );\n }\n\n if (facts.ownerBalance !== null && Number(facts.ownerBalance) === 0) {\n // Above the reserve, because refills deliberately leave that much in the\n // payer to pay userOp fees with. Reading it back as funds sent to the wrong\n // address would tell the user to move money the CLI put there on purpose.\n const payerHoldsMoreThanItsGas =\n facts.payerBalance !== null && Number(facts.payerBalance) > (facts.payerReserve ?? 0);\n problems.push(\n payerHoldsMoreThanItsGas\n ? 'The owner account is empty but the payer holds USDC. Payments will work, but they bypass the ' +\n 'permission, so the cap you granted is not applying. Move the funds to the owner.'\n : 'The owner account holds no USDC, so there is nothing to pay with.'\n );\n }\n\n // Before the session cap: this is the one that mirrors the permission, so when\n // both are exhausted it is the more useful thing to say, and it frees up on its\n // own rather than needing a config change.\n if (facts.periodCap != null && facts.periodSpent != null && facts.periodSpent >= facts.periodCap) {\n problems.push(\n `The granted allowance for this ${facts.periodLabel ?? 'period'} is used up. It resets at the end of ` +\n 'the window, or grant a new permission with `jaw session setup --x402`.'\n );\n }\n\n if (facts.sessionCap !== null && facts.spent >= facts.sessionCap) {\n problems.push(\n 'The session cap is used up. Raise it with `jaw config set x402.maxTotalPerSession <base units>` ' +\n 'or start a new session.'\n );\n }\n\n return problems;\n}\n","import { parseUnits } from 'viem';\nimport { parseLimit, type LimitPeriod } from './grant-preset.js';\nimport { describeSpendPeriod, periodLengthSeconds } from './period.js';\nimport { USDC_BY_NETWORK } from './asset-registry.js';\nimport { formatUsdc } from './status-report.js';\nimport type { PermissionsConfig } from '../lib/types.js';\n\n/**\n * The most a grant made from this machine may ask for, set by a human.\n *\n * The flow worth having is an agent that hits a 402, asks for a budget, and a\n * human approves it in the browser. It already works, and it works by accident:\n * an agent with shell access runs `jaw session setup --x402 --limit <whatever it\n * likes>`, and the browser screen is the only thing standing between that number\n * and an approval. That makes a grant screen the entire security boundary, and\n * screens get clicked through.\n *\n * A ceiling narrows that for anyone driving the CLI from a terminal. The human\n * names the most they are willing to grant, once; the agent can ask for that or\n * less, and the browser confirms a number that was already bounded. It is the\n * same split the x402 caps already use: the per-period caps and the rest are\n * deliberately unreachable from the MCP tools, because an agent must not raise\n * its own spending caps.\n *\n * It is not the bound the design leans on, and it cannot be, because it assumes\n * a terminal. The case being built for is the MCP added to a chat client as a\n * connector, which asks for a budget, asks again when that runs low, and may\n * have no local machine in the picture at all. A bound has to be enforced and\n * visible where the human actually is, which is the grant screen. Not the bare\n * screen above, which is exactly the one that gets clicked through: one that\n * shows the amount and the period it is being asked to approve. That part is\n * keys-side. Read this as a convenience for terminal users and the screen as\n * the control.\n *\n * Unset means no ceiling, which is what every install has today.\n */\n\n/**\n * Why the grant is more than the ceiling allows, or null when it is not.\n *\n * Two conditions, both conservative in the same direction: the allowance may not\n * exceed the ceiling's, and the period may not be shorter than the ceiling's. A\n * shorter period is more money over the same time even at the same allowance, so\n * `10/hour` is not under a `10/day` ceiling. Together they are stricter than\n * comparing rates, and they can be said in one sentence, which matters for a\n * refusal someone reads while they are trying to get work done.\n *\n * Checked against the resolved permission rather than the `--limit` string, so a\n * hand-written `--permissions` is bounded by the same number. That is the whole\n * point: a bypass an agent can reach is not a ceiling.\n */\nexport function whyGrantExceedsCeiling(\n permissions: PermissionsConfig,\n chainId: number,\n ceiling: string | undefined\n): string | null {\n if (!ceiling) return null;\n\n let parsed: { amount: string; period: LimitPeriod };\n try {\n parsed = parseLimit(ceiling);\n } catch {\n // A hand-edited ceiling must not become a way past it, and must not take\n // down every setup either. Refuse the grant and say which is which.\n return `The grant ceiling in your config is not a valid limit: ${ceiling}. Fix it with \\`jaw config set grantCeiling <amount>/<period>\\`, or remove it.`;\n }\n\n const usdc = Object.values(USDC_BY_NETWORK).find((asset) => asset.chainId === chainId);\n if (!usdc) {\n // The ceiling is an amount of USDC, and this chain has none in the registry\n // to price it against. A permission that spends nothing is still fine; one\n // that spends is refused for the same reason an unpriceable token is, since\n // silently skipping the check on four-fifths of the chains would leave the\n // ceiling true only where someone happened to look.\n return (permissions.spends ?? []).length > 0\n ? `The grant ceiling is set to ${ceiling}, and chain ${chainId} has no USDC in the registry to measure a spend against it. Grant on a supported chain, or remove the ceiling with \\`jaw config set grantCeiling \"\"\\`.`\n : null;\n }\n\n const maxAllowance = parseUnits(parsed.amount, usdc.decimals);\n const ceilingSeconds = periodLengthSeconds(parsed.period, 1, 'max');\n if (ceilingSeconds === null) return null;\n\n for (const spend of permissions.spends ?? []) {\n if (spend.token.toLowerCase() !== usdc.address.toLowerCase()) {\n // The ceiling is an amount of USDC. A spend on anything else cannot be\n // measured against it, and letting it through unmeasured would be a way\n // around the ceiling rather than an exception to it.\n return `The grant ceiling is set to ${ceiling}, and this permission spends ${spend.token}, which cannot be measured against it. Grant USDC, or remove the ceiling with \\`jaw config set grantCeiling \"\"\\`.`;\n }\n\n let allowance: bigint;\n try {\n allowance = BigInt(spend.allowance);\n } catch {\n return `This permission asks for an allowance that cannot be read: ${spend.allowance}.`;\n }\n\n if (allowance > maxAllowance) {\n return `This grant asks for ${formatUsdc(allowance.toString(), usdc.decimals)} per period, over the ${ceiling} ceiling set on this machine. Lower it, or raise the ceiling with \\`jaw config set grantCeiling <amount>/<period>\\`.`;\n }\n\n const grantSeconds = periodLengthSeconds(spend.unit, spend.multiplier ?? 1, 'min');\n if (grantSeconds === null) {\n return `This permission uses a spend period this CLI does not recognise: ${spend.unit}.`;\n }\n // The same period as the ceiling is never too short, and it has to be said\n // outright: a month is measured at its shortest here and at its longest on\n // the ceiling, so 28 days against 31 refused `10/month` under a `10/month`\n // ceiling. The two tables exist to keep a *different* unit from rounding\n // its way past, and an identical one needs no rounding at all.\n // `parseLimit` gives the ceiling a multiplier of one, so any grant on the\n // same unit runs at least as long as it.\n const sameUnit = spend.unit === parsed.period;\n if (!sameUnit && grantSeconds < ceilingSeconds) {\n return `This grant resets its allowance every ${describeSpendPeriod(spend.unit, spend.multiplier ?? 1)}, which is more often than the ${ceiling} ceiling set on this machine allows. A shorter period is more money over the same time, even at the same allowance.`;\n }\n }\n\n return null;\n}\n","import { createPublicClient, http, erc20Abi, formatUnits, type Chain, type PublicClient } from 'viem';\nimport { base, baseSepolia, polygon, polygonAmoy } from 'viem/chains';\nimport { usdcForNetwork, USDC_BY_NETWORK, type UsdcAsset } from './asset-registry.js';\nimport { loadConfig } from '../lib/config.js';\n\n// The JAW proxy RPC endpoint, mirrored from core's JAW_RPC_URL. Kept as a local\n// literal rather than an import because `@jaw.id/core` is lazy-loaded in the CLI\n// (a static import would pull it into startup); keep in sync if core's URL moves.\nconst JAW_RPC_URL = 'https://api.justaname.id/proxy/v1/rpc';\n\nconst CHAINS: Record<number, Chain> = {\n [base.id]: base,\n [baseSepolia.id]: baseSepolia,\n [polygon.id]: polygon,\n [polygonAmoy.id]: polygonAmoy,\n};\n\n// The viem chains here and USDC_BY_NETWORK in asset-registry are two lists that\n// must cover the same chain ids. Assert it at load so adding a USDC entry\n// without its viem chain fails loudly here instead of silently building a\n// client with `chain: undefined` (wrong gas/explorer defaults) at read time.\nfor (const chainId of Object.values(USDC_BY_NETWORK).map((a) => a.chainId)) {\n if (!CHAINS[chainId]) {\n throw new Error(\n `x402 balance: USDC registry has chain ${chainId} but no viem chain is mapped for it in balance.ts`\n );\n }\n}\n\n// One client per (chain, apiKey) across the process — a fresh transport per read\n// is wasted setup once balance checks run more than once per payment. Keying on\n// the apiKey too matters for the long-lived `jaw mcp` server: a first read before\n// a key is configured would otherwise cache the public-RPC client forever, so a\n// later `jaw config set apiKey` (or a key change) never takes effect. A new key\n// yields a new cache entry and a keyed transport; the stale entry just goes cold.\nconst clients = new Map<string, PublicClient>();\n\n/**\n * Route reads through the same JAW proxy core uses, so the x402 modules see the\n * same node/state core does and don't depend on viem's public RPC fallback\n * (rate-limited and flaky). This matters for the delegation probe in payer.ts:\n * a dropped getCode there would sign a raw signature where a wrapped one was\n * needed. Falls back to the public RPC when no apiKey is configured (e.g. tests).\n */\nfunction rpcTransport(chainId: number, apiKey?: string) {\n if (!apiKey) return http();\n return http(`${JAW_RPC_URL}?chainId=${chainId}&api-key=${apiKey}`);\n}\n\n/** Shared per-(chain, apiKey) public client for the x402 modules (reads only). */\nexport function publicClientFor(chainId: number): PublicClient {\n const chain = CHAINS[chainId];\n if (!chain) throw new Error(`x402: no viem chain configured for chainId ${chainId}`);\n const apiKey = loadConfig().apiKey;\n const key = `${chainId}:${apiKey ?? ''}`;\n let client = clients.get(key);\n if (!client) {\n client = createPublicClient({ chain, transport: rpcTransport(chainId, apiKey) });\n clients.set(key, client);\n }\n return client;\n}\n\n/** Reads the raw USDC balance (base units) of `owner`. Injectable for tests. */\nexport type BalanceReader = (asset: UsdcAsset, owner: `0x${string}`) => Promise<bigint>;\n\nconst readOnChain: BalanceReader = (asset, owner) =>\n publicClientFor(asset.chainId).readContract({\n address: asset.address,\n abi: erc20Abi,\n functionName: 'balanceOf',\n args: [owner],\n });\n\nexport interface UsdcBalance {\n network: string;\n asset: `0x${string}`;\n /** Base units, decimal string. */\n raw: string;\n /** Human-readable amount, formatted with the asset's decimals from the registry. */\n formatted: string;\n}\n\n/**\n * Read an address's USDC balance on a CAIP-2 network so an agent can tell\n * whether it can afford a payment (or confirm one landed).\n */\nexport async function usdcBalance(\n network: string,\n owner: `0x${string}`,\n read: BalanceReader = readOnChain\n): Promise<UsdcBalance> {\n const asset = usdcForNetwork(network);\n if (!asset) throw new Error(`Unsupported x402 network: ${network}`);\n const raw = await read(asset, owner);\n return { network, asset: asset.address, raw: raw.toString(), formatted: formatUnits(raw, asset.decimals) };\n}\n","import type { UsdcAsset } from './asset-registry.js';\n\n/**\n * The USDC a refill leaves behind so the next one can pay its own fee, in base\n * units of `asset`.\n *\n * Measured rather than guessed: a session's first operation, the most expensive\n * one it sends because it carries the EIP-7702 authorization and bootstraps the\n * permission manager as a co-owner, cost 0.0094 USDC on Base Sepolia. A tenth of\n * a token leaves ten times that.\n *\n * The grant seeds the session too, but it prices its own amount off the\n * paymaster's rate for the token (`account/spenderPrefund.ts` in @jaw.id/core),\n * so this is no longer a copy of that number and the two do not have to match.\n * All that is asked of either is that it covers an operation.\n *\n * It costs the granted allowance 0.10 once per session and not once per refill:\n * a refill fills the payer to price plus reserve, the payment takes the price,\n * and the reserve stays for the next one.\n *\n * An `upto` session asks for a second one on the payment that grants the\n * Permit2 allowance. That approval is an operation the payer pays for out of\n * its own balance, and a payer holding exactly the price cannot, so the bar for\n * skipping the refill rises by a reserve on top of the one every refill leaves.\n * The approval spends about a hundredth of it and the rest stays in the payer,\n * the same as the first.\n */\nexport function gasReserve(asset: UsdcAsset): bigint {\n return 10n ** BigInt(asset.decimals) / 10n;\n}\n\n/**\n * What one operation costs the session, in base units of `asset`.\n *\n * A cent, rounded up from the 0.0094 measured above so the figure stays a round\n * number rather than pretending to a precision a gas price does not have. It is\n * the floor a session has to clear to be able to send anything at all, which is\n * a different question from `gasReserve`: that one decides how much to leave\n * behind, this one decides whether there is enough to act.\n */\nexport function firstOperationCost(asset: UsdcAsset): bigint {\n return 10n ** BigInt(asset.decimals) / 100n;\n}\n","import { usdcForNetwork } from './asset-registry.js';\nimport { usdcBalance } from './balance.js';\nimport { firstOperationCost, gasReserve } from './gas-reserve.js';\nimport { formatUsdc } from './status-report.js';\n\n/**\n * Why a session cannot be set up yet, or null when it can.\n *\n * The grant carries a small transfer to the session account, so its first\n * operation can pay its own fee instead of needing someone to sponsor it, and\n * that transfer comes out of the account approving the permission. Granting\n * anyway leaves a permission that cannot be used until the account is funded and\n * the whole setup is run again, which revokes and re-grants.\n *\n * The account is only knowable here: it is whichever one the user connects with\n * in the browser, and the grant response is what would otherwise report it.\n */\nexport interface OwnerFundingCheck {\n chainId: number;\n /** The open browser bridge, asked for the connected account. */\n request(method: string, params?: unknown): Promise<unknown>;\n /** Injected for tests. */\n readBalance?: (network: string, owner: `0x${string}`) => Promise<bigint>;\n}\n\nexport async function whyOwnerCannotFundSession(check: OwnerFundingCheck): Promise<string | null> {\n const asset = usdcForNetwork(`eip155:${check.chainId}`);\n // No USDC on this chain is no x402 grant to fund, and the preset would not\n // have built one either.\n if (!asset) return null;\n\n const accounts = (await check.request('eth_requestAccounts')) as string[] | undefined;\n const owner = accounts?.[0];\n if (!owner) return null;\n\n const read =\n check.readBalance ??\n (async (network: string, address: `0x${string}`) => BigInt((await usdcBalance(network, address)).raw));\n\n let held: bigint;\n try {\n held = await read(asset.wireNetwork, owner as `0x${string}`);\n } catch {\n // An unreachable RPC is not a reason to refuse a grant. This check exists to\n // fail early with a readable message; the wallet makes the same one against\n // its own node before building the transfer, and skips it when the account\n // cannot cover it. Losing the early warning costs a clearer error, not the\n // guarantee.\n return null;\n }\n\n const needed = gasReserve(asset);\n if (held >= needed) return null;\n\n return (\n `${owner} holds ${formatUsdc(held.toString(), asset.decimals)} on chain ${check.chainId}, and setting up a ` +\n `session needs at least ${formatUsdc(needed.toString(), asset.decimals)} there. That much rides along in the ` +\n 'grant so the session can pay for its own first transaction. Fund the account and run this again.'\n );\n}\n\n/**\n * Why the session cannot pay for anything yet, or null when it can.\n *\n * The counterpart to the check above, on the other side of the grant. That one\n * refuses to grant when the account could not afford to seed the session; this\n * one runs after a grant it could afford, and catches a session that came out\n * unable to send anything.\n *\n * Scoped to the x402 preset by its caller, and it has to be. The wallet seeds in\n * whatever token the permission names, picking the first ERC-20 spend in it, and\n * a permission that authorises no spend at all is correctly seeded with nothing.\n * Reading USDC would then be reading the wrong token, or the wrong question. The\n * preset is the one grant that always names USDC.\n *\n * What it does NOT do is diagnose. `buildSpenderPrefundCall` declines for eight\n * different reasons, of which a wallet not implementing the capability is only\n * one: no exchange rate for the token, a granted allowance too small to price\n * against, a paymaster context without gas, an owner balance that no longer\n * covers the seed plus the grant's own fee. So the message states what is true\n * and observable, that the session cannot pay, and offers the causes rather than\n * asserting the one that is most often right.\n */\nexport interface SpenderFundingCheck {\n chainId: number;\n /** The session account, which is the one that will send and be charged. */\n spender: `0x${string}`;\n /** Injected for tests. */\n readBalance?: (network: string, address: `0x${string}`) => Promise<bigint>;\n /**\n * How long to wait on the node. The session is already created and saved by\n * the time this runs, so a stalled RPC must not hold the command open after\n * its work is done: viem retries three times at ten seconds, which is most of\n * a minute of silence for a warning nobody is waiting on.\n */\n timeoutMs?: number;\n}\n\nexport async function whySpenderCannotPay(check: SpenderFundingCheck): Promise<string | null> {\n const asset = usdcForNetwork(`eip155:${check.chainId}`);\n // No USDC on this chain means no ERC-20 paymaster to charge, so gas comes\n // from the native balance and an empty USDC balance says nothing.\n if (!asset) return null;\n\n const read =\n check.readBalance ??\n (async (network: string, address: `0x${string}`) => BigInt((await usdcBalance(network, address)).raw));\n\n let held: bigint;\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n const expired = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error('timed out')), check.timeoutMs ?? 5_000);\n });\n held = await Promise.race([read(asset.wireNetwork, check.spender), expired]);\n } catch {\n // An unreachable or slow node is not a reason to end a successful setup\n // with an alarm.\n return null;\n } finally {\n clearTimeout(timer);\n }\n\n // Not \"holds nothing\": a session key is reused by default, so the address can\n // carry dust from a previous life. What matters is whether it can pay for one\n // operation, and a wallet that seeded it priced that operation to do so.\n const needed = firstOperationCost(asset);\n if (held >= needed) return null;\n\n return (\n `${check.spender} holds ${formatUsdc(held.toString(), asset.decimals)} on chain ${check.chainId}, which is ` +\n `not enough to pay for its first operation. The session pays its own gas, and the grant asked this wallet ` +\n `to send it a little along with the permission. Nothing usable arrived: the wallet may not implement that ` +\n `yet, or it could not price the transfer, or the granted allowance was too small to cover one. Send ` +\n `${formatUsdc(needed.toString(), asset.decimals)} to that address and the session works from there.`\n );\n}\n","import { parseAbi, zeroAddress, ContractFunctionRevertedError, BaseError } from 'viem';\nimport { publicClientFor } from './balance.js';\nimport type { GrantedPermission } from '../lib/session-config.js';\n\n/**\n * What the permission manager will say about a session's own permission.\n *\n * Everything the CLI knew about its permission came out of\n * `~/.jaw/session-config.json`, which is written once at setup and never\n * updated. A permission revoked from keys.jaw.id or from another machine, or an\n * allowance drawn down by something other than this CLI, leaves that file\n * saying what was true the day it was written. The chain knows, and the reads\n * are views.\n *\n * None of them take the permission id. `isApproved`, `isRevoked` and\n * `getCurrentPeriod` all take `Permission calldata` and hash it internally, so\n * the struct has to be rebuilt exactly as it was approved. That is what\n * `GrantedPermission` is for, and why `permissionHash` is checked against the\n * id the grant returned before any answer here is trusted.\n */\n\nexport const PERMISSION_MANAGER_ABI = parseAbi([\n 'struct CallPermission { address target; bytes4 selector; address checker; }',\n 'struct SpendLimit { address token; uint160 allowance; uint8 unit; uint16 multiplier; }',\n 'struct Permission { address account; address spender; uint48 start; uint48 end; uint256 salt; CallPermission[] calls; SpendLimit[] spends; }',\n 'struct PeriodSpend { uint48 start; uint48 end; uint160 spend; }',\n 'function getHash(Permission permission) view returns (bytes32)',\n 'function isApproved(Permission permission) view returns (bool)',\n 'function isRevoked(Permission permission) view returns (bool)',\n 'function getCurrentPeriod(Permission permission, SpendLimit spendLimit) view returns (PeriodSpend)',\n // Carried so the two time-bound reverts can be told apart from a node that\n // did not answer. Everything else the manager can revert with decodes to an\n // unnamed error, which is treated as unavailable rather than guessed at.\n 'error JustaPermissionManager_BeforePermissionStart(uint48 currentTimestamp, uint48 start)',\n 'error JustaPermissionManager_AfterPermissionEnd(uint48 currentTimestamp, uint48 end)',\n]);\n\nconst TIME_BOUND_ERRORS = new Set([\n 'JustaPermissionManager_BeforePermissionStart',\n 'JustaPermissionManager_AfterPermissionEnd',\n]);\n\n/**\n * `PeriodUnit` in the contract, by declaration order. `year` is absent on\n * purpose: it has no on-chain unit, and the SDK rewrites it to `month` with the\n * multiplier times twelve before encoding. The struct has to be rebuilt with\n * the same rewrite or it hashes to a different permission.\n */\nconst PERIOD_UNIT_ENUM: Record<string, number> = {\n minute: 0,\n hour: 1,\n day: 2,\n week: 3,\n month: 4,\n forever: 5,\n};\n\ntype ContractSpendLimit = {\n token: `0x${string}`;\n allowance: bigint;\n unit: number;\n multiplier: number;\n};\n\ntype ContractPermission = {\n account: `0x${string}`;\n spender: `0x${string}`;\n start: number;\n end: number;\n salt: bigint;\n calls: ReadonlyArray<{ target: `0x${string}`; selector: `0x${string}`; checker: `0x${string}` }>;\n spends: ReadonlyArray<ContractSpendLimit>;\n};\n\nfunction toContractSpendLimit(spend: GrantedPermission['spends'][number]): ContractSpendLimit | null {\n const unit = spend.unit === 'year' ? 'month' : spend.unit;\n const multiplier = spend.unit === 'year' ? spend.multiplier * 12 : spend.multiplier;\n if (!Object.hasOwn(PERIOD_UNIT_ENUM, unit)) return null;\n return {\n token: spend.token as `0x${string}`,\n allowance: BigInt(spend.allowance),\n unit: PERIOD_UNIT_ENUM[unit],\n multiplier,\n };\n}\n\n/**\n * The stored permission in the shape the contract hashes, or null when it\n * cannot be rebuilt.\n *\n * `checker` is filled with the zero address because the grant response does not\n * carry one and `apiPermissionsToPermission` in the SDK always sets it that\n * way. The day a call checker is actually used that stops being true, and the\n * struct built here hashes to a permission that does not exist. Nothing here\n * can detect that on its own, which is why every caller goes through\n * `readPermissionState` and its hash check first.\n */\nexport function toContractPermission(permission: GrantedPermission): ContractPermission | null {\n const spends: ContractSpendLimit[] = [];\n for (const spend of permission.spends) {\n const converted = toContractSpendLimit(spend);\n if (!converted) return null;\n spends.push(converted);\n }\n let salt: bigint;\n try {\n salt = BigInt(permission.salt);\n } catch {\n return null;\n }\n return {\n account: permission.account as `0x${string}`,\n spender: permission.spender as `0x${string}`,\n start: permission.start,\n end: permission.end,\n salt,\n calls: permission.calls.map((call) => ({\n target: call.target as `0x${string}`,\n selector: call.selector as `0x${string}`,\n checker: zeroAddress,\n })),\n spends,\n };\n}\n\n/**\n * What the chain says about the permission, or why it could not say.\n *\n * `mismatch` is its own answer rather than an error: it means the struct on\n * disk does not hash to the id the grant returned, so every read made from it\n * would be about some other permission. Reporting that is more useful than\n * either a false \"revoked\" or silence.\n */\nexport type PermissionState =\n | { status: 'ok'; approved: boolean; revoked: boolean }\n | { status: 'mismatch' }\n | { status: 'unavailable' };\n\nexport interface PermissionReadTarget {\n chainId: number;\n permissionId: string;\n permission?: GrantedPermission;\n}\n\n/** Injectable for tests, and the seam that keeps the network out of the unit tests. */\nexport interface ReadDeps {\n readContract?: (args: {\n address: `0x${string}`;\n abi: typeof PERMISSION_MANAGER_ABI;\n functionName: 'getHash' | 'isApproved' | 'isRevoked' | 'getCurrentPeriod';\n args: readonly unknown[];\n }) => Promise<unknown>;\n /** The permission manager, injectable so a test does not have to import core. */\n manager?: `0x${string}`;\n /**\n * How long to wait on the node.\n *\n * These reads sit in `session status` and `x402 status`, which were local\n * commands before them, and in the payment path. viem retries three times at\n * ten seconds, so an unreachable node would hold a status report open for\n * most of a minute to add a fact that is optional in every caller. Timing out\n * is the same answer as any other failed read: not knowing.\n */\n timeoutMs?: number;\n}\n\nconst DEFAULT_TIMEOUT_MS = 5_000;\n\n/** Rejects the read once the node has had long enough. */\nasync function within<T>(work: Promise<T>, timeoutMs = DEFAULT_TIMEOUT_MS): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n const expired = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error('timed out')), timeoutMs);\n });\n return await Promise.race([work, expired]);\n } finally {\n clearTimeout(timer);\n }\n}\n\nasync function managerAddress(override?: `0x${string}`): Promise<`0x${string}`> {\n if (override) return override;\n // Lazy, like every other core import in the CLI: a static one pulls the whole\n // SDK into startup for a command that may never read the chain.\n const { PERMISSIONS_MANAGER_ADDRESS } = await import('@jaw.id/core');\n return PERMISSIONS_MANAGER_ADDRESS as `0x${string}`;\n}\n\n/**\n * The read function for this chain, or null when there is none.\n *\n * `publicClientFor` throws for a chain it has no viem entry for, and a session\n * can live on one: `session status` runs for any chain the account supports,\n * while the client here covers the four the USDC registry names. Null rather\n * than a throw, so a chain without a client reads as not knowing instead of\n * taking the command down.\n */\nfunction reader(chainId: number, deps: ReadDeps) {\n if (deps.readContract) return deps.readContract;\n try {\n const client = publicClientFor(chainId);\n return (args: Parameters<NonNullable<ReadDeps['readContract']>>[0]) =>\n client.readContract(args as never) as Promise<unknown>;\n } catch {\n return null;\n }\n}\n\n/**\n * Ask the chain whether the permission is approved and whether it has been\n * revoked.\n *\n * Expiry is deliberately not asked for. The contract's `end` is the same number\n * already in the session config, so a read would only confirm what is on disk.\n * What no local file can know is that someone revoked from another device, and\n * that is the whole reason to make the call.\n */\nexport async function readPermissionState(target: PermissionReadTarget, deps: ReadDeps = {}): Promise<PermissionState> {\n if (!target.permission) return { status: 'unavailable' };\n const permission = toContractPermission(target.permission);\n if (!permission) return { status: 'unavailable' };\n\n const read = reader(target.chainId, deps);\n if (!read) return { status: 'unavailable' };\n\n try {\n const address = await managerAddress(deps.manager);\n const [hash, approved, revoked] = await within(\n Promise.all([\n read({ address, abi: PERMISSION_MANAGER_ABI, functionName: 'getHash', args: [permission] }),\n read({ address, abi: PERMISSION_MANAGER_ABI, functionName: 'isApproved', args: [permission] }),\n read({ address, abi: PERMISSION_MANAGER_ABI, functionName: 'isRevoked', args: [permission] }),\n ]),\n deps.timeoutMs\n );\n if (typeof hash !== 'string' || hash.toLowerCase() !== target.permissionId.toLowerCase()) {\n return { status: 'mismatch' };\n }\n return { status: 'ok', approved: approved === true, revoked: revoked === true };\n } catch {\n // An unreachable node is not evidence about a permission. Callers report\n // that they could not tell, never that the session is dead.\n return { status: 'unavailable' };\n }\n}\n\n/**\n * What the on-chain allowance has actually lost this period.\n *\n * `outside-window` is the permission being expired or not yet started:\n * `getCurrentPeriod` runs the same time-bound check the spend path does and\n * reverts rather than answering zero, so the revert is the answer and not a\n * failure.\n */\nexport type OnChainPeriod =\n | { status: 'ok'; start: number; end: number; spend: bigint }\n | { status: 'outside-window' }\n | { status: 'unavailable' };\n\n/** One limit's counter, tagged with the limit it belongs to. */\nexport interface OnChainLimit {\n token: string;\n unit: string;\n multiplier: number;\n allowance: string;\n period: OnChainPeriod;\n}\n\n/**\n * The current period for every spend limit the permission puts on `token`.\n *\n * All of them, because the contract charges all of them: the counter lives at\n * `_lastUpdatedPeriod[permissionHash][spendLimitHash]`, so a permission with\n * several limits on one token has several counters and reading one answers\n * about one budget. Issued together and awaited as one, so N limits cost the\n * latency of one rather than N; the client does not batch them into a single\n * request, so it is still N+1 calls on the wire.\n *\n * The hash is checked alongside them. `getCurrentPeriod` does not require the\n * permission to exist: handed a struct that hashes to something else it answers\n * about that other hash, as a zeroed counter over a window built from the\n * on-disk start.\n */\nexport async function readCurrentPeriods(\n target: PermissionReadTarget & { token: string },\n deps: ReadDeps = {}\n): Promise<OnChainLimit[]> {\n if (!target.permission) return [];\n const permission = toContractPermission(target.permission);\n if (!permission) return [];\n\n const granted = target.permission.spends;\n const indexes = granted\n .map((spend, index) => ({ spend, index }))\n .filter(({ spend }) => spend.token.toLowerCase() === target.token.toLowerCase());\n if (indexes.length === 0) return [];\n\n const unreadable = indexes.map(({ spend }) => ({ ...spend, period: { status: 'unavailable' as const } }));\n\n const read = reader(target.chainId, deps);\n if (!read) return unreadable;\n\n try {\n const address = await managerAddress(deps.manager);\n const settled = await within(\n Promise.allSettled([\n read({ address, abi: PERMISSION_MANAGER_ABI, functionName: 'getHash', args: [permission] }),\n ...indexes.map(({ index }) =>\n read({\n address,\n abi: PERMISSION_MANAGER_ABI,\n functionName: 'getCurrentPeriod',\n args: [permission, permission.spends[index]],\n })\n ),\n ]),\n deps.timeoutMs\n );\n\n const [hashed, ...counters] = settled;\n const hash = hashed.status === 'fulfilled' ? hashed.value : null;\n if (typeof hash !== 'string' || hash.toLowerCase() !== target.permissionId.toLowerCase()) {\n return unreadable;\n }\n\n return indexes.map(({ spend }, i) => {\n const result = counters[i];\n if (result.status === 'rejected') {\n return {\n ...spend,\n period: isTimeBoundRevert(result.reason)\n ? ({ status: 'outside-window' } as const)\n : ({ status: 'unavailable' } as const),\n };\n }\n const period = result.value as { start: number; end: number; spend: bigint } | undefined;\n return {\n ...spend,\n period: period\n ? ({\n status: 'ok',\n start: Number(period.start),\n end: Number(period.end),\n spend: BigInt(period.spend),\n } as const)\n : ({ status: 'unavailable' } as const),\n };\n });\n } catch {\n return unreadable;\n }\n}\n\n/** Whether a failed read was the contract refusing on time bounds rather than a node not answering. */\nfunction isTimeBoundRevert(err: unknown): boolean {\n if (!(err instanceof BaseError)) return false;\n const revert = err.walk((e) => e instanceof ContractFunctionRevertedError);\n return revert instanceof ContractFunctionRevertedError && TIME_BOUND_ERRORS.has(revert.data?.errorName ?? '');\n}\n\n/**\n * What the chain says about a session's permission, flattened to one word.\n *\n * `unknown` covers every way of not knowing, which callers treat alike: a node\n * that did not answer, a chain with no client, a session written before the\n * struct was stored, and a struct that cannot be rebuilt. None of them are\n * evidence about a permission, so none of them may read as dead.\n */\nexport type PermissionLiveness = 'active' | 'revoked' | 'unapproved' | 'mismatch' | 'unknown';\n\n/** `readPermissionState` for the three status surfaces, which all want the one word. */\nexport async function readLiveness(session: PermissionReadTarget, deps: ReadDeps = {}): Promise<PermissionLiveness> {\n const state = await readPermissionState(session, deps);\n if (state.status === 'unavailable') return 'unknown';\n if (state.status === 'mismatch') return 'mismatch';\n if (state.revoked) return 'revoked';\n return state.approved ? 'active' : 'unapproved';\n}\n","import { saveRecoveredPermission, parseGrantedPermission, type SessionConfig } from '../lib/session-config.js';\nimport type { GrantedPermission } from '../lib/session-config.js';\n\n/**\n * The permission struct for a session that was created before the CLI kept one.\n *\n * Those sessions hold only the id, and no view on the permission manager takes\n * an id, so every on-chain read reports \"cannot tell\" and `session add` refuses\n * for want of a scope to merge against. Telling people to run setup again is a\n * poor answer when the grant is recoverable: the relay stores what was granted,\n * keyed by the same hash, and `getPermissionFromRelay` returns it.\n *\n * Recovered once and written back, so this costs one GET on the first command\n * that needs it and nothing afterwards. Anything that goes wrong leaves the\n * session exactly as it was, which is the behaviour every such session had\n * before this existed: a failed recovery must not turn a working command into\n * an error.\n */\n\nconst RECOVERY_TIMEOUT_MS = 5_000;\n\nexport interface RecoveryDeps {\n /** Injected for tests, and so the unit tests never import core. */\n fetchPermission?: (permissionId: string, apiKey: string) => Promise<unknown>;\n timeoutMs?: number;\n}\n\nexport async function recoverPermission(\n session: SessionConfig,\n apiKey: string | undefined,\n deps: RecoveryDeps = {}\n): Promise<GrantedPermission | undefined> {\n if (session.permission) return session.permission;\n if (!apiKey) return undefined;\n\n const fetchPermission =\n deps.fetchPermission ??\n (async (id: string, key: string) => {\n // Lazy, like every other core import in the CLI: a static one pulls the\n // whole SDK into startup for a command that may never need it.\n const { getPermissionFromRelay } = await import('@jaw.id/core');\n return getPermissionFromRelay(id as `0x${string}`, key);\n });\n\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n const expired = new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error('timed out')), deps.timeoutMs ?? RECOVERY_TIMEOUT_MS);\n });\n const relayed = await Promise.race([fetchPermission(session.permissionId, apiKey), expired]);\n const permission = parseGrantedPermission(relayed);\n if (!permission) return undefined;\n // Checked against the session before it is trusted. The on-chain `getHash`\n // gate covers the case where the chain can be reached, and `session add`\n // goes ahead on `unknown`, which is exactly what a chain outside the\n // client's registry returns: there the union would be built from an\n // unverified relay response with nothing local to corroborate it. These\n // three cost nothing and make it a response about this session or none.\n if (\n permission.account.toLowerCase() !== session.ownerAddress.toLowerCase() ||\n permission.spender.toLowerCase() !== session.sessionAddress.toLowerCase() ||\n permission.end !== session.expiry // safe now that nothing else rewrites expiry\n ) {\n return undefined;\n }\n // Whether it describes the permission that was granted is settled on chain,\n // by the `getHash` check every read here goes through. Storing one that does\n // not match costs a `mismatch` report, which is what the session already\n // showed as `unknown`, and never a wrong answer.\n // Undefined when it did not land, which means the session went away while\n // this was waiting on the relay. Handing the struct back anyway would let a\n // caller go on to merge against, or report on, a session that no longer\n // exists.\n return saveRecoveredPermission(session, permission) ? permission : undefined;\n } catch {\n return undefined;\n } finally {\n clearTimeout(timer);\n }\n}\n","import { toFunctionSelector } from 'viem';\nimport { describeSpendPeriod } from './period.js';\nimport type { GrantedPermission } from '../lib/session-config.js';\nimport type { PermissionsConfig } from '../lib/types.js';\n\n/**\n * The union of what a session already grants and what is being added.\n *\n * A session holds one permission, and `session setup` replaces it. An agent\n * that has a scoped session and then discovers it needs to pay had no way to\n * add that: re-running setup revokes the grant it is working under, so it loses\n * its other capabilities mid-task, and the only way to have both was to\n * hand-write the union as one `--permissions` document.\n *\n * The union is computable now only because the granted permission is stored as\n * the contract holds it. Before that the CLI kept a USDC spend limit and\n * nothing else, so the existing scope could not be reconstructed to merge\n * against.\n */\n\n/**\n * A call is the same call when it targets the same function on the same\n * contract.\n *\n * The selector is derived from the signature when that is all an entry carries,\n * which is how the x402 preset writes them while the stored permission carries\n * selectors. Comparing the two forms directly matched nothing, so\n * `session add --x402` was never a no-op: every run re-granted, revoked, cost\n * two browser approvals, and left another copy of the same call on the\n * permission.\n */\nfunction callKey(call: { target: string; selector?: string; functionSignature?: string }): string | null {\n const selector = call.selector ?? (call.functionSignature ? safeSelector(call.functionSignature) : undefined);\n return selector ? `${call.target.toLowerCase()}:${selector.toLowerCase()}` : null;\n}\n\nfunction safeSelector(signature: string): string | undefined {\n try {\n return toFunctionSelector(signature);\n } catch {\n // A signature the SDK will reject later. Left unkeyed rather than thrown on:\n // this is a merge, and the grant is where a bad signature belongs refused.\n return undefined;\n }\n}\n\n/**\n * A limit is superseded by one that meters the same token over the same window,\n * and only by that.\n *\n * Keying on the token alone was worse in the other direction: a session holding\n * a monthly budget and a daily one, taking `add --x402` with no `--limit`,\n * dropped both for the preset's default. A command whose whole promise is to\n * add without taking away removed a cap the request never mentioned, and the\n * ceiling cannot catch it, since it compares one entry at a time.\n *\n * What the remaining windows do to each other is real but not this function's\n * to resolve, and `describeMerge` says it out loud:\n * `_checkAndIncrementSpend` charges every limit whose token matches rather than\n * stopping at the first (`JustaPermissionManager.sol:1069`, \"Don't break,\n * continue checking all limits for this token\"), so limits on one token are\n * ANDed and the tightest binds.\n */\nfunction spendKey(spend: { token: string; unit: string; multiplier?: number }): string {\n return `${spend.token.toLowerCase()}:${spend.unit}:${spend.multiplier ?? 1}`;\n}\n\nfunction tokenKey(spend: { token: string }): string {\n return spend.token.toLowerCase();\n}\n\nexport function mergePermissions(existing: GrantedPermission, addition: PermissionsConfig): PermissionsConfig {\n // Typed as the wider config shape: an addition may name a call by signature\n // instead of selector, which is what the x402 preset does.\n const calls: NonNullable<PermissionsConfig['calls']> = existing.calls.map((call) => ({\n target: call.target,\n selector: call.selector,\n }));\n const seenCalls = new Set(existing.calls.map(callKey));\n for (const call of addition.calls ?? []) {\n const key = callKey(call);\n if (key && seenCalls.has(key)) continue;\n if (key) seenCalls.add(key);\n calls.push(call);\n }\n\n const superseded = new Set((addition.spends ?? []).map(spendKey));\n const spends = existing.spends\n .filter((spend) => !superseded.has(spendKey(spend)))\n .map((spend) => ({\n token: spend.token,\n // Normalised out of the hex the grant response carries, so the merged\n // document reads the way a hand-written one does.\n allowance: BigInt(spend.allowance).toString(),\n unit: spend.unit,\n multiplier: spend.multiplier,\n }));\n for (const spend of addition.spends ?? []) {\n spends.push({\n token: spend.token,\n allowance: BigInt(spend.allowance).toString(),\n unit: spend.unit,\n multiplier: spend.multiplier ?? 1,\n });\n }\n\n // Absent rather than empty. The validator rejects a `spends: []` outright,\n // and a calls-only session merged with a calls-only addition produces exactly\n // that, so every such add threw after the browser had already been opened.\n return {\n ...(calls.length > 0 ? { calls } : {}),\n ...(spends.length > 0 ? { spends } : {}),\n };\n}\n\n/** One line per change, for the summary printed before the browser opens. */\nexport function describeMerge(existing: GrantedPermission, merged: PermissionsConfig): string[] {\n const lines: string[] = [];\n const hadCalls = new Set(existing.calls.map(callKey));\n for (const call of merged.calls ?? []) {\n const key = callKey(call);\n if (key && hadCalls.has(key)) continue;\n lines.push(` + call ${call.target} ${call.selector ?? call.functionSignature ?? ''}`.trimEnd());\n }\n\n const had = new Map(existing.spends.map((spend) => [spendKey(spend), BigInt(spend.allowance)]));\n const changed: Array<{ token: string; allowance: string; unit: string; multiplier?: number }> = [];\n for (const spend of merged.spends ?? []) {\n const was = had.get(spendKey(spend));\n const now = BigInt(spend.allowance);\n if (was === undefined) {\n lines.push(\n ` + spend ${spend.allowance} of ${spend.token} per ${describeSpendPeriod(spend.unit, spend.multiplier)}`\n );\n changed.push(spend);\n } else if (was !== now) {\n lines.push(\n ` ~ spend ${spend.token} per ${describeSpendPeriod(spend.unit, spend.multiplier)}: ${was} to ${now}`\n );\n changed.push(spend);\n }\n }\n\n // Every other limit on the same token, named rather than ranked. All of them\n // are charged, so the tightest binds, and which one that is depends on the\n // question being asked: a 1-a-day and a 100-a-month limit constrain different\n // things and neither is simply tighter. What a summary can say honestly is\n // that they are still there, because listing only the addition reads as a\n // raise that the others may not allow.\n for (const spend of changed) {\n const others = (merged.spends ?? []).filter((o) => o !== spend && tokenKey(o) === tokenKey(spend));\n for (const other of others) {\n lines.push(\n ` ! note ${other.allowance} per ${describeSpendPeriod(other.unit, other.multiplier)} on the same token still applies; ` +\n 'every limit on a token is charged, so the tightest of them binds'\n );\n }\n }\n\n return lines;\n}\n","import { Flags } from '@oclif/core';\nimport * as fs from 'node:fs';\nimport { BaseCommand } from '../../base-command.js';\nimport { loadConfig } from '../../lib/config.js';\nimport { getBridge } from '../../lib/bridge-singleton.js';\nimport { keystoreExists } from '../../lib/keystore.js';\nimport {\n isLegacySession,\n liveOrphans,\n loadSessionConfig,\n parseGrantedPermission,\n saveRevokeProgress,\n saveSessionConfig,\n} from '../../lib/session-config.js';\nimport type { OutputFormat, PermissionsConfig } from '../../lib/types.js';\nimport { parsePermissionsConfig } from '../../lib/validation.js';\nimport { buildX402Permissions, DEFAULT_X402_LIMIT } from '../../x402/grant-preset.js';\nimport { whyGrantExceedsCeiling } from '../../x402/grant-ceiling.js';\nimport { whyOwnerCannotFundSession, whySpenderCannotPay } from '../../x402/funded-owner.js';\nimport { readLiveness } from '../../x402/permission-onchain.js';\nimport { recoverPermission } from '../../x402/permission-recovery.js';\nimport { mergePermissions, describeMerge } from '../../x402/merge-permissions.js';\n\n/**\n * Add a capability to a session without taking away the ones it has.\n *\n * `session setup` replaces a session. An agent working under a scoped session\n * that then discovers it needs to pay could only re-run setup, which revokes\n * the grant it is working under, so it loses its other capabilities in the\n * middle of the task. The alternative was hand-writing the union as one\n * `--permissions` document, which means knowing the scope you already have.\n *\n * The session still holds one permission afterwards. The union is granted as a\n * new one and the old is revoked, rather than the session tracking several,\n * because two live grants are two independent budgets on chain: two of 5 a day\n * are 10 a day, and nothing in the system represents the total. One permission\n * keeps the number on screen the number that binds.\n *\n * The key is kept, which is the point: the agent's address, its balance and its\n * delegation all survive.\n */\nexport default class SessionAdd extends BaseCommand {\n static override description =\n 'Add permissions to the current session, keeping the ones it already has (one browser approval to grant, one to revoke the old).';\n\n static override examples = [\n '<%= config.bin %> session add --x402',\n '<%= config.bin %> session add --x402 --limit 10/day',\n '<%= config.bin %> session add --permissions \\'{\"calls\":[...]}\\'',\n ];\n\n static override flags = {\n ...BaseCommand.baseFlags,\n permissions: Flags.string({\n description: 'Permissions to add (inline JSON or file path).',\n exclusive: ['x402'],\n }),\n x402: Flags.boolean({\n description: 'Add exactly what x402 payments need on the session chain. Tune the cap with --limit.',\n default: false,\n exclusive: ['permissions'],\n }),\n limit: Flags.string({\n description: `Spend cap for --x402, as <amount>/<period> (default ${DEFAULT_X402_LIMIT}).`,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(SessionAdd);\n const config = loadConfig();\n const format = flags.output as OutputFormat;\n const apiKey = this.resolveApiKey(flags);\n\n if (flags.limit && !flags.x402) {\n this.error('--limit only applies to --x402. Re-run with --x402, or set the cap inside --permissions.');\n }\n if (!flags.x402 && !flags.permissions) {\n this.error('Nothing to add. Pass --x402 for the payment preset, or --permissions with a scope.');\n }\n if (!keystoreExists()) {\n this.error('No session to add to. Run `jaw session setup` first.');\n }\n\n const session = loadSessionConfig();\n if (session.expiry <= Date.now() / 1000) {\n this.error('The session expired, so there is nothing to add to. Run `jaw session setup` to create a new one.');\n }\n if (isLegacySession(session)) {\n this.error(\n 'This session was created by an older CLI and cannot be added to: its permission belongs to an address ' +\n 'separate from the session key. Run `jaw session setup` to recreate it.'\n );\n }\n // The union needs the scope that is already granted, and only the stored\n // struct has it. A session written before that field keeps working; it just\n // cannot be merged against, because the old scope is not knowable from a\n // permission id.\n // Recovered from the relay when the session predates the CLI storing it,\n // so an older session can be added to rather than told to start over.\n const existing = await recoverPermission(session, apiKey);\n if (!existing) {\n this.error(\n 'This session does not carry the permission it was granted, so what it already allows cannot be read. ' +\n 'Run `jaw session setup` to recreate it, and adding will work from then on.'\n );\n }\n\n // The union is computed from the stored struct, so it has to still describe\n // the permission on chain. A `mismatch` means it does not, and `revoked`\n // means there is nothing to add to; going ahead in either case would merge\n // against a scope that is not live and then revoke the one that is, which is\n // the capability loss this command exists to prevent. Not knowing is not a\n // reason to refuse: it is what every session reports without a reachable\n // node.\n const liveness = await readLiveness({ ...session, permission: existing });\n if (liveness === 'revoked') {\n this.error(\n 'The permission this session names was revoked on chain. Run `jaw session setup` to create a new one.'\n );\n }\n if (liveness === 'mismatch') {\n this.error(\n 'The permission stored for this session does not match the one that was granted, so what it ' +\n 'already allows cannot be read. Run `jaw session setup` to recreate it.'\n );\n }\n\n const addition = this.resolveAddition(flags, session.chainId);\n const merged = mergePermissions(existing, addition);\n const changes = describeMerge(existing, merged);\n if (changes.length === 0) {\n this.log('The session already allows all of this. Nothing to do.');\n return;\n }\n\n // Against what is being added, not the whole merged document. A limit the\n // session already holds cannot be superseded by an addition that does not\n // name its window, so judging the merge refused the add over a number the\n // user never asked for, on a session no command could bring back under the\n // ceiling short of starting over. The ceiling exists to bound what an agent\n // can ask for, and that is exactly the addition.\n const overCeiling = whyGrantExceedsCeiling(addition, session.chainId, config.grantCeiling);\n if (overCeiling) this.error(overCeiling);\n\n // The merge is checked too, and only warned about. What is granted is the\n // union, so a limit the session already holds rides into a new permission\n // on a machine whose ceiling is lower, and checking only the addition\n // cannot see that. It is not a refusal because the addition did not ask for\n // it and no command can lower it, so refusing would block `session add` on\n // that session for good. Saying it is what is left.\n const mergeOverCeiling = whyGrantExceedsCeiling(merged, session.chainId, config.grantCeiling);\n if (mergeOverCeiling) {\n this.logToStderr(\n // Not \"holds more than the ceiling allows\": three of the five reasons\n // this returns are \"cannot be measured against it\" rather than \"is over\n // it\", and a chain with no registry USDC produced a sentence that\n // contradicted itself.\n `Warning: what this session already holds does not clear the grant ceiling on this machine, ` +\n `and re-granting carries it over. ${mergeOverCeiling}`\n );\n }\n\n if (!flags.quiet && format !== 'json') {\n this.log('Adding to the current session:\\n');\n for (const change of changes) this.log(change);\n this.log(\n '\\nThe union is granted as a new permission and the old one is revoked, so the browser asks twice.\\n' +\n 'The session key is kept, so the address and its balance do not change.\\n'\n );\n this.log('Opening browser to approve...');\n }\n\n const permissions = parsePermissionsConfig(merged);\n const bridge = await getBridge({ keysUrl: config.keysUrl, apiKey, chainId: session.chainId, ens: config.ens });\n let granted: unknown;\n try {\n // The account connected in the browser decides who the union belongs to.\n // A different one would grant a permission owned by someone else, leave\n // the revoke of the old one failing because that account does not own it,\n // and quietly move where payments pull from. Checked before the grant,\n // since afterwards it is on chain.\n const accounts = (await bridge.request('eth_requestAccounts')) as string[] | undefined;\n const connected = accounts?.[0];\n if (connected && connected.toLowerCase() !== session.ownerAddress.toLowerCase()) {\n this.error(\n `This session's permission belongs to ${session.ownerAddress}, but ${connected} is connected in the ` +\n 'browser. Connect that account, or run `jaw session setup` to start a session on this one.'\n );\n }\n\n // The same guard setup runs: the grant carries a transfer to the session,\n // and an owner that cannot cover it leaves a permission that cannot be\n // used until it is funded and the whole thing is done again.\n if (flags.x402) {\n const blocked = await whyOwnerCannotFundSession({\n chainId: session.chainId,\n request: (m, p) => bridge.request(m, p),\n });\n if (blocked) this.error(blocked);\n }\n\n granted = await bridge.request('wallet_grantPermissions', [\n {\n spender: session.sessionAddress,\n expiry: session.expiry,\n permissions,\n chainId: session.chainId,\n capabilities: { prefundSpender: true },\n },\n ]);\n } finally {\n bridge.close();\n }\n\n const response = granted as { permissionId: string; account: string };\n const permission = parseGrantedPermission(granted);\n const orphans = liveOrphans(session.orphanedPermissions);\n\n // Written before the revoke is attempted, not after. The union is on chain\n // by now, and anything that throws between here and the write would leave a\n // live permission recorded nowhere: `session revoke` could not reach it,\n // status would not meter it, and the config would still name the old id.\n // Opening the second bridge is one of the things that can throw, which is\n // why it is not enough for the revoke request itself to be guarded.\n //\n // The old permission goes in as an orphan for the same reason, and comes\n // back out below once it is actually revoked.\n const updated = {\n ownerAddress: response.account,\n sessionAddress: session.sessionAddress,\n permissionId: response.permissionId,\n chainId: session.chainId,\n expiry: session.expiry,\n mode: 'eip7702' as const,\n // Kept, not restamped: it is what the session spend total is counted\n // from, and adding a capability must not hand the session cap a clean\n // slate.\n createdAt: session.createdAt,\n ...(permission ? { permission } : {}),\n orphanedPermissions: [{ id: session.permissionId, chainId: session.chainId, expiry: session.expiry }, ...orphans],\n };\n saveSessionConfig(updated);\n\n let revoked = false;\n try {\n const revokeBridge = await getBridge({\n keysUrl: config.keysUrl,\n apiKey,\n chainId: session.chainId,\n ens: config.ens,\n });\n try {\n await revokeBridge.request('wallet_revokePermissions', [{ id: session.permissionId }]);\n revoked = true;\n } finally {\n revokeBridge.close();\n }\n } catch (err) {\n // Not fatal, and not silent. The new permission is live and recorded; the\n // old one stays live until it expires, and it is on the orphan list so\n // `jaw session revoke` can still reach it.\n this.logToStderr(\n `Warning: the new permission was granted, but revoking the old one failed: ` +\n `${err instanceof Error ? err.message : String(err)}. It stays live until it expires, and ` +\n `\\`jaw session revoke\\` will revoke it.`\n );\n }\n\n if (revoked) {\n // The object just written, not a re-read of the file. Reading it back\n // would throw here if another terminal had removed the session in\n // between, after both the grant and the revoke had already succeeded, and\n // would clobber whatever that process wrote.\n saveRevokeProgress({ ...updated, createdAt: session.createdAt }, { orphans, ownPermissionRevoked: false });\n }\n\n if (flags.x402) {\n const unfunded = await whySpenderCannotPay({\n chainId: session.chainId,\n spender: session.sessionAddress as `0x${string}`,\n });\n if (unfunded) this.logToStderr(`\\nWarning: ${unfunded}`);\n }\n\n const summary = {\n sessionAddress: session.sessionAddress,\n permissionId: response.permissionId,\n previousPermissionId: session.permissionId,\n previousRevoked: revoked,\n expiry: session.expiry,\n };\n if (format === 'json' || flags.quiet) {\n this.outputResult(summary, format);\n return;\n }\n this.log('\\nSession updated.\\n');\n this.log(` Session address: ${session.sessionAddress}`);\n this.log(` Permission ID: ${response.permissionId}`);\n this.log(` Chain: ${session.chainId}`);\n this.log(` Expires: ${new Date(session.expiry * 1000).toISOString()}`);\n }\n\n private resolveAddition(\n flags: { x402: boolean; limit?: string; permissions?: string },\n chainId: number\n ): PermissionsConfig {\n if (flags.x402) {\n try {\n return parsePermissionsConfig(buildX402Permissions(chainId, flags.limit));\n } catch (err) {\n this.error(err instanceof Error ? err.message : String(err));\n }\n }\n const value = flags.permissions as string;\n let raw: unknown;\n if (value.trimStart().startsWith('{')) {\n try {\n raw = JSON.parse(value);\n } catch {\n this.error(`--permissions is not valid JSON: ${value}`);\n }\n } else {\n const content = fs.readFileSync(value, 'utf-8');\n try {\n raw = JSON.parse(content);\n } catch {\n this.error(`Permissions file at ${value} is not valid JSON.`);\n }\n }\n return parsePermissionsConfig(raw);\n }\n}\n"]}
|