@jaw.id/cli 0.1.25 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +5 -0
  3. package/README.md +4 -0
  4. package/dist/base-command.js +3 -1
  5. package/dist/base-command.js.map +1 -1
  6. package/dist/commands/config/set.js +140 -12
  7. package/dist/commands/config/set.js.map +1 -1
  8. package/dist/commands/config/show.js +3 -1
  9. package/dist/commands/config/show.js.map +1 -1
  10. package/dist/commands/config/write.js +6 -4
  11. package/dist/commands/config/write.js.map +1 -1
  12. package/dist/commands/disconnect.js +24 -10
  13. package/dist/commands/disconnect.js.map +1 -1
  14. package/dist/commands/mcp/index.js +2426 -94
  15. package/dist/commands/mcp/index.js.map +1 -1
  16. package/dist/commands/rpc/call.js +197 -45
  17. package/dist/commands/rpc/call.js.map +1 -1
  18. package/dist/commands/session/add.js +1547 -0
  19. package/dist/commands/session/add.js.map +1 -0
  20. package/dist/commands/session/revoke.js +181 -54
  21. package/dist/commands/session/revoke.js.map +1 -1
  22. package/dist/commands/session/setup.js +516 -65
  23. package/dist/commands/session/setup.js.map +1 -1
  24. package/dist/commands/session/status.js +315 -6
  25. package/dist/commands/session/status.js.map +1 -1
  26. package/dist/commands/version.js +3 -1
  27. package/dist/commands/version.js.map +1 -1
  28. package/dist/commands/x402/log.js +344 -0
  29. package/dist/commands/x402/log.js.map +1 -0
  30. package/dist/commands/x402/pay.js +2122 -0
  31. package/dist/commands/x402/pay.js.map +1 -0
  32. package/dist/commands/x402/status.js +1047 -0
  33. package/dist/commands/x402/status.js.map +1 -0
  34. package/dist/index.js +41 -14
  35. package/dist/index.js.map +1 -1
  36. package/dist/lib/bridge-singleton.js +41 -14
  37. package/dist/lib/bridge-singleton.js.map +1 -1
  38. package/dist/lib/config.js +26 -3
  39. package/dist/lib/config.js.map +1 -1
  40. package/dist/lib/keystore.js +13 -2
  41. package/dist/lib/keystore.js.map +1 -1
  42. package/dist/lib/paths.js +3 -1
  43. package/dist/lib/paths.js.map +1 -1
  44. package/dist/lib/payment-lock.js +121 -0
  45. package/dist/lib/payment-lock.js.map +1 -0
  46. package/dist/lib/session-bridge.js +148 -24
  47. package/dist/lib/session-bridge.js.map +1 -1
  48. package/dist/lib/session-config.js +78 -11
  49. package/dist/lib/session-config.js.map +1 -1
  50. package/dist/lib/terminal.js +22 -0
  51. package/dist/lib/terminal.js.map +1 -0
  52. package/dist/lib/validation.js +3 -3
  53. package/dist/lib/validation.js.map +1 -1
  54. package/dist/lib/ws-bridge.js +22 -10
  55. package/dist/lib/ws-bridge.js.map +1 -1
  56. package/dist/mcp/handlers/config.js +73 -6
  57. package/dist/mcp/handlers/config.js.map +1 -1
  58. package/dist/mcp/handlers/daemon.js +43 -12
  59. package/dist/mcp/handlers/daemon.js.map +1 -1
  60. package/dist/mcp/handlers/resources.js +119 -0
  61. package/dist/mcp/handlers/resources.js.map +1 -1
  62. package/dist/mcp/handlers/rpc.js +269 -60
  63. package/dist/mcp/handlers/rpc.js.map +1 -1
  64. package/dist/mcp/helpers.js +50 -3
  65. package/dist/mcp/helpers.js.map +1 -1
  66. package/dist/mcp/server.js +2426 -94
  67. package/dist/mcp/server.js.map +1 -1
  68. package/dist/mcp/tools.js +43 -3
  69. package/dist/mcp/tools.js.map +1 -1
  70. package/dist/x402/log-view.js +160 -0
  71. package/dist/x402/log-view.js.map +1 -0
  72. package/dist/x402/status-report.js +90 -0
  73. package/dist/x402/status-report.js.map +1 -0
  74. package/oclif.manifest.json +398 -4
  75. package/package.json +8 -3
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/paths.ts","../../../src/lib/validation.ts","../../../src/lib/config.ts","../../../src/lib/output.ts","../../../src/base-command.ts","../../../src/lib/crypto.ts","../../../src/lib/ws-bridge.ts","../../../src/lib/relay-session.ts","../../../src/lib/bridge-singleton.ts","../../../src/lib/keystore.ts","../../../src/lib/session-config.ts","../../../src/commands/session/setup.ts"],"names":["fs2","crypto2","crypto3","fs4","fs5","Flags","fs6"],"mappings":"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","file":"setup.js","sourcesContent":["import * as path from 'node:path';\nimport * as os from 'node:os';\n\nconst JAW_DIR = path.join(os.homedir(), '.jaw');\n\nexport const PATHS = {\n root: JAW_DIR,\n config: path.join(JAW_DIR, 'config.json'),\n session: path.join(JAW_DIR, 'session.json'),\n relay: path.join(JAW_DIR, 'relay.json'),\n keystore: path.join(JAW_DIR, 'keystore.json'),\n sessionConfig: path.join(JAW_DIR, 'session-config.json'),\n} as const;\n","import type { PermissionsConfig } from './types.js';\n\nconst ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;\nconst SELECTOR_RE = /^0x[0-9a-fA-F]{8}$/;\nconst HEX_RE = /^0x[0-9a-fA-F]+$/;\nconst VALID_SPEND_UNITS = new Set(['minute', 'hour', 'day', 'week', 'month', 'year', 'forever']);\n\nexport function parsePermissionsConfig(raw: unknown): PermissionsConfig {\n const errors: string[] = [];\n\n if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {\n throw new Error('Invalid permissions:\\n - Must be an object');\n }\n\n const obj = raw as Record<string, unknown>;\n const calls = obj.calls as unknown[] | undefined;\n const spends = obj.spends as unknown[] | undefined;\n\n if (!calls && !spends) {\n throw new Error('Invalid permissions:\\n - Must include at least \"calls\" or \"spends\"');\n }\n\n if (calls !== undefined) {\n if (!Array.isArray(calls) || calls.length === 0) {\n errors.push('calls: Must be a non-empty array');\n } else {\n for (let i = 0; i < calls.length; i++) {\n const c = calls[i] as Record<string, unknown>;\n if (!c || typeof c !== 'object') {\n errors.push(`calls.${i}: Must be an object`);\n continue;\n }\n if (typeof c.target !== 'string' || !ADDRESS_RE.test(c.target)) {\n errors.push(`calls.${i}.target: Must be a valid 0x address (40 hex chars)`);\n }\n if (c.selector !== undefined && (typeof c.selector !== 'string' || !SELECTOR_RE.test(c.selector))) {\n errors.push(`calls.${i}.selector: Must be a 4-byte hex selector (e.g. 0xa9059cbb)`);\n }\n }\n }\n }\n\n if (spends !== undefined) {\n if (!Array.isArray(spends) || spends.length === 0) {\n errors.push('spends: Must be a non-empty array');\n } else {\n for (let i = 0; i < spends.length; i++) {\n const s = spends[i] as Record<string, unknown>;\n if (!s || typeof s !== 'object') {\n errors.push(`spends.${i}: Must be an object`);\n continue;\n }\n if (typeof s.token !== 'string' || !ADDRESS_RE.test(s.token)) {\n errors.push(`spends.${i}.token: Must be a valid 0x address (40 hex chars)`);\n }\n if (typeof s.allowance !== 'string' || !HEX_RE.test(s.allowance)) {\n errors.push(`spends.${i}.allowance: Must be a non-empty 0x hex value`);\n }\n if (typeof s.unit !== 'string' || !VALID_SPEND_UNITS.has(s.unit)) {\n errors.push(`spends.${i}.unit: Must be one of: ${[...VALID_SPEND_UNITS].join(', ')}`);\n }\n if (s.multiplier !== undefined && (!Number.isInteger(s.multiplier) || (s.multiplier as number) < 1)) {\n errors.push(`spends.${i}.multiplier: Must be a positive integer`);\n }\n }\n }\n }\n\n if (errors.length > 0) {\n throw new Error(`Invalid permissions:\\n${errors.map((e) => ` - ${e}`).join('\\n')}`);\n }\n\n return raw as PermissionsConfig;\n}\n\nexport function isValidKeysUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n const isTrustedHost =\n parsed.hostname.endsWith('.jaw.id') ||\n parsed.hostname === 'jaw.id' ||\n parsed.hostname === 'localhost' ||\n parsed.hostname === '127.0.0.1';\n const isSecure = parsed.protocol === 'https:' || parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1';\n return isTrustedHost && isSecure;\n } catch {\n return false;\n }\n}\n\nexport function isValidRelayUrl(url: string): boolean {\n try {\n const parsed = new URL(url);\n const isTrustedHost =\n parsed.hostname.endsWith('.jaw.id') ||\n parsed.hostname === 'jaw.id' ||\n parsed.hostname === 'localhost' ||\n parsed.hostname === '127.0.0.1';\n const isSecure = parsed.protocol === 'wss:' || parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1';\n const isWebSocket = parsed.protocol === 'wss:' || parsed.protocol === 'ws:';\n return isTrustedHost && isSecure && isWebSocket;\n } catch {\n return false;\n }\n}\n","import * as fs from 'node:fs';\nimport { PATHS } from './paths.js';\nimport type { JawConfig } from './types.js';\nimport { isValidKeysUrl, isValidRelayUrl } from './validation.js';\n\nexport function ensureDir(dir: string): void {\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n fs.chmodSync(dir, 0o700);\n}\n\nfunction migrateConfig(config: JawConfig): JawConfig {\n if (config.paymasterUrl && !config.paymasters) {\n const chainId = config.defaultChain ?? 1;\n config.paymasters = { [chainId]: { url: config.paymasterUrl } };\n delete config.paymasterUrl;\n saveConfig(config);\n }\n return config;\n}\n\nexport function loadConfig(): JawConfig {\n if (!fs.existsSync(PATHS.config)) {\n return {};\n }\n const raw = fs.readFileSync(PATHS.config, 'utf-8');\n try {\n const config = JSON.parse(raw) as JawConfig;\n return migrateConfig(config);\n } catch {\n throw new Error(\n `Config file at ${PATHS.config} is not valid JSON. Run \\`jaw config set apiKey=<key>\\` to reset it.`\n );\n }\n}\n\nexport function saveConfig(config: JawConfig): void {\n ensureDir(PATHS.root);\n fs.writeFileSync(PATHS.config, JSON.stringify(config, null, 2) + '\\n', {\n encoding: 'utf-8',\n mode: 0o600,\n });\n}\n\n/** Paymaster URLs embed provider API keys as query params (e.g. Pimlico's ?apikey=...). */\nfunction redactUrlSecrets(url: string): string {\n try {\n const parsed = new URL(url);\n for (const key of [...parsed.searchParams.keys()]) {\n parsed.searchParams.set(key, '***');\n }\n return parsed.toString();\n } catch {\n return '***';\n }\n}\n\nexport function redactConfig(config: JawConfig): Record<string, unknown> {\n return {\n ...config,\n apiKey: config.apiKey ? `${config.apiKey.slice(0, 8)}...` : undefined,\n ...(config.paymasters && {\n paymasters: Object.fromEntries(\n Object.entries(config.paymasters).map(([chainId, pm]) => [\n chainId,\n // context is a free-form object (usually just a sponsorshipPolicyId) but a\n // provider could stash a token there, so mask it rather than hand it to the agent.\n { ...pm, url: redactUrlSecrets(pm.url), context: pm.context ? '***' : undefined },\n ])\n ),\n }),\n };\n}\n\nexport function setConfigValue(key: keyof JawConfig, value: string | number): void {\n if (key === 'keysUrl' && typeof value === 'string' && !isValidKeysUrl(value)) {\n throw new Error(`Untrusted keysUrl: ${value}. Must be a *.jaw.id domain (HTTPS) or localhost.`);\n }\n if (key === 'relayUrl' && typeof value === 'string' && !isValidRelayUrl(value)) {\n throw new Error(`Untrusted relayUrl: ${value}. Must be wss://*.jaw.id or ws://localhost.`);\n }\n const config = loadConfig();\n const updated = { ...config, [key]: value };\n saveConfig(updated);\n}\n","import type { OutputFormat } from './types.js';\n\nexport function formatOutput(data: unknown, format: OutputFormat): string {\n if (format === 'json') {\n return JSON.stringify(data, replaceBigInt, 2);\n }\n return formatHuman(data);\n}\n\nfunction replaceBigInt(_key: string, value: unknown): unknown {\n if (typeof value === 'bigint') {\n return value.toString();\n }\n return value;\n}\n\nfunction formatHuman(data: unknown, indent = 0): string {\n if (data === null || data === undefined) {\n return 'null';\n }\n\n if (typeof data === 'string' || typeof data === 'number' || typeof data === 'boolean' || typeof data === 'bigint') {\n return String(data);\n }\n\n if (Array.isArray(data)) {\n if (data.length === 0) return '(empty)';\n return data.map((item, i) => `${i + 1}. ${formatHuman(item, indent + 2)}`).join('\\n');\n }\n\n if (typeof data === 'object') {\n const entries = Object.entries(data as Record<string, unknown>);\n if (entries.length === 0) return '(empty)';\n const pad = ' '.repeat(indent);\n const maxKeyLen = Math.max(...entries.map(([k]) => k.length));\n return entries\n .map(([key, val]) => {\n const paddedKey = key.padEnd(maxKeyLen);\n const valStr = typeof val === 'object' && val !== null ? '\\n' + formatHuman(val, indent + 2) : String(val);\n return `${pad}${paddedKey} ${valStr}`;\n })\n .join('\\n');\n }\n\n return String(data);\n}\n","import { Command, Flags } from '@oclif/core';\nimport type { OutputFormat } from './lib/types.js';\nimport { loadConfig } from './lib/config.js';\nimport { formatOutput } from './lib/output.js';\n\nexport abstract class BaseCommand extends Command {\n static override baseFlags = {\n output: Flags.string({\n char: 'o',\n description: 'Output format',\n options: ['json', 'human'],\n default: 'human',\n env: 'JAW_OUTPUT',\n }),\n chain: Flags.integer({\n char: 'c',\n description: 'Chain ID',\n env: 'JAW_CHAIN_ID',\n }),\n 'api-key': Flags.string({\n description: 'JAW API key',\n env: 'JAW_API_KEY',\n }),\n yes: Flags.boolean({\n char: 'y',\n description: 'Skip confirmations (for AI agents)',\n default: false,\n }),\n quiet: Flags.boolean({\n char: 'q',\n description: 'Suppress non-essential output',\n default: false,\n }),\n };\n\n protected resolveApiKey(flags: { 'api-key'?: string }): string {\n const apiKey = flags['api-key'] ?? loadConfig().apiKey;\n if (!apiKey) {\n this.error('API key required. Set via --api-key, JAW_API_KEY env, or `jaw config set apiKey <key>`');\n }\n return apiKey;\n }\n\n protected resolveChainId(flags: { chain?: number }): number {\n const chainId = flags.chain ?? loadConfig().defaultChain;\n if (!chainId) {\n this.error('Chain ID required. Set via --chain, JAW_CHAIN_ID env, or `jaw config set defaultChain <id>`');\n }\n return chainId;\n }\n\n protected outputResult(data: unknown, format: OutputFormat): void {\n const output = formatOutput(data, format);\n this.log(output);\n }\n}\n","/**\n * E2E encryption primitives for CLI ↔ browser communication.\n *\n * Uses ECDH P-256 for key exchange and AES-256-GCM for message encryption.\n * Mirrors the same crypto operations in @jaw.id/core but uses only\n * Node.js built-in crypto.subtle — no external dependencies.\n */\n\nimport type { webcrypto } from 'node:crypto';\n\ntype CKey = webcrypto.CryptoKey;\ntype CKeyPair = webcrypto.CryptoKeyPair;\n\nconst subtle = globalThis.crypto.subtle;\n\n// ── Key generation ───────────────────────────────────────────────\n\nexport async function generateKeyPair(): Promise<CKeyPair> {\n return subtle.generateKey({ name: 'ECDH', namedCurve: 'P-256' }, true, ['deriveKey']) as Promise<CKeyPair>;\n}\n\nexport async function deriveSharedSecret(privateKey: CKey, peerPublicKey: CKey): Promise<CKey> {\n return subtle.deriveKey(\n { name: 'ECDH', public: peerPublicKey },\n privateKey,\n { name: 'AES-GCM', length: 256 },\n false,\n ['encrypt', 'decrypt']\n );\n}\n\n// ── Encrypt / Decrypt ────────────────────────────────────────────\n\nexport interface EncryptedEnvelope {\n iv: string; // base64\n ciphertext: string; // base64\n}\n\nexport async function encryptMessage(sharedSecret: CKey, payload: Record<string, unknown>): Promise<EncryptedEnvelope> {\n const iv = globalThis.crypto.getRandomValues(new Uint8Array(12));\n const plaintext = new TextEncoder().encode(JSON.stringify(payload));\n const cipherBuf = await subtle.encrypt({ name: 'AES-GCM', iv }, sharedSecret, plaintext);\n return {\n iv: bufferToBase64(iv),\n ciphertext: bufferToBase64(new Uint8Array(cipherBuf)),\n };\n}\n\nexport async function decryptMessage(\n sharedSecret: CKey,\n envelope: EncryptedEnvelope\n): Promise<Record<string, unknown>> {\n const iv = Buffer.from(envelope.iv, 'base64');\n const ciphertext = Buffer.from(envelope.ciphertext, 'base64');\n const plainBuf = await subtle.decrypt({ name: 'AES-GCM', iv }, sharedSecret, ciphertext);\n return JSON.parse(new TextDecoder().decode(plainBuf));\n}\n\n// ── Key import / export (hex) ────────────────────────────────────\n\nexport async function exportKeyToHex(type: 'private' | 'public', key: CKey): Promise<string> {\n const format = type === 'private' ? 'pkcs8' : 'spki';\n const buf = await subtle.exportKey(format, key);\n return bytesToHex(new Uint8Array(buf));\n}\n\nexport async function importKeyFromHex(type: 'private' | 'public', hex: string): Promise<CKey> {\n const format = type === 'private' ? 'pkcs8' : 'spki';\n return subtle.importKey(\n format,\n Buffer.from(hexToBytes(hex)),\n { name: 'ECDH', namedCurve: 'P-256' },\n true,\n type === 'private' ? ['deriveKey'] : []\n );\n}\n\n// ── Encoding helpers ─────────────────────────────────────────────\n\nfunction bytesToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\nfunction hexToBytes(hex: string): Uint8Array {\n if (hex.length % 2 !== 0) throw new Error('Invalid hex: odd length');\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);\n }\n return bytes;\n}\n\nfunction bufferToBase64(buf: Uint8Array): string {\n return Buffer.from(buf).toString('base64');\n}\n","/**\n * WSBridge — CLI-side relay client\n *\n * Connects to the cloud relay (wss://relay.jaw.id) instead of a local daemon.\n * All messages (except key_exchange) are E2E encrypted via ECDH + AES-256-GCM.\n */\n\nimport * as crypto from 'node:crypto';\nimport type { webcrypto } from 'node:crypto';\nimport WebSocket from 'ws';\nimport {\n deriveSharedSecret,\n encryptMessage,\n decryptMessage,\n importKeyFromHex,\n type EncryptedEnvelope,\n} from './crypto.js';\n\ntype CKey = webcrypto.CryptoKey;\n\nexport interface WSBridgeConfig {\n apiKey: string;\n chainId: number;\n ens?: string;\n paymasterUrl?: string;\n}\n\nexport interface WSBridgeOptions {\n relayUrl: string;\n session: string;\n timeout?: number;\n config: WSBridgeConfig;\n /** CLI's ECDH private key (hex). Loaded from relay.json for existing sessions. */\n privateKeyHex: string;\n /** CLI's ECDH public key (hex). Sent to browser for key derivation. */\n publicKeyHex: string;\n /** Browser's ECDH public key (hex). Null if new session (key exchange needed). */\n peerPublicKeyHex: string | null;\n}\n\nconst DEFAULT_TIMEOUT_MS = 120_000;\n\n/**\n * Maximum outbound message size (5 MB).\n *\n * wallet_sendCalls with large batches (50+ calls, complex calldata) can reach\n * hundreds of KB. Base64 encoding of the AES-GCM ciphertext adds ~33% overhead.\n * 5 MB is generous enough for any realistic batch while still preventing\n * accidental memory issues.\n */\nconst MAX_MESSAGE_BYTES = 5 * 1024 * 1024;\n\n/** Minimum time between browser reopen attempts (ms). */\nconst BROWSER_REOPEN_COOLDOWN_MS = 5_000;\n\n/** Maximum reconnection attempts before giving up. */\nconst MAX_RECONNECT_ATTEMPTS = 3;\n\n/** Base delay for exponential backoff (ms). */\nconst RECONNECT_BASE_DELAY_MS = 1_000;\n\nexport class WSBridge {\n private readonly relayUrl: string;\n private readonly session: string;\n private readonly timeout: number;\n private readonly config: WSBridgeConfig;\n private readonly privateKeyHex: string;\n readonly publicKeyHex: string;\n private peerPublicKeyHex: string | null;\n private sharedSecret: CKey | null = null;\n private ws: WebSocket | null = null;\n private disposed = false;\n\n // Auto-reopen browser state\n private onBrowserNeeded: (() => Promise<void>) | undefined;\n private onPeerKeyChanged: ((key: string) => void) | undefined;\n private lastBrowserOpenTime = 0;\n\n // Reconnection state\n private reconnectAttempts = 0;\n\n /** Updated after key exchange — caller should persist this. */\n get peerPublicKey(): string | null {\n return this.peerPublicKeyHex;\n }\n\n constructor(options: WSBridgeOptions) {\n this.relayUrl = options.relayUrl;\n this.session = options.session;\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;\n this.config = options.config;\n this.privateKeyHex = options.privateKeyHex;\n this.publicKeyHex = options.publicKeyHex;\n this.peerPublicKeyHex = options.peerPublicKeyHex;\n }\n\n /**\n * Connect to the relay and wait for the browser to be ready.\n *\n * @param onBrowserNeeded — called when the relay reports no browser connected.\n * @param onPeerKeyChanged — called when a key_exchange updates the peer key.\n */\n async connect(\n onBrowserNeeded?: () => Promise<void>,\n onPeerKeyChanged?: (newPeerPublicKeyHex: string) => void\n ): Promise<void> {\n // Store callbacks for auto-reopen on browser disconnect\n this.onBrowserNeeded = onBrowserNeeded;\n this.onPeerKeyChanged = onPeerKeyChanged;\n\n // Pre-derive shared secret if we already have the peer key\n if (this.peerPublicKeyHex) {\n await this.deriveSecret();\n }\n\n return this.connectInternal(onBrowserNeeded, onPeerKeyChanged);\n }\n\n private async connectInternal(\n onBrowserNeeded?: () => Promise<void>,\n onPeerKeyChanged?: (newPeerPublicKeyHex: string) => void\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n const url = `${this.relayUrl}?session=${encodeURIComponent(this.session)}&role=cli`;\n const ws = new WebSocket(url);\n\n let browserOpened = false;\n let resolved = false;\n let expectingKeyExchange = !this.peerPublicKeyHex;\n\n const timer = setTimeout(() => {\n ws.close();\n reject(new Error('Browser did not connect in time.\\n' + 'Run `jaw disconnect` then try again.'));\n }, 30_000);\n\n const sendEncryptedInit = async () => {\n if (!this.sharedSecret) return;\n const envelope = await encryptMessage(this.sharedSecret, {\n type: 'init',\n apiKey: this.config.apiKey,\n chainId: this.config.chainId,\n ens: this.config.ens,\n paymasterUrl: this.config.paymasterUrl,\n });\n this.sendRaw(ws, JSON.stringify({ type: 'encrypted', ...envelope }));\n };\n\n const waitForReady = () => {\n const readyTimer = setTimeout(() => {\n ws.close();\n reject(new Error('Browser SDK did not become ready in time.'));\n }, 15_000);\n\n const onMsg = async (data: WebSocket.Data) => {\n const msg = safeParse(data);\n if (!msg) return;\n\n if (msg.type === 'encrypted' && this.sharedSecret) {\n try {\n const inner = await decryptMessage(this.sharedSecret, msg as unknown as EncryptedEnvelope);\n if (inner.type === 'ready') {\n clearTimeout(readyTimer);\n ws.off('message', onMsg);\n this.reconnectAttempts = 0; // Reset on successful connect\n resolve();\n }\n } catch {\n // Not a valid encrypted message for us, ignore\n }\n }\n };\n ws.on('message', onMsg);\n };\n\n const onBrowserReady = async () => {\n if (resolved) return;\n resolved = true;\n clearTimeout(timer);\n // Set up listener BEFORE sending init to avoid missing the ready response\n waitForReady();\n await sendEncryptedInit();\n };\n\n ws.on('open', () => {\n this.ws = ws;\n });\n\n ws.on('message', async (data) => {\n const msg = safeParse(data);\n if (!msg) return;\n\n if (msg.type === 'status') {\n if (msg.browserConnected) {\n if (this.sharedSecret) {\n // Already have shared secret — skip key exchange\n await onBrowserReady();\n } else {\n // Browser is connected but we don't have its key yet.\n expectingKeyExchange = true;\n }\n } else if (!browserOpened && onBrowserNeeded) {\n browserOpened = true;\n expectingKeyExchange = true;\n onBrowserNeeded().catch(() => {\n /* best effort */\n });\n } else if (!onBrowserNeeded) {\n // Reuse path (bridge-singleton.ts called connectBridge with\n // openBrowser=false): the relay reports no browser connected and\n // we have no callback to open one. Bail immediately so the\n // caller can fall through to a fresh session, instead of waiting\n // out the 30s connect-timer.\n clearTimeout(timer);\n ws.close();\n reject(new Error('Browser not connected — relay session is stale.'));\n }\n } else if (msg.type === 'browser_connected') {\n expectingKeyExchange = true;\n // Wait for key_exchange from browser\n } else if (msg.type === 'browser_disconnected') {\n // Browser tab closed — attempt to reopen after cooldown\n this.handleBrowserDisconnect();\n } else if (msg.type === 'key_exchange' && expectingKeyExchange) {\n expectingKeyExchange = false;\n const peerKey = msg.publicKey as string;\n this.peerPublicKeyHex = peerKey;\n await this.deriveSecret();\n onPeerKeyChanged?.(peerKey);\n await onBrowserReady();\n }\n });\n\n ws.on('error', (err) => {\n clearTimeout(timer);\n reject(err);\n });\n\n ws.on('close', () => {\n clearTimeout(timer);\n if (!this.disposed) {\n this.handleRelayDisconnect();\n }\n });\n });\n }\n\n /**\n * Send an encrypted RPC request through the relay to the browser SDK.\n */\n async request(method: string, params?: unknown): Promise<unknown> {\n const ws = this.ws;\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n throw new Error('Not connected to relay');\n }\n if (!this.sharedSecret) {\n throw new Error('No shared secret — key exchange not completed');\n }\n\n const id = crypto.randomUUID();\n\n const envelope = await encryptMessage(this.sharedSecret, {\n type: 'rpc_request',\n id,\n method,\n params,\n });\n\n const serialized = JSON.stringify({ type: 'encrypted', ...envelope });\n assertMessageSize(serialized, method);\n\n return new Promise<unknown>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(\n new Error(`Request timed out after ${this.timeout / 1000}s. ` + 'Did you complete the action in the browser?')\n );\n this.close();\n }, this.timeout);\n\n const onMessage = async (data: WebSocket.Data) => {\n const msg = safeParse(data);\n if (!msg || msg.type !== 'encrypted' || !this.sharedSecret) return;\n\n try {\n const inner = await decryptMessage(this.sharedSecret, msg as unknown as EncryptedEnvelope);\n if (inner.type === 'rpc_response' && inner.id === id) {\n clearTimeout(timer);\n ws.off('message', onMessage);\n\n if (inner.success) {\n resolve(inner.data);\n } else {\n const err = inner.error as { code: number; message: string } | undefined;\n reject(new Error(err ? `[${err.code}] ${err.message}` : 'Request failed'));\n }\n }\n } catch {\n // Decryption failed — not our message or tampered, ignore\n }\n };\n\n ws.on('message', onMessage);\n this.sendRaw(ws, serialized);\n });\n }\n\n async shutdown(): Promise<void> {\n this.disposed = true;\n if (this.ws?.readyState === WebSocket.OPEN && this.sharedSecret) {\n try {\n const envelope = await encryptMessage(this.sharedSecret, {\n type: 'shutdown',\n });\n this.sendRaw(this.ws, JSON.stringify({ type: 'encrypted', ...envelope }));\n } catch {\n // Best effort\n }\n }\n this.close();\n }\n\n /**\n * Connect to relay and send shutdown directly — no init/ready handshake.\n * Used by `jaw disconnect` when we just need to tell the browser to close.\n */\n async connectAndShutdown(): Promise<void> {\n if (!this.peerPublicKeyHex) {\n // No peer key means browser never connected — nothing to shut down\n return;\n }\n\n this.disposed = true;\n await this.deriveSecret();\n\n return new Promise<void>((resolve) => {\n const url = `${this.relayUrl}?session=${encodeURIComponent(this.session)}&role=cli`;\n const ws = new WebSocket(url);\n\n const timer = setTimeout(() => {\n try {\n ws.close();\n } catch {\n /* ignore */\n }\n resolve();\n }, 3000);\n\n ws.on('open', async () => {\n this.ws = ws;\n try {\n await this.shutdown();\n } catch {\n // Best effort\n }\n clearTimeout(timer);\n resolve();\n });\n\n ws.on('error', () => {\n clearTimeout(timer);\n resolve();\n });\n });\n }\n\n close(): void {\n this.disposed = true;\n if (this.ws) {\n try {\n this.ws.close();\n } catch {\n // ignore\n }\n this.ws = null;\n }\n }\n\n /**\n * Auto-reopen browser when browser_disconnected is received from relay.\n * Respects a cooldown to prevent rapid re-opening.\n */\n private handleBrowserDisconnect(): void {\n if (this.disposed || !this.onBrowserNeeded) return;\n\n const now = Date.now();\n if (now - this.lastBrowserOpenTime < BROWSER_REOPEN_COOLDOWN_MS) {\n return; // Too soon — skip this reopen\n }\n\n this.lastBrowserOpenTime = now;\n\n // Reset shared secret — the new browser tab will do a fresh key exchange\n this.sharedSecret = null;\n this.peerPublicKeyHex = null;\n\n this.onBrowserNeeded().catch(() => {\n // Best effort — if browser open fails, the next request will error\n });\n }\n\n /**\n * Attempt to reconnect to the relay with exponential backoff\n * when the WebSocket connection drops unexpectedly.\n */\n private handleRelayDisconnect(): void {\n if (this.disposed) return;\n if (this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) return;\n\n const delay = RECONNECT_BASE_DELAY_MS * Math.pow(2, this.reconnectAttempts);\n this.reconnectAttempts++;\n\n setTimeout(() => {\n if (this.disposed) return;\n this.connectInternal(this.onBrowserNeeded, this.onPeerKeyChanged).catch(() => {\n // Reconnection failed — will retry if attempts remain\n });\n }, delay);\n }\n\n /** Send a raw string over the WebSocket, enforcing message size limits. */\n private sendRaw(ws: WebSocket, data: string): void {\n ws.send(data);\n }\n\n private async deriveSecret(): Promise<void> {\n if (!this.peerPublicKeyHex) return;\n const privateKey = await importKeyFromHex('private', this.privateKeyHex);\n const peerPublicKey = await importKeyFromHex('public', this.peerPublicKeyHex);\n this.sharedSecret = await deriveSharedSecret(privateKey, peerPublicKey);\n }\n}\n\n/**\n * Validate message size before sending to the relay.\n * Throws with a descriptive error if the message is too large.\n */\nfunction assertMessageSize(serialized: string, method: string): void {\n const byteLength = Buffer.byteLength(serialized, 'utf-8');\n if (byteLength > MAX_MESSAGE_BYTES) {\n const sizeMB = (byteLength / (1024 * 1024)).toFixed(2);\n throw new Error(\n `Message for ${method} is too large (${sizeMB} MB, limit ${MAX_MESSAGE_BYTES / (1024 * 1024)} MB). ` +\n 'Try reducing the number of calls in your batch.'\n );\n }\n}\n\nfunction safeParse(data: WebSocket.Data): Record<string, unknown> | null {\n try {\n return JSON.parse(data.toString()) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n","/**\n * Relay session persistence (~/.jaw/relay.json).\n * Shared by the bridge lifecycle (bridge-singleton) and status reporting (MCP jaw_status).\n */\n\nimport * as fs from 'node:fs';\nimport { PATHS } from './paths.js';\nimport { ensureDir } from './config.js';\n\nexport interface RelaySession {\n session: string;\n relayUrl: string;\n privateKey: string;\n publicKey: string;\n peerPublicKey: string | null;\n startedAt: string;\n}\n\nexport function loadRelaySession(): RelaySession | null {\n try {\n if (!fs.existsSync(PATHS.relay)) return null;\n const raw = fs.readFileSync(PATHS.relay, 'utf-8');\n const parsed = JSON.parse(raw) as RelaySession;\n // Basic validation\n if (!parsed.session || !parsed.relayUrl || !parsed.privateKey || !parsed.publicKey) {\n return null;\n }\n return parsed;\n } catch {\n return null;\n }\n}\n\nexport function saveRelaySession(info: RelaySession): void {\n ensureDir(PATHS.root);\n fs.writeFileSync(PATHS.relay, JSON.stringify(info, null, 2) + '\\n', {\n encoding: 'utf-8',\n mode: 0o600,\n });\n}\n\nexport function deleteRelaySession(): void {\n try {\n if (fs.existsSync(PATHS.relay)) fs.unlinkSync(PATHS.relay);\n } catch {\n // ignore\n }\n}\n","/**\n * Bridge lifecycle management — relay edition.\n *\n * - Generates a session token + ECDH keypair for new sessions\n * - Opens the browser to keys.jaw.id/cli-bridge\n * - Saves relay state to ~/.jaw/relay.json\n * - Creates a WSBridge client connected to the relay\n */\n\nimport * as fs from 'node:fs';\nimport * as crypto from 'node:crypto';\nimport { PATHS } from './paths.js';\nimport { loadConfig } from './config.js';\nimport { WSBridge } from './ws-bridge.js';\nimport { isValidKeysUrl, isValidRelayUrl } from './validation.js';\nimport { generateKeyPair, exportKeyToHex } from './crypto.js';\nimport { type RelaySession, loadRelaySession, saveRelaySession, deleteRelaySession } from './relay-session.js';\n\nconst DEFAULT_KEYS_URL = 'https://keys.jaw.id';\nconst DEFAULT_RELAY_URL = 'wss://relay.jaw.id';\n\nexport interface BridgeOptions {\n keysUrl?: string;\n relayUrl?: string;\n apiKey: string;\n chainId?: number;\n ens?: string;\n paymasterUrl?: string;\n timeout?: number;\n}\n\n/**\n * Get or create a relay bridge connection.\n */\nexport async function getBridge(options: BridgeOptions): Promise<WSBridge> {\n const config = loadConfig();\n const keysUrl = options.keysUrl ?? config.keysUrl ?? DEFAULT_KEYS_URL;\n const relayUrl = options.relayUrl ?? config.relayUrl ?? DEFAULT_RELAY_URL;\n const chainId = options.chainId ?? config.defaultChain ?? 1;\n if (!isValidKeysUrl(keysUrl)) {\n throw new Error(`Untrusted keysUrl: ${keysUrl}. Must be a *.jaw.id domain (HTTPS) or localhost.`);\n }\n if (!isValidRelayUrl(relayUrl)) {\n throw new Error(`Untrusted relayUrl: ${relayUrl}. Must be wss://*.jaw.id or ws://localhost.`);\n }\n\n // Try existing session first — but never open a browser for a stale session.\n // If the browser is already connected, reuse it. If not, fall through to a new session.\n let relaySession = loadRelaySession();\n if (relaySession && relaySession.relayUrl === relayUrl && relaySession.peerPublicKey) {\n try {\n return await connectBridge(relaySession, options, chainId, keysUrl, relayUrl, false);\n } catch {\n // Connection failed — stale session or relay restarted.\n // Delete and fall through to create a new one.\n deleteRelaySession();\n relaySession = null;\n }\n } else if (relaySession) {\n // Incomplete session (no peer key) — discard\n deleteRelaySession();\n }\n\n // New session — this is the only path that opens a browser\n const session = await createNewSession(relayUrl);\n saveRelaySession(session);\n return await connectBridge(session, options, chainId, keysUrl, relayUrl, true);\n}\n\nasync function createNewSession(relayUrl: string): Promise<RelaySession> {\n const kp = await generateKeyPair();\n const privateKey = await exportKeyToHex('private', kp.privateKey);\n const publicKey = await exportKeyToHex('public', kp.publicKey);\n\n return {\n session: crypto.randomUUID(),\n relayUrl,\n privateKey,\n publicKey,\n peerPublicKey: null,\n startedAt: new Date().toISOString(),\n };\n}\n\nasync function connectBridge(\n relaySession: RelaySession,\n options: BridgeOptions,\n chainId: number,\n keysUrl: string,\n relayUrl: string,\n openBrowser: boolean\n): Promise<WSBridge> {\n const config = loadConfig();\n const bridge = new WSBridge({\n relayUrl,\n session: relaySession.session,\n timeout: options.timeout,\n config: {\n apiKey: options.apiKey,\n chainId,\n ens: options.ens ?? config.ens,\n paymasterUrl: options.paymasterUrl ?? config.paymasters?.[chainId]?.url,\n },\n privateKeyHex: relaySession.privateKey,\n publicKeyHex: relaySession.publicKey,\n peerPublicKeyHex: relaySession.peerPublicKey,\n });\n\n await bridge.connect(\n // onBrowserNeeded — only open a browser for new sessions\n openBrowser\n ? async () => {\n const bridgeUrl = buildBridgeUrl(keysUrl, relaySession.session, relayUrl, relaySession.publicKey);\n const { default: open } = await import('open');\n await open(bridgeUrl);\n }\n : undefined,\n // onPeerKeyChanged\n (newPeerKey) => {\n relaySession.peerPublicKey = newPeerKey;\n saveRelaySession(relaySession);\n }\n );\n\n return bridge;\n}\n\nfunction buildBridgeUrl(keysUrl: string, session: string, relayUrl: string, cliPublicKeyHex: string): string {\n const url = new URL('/cli-bridge', keysUrl);\n url.searchParams.set('session', session);\n url.searchParams.set('relay', relayUrl);\n // CLI public key in fragment — not sent to server\n url.hash = `pk=${cliPublicKeyHex}`;\n return url.toString();\n}\n\n/**\n * Shutdown: close the relay session and clean up.\n */\nexport async function shutdownDaemon(): Promise<void> {\n const session = loadRelaySession();\n if (!session) return;\n\n // Send shutdown directly — no init/ready handshake needed\n try {\n const bridge = new WSBridge({\n relayUrl: session.relayUrl,\n session: session.session,\n timeout: 5000,\n config: { apiKey: '', chainId: 1 },\n privateKeyHex: session.privateKey,\n publicKeyHex: session.publicKey,\n peerPublicKeyHex: session.peerPublicKey,\n });\n await bridge.connectAndShutdown();\n } catch {\n // Best effort — relay or browser may already be gone\n }\n\n deleteRelaySession();\n\n // Legacy cleanup: kill old daemon process and remove files\n const legacyBridge = PATHS.root + '/bridge.json';\n const legacyLog = PATHS.root + '/daemon.log';\n const legacyLock = PATHS.root + '/daemon.lock';\n try {\n if (fs.existsSync(legacyBridge)) {\n const info = JSON.parse(fs.readFileSync(legacyBridge, 'utf-8'));\n if (info.pid && Number.isInteger(info.pid) && info.pid > 0) {\n try {\n process.kill(info.pid, 'SIGTERM');\n } catch {\n /* already dead */\n }\n }\n }\n } catch {\n /* ignore */\n }\n for (const f of [legacyBridge, legacyLog, legacyLock]) {\n try {\n if (fs.existsSync(f)) fs.unlinkSync(f);\n } catch {\n /* ignore */\n }\n }\n}\n","import * as crypto from 'node:crypto';\nimport * as fs from 'node:fs';\nimport { PATHS } from './paths.js';\nimport { ensureDir } from './config.js';\n\ninterface KeystoreFile {\n version: 2;\n privateKey: string;\n address: string;\n createdAt: string;\n}\n\n/**\n * Generate a random secp256k1 private key as 0x-prefixed hex.\n */\nexport function generateSessionKey(): `0x${string}` {\n const bytes = crypto.randomBytes(32);\n return `0x${bytes.toString('hex')}` as `0x${string}`;\n}\n\n/**\n * Save private key to keystore.json.\n * On-chain PermissionManager is the real security boundary — the session key\n * can only act within its granted permission scope regardless of local access.\n */\nexport function saveKeystore(privateKeyHex: string, address: string): void {\n const keystore: KeystoreFile = {\n version: 2,\n privateKey: privateKeyHex,\n address,\n createdAt: new Date().toISOString(),\n };\n\n ensureDir(PATHS.root);\n fs.writeFileSync(PATHS.keystore, JSON.stringify(keystore, null, 2) + '\\n', {\n encoding: 'utf-8',\n mode: 0o600,\n });\n // `mode` is only honored on file creation, not overwrite — re-apply explicitly.\n fs.chmodSync(PATHS.keystore, 0o600);\n}\n\n/**\n * Load private key hex from keystore.json.\n */\nexport function loadSessionKey(): string {\n if (!fs.existsSync(PATHS.keystore)) {\n throw new Error('No session configured. Run `jaw session setup` first.');\n }\n\n const contents = fs.readFileSync(PATHS.keystore, 'utf-8');\n let parsed: KeystoreFile;\n try {\n parsed = JSON.parse(contents) as KeystoreFile;\n } catch {\n throw new Error(`Keystore at ${PATHS.keystore} is corrupted. Run \\`jaw session setup\\` to recreate it.`);\n }\n return parsed.privateKey;\n}\n\n/**\n * Delete keystore.json.\n */\nexport function deleteKeystore(): void {\n if (fs.existsSync(PATHS.keystore)) {\n fs.unlinkSync(PATHS.keystore);\n }\n}\n\n/**\n * Check if keystore.json exists.\n */\nexport function keystoreExists(): boolean {\n return fs.existsSync(PATHS.keystore);\n}\n","import * as fs from 'node:fs';\nimport { PATHS } from './paths.js';\nimport { ensureDir } from './config.js';\n\nexport interface SessionConfig {\n ownerAddress: string;\n sessionAddress: string;\n permissionId: string;\n chainId: number;\n expiry: number;\n createdAt: string;\n}\n\nexport function saveSessionConfig(input: Omit<SessionConfig, 'createdAt'>): void {\n const config: SessionConfig = {\n ...input,\n createdAt: new Date().toISOString(),\n };\n ensureDir(PATHS.root);\n fs.writeFileSync(PATHS.sessionConfig, JSON.stringify(config, null, 2) + '\\n', {\n encoding: 'utf-8',\n mode: 0o600,\n });\n fs.chmodSync(PATHS.sessionConfig, 0o600);\n}\n\nexport function loadSessionConfig(): SessionConfig {\n if (!fs.existsSync(PATHS.sessionConfig)) {\n throw new Error('No session configured. Run `jaw session setup` first.');\n }\n const raw = fs.readFileSync(PATHS.sessionConfig, 'utf-8');\n try {\n return JSON.parse(raw) as SessionConfig;\n } catch {\n throw new Error(`Session config at ${PATHS.sessionConfig} is corrupted. Run \\`jaw session setup\\` to recreate it.`);\n }\n}\n\nexport function deleteSessionConfig(): void {\n if (fs.existsSync(PATHS.sessionConfig)) {\n fs.unlinkSync(PATHS.sessionConfig);\n }\n}\n","import { 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 { generateSessionKey, saveKeystore, keystoreExists, loadSessionKey } from '../../lib/keystore.js';\nimport { saveSessionConfig, loadSessionConfig } from '../../lib/session-config.js';\nimport type { OutputFormat, PermissionsConfig } from '../../lib/types.js';\nimport { parsePermissionsConfig } from '../../lib/validation.js';\n\nexport default class SessionSetup extends BaseCommand {\n static override description =\n 'Generate a session key and grant scoped on-chain permissions (one-time browser approval).';\n\n static override examples = [\n '<%= config.bin %> session setup --chain 84532',\n '<%= config.bin %> session setup --permissions \\'{\"calls\":[...]}\\' --expiry 14',\n '<%= config.bin %> session setup --permissions ./permissions.json',\n ];\n\n static override flags = {\n ...BaseCommand.baseFlags,\n permissions: Flags.string({\n description: 'Permission scope (inline JSON or file path). Overrides config.permissions.',\n }),\n expiry: Flags.integer({\n description: 'Permission expiry in days. Overrides config.sessionExpiry.',\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(SessionSetup);\n const config = loadConfig();\n const format = flags.output as OutputFormat;\n const apiKey = this.resolveApiKey(flags);\n const chainId = this.resolveChainId(flags);\n\n // 1. Check existing session\n let reuseKey: string | null = null;\n let oldPermissionRevoked = false;\n\n if (keystoreExists()) {\n const existing = loadSessionConfig();\n const isActive = existing.expiry > Date.now() / 1000;\n\n // The prompt path uses readline against process.stdin. With non-TTY stdin\n // (pipes, heredocs, CI), readline races against the awaited bridge call\n // below: stdin EOFs while the browser approval is pending, readline auto-\n // closes, and the second `ask` throws ERR_USE_AFTER_CLOSE *after* on-chain\n // state has already mutated. Require --yes for non-interactive use.\n if (!flags.yes && !process.stdin.isTTY) {\n this.error(\n 'Existing session found, but stdin is not a terminal ' +\n '(piped, redirected, or running in CI). ' +\n 'Re-run with --yes to overwrite the existing session non-interactively.'\n );\n }\n\n if (!flags.yes) {\n const readline = await import('node:readline');\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n const ask = (q: string) => new Promise<string>((resolve) => rl.question(q, resolve));\n\n if (isActive) {\n const remaining = Math.floor((existing.expiry - Date.now() / 1000) / 86400);\n this.log('Active session found:\\n');\n this.log(` Session address: ${existing.sessionAddress}`);\n this.log(` Permission ID: ${existing.permissionId}`);\n this.log(` Chain: ${existing.chainId}`);\n this.log(\n ` Expires: ${new Date(existing.expiry * 1000).toISOString()} (${remaining} days remaining)`\n );\n this.log('\\nThe old on-chain permission will NOT be revoked automatically.');\n this.log('Anyone with the old session key can still use it until expiry.\\n');\n\n const revokeAnswer = await ask('Revoke old permission on-chain first? (Y/n) ');\n if (revokeAnswer.toLowerCase() !== 'n') {\n this.log('Opening browser to revoke old permission...');\n const pm = config.paymasters?.[existing.chainId];\n const revokeBridge = await getBridge({\n keysUrl: config.keysUrl,\n apiKey,\n chainId: existing.chainId,\n ens: config.ens,\n paymasterUrl: pm?.url,\n });\n try {\n await revokeBridge.request('wallet_revokePermissions', [{ id: existing.permissionId }]);\n } finally {\n revokeBridge.close();\n }\n oldPermissionRevoked = true;\n this.log('Old permission revoked.');\n }\n\n const reuseAnswer = await ask('Reuse existing session key? (Y/n) ');\n if (reuseAnswer.toLowerCase() !== 'n') {\n reuseKey = loadSessionKey();\n }\n } else {\n const overwrite = await ask('Expired session found. Overwrite? (y/N) ');\n if (overwrite.toLowerCase() !== 'y') {\n rl.close();\n this.log('Aborted.');\n return;\n }\n }\n\n rl.close();\n } else if (isActive) {\n // --yes mode: log warning but continue\n this.logToStderr(\n `Warning: overwriting active session without revoking. ` +\n `Old permission ${existing.permissionId} on chain ${existing.chainId} ` +\n `remains live until ${new Date(existing.expiry * 1000).toISOString()}.`\n );\n }\n\n // Old keystore/session-config are intentionally NOT deleted here.\n // saveKeystore/saveSessionConfig below overwrite them on success;\n // leaving them in place means a failed grant doesn't strand the user\n // with an active on-chain permission and no local key.\n }\n\n // Anything below can throw. If the inner revoke above already mutated\n // on-chain state, surface a recovery hint before re-throwing so the user\n // knows their local session-config now references a revoked permission.\n try {\n // 2. Resolve permissions\n const permissions = this.resolvePermissions(flags.permissions, config.permissions);\n\n // 3. Resolve expiry\n const expiryDays = flags.expiry ?? config.sessionExpiry ?? 7;\n const expiryTimestamp = Math.floor(Date.now() / 1000) + expiryDays * 86400;\n\n // 4. Generate or reuse session key\n const privateKeyHex = (reuseKey ?? generateSessionKey()) as `0x${string}`;\n\n // 5. Create LocalAccount and derive smart account address\n const { privateKeyToAccount } = await import('viem/accounts');\n const localAccount = privateKeyToAccount(privateKeyHex);\n\n const { Account } = await import('@jaw.id/core');\n const pm = config.paymasters?.[chainId];\n const account = await Account.fromLocalAccount(\n {\n chainId,\n apiKey,\n paymasterUrl: pm?.url,\n paymasterContext: pm?.context,\n },\n localAccount\n );\n const sessionAddress = account.address;\n\n // 6. Open browser bridge to grant permissions\n if (!flags.quiet) {\n this.log('Opening browser to approve permissions...');\n }\n\n const bridge = await getBridge({\n keysUrl: config.keysUrl,\n apiKey,\n chainId,\n ens: config.ens,\n paymasterUrl: pm?.url,\n });\n\n let grantResponse: { permissionId: string; account: string };\n try {\n grantResponse = (await bridge.request('wallet_grantPermissions', [\n {\n spender: sessionAddress,\n expiry: expiryTimestamp,\n permissions,\n chainId,\n },\n ])) as { permissionId: string; account: string };\n } finally {\n bridge.close();\n }\n\n // 7. Save keystore\n saveKeystore(privateKeyHex, sessionAddress);\n\n // 8. Save session config\n saveSessionConfig({\n ownerAddress: grantResponse.account,\n sessionAddress,\n permissionId: grantResponse.permissionId,\n chainId,\n expiry: expiryTimestamp,\n });\n\n // 9. Output\n const summary = {\n ownerAddress: grantResponse.account,\n sessionAddress,\n permissionId: grantResponse.permissionId,\n expiry: expiryTimestamp,\n };\n\n if (flags.quiet) {\n this.outputResult(summary, format);\n } else {\n this.log('\\nSession created successfully.\\n');\n this.log(` Session address: ${sessionAddress}`);\n this.log(` Owner address: ${grantResponse.account}`);\n this.log(` Permission ID: ${grantResponse.permissionId}`);\n this.log(` Chain: ${chainId}`);\n this.log(` Expires: ${new Date(expiryTimestamp * 1000).toISOString()} (${expiryDays} days)`);\n this.log('\\nUse --session flag to execute RPC calls in auto mode.');\n }\n } catch (error) {\n if (oldPermissionRevoked) {\n this.logToStderr(\n 'Old permission was revoked on-chain but setup did not complete. ' +\n 'Local session-config still references the revoked permission; ' +\n 'run `jaw session setup` again to create a new session.'\n );\n }\n throw error;\n }\n }\n\n private resolvePermissions(\n flagValue: string | undefined,\n configValue: PermissionsConfig | undefined\n ): PermissionsConfig {\n let raw: unknown;\n\n if (flagValue) {\n if (flagValue.trimStart().startsWith('{')) {\n try {\n raw = JSON.parse(flagValue);\n } catch {\n this.error(`--permissions is not valid JSON: ${flagValue}`);\n }\n } else {\n const content = fs.readFileSync(flagValue, 'utf-8');\n try {\n raw = JSON.parse(content);\n } catch {\n this.error(`Permissions file at ${flagValue} is not valid JSON.`);\n }\n }\n } else if (configValue) {\n raw = configValue;\n } else {\n this.error('Permissions required. Set via --permissions flag or add \"permissions\" to ~/.jaw/config.json');\n }\n\n return parsePermissionsConfig(raw);\n }\n}\n"]}
1
+ {"version":3,"sources":["../../../src/lib/paths.ts","../../../src/lib/validation.ts","../../../src/lib/config.ts","../../../src/lib/output.ts","../../../src/base-command.ts","../../../src/lib/crypto.ts","../../../src/lib/ws-bridge.ts","../../../src/lib/relay-session.ts","../../../src/lib/bridge-singleton.ts","../../../src/lib/keystore.ts","../../../src/lib/session-config.ts","../../../src/x402/asset-registry.ts","../../../src/x402/grant-preset.ts","../../../src/x402/balance.ts","../../../src/x402/gas-reserve.ts","../../../src/x402/amount.ts","../../../src/lib/terminal.ts","../../../src/x402/status-report.ts","../../../src/x402/funded-owner.ts","../../../src/x402/period.ts","../../../src/x402/grant-ceiling.ts","../../../src/commands/session/setup.ts"],"names":["fs","fs2","crypto2","crypto3","ADDRESS_RE","SELECTOR_RE","ALLOWANCE_RE","fs5","base","bound","parseUnits","Flags","fs6"],"mappings":";;;;;;;;;;AAGA,IAAM,OAAA,GAAe,IAAA,CAAA,IAAA,CAAQ,EAAA,CAAA,OAAA,EAAQ,EAAG,MAAM,CAAA;AAEvC,IAAM,KAAA,GAAQ;AAAA,EACnB,IAAA,EAAM,OAAA;AAAA,EACN,MAAA,EAAa,IAAA,CAAA,IAAA,CAAK,OAAA,EAAS,aAAa,CAAA;AAAA,EACxC,OAAA,EAAc,IAAA,CAAA,IAAA,CAAK,OAAA,EAAS,cAAc,CAAA;AAAA,EAC1C,KAAA,EAAY,IAAA,CAAA,IAAA,CAAK,OAAA,EAAS,YAAY,CAAA;AAAA,EACtC,QAAA,EAAe,IAAA,CAAA,IAAA,CAAK,OAAA,EAAS,eAAe,CAAA;AAAA,EAC5C,aAAA,EAAoB,IAAA,CAAA,IAAA,CAAK,OAAA,EAAS,qBAAqB,CAAA;AAAA,EACvD,OAAA,EAAc,IAAA,CAAA,IAAA,CAAK,OAAA,EAAS,gBAAgB,CAAA;AAAA,EAC5C,WAAA,EAAkB,IAAA,CAAA,IAAA,CAAK,OAAA,EAAS,mBAAmB;AACrD,CAAA;;;ACZA,IAAM,UAAA,GAAa,qBAAA;AACnB,IAAM,WAAA,GAAc,oBAAA;AAKpB,IAAM,YAAA,GAAe,2BAAA;AACrB,IAAM,iBAAA,mBAAoB,IAAI,GAAA,CAAI,CAAC,QAAA,EAAU,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAQ,OAAA,EAAS,MAAA,EAAQ,SAAS,CAAC,CAAA;AAExF,SAAS,uBAAuB,GAAA,EAAiC;AACtE,EAAA,MAAM,SAAmB,EAAC;AAE1B,EAAA,IAAI,OAAO,QAAQ,QAAA,IAAY,GAAA,KAAQ,QAAQ,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACjE,IAAA,MAAM,IAAI,MAAM,6CAA6C,CAAA;AAAA,EAC/D;AAEA,EAAA,MAAM,GAAA,GAAM,GAAA;AACZ,EAAA,MAAM,QAAQ,GAAA,CAAI,KAAA;AAClB,EAAA,MAAM,SAAS,GAAA,CAAI,MAAA;AAEnB,EAAA,IAAI,CAAC,KAAA,IAAS,CAAC,MAAA,EAAQ;AACrB,IAAA,MAAM,IAAI,MAAM,qEAAqE,CAAA;AAAA,EACvF;AAEA,EAAA,IAAI,UAAU,MAAA,EAAW;AACvB,IAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,IAAK,KAAA,CAAM,WAAW,CAAA,EAAG;AAC/C,MAAA,MAAA,CAAO,KAAK,kCAAkC,CAAA;AAAA,IAChD,CAAA,MAAO;AACL,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,QAAA,MAAM,CAAA,GAAI,MAAM,CAAC,CAAA;AACjB,QAAA,IAAI,CAAC,CAAA,IAAK,OAAO,CAAA,KAAM,QAAA,EAAU;AAC/B,UAAA,MAAA,CAAO,IAAA,CAAK,CAAA,MAAA,EAAS,CAAC,CAAA,mBAAA,CAAqB,CAAA;AAC3C,UAAA;AAAA,QACF;AACA,QAAA,IAAI,OAAO,EAAE,MAAA,KAAW,QAAA,IAAY,CAAC,UAAA,CAAW,IAAA,CAAK,CAAA,CAAE,MAAM,CAAA,EAAG;AAC9D,UAAA,MAAA,CAAO,IAAA,CAAK,CAAA,MAAA,EAAS,CAAC,CAAA,kDAAA,CAAoD,CAAA;AAAA,QAC5E;AACA,QAAA,IAAI,CAAA,CAAE,QAAA,KAAa,MAAA,KAAc,OAAO,CAAA,CAAE,QAAA,KAAa,QAAA,IAAY,CAAC,WAAA,CAAY,IAAA,CAAK,CAAA,CAAE,QAAQ,CAAA,CAAA,EAAI;AACjG,UAAA,MAAA,CAAO,IAAA,CAAK,CAAA,MAAA,EAAS,CAAC,CAAA,0DAAA,CAA4D,CAAA;AAAA,QACpF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,IAAI,WAAW,MAAA,EAAW;AACxB,IAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,IAAK,MAAA,CAAO,WAAW,CAAA,EAAG;AACjD,MAAA,MAAA,CAAO,KAAK,mCAAmC,CAAA;AAAA,IACjD,CAAA,MAAO;AACL,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AACtC,QAAA,MAAM,CAAA,GAAI,OAAO,CAAC,CAAA;AAClB,QAAA,IAAI,CAAC,CAAA,IAAK,OAAO,CAAA,KAAM,QAAA,EAAU;AAC/B,UAAA,MAAA,CAAO,IAAA,CAAK,CAAA,OAAA,EAAU,CAAC,CAAA,mBAAA,CAAqB,CAAA;AAC5C,UAAA;AAAA,QACF;AACA,QAAA,IAAI,OAAO,EAAE,KAAA,KAAU,QAAA,IAAY,CAAC,UAAA,CAAW,IAAA,CAAK,CAAA,CAAE,KAAK,CAAA,EAAG;AAC5D,UAAA,MAAA,CAAO,IAAA,CAAK,CAAA,OAAA,EAAU,CAAC,CAAA,iDAAA,CAAmD,CAAA;AAAA,QAC5E;AACA,QAAA,IAAI,OAAO,EAAE,SAAA,KAAc,QAAA,IAAY,CAAC,YAAA,CAAa,IAAA,CAAK,CAAA,CAAE,SAAS,CAAA,EAAG;AACtE,UAAA,MAAA,CAAO,IAAA,CAAK,CAAA,OAAA,EAAU,CAAC,CAAA,+CAAA,CAAiD,CAAA;AAAA,QAC1E;AACA,QAAA,IAAI,OAAO,EAAE,IAAA,KAAS,QAAA,IAAY,CAAC,iBAAA,CAAkB,GAAA,CAAI,CAAA,CAAE,IAAI,CAAA,EAAG;AAChE,UAAA,MAAA,CAAO,IAAA,CAAK,CAAA,OAAA,EAAU,CAAC,CAAA,uBAAA,EAA0B,CAAC,GAAG,iBAAiB,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,QACtF;AACA,QAAA,IAAI,CAAA,CAAE,UAAA,KAAe,MAAA,KAAc,CAAC,MAAA,CAAO,SAAA,CAAU,CAAA,CAAE,UAAU,CAAA,IAAM,CAAA,CAAE,UAAA,GAAwB,CAAA,CAAA,EAAI;AACnG,UAAA,MAAA,CAAO,IAAA,CAAK,CAAA,OAAA,EAAU,CAAC,CAAA,uCAAA,CAAyC,CAAA;AAAA,QAClE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AACrB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA;AAAA,EAAyB,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,IAAA,EAAO,CAAC,CAAA,CAAE,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,EACrF;AAEA,EAAA,OAAO,GAAA;AACT;AAEO,SAAS,eAAe,GAAA,EAAsB;AACnD,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAG,CAAA;AAC1B,IAAA,MAAM,aAAA,GACJ,MAAA,CAAO,QAAA,CAAS,QAAA,CAAS,SAAS,CAAA,IAClC,MAAA,CAAO,QAAA,KAAa,QAAA,IACpB,MAAA,CAAO,QAAA,KAAa,WAAA,IACpB,OAAO,QAAA,KAAa,WAAA;AACtB,IAAA,MAAM,QAAA,GAAW,OAAO,QAAA,KAAa,QAAA,IAAY,OAAO,QAAA,KAAa,WAAA,IAAe,OAAO,QAAA,KAAa,WAAA;AACxG,IAAA,OAAO,aAAA,IAAiB,QAAA;AAAA,EAC1B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEO,SAAS,gBAAgB,GAAA,EAAsB;AACpD,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAG,CAAA;AAC1B,IAAA,MAAM,aAAA,GACJ,MAAA,CAAO,QAAA,CAAS,QAAA,CAAS,SAAS,CAAA,IAClC,MAAA,CAAO,QAAA,KAAa,QAAA,IACpB,MAAA,CAAO,QAAA,KAAa,WAAA,IACpB,OAAO,QAAA,KAAa,WAAA;AACtB,IAAA,MAAM,QAAA,GAAW,OAAO,QAAA,KAAa,MAAA,IAAU,OAAO,QAAA,KAAa,WAAA,IAAe,OAAO,QAAA,KAAa,WAAA;AACtG,IAAA,MAAM,WAAA,GAAc,MAAA,CAAO,QAAA,KAAa,MAAA,IAAU,OAAO,QAAA,KAAa,KAAA;AACtE,IAAA,OAAO,iBAAiB,QAAA,IAAY,WAAA;AAAA,EACtC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;;;ACtGO,SAAS,UAAU,GAAA,EAAmB;AAC3C,EAAGA,cAAU,GAAA,EAAK,EAAE,WAAW,IAAA,EAAM,IAAA,EAAM,KAAO,CAAA;AAClD,EAAGA,GAAA,CAAA,SAAA,CAAU,KAAK,GAAK,CAAA;AACzB;AAEA,SAAS,cAAc,MAAA,EAA8B;AACnD,EAAA,IAAI,MAAA,CAAO,YAAA,IAAgB,CAAC,MAAA,CAAO,UAAA,EAAY;AAC7C,IAAA,MAAM,OAAA,GAAU,OAAO,YAAA,IAAgB,CAAA;AACvC,IAAA,MAAA,CAAO,UAAA,GAAa,EAAE,CAAC,OAAO,GAAG,EAAE,GAAA,EAAK,MAAA,CAAO,YAAA,EAAa,EAAE;AAC9D,IAAA,OAAO,MAAA,CAAO,YAAA;AACd,IAAA,UAAA,CAAW,MAAM,CAAA;AAAA,EACnB;AACA,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,UAAA,GAAwB;AACtC,EAAA,IAAI,CAAIA,GAAA,CAAA,UAAA,CAAW,KAAA,CAAM,MAAM,CAAA,EAAG;AAChC,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,MAAM,GAAA,GAASA,GAAA,CAAA,YAAA,CAAa,KAAA,CAAM,MAAA,EAAQ,OAAO,CAAA;AACjD,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC7B,IAAA,OAAO,cAAc,MAAM,CAAA;AAAA,EAC7B,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,eAAA,EAAkB,MAAM,MAAM,CAAA,oEAAA;AAAA,KAChC;AAAA,EACF;AACF;AAEO,SAAS,WAAW,MAAA,EAAyB;AAClD,EAAA,SAAA,CAAU,MAAM,IAAI,CAAA;AACpB,EAAGA,GAAA,CAAA,aAAA,CAAc,MAAM,MAAA,EAAQ,IAAA,CAAK,UAAU,MAAA,EAAQ,IAAA,EAAM,CAAC,CAAA,GAAI,IAAA,EAAM;AAAA,IACrE,QAAA,EAAU,OAAA;AAAA,IACV,IAAA,EAAM;AAAA,GACP,CAAA;AACH;;;ACxCO,SAAS,YAAA,CAAa,MAAe,MAAA,EAA8B;AACxE,EAAA,IAAI,WAAW,MAAA,EAAQ;AACrB,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,IAAA,EAAM,aAAA,EAAe,CAAC,CAAA;AAAA,EAC9C;AACA,EAAA,OAAO,YAAY,IAAI,CAAA;AACzB;AAEA,SAAS,aAAA,CAAc,MAAc,KAAA,EAAyB;AAC5D,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,MAAM,QAAA,EAAS;AAAA,EACxB;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,WAAA,CAAY,IAAA,EAAe,MAAA,GAAS,CAAA,EAAW;AACtD,EAAA,IAAI,IAAA,KAAS,IAAA,IAAQ,IAAA,KAAS,MAAA,EAAW;AACvC,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,IAAI,OAAO,IAAA,KAAS,QAAA,IAAY,OAAO,IAAA,KAAS,QAAA,IAAY,OAAO,IAAA,KAAS,SAAA,IAAa,OAAO,IAAA,KAAS,QAAA,EAAU;AACjH,IAAA,OAAO,OAAO,IAAI,CAAA;AAAA,EACpB;AAEA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,EAAG;AACvB,IAAA,IAAI,IAAA,CAAK,MAAA,KAAW,CAAA,EAAG,OAAO,SAAA;AAC9B,IAAA,OAAO,KAAK,GAAA,CAAI,CAAC,IAAA,EAAM,CAAA,KAAM,GAAG,CAAA,GAAI,CAAC,CAAA,EAAA,EAAK,WAAA,CAAY,MAAM,MAAA,GAAS,CAAC,CAAC,CAAA,CAAE,CAAA,CAAE,KAAK,IAAI,CAAA;AAAA,EACtF;AAEA,EAAA,IAAI,OAAO,SAAS,QAAA,EAAU;AAC5B,IAAA,MAAM,OAAA,GAAU,MAAA,CAAO,OAAA,CAAQ,IAA+B,CAAA;AAC9D,IAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,SAAA;AACjC,IAAA,MAAM,GAAA,GAAM,GAAA,CAAI,MAAA,CAAO,MAAM,CAAA;AAC7B,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,GAAG,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAC,CAAC,CAAA,KAAM,CAAA,CAAE,MAAM,CAAC,CAAA;AAC5D,IAAA,OAAO,QACJ,GAAA,CAAI,CAAC,CAAC,GAAA,EAAK,GAAG,CAAA,KAAM;AACnB,MAAA,MAAM,SAAA,GAAY,GAAA,CAAI,MAAA,CAAO,SAAS,CAAA;AACtC,MAAA,MAAM,MAAA,GAAS,OAAO,GAAA,KAAQ,QAAA,IAAY,GAAA,KAAQ,IAAA,GAAO,IAAA,GAAO,WAAA,CAAY,GAAA,EAAK,MAAA,GAAS,CAAC,CAAA,GAAI,OAAO,GAAG,CAAA;AACzG,MAAA,OAAO,CAAA,EAAG,GAAG,CAAA,EAAG,SAAS,KAAK,MAAM,CAAA,CAAA;AAAA,IACtC,CAAC,CAAA,CACA,IAAA,CAAK,IAAI,CAAA;AAAA,EACd;AAEA,EAAA,OAAO,OAAO,IAAI,CAAA;AACpB;;;ACxCO,IAAe,WAAA,GAAf,cAAmC,OAAA,CAAQ;AAAA,EAChD,OAAgB,SAAA,GAAY;AAAA,IAC1B,MAAA,EAAQ,MAAM,MAAA,CAAO;AAAA,MACnB,IAAA,EAAM,GAAA;AAAA,MACN,WAAA,EAAa,eAAA;AAAA,MACb,OAAA,EAAS,CAAC,MAAA,EAAQ,OAAO,CAAA;AAAA,MACzB,OAAA,EAAS,OAAA;AAAA,MACT,GAAA,EAAK;AAAA,KACN,CAAA;AAAA,IACD,KAAA,EAAO,MAAM,OAAA,CAAQ;AAAA,MACnB,IAAA,EAAM,GAAA;AAAA,MACN,WAAA,EAAa,UAAA;AAAA,MACb,GAAA,EAAK;AAAA,KACN,CAAA;AAAA,IACD,SAAA,EAAW,MAAM,MAAA,CAAO;AAAA,MACtB,WAAA,EAAa,aAAA;AAAA,MACb,GAAA,EAAK;AAAA,KACN,CAAA;AAAA,IACD,GAAA,EAAK,MAAM,OAAA,CAAQ;AAAA,MACjB,IAAA,EAAM,GAAA;AAAA,MACN,WAAA,EAAa,oCAAA;AAAA,MACb,OAAA,EAAS;AAAA,KACV,CAAA;AAAA,IACD,KAAA,EAAO,MAAM,OAAA,CAAQ;AAAA,MACnB,IAAA,EAAM,GAAA;AAAA,MACN,WAAA,EAAa,+BAAA;AAAA,MACb,OAAA,EAAS;AAAA,KACV;AAAA,GACH;AAAA,EAEU,cAAc,KAAA,EAAuC;AAC7D,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,SAAS,CAAA,IAAK,YAAW,CAAE,MAAA;AAChD,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,IAAA,CAAK,MAAM,wFAAwF,CAAA;AAAA,IACrG;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA,EAEU,eAAe,KAAA,EAAmC;AAC1D,IAAA,MAAM,OAAA,GAAU,KAAA,CAAM,KAAA,IAAS,UAAA,EAAW,CAAE,YAAA;AAC5C,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,IAAA,CAAK,MAAM,6FAA6F,CAAA;AAAA,IAC1G;AACA,IAAA,OAAO,OAAA;AAAA,EACT;AAAA,EAEU,YAAA,CAAa,MAAe,MAAA,EAA4B;AAChE,IAAA,MAAM,MAAA,GAAS,YAAA,CAAa,IAAA,EAAM,MAAM,CAAA;AACxC,IAAA,IAAA,CAAK,IAAI,MAAM,CAAA;AAAA,EACjB;AACF,CAAA;;;AC1CA,IAAM,MAAA,GAAS,WAAW,MAAA,CAAO,MAAA;AAIjC,eAAsB,eAAA,GAAqC;AACzD,EAAA,OAAO,MAAA,CAAO,WAAA,CAAY,EAAE,IAAA,EAAM,MAAA,EAAQ,UAAA,EAAY,OAAA,EAAQ,EAAG,IAAA,EAAM,CAAC,WAAW,CAAC,CAAA;AACtF;AAEA,eAAsB,kBAAA,CAAmB,YAAkB,aAAA,EAAoC;AAC7F,EAAA,OAAO,MAAA,CAAO,SAAA;AAAA,IACZ,EAAE,IAAA,EAAM,MAAA,EAAQ,MAAA,EAAQ,aAAA,EAAc;AAAA,IACtC,UAAA;AAAA,IACA,EAAE,IAAA,EAAM,SAAA,EAAW,MAAA,EAAQ,GAAA,EAAI;AAAA,IAC/B,KAAA;AAAA,IACA,CAAC,WAAW,SAAS;AAAA,GACvB;AACF;AASA,eAAsB,cAAA,CAAe,cAAoB,OAAA,EAA8D;AACrH,EAAA,MAAM,KAAK,UAAA,CAAW,MAAA,CAAO,gBAAgB,IAAI,UAAA,CAAW,EAAE,CAAC,CAAA;AAC/D,EAAA,MAAM,SAAA,GAAY,IAAI,WAAA,EAAY,CAAE,OAAO,IAAA,CAAK,SAAA,CAAU,OAAO,CAAC,CAAA;AAClE,EAAA,MAAM,SAAA,GAAY,MAAM,MAAA,CAAO,OAAA,CAAQ,EAAE,MAAM,SAAA,EAAW,EAAA,EAAG,EAAG,YAAA,EAAc,SAAS,CAAA;AACvF,EAAA,OAAO;AAAA,IACL,EAAA,EAAI,eAAe,EAAE,CAAA;AAAA,IACrB,UAAA,EAAY,cAAA,CAAe,IAAI,UAAA,CAAW,SAAS,CAAC;AAAA,GACtD;AACF;AAEA,eAAsB,cAAA,CACpB,cACA,QAAA,EACkC;AAClC,EAAA,MAAM,EAAA,GAAK,MAAA,CAAO,IAAA,CAAK,QAAA,CAAS,IAAI,QAAQ,CAAA;AAC5C,EAAA,MAAM,UAAA,GAAa,MAAA,CAAO,IAAA,CAAK,QAAA,CAAS,YAAY,QAAQ,CAAA;AAC5D,EAAA,MAAM,QAAA,GAAW,MAAM,MAAA,CAAO,OAAA,CAAQ,EAAE,MAAM,SAAA,EAAW,EAAA,EAAG,EAAG,YAAA,EAAc,UAAU,CAAA;AACvF,EAAA,OAAO,KAAK,KAAA,CAAM,IAAI,aAAY,CAAE,MAAA,CAAO,QAAQ,CAAC,CAAA;AACtD;AAIA,eAAsB,cAAA,CAAe,MAA4B,GAAA,EAA4B;AAC3F,EAAA,MAAM,MAAA,GAAS,IAAA,KAAS,SAAA,GAAY,OAAA,GAAU,MAAA;AAC9C,EAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,SAAA,CAAU,QAAQ,GAAG,CAAA;AAC9C,EAAA,OAAO,UAAA,CAAW,IAAI,UAAA,CAAW,GAAG,CAAC,CAAA;AACvC;AAEA,eAAsB,gBAAA,CAAiB,MAA4B,GAAA,EAA4B;AAC7F,EAAA,MAAM,MAAA,GAAS,IAAA,KAAS,SAAA,GAAY,OAAA,GAAU,MAAA;AAC9C,EAAA,OAAO,MAAA,CAAO,SAAA;AAAA,IACZ,MAAA;AAAA,IACA,MAAA,CAAO,IAAA,CAAK,UAAA,CAAW,GAAG,CAAC,CAAA;AAAA,IAC3B,EAAE,IAAA,EAAM,MAAA,EAAQ,UAAA,EAAY,OAAA,EAAQ;AAAA,IACpC,IAAA;AAAA,IACA,IAAA,KAAS,SAAA,GAAY,CAAC,WAAW,IAAI;AAAC,GACxC;AACF;AAIA,SAAS,WAAW,KAAA,EAA2B;AAC7C,EAAA,OAAO,MAAM,IAAA,CAAK,KAAK,CAAA,CACpB,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA,CAAS,EAAE,EAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAC1C,KAAK,EAAE,CAAA;AACZ;AAEA,SAAS,WAAW,GAAA,EAAyB;AAC3C,EAAA,IAAI,IAAI,MAAA,GAAS,CAAA,KAAM,GAAG,MAAM,IAAI,MAAM,yBAAyB,CAAA;AACnE,EAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,GAAA,CAAI,SAAS,CAAC,CAAA;AAC3C,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,MAAA,EAAQ,KAAK,CAAA,EAAG;AACtC,IAAA,KAAA,CAAM,CAAA,GAAI,CAAC,CAAA,GAAI,QAAA,CAAS,GAAA,CAAI,UAAU,CAAA,EAAG,CAAA,GAAI,CAAC,CAAA,EAAG,EAAE,CAAA;AAAA,EACrD;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,eAAe,GAAA,EAAyB;AAC/C,EAAA,OAAO,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA,CAAE,SAAS,QAAQ,CAAA;AAC3C;;;AC1CO,SAAS,iBAAiB,MAAA,EAAiD;AAChF,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,MAAA;AAAA,IACN,QAAQ,MAAA,CAAO,MAAA;AAAA,IACf,SAAS,MAAA,CAAO,OAAA;AAAA,IAChB,KAAK,MAAA,CAAO,GAAA;AAAA,IACZ,cAAc,MAAA,CAAO,YAAA;AAAA,IACrB,GAAI,MAAA,CAAO,YAAA,IAAgB,MAAA,CAAO,gBAAA,GAAmB,EAAE,gBAAA,EAAkB,MAAA,CAAO,gBAAA,EAAiB,GAAI;AAAC,GACxG;AACF;AAEA,IAAM,kBAAA,GAAqB,IAAA;AAS3B,IAAM,0BAAA,GAA6B,GAAA;AAUnC,IAAM,iBAAA,GAAoB,IAAI,IAAA,GAAO,IAAA;AAGrC,IAAM,0BAAA,GAA6B,GAAA;AAGnC,IAAM,sBAAA,GAAyB,CAAA;AAG/B,IAAM,uBAAA,GAA0B,GAAA;AAEzB,IAAM,WAAN,MAAe;AAAA,EACH,QAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,cAAA;AAAA,EACA,MAAA;AAAA,EACA,aAAA;AAAA,EACR,YAAA;AAAA,EACD,gBAAA;AAAA,EACA,YAAA,GAA4B,IAAA;AAAA,EAC5B,EAAA,GAAuB,IAAA;AAAA,EACvB,QAAA,GAAW,KAAA;AAAA;AAAA,EAGX,eAAA;AAAA,EACA,gBAAA;AAAA,EACA,mBAAA,GAAsB,CAAA;AAAA;AAAA,EAGtB,iBAAA,GAAoB,CAAA;AAAA;AAAA,EAG5B,IAAI,aAAA,GAA+B;AACjC,IAAA,OAAO,IAAA,CAAK,gBAAA;AAAA,EACd;AAAA,EAEA,YAAY,OAAA,EAA0B;AACpC,IAAA,IAAA,CAAK,WAAW,OAAA,CAAQ,QAAA;AACxB,IAAA,IAAA,CAAK,UAAU,OAAA,CAAQ,OAAA;AACvB,IAAA,IAAA,CAAK,OAAA,GAAU,QAAQ,OAAA,IAAW,kBAAA;AAClC,IAAA,IAAA,CAAK,cAAA,GAAiB,QAAQ,cAAA,IAAkB,0BAAA;AAChD,IAAA,IAAA,CAAK,SAAS,OAAA,CAAQ,MAAA;AACtB,IAAA,IAAA,CAAK,gBAAgB,OAAA,CAAQ,aAAA;AAC7B,IAAA,IAAA,CAAK,eAAe,OAAA,CAAQ,YAAA;AAC5B,IAAA,IAAA,CAAK,mBAAmB,OAAA,CAAQ,gBAAA;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAA,CACJ,eAAA,EACA,gBAAA,EACe;AAEf,IAAA,IAAA,CAAK,eAAA,GAAkB,eAAA;AACvB,IAAA,IAAA,CAAK,gBAAA,GAAmB,gBAAA;AAGxB,IAAA,IAAI,KAAK,gBAAA,EAAkB;AACzB,MAAA,MAAM,KAAK,YAAA,EAAa;AAAA,IAC1B;AAEA,IAAA,OAAO,IAAA,CAAK,eAAA,CAAgB,eAAA,EAAiB,gBAAgB,CAAA;AAAA,EAC/D;AAAA,EAEA,MAAc,eAAA,CACZ,eAAA,EACA,gBAAA,EACe;AACf,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,MAAM,GAAA,GAAM,GAAG,IAAA,CAAK,QAAQ,YAAY,kBAAA,CAAmB,IAAA,CAAK,OAAO,CAAC,CAAA,SAAA,CAAA;AACxE,MAAA,MAAM,EAAA,GAAK,IAAI,SAAA,CAAU,GAAG,CAAA;AAE5B,MAAA,IAAI,aAAA,GAAgB,KAAA;AACpB,MAAA,IAAI,QAAA,GAAW,KAAA;AACf,MAAA,IAAI,oBAAA,GAAuB,CAAC,IAAA,CAAK,gBAAA;AAEjC,MAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,QAAA,EAAA,CAAG,KAAA,EAAM;AACT,QAAA,MAAA;AAAA,UACE,IAAI,KAAA;AAAA,YACF,kCAAkC,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,cAAA,GAAiB,GAAI,CAAC,CAAA;AAAA,sEAAA;AAAA;AAE1E,SACF;AAAA,MACF,CAAA,EAAG,KAAK,cAAc,CAAA;AAEtB,MAAA,MAAM,oBAAoB,YAAY;AACpC,QAAA,IAAI,CAAC,KAAK,YAAA,EAAc;AACxB,QAAA,MAAM,QAAA,GAAW,MAAM,cAAA,CAAe,IAAA,CAAK,cAAc,gBAAA,CAAiB,IAAA,CAAK,MAAM,CAAC,CAAA;AACtF,QAAA,IAAA,CAAK,OAAA,CAAQ,EAAA,EAAI,IAAA,CAAK,SAAA,CAAU,EAAE,MAAM,WAAA,EAAa,GAAG,QAAA,EAAU,CAAC,CAAA;AAAA,MACrE,CAAA;AAEA,MAAA,MAAM,eAAe,MAAM;AACzB,QAAA,MAAM,UAAA,GAAa,WAAW,MAAM;AAClC,UAAA,EAAA,CAAG,KAAA,EAAM;AACT,UAAA,MAAA,CAAO,IAAI,KAAA,CAAM,2CAA2C,CAAC,CAAA;AAAA,QAC/D,GAAG,IAAM,CAAA;AAET,QAAA,MAAM,KAAA,GAAQ,OAAO,IAAA,KAAyB;AAC5C,UAAA,MAAM,GAAA,GAAM,UAAU,IAAI,CAAA;AAC1B,UAAA,IAAI,CAAC,GAAA,EAAK;AAEV,UAAA,IAAI,GAAA,CAAI,IAAA,KAAS,WAAA,IAAe,IAAA,CAAK,YAAA,EAAc;AACjD,YAAA,IAAI;AACF,cAAA,MAAM,KAAA,GAAQ,MAAM,cAAA,CAAe,IAAA,CAAK,cAAc,GAAmC,CAAA;AACzF,cAAA,IAAI,KAAA,CAAM,SAAS,OAAA,EAAS;AAC1B,gBAAA,YAAA,CAAa,UAAU,CAAA;AACvB,gBAAA,EAAA,CAAG,GAAA,CAAI,WAAW,KAAK,CAAA;AACvB,gBAAA,IAAA,CAAK,iBAAA,GAAoB,CAAA;AACzB,gBAAA,OAAA,EAAQ;AAAA,cACV;AAAA,YACF,CAAA,CAAA,MAAQ;AAAA,YAER;AAAA,UACF;AAAA,QACF,CAAA;AACA,QAAA,EAAA,CAAG,EAAA,CAAG,WAAW,KAAK,CAAA;AAAA,MACxB,CAAA;AAEA,MAAA,MAAM,iBAAiB,YAAY;AACjC,QAAA,IAAI,QAAA,EAAU;AACd,QAAA,QAAA,GAAW,IAAA;AACX,QAAA,YAAA,CAAa,KAAK,CAAA;AAElB,QAAA,YAAA,EAAa;AACb,QAAA,MAAM,iBAAA,EAAkB;AAAA,MAC1B,CAAA;AAEA,MAAA,EAAA,CAAG,EAAA,CAAG,QAAQ,MAAM;AAClB,QAAA,IAAA,CAAK,EAAA,GAAK,EAAA;AAAA,MACZ,CAAC,CAAA;AAED,MAAA,EAAA,CAAG,EAAA,CAAG,SAAA,EAAW,OAAO,IAAA,KAAS;AAC/B,QAAA,MAAM,GAAA,GAAM,UAAU,IAAI,CAAA;AAC1B,QAAA,IAAI,CAAC,GAAA,EAAK;AAEV,QAAA,IAAI,GAAA,CAAI,SAAS,QAAA,EAAU;AACzB,UAAA,IAAI,IAAI,gBAAA,EAAkB;AACxB,YAAA,IAAI,KAAK,YAAA,EAAc;AAErB,cAAA,MAAM,cAAA,EAAe;AAAA,YACvB,CAAA,MAAO;AAEL,cAAA,oBAAA,GAAuB,IAAA;AAAA,YACzB;AAAA,UACF,CAAA,MAAA,IAAW,CAAC,aAAA,IAAiB,eAAA,EAAiB;AAC5C,YAAA,aAAA,GAAgB,IAAA;AAChB,YAAA,oBAAA,GAAuB,IAAA;AACvB,YAAA,eAAA,EAAgB,CAAE,MAAM,MAAM;AAAA,YAE9B,CAAC,CAAA;AAAA,UACH,CAAA,MAAA,IAAW,CAAC,eAAA,EAAiB;AAM3B,YAAA,YAAA,CAAa,KAAK,CAAA;AAClB,YAAA,EAAA,CAAG,KAAA,EAAM;AACT,YAAA,MAAA,CAAO,IAAI,KAAA,CAAM,sDAAiD,CAAC,CAAA;AAAA,UACrE;AAAA,QACF,CAAA,MAAA,IAAW,GAAA,CAAI,IAAA,KAAS,mBAAA,EAAqB;AAC3C,UAAA,oBAAA,GAAuB,IAAA;AAAA,QAEzB,CAAA,MAAA,IAAW,GAAA,CAAI,IAAA,KAAS,sBAAA,EAAwB;AAE9C,UAAA,IAAA,CAAK,uBAAA,EAAwB;AAAA,QAC/B,CAAA,MAAA,IAAW,GAAA,CAAI,IAAA,KAAS,cAAA,IAAkB,oBAAA,EAAsB;AAC9D,UAAA,oBAAA,GAAuB,KAAA;AACvB,UAAA,MAAM,UAAU,GAAA,CAAI,SAAA;AACpB,UAAA,IAAA,CAAK,gBAAA,GAAmB,OAAA;AACxB,UAAA,MAAM,KAAK,YAAA,EAAa;AACxB,UAAA,gBAAA,GAAmB,OAAO,CAAA;AAC1B,UAAA,MAAM,cAAA,EAAe;AAAA,QACvB;AAAA,MACF,CAAC,CAAA;AAED,MAAA,EAAA,CAAG,EAAA,CAAG,OAAA,EAAS,CAAC,GAAA,KAAQ;AACtB,QAAA,YAAA,CAAa,KAAK,CAAA;AAClB,QAAA,MAAA,CAAO,GAAG,CAAA;AAAA,MACZ,CAAC,CAAA;AAED,MAAA,EAAA,CAAG,EAAA,CAAG,SAAS,MAAM;AACnB,QAAA,YAAA,CAAa,KAAK,CAAA;AAClB,QAAA,IAAI,CAAC,KAAK,QAAA,EAAU;AAClB,UAAA,IAAA,CAAK,qBAAA,EAAsB;AAAA,QAC7B;AAAA,MACF,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAA,CAAQ,MAAA,EAAgB,MAAA,EAAoC;AAChE,IAAA,MAAM,KAAK,IAAA,CAAK,EAAA;AAChB,IAAA,IAAI,CAAC,EAAA,IAAM,EAAA,CAAG,UAAA,KAAe,UAAU,IAAA,EAAM;AAC3C,MAAA,MAAM,IAAI,MAAM,wBAAwB,CAAA;AAAA,IAC1C;AACA,IAAA,IAAI,CAAC,KAAK,YAAA,EAAc;AACtB,MAAA,MAAM,IAAI,MAAM,oDAA+C,CAAA;AAAA,IACjE;AAEA,IAAA,MAAM,KAAY,MAAA,CAAA,UAAA,EAAW;AAE7B,IAAA,MAAM,QAAA,GAAW,MAAM,cAAA,CAAe,IAAA,CAAK,YAAA,EAAc;AAAA,MACvD,IAAA,EAAM,aAAA;AAAA,MACN,EAAA;AAAA,MACA,MAAA;AAAA,MACA;AAAA,KACD,CAAA;AAED,IAAA,MAAM,UAAA,GAAa,KAAK,SAAA,CAAU,EAAE,MAAM,WAAA,EAAa,GAAG,UAAU,CAAA;AACpE,IAAA,iBAAA,CAAkB,YAAY,MAAM,CAAA;AAEpC,IAAA,OAAO,IAAI,OAAA,CAAiB,CAAC,OAAA,EAAS,MAAA,KAAW;AAC/C,MAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,QAAA,MAAA;AAAA,UACE,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2B,IAAA,CAAK,OAAA,GAAU,GAAI,CAAA,8CAAA,CAAqD;AAAA,SAC/G;AACA,QAAA,IAAA,CAAK,KAAA,EAAM;AAAA,MACb,CAAA,EAAG,KAAK,OAAO,CAAA;AAEf,MAAA,MAAM,SAAA,GAAY,OAAO,IAAA,KAAyB;AAChD,QAAA,MAAM,GAAA,GAAM,UAAU,IAAI,CAAA;AAC1B,QAAA,IAAI,CAAC,GAAA,IAAO,GAAA,CAAI,SAAS,WAAA,IAAe,CAAC,KAAK,YAAA,EAAc;AAE5D,QAAA,IAAI;AACF,UAAA,MAAM,KAAA,GAAQ,MAAM,cAAA,CAAe,IAAA,CAAK,cAAc,GAAmC,CAAA;AACzF,UAAA,IAAI,KAAA,CAAM,IAAA,KAAS,cAAA,IAAkB,KAAA,CAAM,OAAO,EAAA,EAAI;AACpD,YAAA,YAAA,CAAa,KAAK,CAAA;AAClB,YAAA,EAAA,CAAG,GAAA,CAAI,WAAW,SAAS,CAAA;AAE3B,YAAA,IAAI,MAAM,OAAA,EAAS;AACjB,cAAA,OAAA,CAAQ,MAAM,IAAI,CAAA;AAAA,YACpB,CAAA,MAAO;AACL,cAAA,MAAM,MAAM,KAAA,CAAM,KAAA;AAClB,cAAA,MAAA,CAAO,IAAI,KAAA,CAAM,GAAA,GAAM,CAAA,CAAA,EAAI,GAAA,CAAI,IAAI,CAAA,EAAA,EAAK,GAAA,CAAI,OAAO,CAAA,CAAA,GAAK,gBAAgB,CAAC,CAAA;AAAA,YAC3E;AAAA,UACF;AAAA,QACF,CAAA,CAAA,MAAQ;AAAA,QAER;AAAA,MACF,CAAA;AAEA,MAAA,EAAA,CAAG,EAAA,CAAG,WAAW,SAAS,CAAA;AAC1B,MAAA,IAAA,CAAK,OAAA,CAAQ,IAAI,UAAU,CAAA;AAAA,IAC7B,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,QAAA,GAA0B;AAC9B,IAAA,IAAA,CAAK,QAAA,GAAW,IAAA;AAChB,IAAA,IAAI,KAAK,EAAA,EAAI,UAAA,KAAe,SAAA,CAAU,IAAA,IAAQ,KAAK,YAAA,EAAc;AAC/D,MAAA,IAAI;AACF,QAAA,MAAM,QAAA,GAAW,MAAM,cAAA,CAAe,IAAA,CAAK,YAAA,EAAc;AAAA,UACvD,IAAA,EAAM;AAAA,SACP,CAAA;AACD,QAAA,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,EAAA,EAAI,IAAA,CAAK,SAAA,CAAU,EAAE,IAAA,EAAM,WAAA,EAAa,GAAG,QAAA,EAAU,CAAC,CAAA;AAAA,MAC1E,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AACA,IAAA,IAAA,CAAK,KAAA,EAAM;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,kBAAA,GAAoC;AACxC,IAAA,IAAI,CAAC,KAAK,gBAAA,EAAkB;AAE1B,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,QAAA,GAAW,IAAA;AAChB,IAAA,MAAM,KAAK,YAAA,EAAa;AAExB,IAAA,OAAO,IAAI,OAAA,CAAc,CAAC,OAAA,KAAY;AACpC,MAAA,MAAM,GAAA,GAAM,GAAG,IAAA,CAAK,QAAQ,YAAY,kBAAA,CAAmB,IAAA,CAAK,OAAO,CAAC,CAAA,SAAA,CAAA;AACxE,MAAA,MAAM,EAAA,GAAK,IAAI,SAAA,CAAU,GAAG,CAAA;AAE5B,MAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,QAAA,IAAI;AACF,UAAA,EAAA,CAAG,KAAA,EAAM;AAAA,QACX,CAAA,CAAA,MAAQ;AAAA,QAER;AACA,QAAA,OAAA,EAAQ;AAAA,MACV,GAAG,GAAI,CAAA;AAEP,MAAA,EAAA,CAAG,EAAA,CAAG,QAAQ,YAAY;AACxB,QAAA,IAAA,CAAK,EAAA,GAAK,EAAA;AACV,QAAA,IAAI;AACF,UAAA,MAAM,KAAK,QAAA,EAAS;AAAA,QACtB,CAAA,CAAA,MAAQ;AAAA,QAER;AACA,QAAA,YAAA,CAAa,KAAK,CAAA;AAClB,QAAA,OAAA,EAAQ;AAAA,MACV,CAAC,CAAA;AAED,MAAA,EAAA,CAAG,EAAA,CAAG,SAAS,MAAM;AACnB,QAAA,YAAA,CAAa,KAAK,CAAA;AAClB,QAAA,OAAA,EAAQ;AAAA,MACV,CAAC,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,QAAA,GAAW,IAAA;AAChB,IAAA,IAAI,KAAK,EAAA,EAAI;AACX,MAAA,IAAI;AACF,QAAA,IAAA,CAAK,GAAG,KAAA,EAAM;AAAA,MAChB,CAAA,CAAA,MAAQ;AAAA,MAER;AACA,MAAA,IAAA,CAAK,EAAA,GAAK,IAAA;AAAA,IACZ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,uBAAA,GAAgC;AACtC,IAAA,IAAI,IAAA,CAAK,QAAA,IAAY,CAAC,IAAA,CAAK,eAAA,EAAiB;AAE5C,IAAA,MAAM,GAAA,GAAM,KAAK,GAAA,EAAI;AACrB,IAAA,IAAI,GAAA,GAAM,IAAA,CAAK,mBAAA,GAAsB,0BAAA,EAA4B;AAC/D,MAAA;AAAA,IACF;AAEA,IAAA,IAAA,CAAK,mBAAA,GAAsB,GAAA;AAG3B,IAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AACpB,IAAA,IAAA,CAAK,gBAAA,GAAmB,IAAA;AAExB,IAAA,IAAA,CAAK,eAAA,EAAgB,CAAE,KAAA,CAAM,MAAM;AAAA,IAEnC,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,qBAAA,GAA8B;AACpC,IAAA,IAAI,KAAK,QAAA,EAAU;AACnB,IAAA,IAAI,IAAA,CAAK,qBAAqB,sBAAA,EAAwB;AAEtD,IAAA,MAAM,QAAQ,uBAAA,GAA0B,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,KAAK,iBAAiB,CAAA;AAC1E,IAAA,IAAA,CAAK,iBAAA,EAAA;AAEL,IAAA,UAAA,CAAW,MAAM;AACf,MAAA,IAAI,KAAK,QAAA,EAAU;AACnB,MAAA,IAAA,CAAK,gBAAgB,IAAA,CAAK,eAAA,EAAiB,KAAK,gBAAgB,CAAA,CAAE,MAAM,MAAM;AAAA,MAE9E,CAAC,CAAA;AAAA,IACH,GAAG,KAAK,CAAA;AAAA,EACV;AAAA;AAAA,EAGQ,OAAA,CAAQ,IAAe,IAAA,EAAoB;AACjD,IAAA,EAAA,CAAG,KAAK,IAAI,CAAA;AAAA,EACd;AAAA,EAEA,MAAc,YAAA,GAA8B;AAC1C,IAAA,IAAI,CAAC,KAAK,gBAAA,EAAkB;AAC5B,IAAA,MAAM,UAAA,GAAa,MAAM,gBAAA,CAAiB,SAAA,EAAW,KAAK,aAAa,CAAA;AACvE,IAAA,MAAM,aAAA,GAAgB,MAAM,gBAAA,CAAiB,QAAA,EAAU,KAAK,gBAAgB,CAAA;AAC5E,IAAA,IAAA,CAAK,YAAA,GAAe,MAAM,kBAAA,CAAmB,UAAA,EAAY,aAAa,CAAA;AAAA,EACxE;AACF,CAAA;AAMA,SAAS,iBAAA,CAAkB,YAAoB,MAAA,EAAsB;AACnE,EAAA,MAAM,UAAA,GAAa,MAAA,CAAO,UAAA,CAAW,UAAA,EAAY,OAAO,CAAA;AACxD,EAAA,IAAI,aAAa,iBAAA,EAAmB;AAClC,IAAA,MAAM,MAAA,GAAA,CAAU,UAAA,IAAc,IAAA,GAAO,IAAA,CAAA,EAAO,QAAQ,CAAC,CAAA;AACrD,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,eAAe,MAAM,CAAA,eAAA,EAAkB,MAAM,CAAA,WAAA,EAAc,iBAAA,IAAqB,OAAO,IAAA,CAAK,CAAA,qDAAA;AAAA,KAE9F;AAAA,EACF;AACF;AAEA,SAAS,UAAU,IAAA,EAAsD;AACvE,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,QAAA,EAAU,CAAA;AAAA,EACnC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;ACrdO,SAAS,gBAAA,GAAwC;AACtD,EAAA,IAAI;AACF,IAAA,IAAI,CAAIC,GAAA,CAAA,UAAA,CAAW,KAAA,CAAM,KAAK,GAAG,OAAO,IAAA;AACxC,IAAA,MAAM,GAAA,GAASA,GAAA,CAAA,YAAA,CAAa,KAAA,CAAM,KAAA,EAAO,OAAO,CAAA;AAChD,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAE7B,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,IAAW,CAAC,MAAA,CAAO,QAAA,IAAY,CAAC,MAAA,CAAO,UAAA,IAAc,CAAC,MAAA,CAAO,SAAA,EAAW;AAClF,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEO,SAAS,iBAAiB,IAAA,EAA0B;AACzD,EAAA,SAAA,CAAU,MAAM,IAAI,CAAA;AACpB,EAAGA,GAAA,CAAA,aAAA,CAAc,MAAM,KAAA,EAAO,IAAA,CAAK,UAAU,IAAA,EAAM,IAAA,EAAM,CAAC,CAAA,GAAI,IAAA,EAAM;AAAA,IAClE,QAAA,EAAU,OAAA;AAAA,IACV,IAAA,EAAM;AAAA,GACP,CAAA;AACH;AAEO,SAAS,kBAAA,GAA2B;AACzC,EAAA,IAAI;AACF,IAAA,IAAOA,eAAW,KAAA,CAAM,KAAK,GAAMA,GAAA,CAAA,UAAA,CAAW,MAAM,KAAK,CAAA;AAAA,EAC3D,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;;;AC7BA,IAAM,gBAAA,GAAmB,qBAAA;AACzB,IAAM,iBAAA,GAAoB,oBAAA;AAe1B,eAAsB,UAAU,OAAA,EAA2C;AACzE,EAAA,MAAM,SAAS,UAAA,EAAW;AAM1B,EAAA,MAAM,UAAA,GAAa,MAAA,CAAO,OAAA,CAAQ,GAAA,CAAI,uBAAuB,CAAC,CAAA;AAC9D,EAAA,MAAM,UAAU,MAAA,CAAO,QAAA,CAAS,UAAU,CAAA,IAAK,UAAA,GAAa,IAAI,UAAA,GAAa,MAAA;AAC7E,EAAA,MAAM,OAAA,GAAU,QAAQ,OAAA,IAAW,OAAA;AAKnC,EAAA,MAAM,cAAA,GAAiB,QAAQ,cAAA,IAAkB,OAAA;AACjD,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,IAAW,MAAA,CAAO,OAAA,IAAW,gBAAA;AACrD,EAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,QAAA,IAAY,MAAA,CAAO,QAAA,IAAY,iBAAA;AACxD,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,IAAW,MAAA,CAAO,YAAA,IAAgB,CAAA;AAC1D,EAAA,IAAI,CAAC,cAAA,CAAe,OAAO,CAAA,EAAG;AAC5B,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mBAAA,EAAsB,OAAO,CAAA,iDAAA,CAAmD,CAAA;AAAA,EAClG;AACA,EAAA,IAAI,CAAC,eAAA,CAAgB,QAAQ,CAAA,EAAG;AAC9B,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,oBAAA,EAAuB,QAAQ,CAAA,2CAAA,CAA6C,CAAA;AAAA,EAC9F;AAIA,EAAA,IAAI,eAAe,gBAAA,EAAiB;AACpC,EAAA,IAAI,YAAA,IAAgB,YAAA,CAAa,QAAA,KAAa,QAAA,IAAY,aAAa,aAAA,EAAe;AACpF,IAAA,IAAI;AAOF,MAAA,OAAO,MAAM,aAAA,CAAc,EAAE,GAAG,OAAA,EAAS,OAAA,EAAQ,EAAG,YAAA,EAAc,OAAA,EAAS,OAAA,EAAS,QAAA,EAAU,KAAK,CAAA;AAAA,IACrG,CAAA,CAAA,MAAQ;AAGN,MAAA,kBAAA,EAAmB;AACnB,MAAA,YAAA,GAAe,IAAA;AAAA,IACjB;AAAA,EACF,WAAW,YAAA,EAAc;AAEvB,IAAA,kBAAA,EAAmB;AAAA,EACrB;AAGA,EAAA,MAAM,OAAA,GAAU,MAAM,gBAAA,CAAiB,QAAQ,CAAA;AAC/C,EAAA,gBAAA,CAAiB,OAAO,CAAA;AACxB,EAAA,OAAO,MAAM,aAAA,CAAc,EAAE,GAAG,OAAA,EAAS,OAAA,EAAS,cAAA,EAAe,EAAG,OAAA,EAAS,OAAA,EAAS,OAAA,EAAS,QAAA,EAAU,IAAI,CAAA;AAC/G;AAEA,eAAe,iBAAiB,QAAA,EAAyC;AACvE,EAAA,MAAM,EAAA,GAAK,MAAM,eAAA,EAAgB;AACjC,EAAA,MAAM,UAAA,GAAa,MAAM,cAAA,CAAe,SAAA,EAAW,GAAG,UAAU,CAAA;AAChE,EAAA,MAAM,SAAA,GAAY,MAAM,cAAA,CAAe,QAAA,EAAU,GAAG,SAAS,CAAA;AAE7D,EAAA,OAAO;AAAA,IACL,SAAgBC,MAAA,CAAA,UAAA,EAAW;AAAA,IAC3B,QAAA;AAAA,IACA,UAAA;AAAA,IACA,SAAA;AAAA,IACA,aAAA,EAAe,IAAA;AAAA,IACf,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,GACpC;AACF;AAEA,eAAe,cACb,OAAA,EACA,YAAA,EACA,OAAA,EACA,OAAA,EACA,UACA,WAAA,EACmB;AACnB,EAAA,MAAM,SAAS,UAAA,EAAW;AAI1B,EAAA,MAAM,SAAA,GAAY,MAAA,CAAO,UAAA,GAAa,OAAO,CAAA;AAC7C,EAAA,MAAM,MAAA,GAAS,IAAI,QAAA,CAAS;AAAA,IAC1B,QAAA;AAAA,IACA,SAAS,YAAA,CAAa,OAAA;AAAA,IACtB,SAAS,OAAA,CAAQ,OAAA;AAAA,IACjB,gBAAgB,OAAA,CAAQ,cAAA;AAAA,IACxB,MAAA,EAAQ;AAAA,MACN,QAAQ,OAAA,CAAQ,MAAA;AAAA,MAChB,OAAA;AAAA,MACA,GAAA,EAAK,OAAA,CAAQ,GAAA,IAAO,MAAA,CAAO,GAAA;AAAA,MAC3B,cAAc,SAAA,EAAW,GAAA;AAAA,MACzB,kBAAkB,SAAA,EAAW;AAAA,KAC/B;AAAA,IACA,eAAe,YAAA,CAAa,UAAA;AAAA,IAC5B,cAAc,YAAA,CAAa,SAAA;AAAA,IAC3B,kBAAkB,YAAA,CAAa;AAAA,GAChC,CAAA;AAED,EAAA,MAAM,MAAA,CAAO,OAAA;AAAA;AAAA,IAEX,cACI,YAAY;AACV,MAAA,MAAM,YAAY,cAAA,CAAe,OAAA,EAAS,aAAa,OAAA,EAAS,QAAA,EAAU,aAAa,SAAS,CAAA;AAMhG,MAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,gBAAgB,CAAA,EAAG;AACjC,QAAA,OAAA,CAAQ,OAAO,KAAA,CAAM,CAAA;AAAA,EAA8B,SAAS;AAAA,CAAI,CAAA;AAChE,QAAA;AAAA,MACF;AACA,MAAA,MAAM,EAAE,OAAA,EAAS,IAAA,EAAK,GAAI,MAAM,OAAO,MAAM,CAAA;AAC7C,MAAA,MAAM,KAAK,SAAS,CAAA;AAAA,IACtB,CAAA,GACA,MAAA;AAAA;AAAA,IAEJ,CAAC,UAAA,KAAe;AACd,MAAA,YAAA,CAAa,aAAA,GAAgB,UAAA;AAC7B,MAAA,gBAAA,CAAiB,YAAY,CAAA;AAAA,IAC/B;AAAA,GACF;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,cAAA,CAAe,OAAA,EAAiB,OAAA,EAAiB,QAAA,EAAkB,eAAA,EAAiC;AAC3G,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,aAAA,EAAe,OAAO,CAAA;AAC1C,EAAA,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,SAAA,EAAW,OAAO,CAAA;AACvC,EAAA,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,OAAA,EAAS,QAAQ,CAAA;AAEtC,EAAA,GAAA,CAAI,IAAA,GAAO,MAAM,eAAe,CAAA,CAAA;AAChC,EAAA,OAAO,IAAI,QAAA,EAAS;AACtB;ACzJO,SAAS,kBAAA,GAAoC;AAClD,EAAA,MAAM,KAAA,GAAeC,mBAAY,EAAE,CAAA;AACnC,EAAA,OAAO,CAAA,EAAA,EAAK,KAAA,CAAM,QAAA,CAAS,KAAK,CAAC,CAAA,CAAA;AACnC;AAOO,SAAS,YAAA,CAAa,eAAuB,OAAA,EAAuB;AACzE,EAAA,MAAM,QAAA,GAAyB;AAAA,IAC7B,OAAA,EAAS,CAAA;AAAA,IACT,UAAA,EAAY,aAAA;AAAA,IACZ,OAAA;AAAA,IACA,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,GACpC;AAEA,EAAA,SAAA,CAAU,MAAM,IAAI,CAAA;AACpB,EAAG,GAAA,CAAA,aAAA,CAAc,MAAM,QAAA,EAAU,IAAA,CAAK,UAAU,QAAA,EAAU,IAAA,EAAM,CAAC,CAAA,GAAI,IAAA,EAAM;AAAA,IACzE,QAAA,EAAU,OAAA;AAAA,IACV,IAAA,EAAM;AAAA,GACP,CAAA;AAED,EAAG,GAAA,CAAA,SAAA,CAAU,KAAA,CAAM,QAAA,EAAU,GAAK,CAAA;AACpC;AAKO,SAAS,cAAA,GAAyB;AACvC,EAAA,IAAI,CAAI,GAAA,CAAA,UAAA,CAAW,KAAA,CAAM,QAAQ,CAAA,EAAG;AAClC,IAAA,MAAM,IAAI,MAAM,uDAAuD,CAAA;AAAA,EACzE;AAEA,EAAA,MAAM,QAAA,GAAc,GAAA,CAAA,YAAA,CAAa,KAAA,CAAM,QAAA,EAAU,OAAO,CAAA;AACxD,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,IAAA,CAAK,MAAM,QAAQ,CAAA;AAAA,EAC9B,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,YAAA,EAAe,KAAA,CAAM,QAAQ,CAAA,wDAAA,CAA0D,CAAA;AAAA,EACzG;AACA,EAAA,OAAO,MAAA,CAAO,UAAA;AAChB;AAOO,SAAS,sBAAA,GAAwC;AACtD,EAAA,IAAI;AACF,IAAA,IAAI,CAAI,GAAA,CAAA,UAAA,CAAW,KAAA,CAAM,QAAQ,GAAG,OAAO,IAAA;AAC3C,IAAA,MAAM,SAAS,IAAA,CAAK,KAAA,CAAS,iBAAa,KAAA,CAAM,QAAA,EAAU,OAAO,CAAC,CAAA;AAClE,IAAA,OAAO,OAAO,OAAA,IAAW,IAAA;AAAA,EAC3B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAcO,SAAS,cAAA,GAA0B;AACxC,EAAA,OAAU,GAAA,CAAA,UAAA,CAAW,MAAM,QAAQ,CAAA;AACrC;ACtCA,IAAMC,WAAAA,GAAa,qBAAA;AACnB,IAAMC,YAAAA,GAAc,oBAAA;AACpB,IAAM,MAAA,GAAS,kBAAA;AAEf,IAAMC,aAAAA,GAAe,2BAAA;AAErB,IAAM,WAAA,mBAAc,IAAI,GAAA,CAAI,CAAC,QAAA,EAAU,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAQ,OAAA,EAAS,MAAA,EAAQ,SAAS,CAAC,CAAA;AAEzF,SAAS,cAAc,KAAA,EAAiC;AACtD,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,OAAO,SAAA,CAAU,KAAK,KAAK,KAAA,GAAQ,CAAA;AACzE;AAgBO,SAAS,uBAAuB,GAAA,EAA6C;AAClF,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,IAAY,GAAA,KAAQ,MAAM,OAAO,MAAA;AACpD,EAAA,MAAM,CAAA,GAAI,GAAA;AAEV,EAAA,MAAM,EAAE,OAAA,EAAS,OAAA,EAAS,IAAA,EAAK,GAAI,CAAA;AACnC,EAAA,IAAI,OAAO,YAAY,QAAA,IAAY,CAACF,YAAW,IAAA,CAAK,OAAO,GAAG,OAAO,MAAA;AACrE,EAAA,IAAI,OAAO,YAAY,QAAA,IAAY,CAACA,YAAW,IAAA,CAAK,OAAO,GAAG,OAAO,MAAA;AACrE,EAAA,IAAI,OAAO,SAAS,QAAA,IAAY,CAAC,OAAO,IAAA,CAAK,IAAI,GAAG,OAAO,MAAA;AAC3D,EAAA,IAAI,CAAC,aAAA,CAAc,CAAA,CAAE,KAAK,CAAA,IAAK,CAAC,aAAA,CAAc,CAAA,CAAE,GAAG,CAAA,EAAG,OAAO,MAAA;AAE7D,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,CAAA,CAAE,KAAK,KAAK,CAAA,CAAE,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,MAAA;AAC5D,EAAA,MAAM,QAAoC,EAAC;AAC3C,EAAA,KAAA,MAAW,KAAA,IAAS,EAAE,KAAA,EAAO;AAC3B,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,MAAM,OAAO,MAAA;AACxD,IAAA,MAAM,EAAE,MAAA,EAAQ,QAAA,EAAS,GAAI,KAAA;AAC7B,IAAA,IAAI,OAAO,WAAW,QAAA,IAAY,CAACA,YAAW,IAAA,CAAK,MAAM,GAAG,OAAO,MAAA;AAGnE,IAAA,IAAI,OAAO,aAAa,QAAA,IAAY,CAACC,aAAY,IAAA,CAAK,QAAQ,GAAG,OAAO,MAAA;AACxE,IAAA,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,QAAA,EAAU,CAAA;AAAA,EACjC;AAEA,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,CAAA,CAAE,MAAM,GAAG,OAAO,MAAA;AACrC,EAAA,MAAM,SAAsC,EAAC;AAC7C,EAAA,KAAA,MAAW,KAAA,IAAS,EAAE,MAAA,EAAQ;AAC5B,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,MAAM,OAAO,MAAA;AACxD,IAAA,MAAM,EAAE,KAAA,EAAO,SAAA,EAAW,IAAA,EAAM,YAAW,GAAI,KAAA;AAC/C,IAAA,IAAI,OAAO,UAAU,QAAA,IAAY,CAACD,YAAW,IAAA,CAAK,KAAK,GAAG,OAAO,MAAA;AACjE,IAAA,IAAI,OAAO,cAAc,QAAA,IAAY,CAACE,cAAa,IAAA,CAAK,SAAS,GAAG,OAAO,MAAA;AAC3E,IAAA,IAAI,OAAO,SAAS,QAAA,IAAY,CAAC,YAAY,GAAA,CAAI,IAAI,GAAG,OAAO,MAAA;AAI/D,IAAA,IAAI,CAAC,aAAA,CAAc,UAAU,CAAA,IAAK,UAAA,GAAa,OAAO,OAAO,MAAA;AAC7D,IAAA,MAAA,CAAO,KAAK,EAAE,KAAA,EAAO,SAAA,EAAW,IAAA,EAAM,YAAY,CAAA;AAAA,EACpD;AAEA,EAAA,OAAO,EAAE,OAAA,EAAS,OAAA,EAAS,KAAA,EAAO,CAAA,CAAE,KAAA,EAAO,GAAA,EAAK,CAAA,CAAE,GAAA,EAAK,IAAA,EAAM,KAAA,EAAO,MAAA,EAAO;AAC7E;AAuEO,SAAS,YACd,OAAA,EACA,GAAA,GAAc,IAAA,CAAK,GAAA,KAAQ,GAAA,EACL;AACtB,EAAA,OAAA,CAAQ,OAAA,IAAW,EAAC,EAAG,MAAA,CAAO,CAAC,MAAA,KAAW,MAAA,CAAO,SAAS,GAAG,CAAA;AAC/D;AASO,SAAS,kBACd,KAAA,EAWM;AACN,EAAA,kBAAA,CAAmB,EAAE,GAAG,KAAA,EAAO,SAAA,EAAW,KAAA,CAAM,SAAA,IAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY,EAAG,CAAA;AACzF;AAYA,SAAS,mBAAmB,MAAA,EAA6B;AACvD,EAAA,SAAA,CAAU,MAAM,IAAI,CAAA;AACpB,EAAA,MAAM,OAAO,CAAA,EAAG,KAAA,CAAM,aAAa,CAAA,CAAA,EAAI,QAAQ,GAAG,CAAA,IAAA,CAAA;AAClD,EAAGC,GAAA,CAAA,aAAA,CAAc,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,QAAQ,IAAA,EAAM,CAAC,CAAA,GAAI,IAAA,EAAM,EAAE,QAAA,EAAU,OAAA,EAAS,IAAA,EAAM,KAAO,CAAA;AACjG,EAAGA,GAAA,CAAA,SAAA,CAAU,MAAM,GAAK,CAAA;AACxB,EAAGA,GAAA,CAAA,UAAA,CAAW,IAAA,EAAM,KAAA,CAAM,aAAa,CAAA;AACzC;AAiEO,SAAS,iBAAA,GAAmC;AACjD,EAAA,IAAI,CAAIA,GAAA,CAAA,UAAA,CAAW,KAAA,CAAM,aAAa,CAAA,EAAG;AACvC,IAAA,MAAM,IAAI,MAAM,uDAAuD,CAAA;AAAA,EACzE;AACA,EAAA,MAAM,GAAA,GAASA,GAAA,CAAA,YAAA,CAAa,KAAA,CAAM,aAAA,EAAe,OAAO,CAAA;AACxD,EAAA,IAAI;AACF,IAAA,OAAO,IAAA,CAAK,MAAM,GAAG,CAAA;AAAA,EACvB,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,kBAAA,EAAqB,KAAA,CAAM,aAAa,CAAA,wDAAA,CAA0D,CAAA;AAAA,EACpH;AACF;AAQO,SAAS,oBAAA,GAA6C;AAC3D,EAAA,IAAI;AACF,IAAA,OAAO,iBAAA,EAAkB;AAAA,EAC3B,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;;;AC1SO,IAAM,eAAA,GAA6C;AAAA,EACxD,aAAA,EAAe;AAAA,IACb,OAAA,EAAS,4CAAA;AAAA,IACT,OAAA,EAAS,IAAA;AAAA,IACT,WAAA,EAAa,aAAA;AAAA,IACb,QAAA,EAAU,UAAA;AAAA,IACV,WAAA,EAAa,GAAA;AAAA,IACb,QAAA,EAAU;AAAA,GACZ;AAAA,EACA,cAAA,EAAgB;AAAA,IACd,OAAA,EAAS,4CAAA;AAAA,IACT,OAAA,EAAS,KAAA;AAAA,IACT,WAAA,EAAa,cAAA;AAAA,IACb,QAAA,EAAU,MAAA;AAAA,IACV,WAAA,EAAa,GAAA;AAAA,IACb,QAAA,EAAU;AAAA,GACZ;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,OAAA,EAAS,4CAAA;AAAA,IACT,OAAA,EAAS,GAAA;AAAA,IACT,WAAA,EAAa,YAAA;AAAA,IACb,QAAA,EAAU,UAAA;AAAA,IACV,WAAA,EAAa,GAAA;AAAA,IACb,QAAA,EAAU;AAAA,GACZ;AAAA,EACA,cAAA,EAAgB;AAAA,IACd,OAAA,EAAS,4CAAA;AAAA,IACT,OAAA,EAAS,KAAA;AAAA,IACT,WAAA,EAAa,cAAA;AAAA,IACb,QAAA,EAAU,MAAA;AAAA,IACV,WAAA,EAAa,GAAA;AAAA,IACb,QAAA,EAAU;AAAA;AAEd,CAAA;AAUO,SAAS,eAAe,OAAA,EAAwC;AACrE,EAAA,OAAO,OAAO,MAAA,CAAO,eAAA,EAAiB,OAAO,CAAA,GAAI,eAAA,CAAgB,OAAO,CAAA,GAAI,MAAA;AAC9E;;;ACpDA,IAAM,kBAAA,GAAqB,2BAAA;AAG3B,IAAM,aAAA,GAAgB,MAAM,IAAA,GAAO,EAAA;AAG5B,IAAM,aAAA,GAAgB,CAAC,QAAA,EAAU,MAAA,EAAQ,OAAO,MAAA,EAAQ,OAAA,EAAS,QAAQ,SAAS,CAAA;AAIlF,IAAM,kBAAA,GAAqB,QAAA;AAa3B,SAAS,WAAW,KAAA,EAA4B;AACrD,EAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,EAAA,IAAI,CAAC,OAAA,EAAS,MAAM,IAAI,MAAM,oEAAoE,CAAA;AAElG,EAAA,MAAM,CAAC,WAAW,SAAA,GAAY,KAAA,EAAO,GAAG,IAAI,CAAA,GAAI,OAAA,CAAQ,KAAA,CAAM,GAAG,CAAA;AACjE,EAAA,IAAI,IAAA,CAAK,SAAS,CAAA,EAAG;AACnB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkB,KAAK,CAAA,kDAAA,CAAoD,CAAA;AAAA,EAC7F;AAEA,EAAA,MAAM,MAAA,GAAS,UAAU,IAAA,EAAK;AAG9B,EAAA,IAAI,CAAC,eAAA,CAAgB,IAAA,CAAK,MAAM,CAAA,EAAG;AACjC,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,sBAAA,EAAyB,SAAS,CAAA,qDAAA,CAAuD,CAAA;AAAA,EAC3G;AAEA,EAAA,MAAM,MAAA,GAAS,SAAA,CAAU,IAAA,EAAK,CAAE,WAAA,EAAY;AAC5C,EAAA,IAAI,CAAE,aAAA,CAAoC,QAAA,CAAS,MAAM,CAAA,EAAG;AAC1D,IAAA,MAAM,IAAI,MAAM,CAAA,sBAAA,EAAyB,SAAS,uBAAuB,aAAA,CAAc,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAG,CAAA;AAAA,EACtG;AAEA,EAAA,OAAO,EAAE,QAAQ,MAAA,EAAO;AAC1B;AAOO,SAAS,oBAAA,CAAqB,OAAA,EAAiB,KAAA,GAAgB,kBAAA,EAAuC;AAC3G,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,MAAA,CAAO,eAAe,CAAA,CAAE,KAAK,CAAC,KAAA,KAAU,KAAA,CAAM,OAAA,KAAY,OAAO,CAAA;AACrF,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,MAAM,YAAY,MAAA,CAAO,MAAA,CAAO,eAAe,CAAA,CAC5C,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,CAAA,CACpB,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,IAAI,CAAC,CAAA,CACpB,KAAK,IAAI,CAAA;AACZ,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,6BAAA,EAAgC,OAAO,CAAA,kCAAA,EAAqC,SAAS,CAAA,CAAA,CAAG,CAAA;AAAA,EAC1G;AAEA,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,WAAW,KAAK,CAAA;AAC3C,EAAA,IAAI,SAAA;AACJ,EAAA,IAAI;AACF,IAAA,SAAA,GAAY,UAAA,CAAW,MAAA,EAAQ,IAAA,CAAK,QAAQ,CAAA;AAAA,EAC9C,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,sBAAA,EAAyB,MAAM,CAAA,mBAAA,EAAsB,IAAA,CAAK,QAAQ,CAAA,UAAA,CAAY,CAAA;AAAA,EAChG;AACA,EAAA,IAAI,aAAa,EAAA,EAAI;AACnB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,OAAA,EAAU,KAAK,CAAA,qDAAA,CAAuD,CAAA;AAAA,EACxF;AAIA,EAAA,IAAI,YAAY,aAAA,EAAe;AAC7B,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,OAAA,EAAU,KAAK,CAAA,iDAAA,EAAoD,aAAa,CAAA,EAAA,CAAI,CAAA;AAAA,EACtG;AAEA,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,CAAC,EAAE,MAAA,EAAQ,KAAK,OAAA,EAAS,iBAAA,EAAmB,oBAAoB,CAAA;AAAA,IACvE,MAAA,EAAQ,CAAC,EAAE,KAAA,EAAO,KAAK,OAAA,EAAS,SAAA,EAAW,SAAA,CAAU,QAAA,EAAS,EAAG,IAAA,EAAM,MAAA,EAAQ,UAAA,EAAY,GAAG;AAAA,GAChG;AACF;AAGO,SAAS,iBAAA,CAAkB,QAAgB,kBAAA,EAA4B;AAC5E,EAAA,MAAM,EAAE,MAAA,EAAQ,MAAA,EAAO,GAAI,WAAW,KAAK,CAAA;AAC3C,EAAA,MAAM,GAAA,GAAM,MAAA,KAAW,SAAA,GAAY,UAAA,GAAa,OAAO,MAAM,CAAA,CAAA;AAC7D,EAAA,OAAO,CAAA,EAAG,MAAM,CAAA,MAAA,EAAS,GAAG,CAAA,gBAAA,CAAA;AAC9B;AClGA,IAAM,WAAA,GAAc,uCAAA;AAEpB,IAAM,MAAA,GAAgC;AAAA,EACpC,CAAC,IAAA,CAAK,EAAE,GAAG,IAAA;AAAA,EACX,CAAC,WAAA,CAAY,EAAE,GAAG,WAAA;AAAA,EAClB,CAAC,OAAA,CAAQ,EAAE,GAAG,OAAA;AAAA,EACd,CAAC,WAAA,CAAY,EAAE,GAAG;AACpB,CAAA;AAMA,KAAA,MAAW,OAAA,IAAW,MAAA,CAAO,MAAA,CAAO,eAAe,CAAA,CAAE,IAAI,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,CAAA,EAAG;AAC1E,EAAA,IAAI,CAAC,MAAA,CAAO,OAAO,CAAA,EAAG;AACpB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,yCAAyC,OAAO,CAAA,iDAAA;AAAA,KAClD;AAAA,EACF;AACF;AAQA,IAAM,OAAA,uBAAc,GAAA,EAA0B;AAS9C,SAAS,YAAA,CAAa,SAAiB,MAAA,EAAiB;AACtD,EAAA,IAAI,CAAC,MAAA,EAAQ,OAAO,IAAA,EAAK;AACzB,EAAA,OAAO,KAAK,CAAA,EAAG,WAAW,YAAY,OAAO,CAAA,SAAA,EAAY,MAAM,CAAA,CAAE,CAAA;AACnE;AAGO,SAAS,gBAAgB,OAAA,EAA+B;AAC7D,EAAA,MAAM,KAAA,GAAQ,OAAO,OAAO,CAAA;AAC5B,EAAA,IAAI,CAAC,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,CAAA,2CAAA,EAA8C,OAAO,CAAA,CAAE,CAAA;AACnF,EAAA,MAAM,MAAA,GAAS,YAAW,CAAE,MAAA;AAC5B,EAAA,MAAM,GAAA,GAAM,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,UAAU,EAAE,CAAA,CAAA;AACtC,EAAA,IAAI,MAAA,GAAS,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA;AAC5B,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAA,GAAS,kBAAA,CAAmB,EAAE,KAAA,EAAO,SAAA,EAAW,aAAa,OAAA,EAAS,MAAM,GAAG,CAAA;AAC/E,IAAA,OAAA,CAAQ,GAAA,CAAI,KAAK,MAAM,CAAA;AAAA,EACzB;AACA,EAAA,OAAO,MAAA;AACT;AAKA,IAAM,WAAA,GAA6B,CAAC,KAAA,EAAO,KAAA,KACzC,gBAAgB,KAAA,CAAM,OAAO,EAAE,YAAA,CAAa;AAAA,EAC1C,SAAS,KAAA,CAAM,OAAA;AAAA,EACf,GAAA,EAAK,QAAA;AAAA,EACL,YAAA,EAAc,WAAA;AAAA,EACd,IAAA,EAAM,CAAC,KAAK;AACd,CAAC,CAAA;AAeH,eAAsB,WAAA,CACpB,OAAA,EACA,KAAA,EACA,IAAA,GAAsB,WAAA,EACA;AACtB,EAAA,MAAM,KAAA,GAAQ,eAAe,OAAO,CAAA;AACpC,EAAA,IAAI,CAAC,KAAA,EAAO,MAAM,IAAI,KAAA,CAAM,CAAA,0BAAA,EAA6B,OAAO,CAAA,CAAE,CAAA;AAClE,EAAA,MAAM,GAAA,GAAM,MAAM,IAAA,CAAK,KAAA,EAAO,KAAK,CAAA;AACnC,EAAA,OAAO,EAAE,OAAA,EAAS,KAAA,EAAO,KAAA,CAAM,SAAS,GAAA,EAAK,GAAA,CAAI,QAAA,EAAS,EAAG,SAAA,EAAW,WAAA,CAAY,GAAA,EAAK,KAAA,CAAM,QAAQ,CAAA,EAAE;AAC3G;;;ACrEO,SAAS,WAAW,KAAA,EAA0B;AACnD,EAAA,OAAO,GAAA,IAAO,MAAA,CAAO,KAAA,CAAM,QAAQ,CAAA,GAAI,GAAA;AACzC;AAWO,SAAS,mBAAmB,KAAA,EAA0B;AAC3D,EAAA,OAAO,GAAA,IAAO,MAAA,CAAO,KAAA,CAAM,QAAQ,CAAA,GAAI,IAAA;AACzC;;;ACnCO,SAAS,YAAY,KAAA,EAAiD;AAG3E,EAAA,IAAI,UAAU,MAAA,IAAa,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,IAAI,OAAO,IAAA;AAClE,EAAA,IAAI;AACF,IAAA,OAAO,OAAO,KAAK,CAAA;AAAA,EACrB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;;;ACUA,IAAM,kBAAA,GAAqB,8DAAA;AAQ3B,IAAM,aAAA,GAAgB,+BAAA;AAGtB,IAAM,WAAA,GAAc,QAAA;AAEb,IAAM,mBAAA,GAAsB,GAAA;AAEnC,SAAS,KAAA,CAAM,MAAc,SAAA,EAA2B;AACtD,EAAA,IAAI,IAAA,CAAK,MAAA,IAAU,SAAA,EAAW,OAAO,IAAA;AAErC,EAAA,OAAO,CAAA,EAAG,KAAK,KAAA,CAAM,CAAA,EAAG,SAAS,CAAC,CAAA,QAAA,EAAW,IAAA,CAAK,MAAA,GAAS,SAAS,CAAA,iBAAA,CAAA;AACtE;AAUO,SAAS,YAAA,CAAa,KAAA,EAAgB,SAAA,GAAoB,mBAAA,EAA6B;AAC5F,EAAA,MAAM,OAAO,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,GAAQ,OAAO,KAAK,CAAA;AAC7D,EAAA,OAAO,KAAA,CAAM,IAAA,CAAK,OAAA,CAAQ,aAAA,EAAe,WAAW,EAAE,OAAA,CAAQ,kBAAA,EAAoB,WAAW,CAAA,EAAG,SAAS,CAAA;AAC3G;;;AChDO,SAAS,UAAA,CAAWC,OAA0B,QAAA,EAA0B;AAC7E,EAAA,IAAIA,KAAAA,KAAS,QAAW,OAAO,WAAA;AAC/B,EAAA,MAAM,KAAA,GAAQ,YAAYA,KAAI,CAAA;AAG9B,EAAA,IAAI,UAAU,IAAA,EAAM,OAAO,GAAG,YAAA,CAAaA,KAAAA,EAAM,EAAE,CAAC,CAAA,UAAA,CAAA;AACpD,EAAA,MAAM,KAAA,GAAQ,GAAA,IAAO,MAAA,CAAO,QAAQ,CAAA;AACpC,EAAA,MAAM,QAAQ,KAAA,GAAQ,KAAA;AACtB,EAAA,MAAM,IAAA,GAAA,CAAQ,KAAA,GAAQ,KAAA,EAAO,QAAA,EAAS,CAAE,QAAA,CAAS,QAAA,EAAU,GAAG,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AACjF,EAAA,OAAO,GAAG,KAAK,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,IAAI,KAAK,EAAE,CAAA,KAAA,CAAA;AAC1C;;;ACKA,eAAsB,0BAA0B,KAAA,EAAkD;AAChG,EAAA,MAAM,KAAA,GAAQ,cAAA,CAAe,CAAA,OAAA,EAAU,KAAA,CAAM,OAAO,CAAA,CAAE,CAAA;AAGtD,EAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AAEnB,EAAA,MAAM,QAAA,GAAY,MAAM,KAAA,CAAM,OAAA,CAAQ,qBAAqB,CAAA;AAC3D,EAAA,MAAM,KAAA,GAAQ,WAAW,CAAC,CAAA;AAC1B,EAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AAEnB,EAAA,MAAM,IAAA,GACJ,KAAA,CAAM,WAAA,KACL,OAAO,OAAA,EAAiB,OAAA,KAA2B,MAAA,CAAA,CAAQ,MAAM,WAAA,CAAY,OAAA,EAAS,OAAO,CAAA,EAAG,GAAG,CAAA,CAAA;AAEtG,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI;AACF,IAAA,IAAA,GAAO,MAAM,IAAA,CAAK,KAAA,CAAM,WAAA,EAAa,KAAsB,CAAA;AAAA,EAC7D,CAAA,CAAA,MAAQ;AAMN,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,MAAA,GAAS,WAAW,KAAK,CAAA;AAC/B,EAAA,IAAI,IAAA,IAAQ,QAAQ,OAAO,IAAA;AAE3B,EAAA,OACE,CAAA,EAAG,KAAK,CAAA,OAAA,EAAU,UAAA,CAAW,KAAK,QAAA,EAAS,EAAG,MAAM,QAAQ,CAAC,aAAa,KAAA,CAAM,OAAO,6CAC7D,UAAA,CAAW,MAAA,CAAO,UAAS,EAAG,KAAA,CAAM,QAAQ,CAAC,CAAA,qIAAA,CAAA;AAG3E;AAuCA,eAAsB,oBAAoB,KAAA,EAAoD;AAC5F,EAAA,MAAM,KAAA,GAAQ,cAAA,CAAe,CAAA,OAAA,EAAU,KAAA,CAAM,OAAO,CAAA,CAAE,CAAA;AAGtD,EAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AAEnB,EAAA,MAAM,IAAA,GACJ,KAAA,CAAM,WAAA,KACL,OAAO,OAAA,EAAiB,OAAA,KAA2B,MAAA,CAAA,CAAQ,MAAM,WAAA,CAAY,OAAA,EAAS,OAAO,CAAA,EAAG,GAAG,CAAA,CAAA;AAEtG,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAe,CAAC,GAAG,MAAA,KAAW;AAChD,MAAA,KAAA,GAAQ,UAAA,CAAW,MAAM,MAAA,CAAO,IAAI,KAAA,CAAM,WAAW,CAAC,CAAA,EAAG,KAAA,CAAM,SAAA,IAAa,GAAK,CAAA;AAAA,IACnF,CAAC,CAAA;AACD,IAAA,IAAA,GAAO,MAAM,OAAA,CAAQ,IAAA,CAAK,CAAC,IAAA,CAAK,KAAA,CAAM,WAAA,EAAa,KAAA,CAAM,OAAO,CAAA,EAAG,OAAO,CAAC,CAAA;AAAA,EAC7E,CAAA,CAAA,MAAQ;AAGN,IAAA,OAAO,IAAA;AAAA,EACT,CAAA,SAAE;AACA,IAAA,YAAA,CAAa,KAAK,CAAA;AAAA,EACpB;AAKA,EAAA,MAAM,MAAA,GAAS,mBAAmB,KAAK,CAAA;AACvC,EAAA,IAAI,IAAA,IAAQ,QAAQ,OAAO,IAAA;AAE3B,EAAA,OACE,CAAA,EAAG,MAAM,OAAO,CAAA,OAAA,EAAU,WAAW,IAAA,CAAK,QAAA,IAAY,KAAA,CAAM,QAAQ,CAAC,CAAA,UAAA,EAAa,KAAA,CAAM,OAAO,CAAA,gUAAA,EAI5F,UAAA,CAAW,OAAO,QAAA,EAAS,EAAG,KAAA,CAAM,QAAQ,CAAC,CAAA,kDAAA,CAAA;AAEpD;;;ACcO,SAAS,mBAAA,CAAoB,MAAc,UAAA,EAA6B;AAC7E,EAAA,MAAM,CAAA,GAAI,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,KAAA,CAAM,UAAA,IAAc,CAAC,CAAC,CAAA;AACjD,EAAA,OAAO,MAAM,CAAA,GAAI,IAAA,GAAO,CAAA,EAAG,CAAC,IAAI,IAAI,CAAA,CAAA,CAAA;AACtC;AAeO,SAAS,mBAAA,CAAoB,IAAA,EAAc,UAAA,EAAoBC,MAAAA,EAAqC;AACzG,EAAA,MAAM,OAAA,GAAkC;AAAA,IACtC,MAAA,EAAQ,EAAA;AAAA,IACR,IAAA,EAAM,IAAA;AAAA,IACN,GAAA,EAAK,KAAA;AAAA,IACL,IAAA,EAAM,MAAA;AAAA,IACN,KAAA,EAAA,CAAQA,MAAAA,KAAU,KAAA,GAAQ,EAAA,GAAK,EAAA,IAAM,KAAA;AAAA,IACrC,IAAA,EAAA,CAAOA,MAAAA,KAAU,KAAA,GAAQ,GAAA,GAAM,GAAA,IAAO,KAAA;AAAA,IACtC,SAAS,MAAA,CAAO;AAAA,GAClB;AACA,EAAA,IAAI,CAAC,MAAA,CAAO,MAAA,CAAO,OAAA,EAAS,IAAI,GAAG,OAAO,IAAA;AAC1C,EAAA,OAAO,OAAA,CAAQ,IAAI,CAAA,GAAI,IAAA,CAAK,IAAI,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,UAAU,CAAC,CAAA;AAC3D;;;ACjIO,SAAS,sBAAA,CACd,WAAA,EACA,OAAA,EACA,OAAA,EACe;AACf,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AAErB,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAA,GAAS,WAAW,OAAO,CAAA;AAAA,EAC7B,CAAA,CAAA,MAAQ;AAGN,IAAA,OAAO,0DAA0D,OAAO,CAAA,8EAAA,CAAA;AAAA,EAC1E;AAEA,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,MAAA,CAAO,eAAe,CAAA,CAAE,KAAK,CAAC,KAAA,KAAU,KAAA,CAAM,OAAA,KAAY,OAAO,CAAA;AACrF,EAAA,IAAI,CAAC,IAAA,EAAM;AAMT,IAAA,OAAA,CAAQ,WAAA,CAAY,MAAA,IAAU,EAAC,EAAG,MAAA,GAAS,IACvC,CAAA,4BAAA,EAA+B,OAAO,CAAA,YAAA,EAAe,OAAO,CAAA,sJAAA,CAAA,GAC5D,IAAA;AAAA,EACN;AAEA,EAAA,MAAM,YAAA,GAAeC,UAAAA,CAAW,MAAA,CAAO,MAAA,EAAQ,KAAK,QAAQ,CAAA;AAC5D,EAAA,MAAM,cAAA,GAAiB,mBAAA,CAAoB,MAAA,CAAO,MAAA,EAAQ,GAAG,KAAK,CAAA;AAClE,EAAA,IAAI,cAAA,KAAmB,MAAM,OAAO,IAAA;AAEpC,EAAA,KAAA,MAAW,KAAA,IAAS,WAAA,CAAY,MAAA,IAAU,EAAC,EAAG;AAC5C,IAAA,IAAI,MAAM,KAAA,CAAM,WAAA,OAAkB,IAAA,CAAK,OAAA,CAAQ,aAAY,EAAG;AAI5D,MAAA,OAAO,CAAA,4BAAA,EAA+B,OAAO,CAAA,6BAAA,EAAgC,KAAA,CAAM,KAAK,CAAA,iHAAA,CAAA;AAAA,IAC1F;AAEA,IAAA,IAAI,SAAA;AACJ,IAAA,IAAI;AACF,MAAA,SAAA,GAAY,MAAA,CAAO,MAAM,SAAS,CAAA;AAAA,IACpC,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,CAAA,2DAAA,EAA8D,MAAM,SAAS,CAAA,CAAA,CAAA;AAAA,IACtF;AAEA,IAAA,IAAI,YAAY,YAAA,EAAc;AAC5B,MAAA,OAAO,CAAA,oBAAA,EAAuB,WAAW,SAAA,CAAU,QAAA,IAAY,IAAA,CAAK,QAAQ,CAAC,CAAA,sBAAA,EAAyB,OAAO,CAAA,oHAAA,CAAA;AAAA,IAC/G;AAEA,IAAA,MAAM,eAAe,mBAAA,CAAoB,KAAA,CAAM,MAAM,KAAA,CAAM,UAAA,IAAc,GAAG,KAAK,CAAA;AACjF,IAAA,IAAI,iBAAiB,IAAA,EAAM;AACzB,MAAA,OAAO,CAAA,iEAAA,EAAoE,MAAM,IAAI,CAAA,CAAA,CAAA;AAAA,IACvF;AAQA,IAAA,MAAM,QAAA,GAAW,KAAA,CAAM,IAAA,KAAS,MAAA,CAAO,MAAA;AACvC,IAAA,IAAI,CAAC,QAAA,IAAY,YAAA,GAAe,cAAA,EAAgB;AAC9C,MAAA,OAAO,CAAA,sCAAA,EAAyC,oBAAoB,KAAA,CAAM,IAAA,EAAM,MAAM,UAAA,IAAc,CAAC,CAAC,CAAA,+BAAA,EAAkC,OAAO,CAAA,mHAAA,CAAA;AAAA,IACjJ;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT;;;AC/FA,IAAqB,YAAA,GAArB,MAAqB,aAAA,SAAqB,WAAA,CAAY;AAAA,EACpD,OAAgB,WAAA,GACd,2FAAA;AAAA,EAEF,OAAgB,QAAA,GAAW;AAAA,IACzB,qDAAA;AAAA,IACA,gFAAA;AAAA,IACA,+CAAA;AAAA,IACA,CAAA,2EAAA,CAAA;AAAA,IACA;AAAA,GACF;AAAA,EAEA,OAAgB,KAAA,GAAQ;AAAA,IACtB,GAAG,WAAA,CAAY,SAAA;AAAA,IACf,WAAA,EAAaC,MAAM,MAAA,CAAO;AAAA,MACxB,WAAA,EAAa,4EAAA;AAAA,MACb,SAAA,EAAW,CAAC,MAAM;AAAA,KACnB,CAAA;AAAA,IACD,IAAA,EAAMA,MAAM,OAAA,CAAQ;AAAA,MAClB,WAAA,EACE,gPAAA;AAAA,MAGF,OAAA,EAAS,KAAA;AAAA,MACT,SAAA,EAAW,CAAC,aAAa;AAAA,KAC1B,CAAA;AAAA,IACD,KAAA,EAAOA,MAAM,MAAA,CAAO;AAAA,MAClB,WAAA,EAAa,uDAAuD,kBAAkB,CAAA,yCAAA;AAAA;AAAA;AAAA,KAGvF,CAAA;AAAA,IACD,MAAA,EAAQA,MAAM,OAAA,CAAQ;AAAA,MACpB,WAAA,EAAa;AAAA,KACd;AAAA,GACH;AAAA,EAEA,MAAM,GAAA,GAAqB;AACzB,IAAA,MAAM,EAAE,KAAA,EAAM,GAAI,MAAM,IAAA,CAAK,MAAM,aAAY,CAAA;AAC/C,IAAA,MAAM,SAAS,UAAA,EAAW;AAC1B,IAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AACrB,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,aAAA,CAAc,KAAK,CAAA;AACvC,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,cAAA,CAAe,KAAK,CAAA;AAEzC,IAAA,IAAI,KAAA,CAAM,KAAA,IAAS,CAAC,KAAA,CAAM,IAAA,EAAM;AAC9B,MAAA,IAAA,CAAK,MAAM,0FAA0F,CAAA;AAAA,IACvG;AAUA,IAAA,MAAM,sBAAsB,IAAA,CAAK,kBAAA,CAAmB,KAAA,CAAM,WAAA,EAAa,OAAO,WAAA,EAAa;AAAA,MACzF,MAAM,KAAA,CAAM,IAAA;AAAA,MACZ,OAAO,KAAA,CAAM,KAAA;AAAA,MACb;AAAA,KACD,CAAA;AACD,IAAA,MAAM,WAAA,GAAc,sBAAA,CAAuB,mBAAA,EAAqB,OAAA,EAAS,OAAO,YAAY,CAAA;AAC5F,IAAA,IAAI,WAAA,EAAa,IAAA,CAAK,KAAA,CAAM,WAAW,CAAA;AAGvC,IAAA,IAAI,QAAA,GAA0B,IAAA;AAC9B,IAAA,IAAI,oBAAA,GAAuB,KAAA;AAI3B,IAAA,IAAI,WAAiC,EAAC;AAEtC,IAAA,IAAI,gBAAe,EAAG;AAMpB,MAAA,MAAM,WAAW,oBAAA,EAAqB;AACtC,MAAA,MAAM,WAAW,QAAA,KAAa,IAAA,IAAQ,SAAS,MAAA,GAAS,IAAA,CAAK,KAAI,GAAI,GAAA;AACrE,MAAA,QAAA,GAAW,WAAA,CAAY,UAAU,mBAAmB,CAAA;AAOpD,MAAA,IAAI,CAAC,KAAA,CAAM,GAAA,IAAO,CAAC,OAAA,CAAQ,MAAM,KAAA,EAAO;AACtC,QAAA,IAAA,CAAK,KAAA;AAAA,UACH;AAAA,SAGF;AAAA,MACF;AAEA,MAAA,IAAI,CAAC,MAAM,GAAA,EAAK;AACd,QAAA,MAAM,QAAA,GAAW,MAAM,OAAO,UAAe,CAAA;AAC7C,QAAA,MAAM,EAAA,GAAK,QAAA,CAAS,eAAA,CAAgB,EAAE,KAAA,EAAO,QAAQ,KAAA,EAAO,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAQ,CAAA;AACpF,QAAA,MAAM,GAAA,GAAM,CAAC,CAAA,KAAc,IAAI,OAAA,CAAgB,CAAC,OAAA,KAAY,EAAA,CAAG,QAAA,CAAS,CAAA,EAAG,OAAO,CAAC,CAAA;AAEnF,QAAA,IAAI,CAAC,QAAA,EAAU;AACb,UAAA,MAAM,gBAAgB,sBAAA,EAAuB;AAC7C,UAAA,IAAA,CAAK,IAAI,0DAA0D,CAAA;AACnE,UAAA,IAAI,aAAA,EAAe;AACjB,YAAA,IAAA,CAAK,GAAA,CAAI,CAAA,oBAAA,EAAuB,aAAa,CAAA,CAAE,CAAA;AAAA,UACjD;AACA,UAAA,IAAA,CAAK,GAAA;AAAA,YACH;AAAA,WAGF;AAEA,UAAA,MAAM,WAAA,GAAc,MAAM,GAAA,CAAI,oCAAoC,CAAA;AAClE,UAAA,IAAI,WAAA,CAAY,WAAA,EAAY,KAAM,GAAA,EAAK;AACrC,YAAA,QAAA,GAAW,cAAA,EAAe;AAAA,UAC5B;AAAA,QACF,WAAW,QAAA,EAAU;AACnB,UAAA,MAAM,SAAA,GAAY,KAAK,KAAA,CAAA,CAAO,QAAA,CAAS,SAAS,IAAA,CAAK,GAAA,EAAI,GAAI,GAAA,IAAQ,KAAK,CAAA;AAC1E,UAAA,IAAA,CAAK,IAAI,yBAAyB,CAAA;AAClC,UAAA,IAAA,CAAK,GAAA,CAAI,CAAA,oBAAA,EAAuB,QAAA,CAAS,cAAc,CAAA,CAAE,CAAA;AACzD,UAAA,IAAA,CAAK,GAAA,CAAI,CAAA,oBAAA,EAAuB,QAAA,CAAS,YAAY,CAAA,CAAE,CAAA;AACvD,UAAA,IAAA,CAAK,GAAA,CAAI,CAAA,oBAAA,EAAuB,QAAA,CAAS,OAAO,CAAA,CAAE,CAAA;AAClD,UAAA,IAAA,CAAK,GAAA;AAAA,YACH,CAAA,oBAAA,EAAuB,IAAI,IAAA,CAAK,QAAA,CAAS,MAAA,GAAS,GAAI,CAAA,CAAE,WAAA,EAAa,CAAA,EAAA,EAAK,SAAS,CAAA,gBAAA;AAAA,WACrF;AACA,UAAA,IAAA,CAAK,IAAI,kEAAkE,CAAA;AAC3E,UAAA,IAAA,CAAK,IAAI,kEAAkE,CAAA;AAE3E,UAAA,MAAM,YAAA,GAAe,MAAM,GAAA,CAAI,8CAA8C,CAAA;AAC7E,UAAA,IAAI,YAAA,CAAa,WAAA,EAAY,KAAM,GAAA,EAAK;AACtC,YAAA,IAAA,CAAK,IAAI,6CAA6C,CAAA;AACtD,YAAA,MAAM,YAAA,GAAe,MAAM,SAAA,CAAU;AAAA,cACnC,SAAS,MAAA,CAAO,OAAA;AAAA,cAChB,MAAA;AAAA,cACA,SAAS,QAAA,CAAS,OAAA;AAAA,cAClB,KAAK,MAAA,CAAO;AAAA,aACb,CAAA;AACD,YAAA,IAAI;AACF,cAAA,MAAM,YAAA,CAAa,QAAQ,0BAAA,EAA4B,CAAC,EAAE,EAAA,EAAI,QAAA,CAAS,YAAA,EAAc,CAAC,CAAA;AAAA,YACxF,CAAA,SAAE;AACA,cAAA,YAAA,CAAa,KAAA,EAAM;AAAA,YACrB;AACA,YAAA,oBAAA,GAAuB,IAAA;AACvB,YAAA,IAAA,CAAK,IAAI,yBAAyB,CAAA;AAAA,UACpC,CAAA,MAAO;AACL,YAAA,QAAA,GAAW,CAAC,QAAA,CAAS,QAAQ,CAAA,EAAG,GAAG,QAAQ,CAAA;AAC3C,YAAA,IAAA,CAAK,GAAA;AAAA,cACH;AAAA,aAEF;AAAA,UACF;AAEA,UAAA,MAAM,WAAA,GAAc,MAAM,GAAA,CAAI,oCAAoC,CAAA;AAClE,UAAA,IAAI,WAAA,CAAY,WAAA,EAAY,KAAM,GAAA,EAAK;AACrC,YAAA,QAAA,GAAW,cAAA,EAAe;AAAA,UAC5B;AAAA,QACF,CAAA,MAAO;AACL,UAAA,MAAM,SAAA,GAAY,MAAM,GAAA,CAAI,0CAA0C,CAAA;AACtE,UAAA,IAAI,SAAA,CAAU,WAAA,EAAY,KAAM,GAAA,EAAK;AACnC,YAAA,EAAA,CAAG,KAAA,EAAM;AACT,YAAA,IAAA,CAAK,IAAI,UAAU,CAAA;AACnB,YAAA;AAAA,UACF;AAAA,QACF;AAEA,QAAA,EAAA,CAAG,KAAA,EAAM;AAAA,MACX,CAAA,MAAA,IAAW,CAAC,QAAA,EAAU;AAGpB,QAAA,MAAM,gBAAgB,sBAAA,EAAuB;AAC7C,QAAA,IAAA,CAAK,WAAA;AAAA,UACH,CAAA,oBAAA,EAAuB,aAAA,GAAgB,CAAA,CAAA,EAAI,aAAa,KAAK,EAAE,CAAA,0JAAA;AAAA,SAGjE;AAAA,MACF,WAAW,QAAA,EAAU;AAOnB,QAAA,QAAA,GAAW,CAAC,QAAA,CAAS,QAAQ,CAAA,EAAG,GAAG,QAAQ,CAAA;AAC3C,QAAA,IAAA,CAAK,WAAA;AAAA,UACH,CAAA,qEAAA,EACoB,QAAA,CAAS,YAAY,CAAA,UAAA,EAAa,SAAS,OAAO,CAAA,oBAAA,EAC9C,IAAI,IAAA,CAAK,QAAA,CAAS,MAAA,GAAS,GAAI,CAAA,CAAE,aAAa,CAAA,4EAAA;AAAA,SAExE;AAAA,MACF;AAAA,IAMF;AAKA,IAAA,IAAI;AAEF,MAAA,MAAM,WAAA,GAAc,mBAAA;AAGpB,MAAA,MAAM,UAAA,GAAa,KAAA,CAAM,MAAA,IAAU,MAAA,CAAO,aAAA,IAAiB,CAAA;AAC3D,MAAA,MAAM,eAAA,GAAkB,KAAK,KAAA,CAAM,IAAA,CAAK,KAAI,GAAI,GAAI,IAAI,UAAA,GAAa,KAAA;AAGrE,MAAA,MAAM,aAAA,GAAiB,YAAY,kBAAA,EAAmB;AAGtD,MAAA,MAAM,EAAE,mBAAA,EAAoB,GAAI,MAAM,OAAO,eAAe,CAAA;AAC5D,MAAA,MAAM,YAAA,GAAe,oBAAoB,aAAa,CAAA;AAEtD,MAAA,MAAM,EAAE,OAAA,EAAQ,GAAI,MAAM,OAAO,cAAc,CAAA;AAC/C,MAAA,MAAM,EAAA,GAAK,MAAA,CAAO,UAAA,GAAa,OAAO,CAAA;AAMtC,MAAA,MAAM,IAAA,GAAO,SAAA;AACb,MAAA,MAAM,OAAA,GAAU,MAAM,OAAA,CAAQ,gBAAA;AAAA,QAC5B;AAAA,UACE,OAAA;AAAA,UACA,MAAA;AAAA,UACA,cAAc,EAAA,EAAI,GAAA;AAAA,UAClB,kBAAkB,EAAA,EAAI;AAAA,SACxB;AAAA,QACA,YAAA;AAAA,QACA,EAAE,SAAS,IAAA;AAAK,OAClB;AACA,MAAA,MAAM,iBAAiB,OAAA,CAAQ,OAAA;AAG/B,MAAA,IAAI,CAAC,MAAM,KAAA,EAAO;AAChB,QAAA,IAAI,MAAM,IAAA,EAAM;AAGd,UAAA,IAAA,CAAK,GAAA;AAAA,YACH,oDAAoD,OAAO,CAAA;AAAA;AAAA;AAAA;AAAA,WAG7D;AAAA,QACF;AACA,QAAA,IAAA,CAAK,IAAI,2CAA2C,CAAA;AAAA,MACtD;AAEA,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,CAAU;AAAA,QAC7B,SAAS,MAAA,CAAO,OAAA;AAAA,QAChB,MAAA;AAAA,QACA,OAAA;AAAA,QACA,KAAK,MAAA,CAAO;AAAA,OACb,CAAA;AAMD,MAAA,IAAI,OAAA;AACJ,MAAA,IAAI;AACF,QAAA,IAAI,MAAM,IAAA,EAAM;AACd,UAAA,MAAM,OAAA,GAAU,MAAM,yBAAA,CAA0B,EAAE,SAAS,OAAA,EAAS,CAAC,CAAA,EAAG,CAAA,KAAM,MAAA,CAAO,OAAA,CAAQ,CAAA,EAAG,CAAC,GAAG,CAAA;AACpG,UAAA,IAAI,OAAA,EAAS,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA;AAAA,QACjC;AAEA,QAAA,OAAA,GAAU,MAAM,MAAA,CAAO,OAAA,CAAQ,yBAAA,EAA2B;AAAA,UACxD;AAAA,YACE,OAAA,EAAS,cAAA;AAAA,YACT,MAAA,EAAQ,eAAA;AAAA,YACR,WAAA;AAAA,YACA,OAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAKA,YAAA,EAAc,EAAE,cAAA,EAAgB,IAAA;AAAK;AACvC,SACD,CAAA;AAAA,MACH,CAAA,SAAE;AACA,QAAA,MAAA,CAAO,KAAA,EAAM;AAAA,MACf;AAEA,MAAA,MAAM,aAAA,GAAgB,OAAA;AAGtB,MAAA,MAAM,UAAA,GAAa,uBAAuB,OAAO,CAAA;AAGjD,MAAA,YAAA,CAAa,eAAe,cAAc,CAAA;AAG1C,MAAA,iBAAA,CAAkB;AAAA,QAChB,cAAc,aAAA,CAAc,OAAA;AAAA,QAC5B,cAAA;AAAA,QACA,cAAc,aAAA,CAAc,YAAA;AAAA,QAC5B,OAAA;AAAA,QACA,MAAA,EAAQ,eAAA;AAAA,QACR,IAAA;AAAA,QACA,GAAI,UAAA,GAAa,EAAE,UAAA,KAAe,EAAC;AAAA,QACnC,GAAI,SAAS,MAAA,GAAS,CAAA,GAAI,EAAE,mBAAA,EAAqB,QAAA,KAAa;AAAC,OAChE,CAAA;AAcD,MAAA,IAAI,MAAM,IAAA,EAAM;AACd,QAAA,MAAM,WAAW,MAAM,mBAAA,CAAoB,EAAE,OAAA,EAAS,OAAA,EAAS,gBAAgB,CAAA;AAC/E,QAAA,IAAI,QAAA,OAAe,WAAA,CAAY;AAAA,SAAA,EAAc,QAAQ,CAAA,CAAE,CAAA;AAAA,MACzD;AAGA,MAAA,MAAM,OAAA,GAAU;AAAA,QACd,cAAc,aAAA,CAAc,OAAA;AAAA,QAC5B,cAAA;AAAA,QACA,cAAc,aAAA,CAAc,YAAA;AAAA,QAC5B,MAAA,EAAQ,eAAA;AAAA,QACR;AAAA,OACF;AAEA,MAAA,IAAI,MAAM,KAAA,EAAO;AACf,QAAA,IAAA,CAAK,YAAA,CAAa,SAAS,MAAM,CAAA;AAAA,MACnC,CAAA,MAAO;AACL,QAAA,IAAA,CAAK,IAAI,mCAAmC,CAAA;AAC5C,QAAA,IAAA,CAAK,GAAA,CAAI,CAAA,oBAAA,EAAuB,cAAc,CAAA,CAAE,CAAA;AAChD,QAAA,IAAA,CAAK,IAAI,+DAA+D,CAAA;AACxE,QAAA,IAAA,CAAK,GAAA,CAAI,CAAA,oBAAA,EAAuB,aAAA,CAAc,OAAO,CAAA,CAAE,CAAA;AACvD,QAAA,IAAI,MAAM,IAAA,EAAM;AAKd,UAAA,IAAA,CAAK,IAAI,CAAA,wDAAA,EAA2D,iBAAA,CAAkB,KAAA,CAAM,KAAK,CAAC,CAAA,CAAA,CAAG,CAAA;AAAA,QACvG;AACA,QAAA,IAAA,CAAK,GAAA,CAAI,CAAA,oBAAA,EAAuB,aAAA,CAAc,YAAY,CAAA,CAAE,CAAA;AAC5D,QAAA,IAAA,CAAK,GAAA,CAAI,CAAA,oBAAA,EAAuB,OAAO,CAAA,CAAE,CAAA;AACzC,QAAA,IAAA,CAAK,GAAA,CAAI,CAAA,oBAAA,EAAuB,IAAI,IAAA,CAAK,eAAA,GAAkB,GAAI,CAAA,CAAE,WAAA,EAAa,CAAA,EAAA,EAAK,UAAU,CAAA,MAAA,CAAQ,CAAA;AACrG,QAAA,IAAA,CAAK,IAAI,yDAAyD,CAAA;AAAA,MACpE;AAAA,IACF,SAAS,KAAA,EAAO;AACd,MAAA,IAAI,oBAAA,EAAsB;AACxB,QAAA,IAAA,CAAK,WAAA;AAAA,UACH;AAAA,SAGF;AAAA,MACF;AACA,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF;AAAA,EAEQ,kBAAA,CACN,SAAA,EACA,WAAA,EACA,MAAA,EACmB;AACnB,IAAA,IAAI,GAAA;AAKJ,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,IAAI;AACF,QAAA,GAAA,GAAM,oBAAA,CAAqB,MAAA,CAAO,OAAA,EAAS,MAAA,CAAO,KAAK,CAAA;AAAA,MACzD,SAAS,GAAA,EAAK;AACZ,QAAA,IAAA,CAAK,MAAM,GAAA,YAAe,KAAA,GAAQ,IAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,MAC7D;AAAA,IACF,WAAW,SAAA,EAAW;AACpB,MAAA,IAAI,SAAA,CAAU,SAAA,EAAU,CAAE,UAAA,CAAW,GAAG,CAAA,EAAG;AACzC,QAAA,IAAI;AACF,UAAA,GAAA,GAAM,IAAA,CAAK,MAAM,SAAS,CAAA;AAAA,QAC5B,CAAA,CAAA,MAAQ;AACN,UAAA,IAAA,CAAK,KAAA,CAAM,CAAA,iCAAA,EAAoC,SAAS,CAAA,CAAE,CAAA;AAAA,QAC5D;AAAA,MACF,CAAA,MAAO;AACL,QAAA,MAAM,OAAA,GAAaC,GAAA,CAAA,YAAA,CAAa,SAAA,EAAW,OAAO,CAAA;AAClD,QAAA,IAAI;AACF,UAAA,GAAA,GAAM,IAAA,CAAK,MAAM,OAAO,CAAA;AAAA,QAC1B,CAAA,CAAA,MAAQ;AACN,UAAA,IAAA,CAAK,KAAA,CAAM,CAAA,oBAAA,EAAuB,SAAS,CAAA,mBAAA,CAAqB,CAAA;AAAA,QAClE;AAAA,MACF;AAAA,IACF,WAAW,WAAA,EAAa;AACtB,MAAA,GAAA,GAAM,WAAA;AAAA,IACR,CAAA,MAAO;AACL,MAAA,IAAA,CAAK,KAAA;AAAA,QACH;AAAA,OAEF;AAAA,IACF;AAEA,IAAA,OAAO,uBAAuB,GAAG,CAAA;AAAA,EACnC;AACF;AAGA,SAAS,SAAS,OAAA,EAAwF;AACxG,EAAA,OAAO,EAAE,IAAI,OAAA,CAAQ,YAAA,EAAc,SAAS,OAAA,CAAQ,OAAA,EAAS,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAO;AACtF","file":"setup.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","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","/**\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 { 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","/**\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","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 { 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 {\n generateSessionKey,\n saveKeystore,\n keystoreExists,\n loadSessionKey,\n tryLoadKeystoreAddress,\n} from '../../lib/keystore.js';\nimport {\n liveOrphans,\n parseGrantedPermission,\n saveSessionConfig,\n tryLoadSessionConfig,\n type OrphanedPermission,\n} from '../../lib/session-config.js';\nimport type { OutputFormat, PermissionsConfig } from '../../lib/types.js';\nimport { parsePermissionsConfig } from '../../lib/validation.js';\nimport { buildX402Permissions, describeX402Grant, DEFAULT_X402_LIMIT } from '../../x402/grant-preset.js';\nimport { whyOwnerCannotFundSession, whySpenderCannotPay } from '../../x402/funded-owner.js';\nimport { whyGrantExceedsCeiling } from '../../x402/grant-ceiling.js';\n\nexport default class SessionSetup extends BaseCommand {\n static override description =\n 'Generate a session key and grant scoped on-chain permissions (one-time browser approval).';\n\n static override examples = [\n '<%= config.bin %> session setup --chain 8453 --x402',\n '<%= config.bin %> session setup --chain 8453 --x402 --limit 25/day --expiry 14',\n '<%= config.bin %> session setup --chain 84532',\n '<%= config.bin %> session setup --permissions \\'{\"calls\":[...]}\\' --expiry 14',\n '<%= config.bin %> session setup --permissions ./permissions.json',\n ];\n\n static override flags = {\n ...BaseCommand.baseFlags,\n permissions: Flags.string({\n description: 'Permission scope (inline JSON or file path). Overrides config.permissions.',\n exclusive: ['x402'],\n }),\n x402: Flags.boolean({\n description:\n 'Grant exactly what x402 payments need on this chain: a USDC transfer capped per period. ' +\n 'Builds the permission from the asset registry so the USDC address and function signature ' +\n 'do not have to be written by hand. 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}). Examples: 25/day, 2.5/week, 100/month.`,\n // No `dependsOn: ['x402']`: a boolean flag with a default always reads as\n // provided, so oclif would never fire it. Checked in run() instead.\n }),\n expiry: Flags.integer({\n description: 'Permission expiry in days. Overrides config.sessionExpiry.',\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(SessionSetup);\n const config = loadConfig();\n const format = flags.output as OutputFormat;\n const apiKey = this.resolveApiKey(flags);\n const chainId = this.resolveChainId(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\n // The ceiling a human set at a terminal, checked against the resolved\n // permission rather than the --limit string so a hand-written --permissions\n // is bounded by the same number.\n //\n // First of everything, because it is a local refusal and the block below can\n // revoke the existing permission on chain. Checked after that, a `--limit`\n // over the ceiling cost the user the permission they already had and left\n // them with none: the revoke had happened, the new grant never would.\n const resolvedPermissions = this.resolvePermissions(flags.permissions, config.permissions, {\n x402: flags.x402,\n limit: flags.limit,\n chainId,\n });\n const overCeiling = whyGrantExceedsCeiling(resolvedPermissions, chainId, config.grantCeiling);\n if (overCeiling) this.error(overCeiling);\n\n // 1. Check existing session\n let reuseKey: string | null = null;\n let oldPermissionRevoked = false;\n // Permissions this key still holds that the new session will not name.\n // Carried across the overwrite so `session revoke` can still reach them:\n // the id used to live only in the file being replaced.\n let orphaned: OrphanedPermission[] = [];\n\n if (keystoreExists()) {\n // A keystore can outlive its session-config: setup interrupted between the\n // grant and the config write, a manual delete, a half-restored backup.\n // Throwing here made `session setup` fail with \"No session configured. Run\n // `jaw session setup` first\", so the only way out was deleting the keystore\n // by hand, which strands the key while its on-chain permission stays live.\n const existing = tryLoadSessionConfig();\n const isActive = existing !== null && existing.expiry > Date.now() / 1000;\n orphaned = liveOrphans(existing?.orphanedPermissions);\n\n // The prompt path uses readline against process.stdin. With non-TTY stdin\n // (pipes, heredocs, CI), readline races against the awaited bridge call\n // below: stdin EOFs while the browser approval is pending, readline auto-\n // closes, and the second `ask` throws ERR_USE_AFTER_CLOSE *after* on-chain\n // state has already mutated. Require --yes for non-interactive use.\n if (!flags.yes && !process.stdin.isTTY) {\n this.error(\n 'Existing session key found, but stdin is not a terminal ' +\n '(piped, redirected, or running in CI). ' +\n 'Re-run with --yes to overwrite the existing session non-interactively.'\n );\n }\n\n if (!flags.yes) {\n const readline = await import('node:readline');\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n const ask = (q: string) => new Promise<string>((resolve) => rl.question(q, resolve));\n\n if (!existing) {\n const orphanAddress = tryLoadKeystoreAddress();\n this.log('Session key found, but no session config alongside it.\\n');\n if (orphanAddress) {\n this.log(` Key address: ${orphanAddress}`);\n }\n this.log(\n '\\nIf that key still holds a live on-chain permission it cannot be revoked\\n' +\n 'automatically, because the permission id lived in the missing config.\\n' +\n 'Reusing the key keeps a single key in play instead of leaving two.\\n'\n );\n\n const reuseAnswer = await ask('Reuse existing session key? (Y/n) ');\n if (reuseAnswer.toLowerCase() !== 'n') {\n reuseKey = loadSessionKey();\n }\n } else if (isActive) {\n const remaining = Math.floor((existing.expiry - Date.now() / 1000) / 86400);\n this.log('Active session found:\\n');\n this.log(` Session address: ${existing.sessionAddress}`);\n this.log(` Permission ID: ${existing.permissionId}`);\n this.log(` Chain: ${existing.chainId}`);\n this.log(\n ` Expires: ${new Date(existing.expiry * 1000).toISOString()} (${remaining} days remaining)`\n );\n this.log('\\nThe old on-chain permission will NOT be revoked automatically.');\n this.log('Anyone with the old session key can still use it until expiry.\\n');\n\n const revokeAnswer = await ask('Revoke old permission on-chain first? (Y/n) ');\n if (revokeAnswer.toLowerCase() !== 'n') {\n this.log('Opening browser to revoke old permission...');\n const revokeBridge = await getBridge({\n keysUrl: config.keysUrl,\n apiKey,\n chainId: existing.chainId,\n ens: config.ens,\n });\n try {\n await revokeBridge.request('wallet_revokePermissions', [{ id: existing.permissionId }]);\n } finally {\n revokeBridge.close();\n }\n oldPermissionRevoked = true;\n this.log('Old permission revoked.');\n } else {\n orphaned = [orphanOf(existing), ...orphaned];\n this.log(\n 'Keeping the old permission. It stays live until it expires, and the new session will ' +\n 'not name it, so `jaw session revoke` will revoke both.'\n );\n }\n\n const reuseAnswer = await ask('Reuse existing session key? (Y/n) ');\n if (reuseAnswer.toLowerCase() !== 'n') {\n reuseKey = loadSessionKey();\n }\n } else {\n const overwrite = await ask('Expired session found. Overwrite? (y/N) ');\n if (overwrite.toLowerCase() !== 'y') {\n rl.close();\n this.log('Aborted.');\n return;\n }\n }\n\n rl.close();\n } else if (!existing) {\n // --yes mode, orphaned key: a new one is generated below, so say which\n // key is being left behind rather than dropping it silently.\n const orphanAddress = tryLoadKeystoreAddress();\n this.logToStderr(\n `Warning: session key${orphanAddress ? ` ${orphanAddress}` : ''} has no session config. ` +\n `Generating a new key; any permission the old one still holds cannot be ` +\n `revoked automatically because the permission id is unknown.`\n );\n } else if (isActive) {\n // --yes never revokes, so the old permission stays live on the account\n // after this one is granted. The key that could use it does not survive\n // here (this path always generates a fresh one, and `saveKeystore`\n // overwrites), but the grant does, and it is the grant that has to be\n // revocable. Before this, the warning below was the only trace and the\n // id went away with the overwritten config.\n orphaned = [orphanOf(existing), ...orphaned];\n this.logToStderr(\n `Warning: overwriting active session without revoking. ` +\n `Old permission ${existing.permissionId} on chain ${existing.chainId} ` +\n `remains live until ${new Date(existing.expiry * 1000).toISOString()}. ` +\n `Recorded on the new session, so \\`jaw session revoke\\` will revoke it too.`\n );\n }\n\n // Old keystore/session-config are intentionally NOT deleted here.\n // saveKeystore/saveSessionConfig below overwrite them on success;\n // leaving them in place means a failed grant doesn't strand the user\n // with an active on-chain permission and no local key.\n }\n\n // Anything below can throw. If the inner revoke above already mutated\n // on-chain state, surface a recovery hint before re-throwing so the user\n // knows their local session-config now references a revoked permission.\n try {\n // 2. Resolved above, before anything that mutates on-chain state.\n const permissions = resolvedPermissions;\n\n // 3. Resolve expiry\n const expiryDays = flags.expiry ?? config.sessionExpiry ?? 7;\n const expiryTimestamp = Math.floor(Date.now() / 1000) + expiryDays * 86400;\n\n // 4. Generate or reuse session key\n const privateKeyHex = (reuseKey ?? generateSessionKey()) as `0x${string}`;\n\n // 5. Create LocalAccount and derive smart account address\n const { privateKeyToAccount } = await import('viem/accounts');\n const localAccount = privateKeyToAccount(privateKeyHex);\n\n const { Account } = await import('@jaw.id/core');\n const pm = config.paymasters?.[chainId];\n // EIP-7702 keeps the session address equal to the session key EOA, with\n // the delegation riding the first userOp. That is what lets the account\n // holding the USDC be the same one the ERC-20 paymaster charges for the\n // ops it sends; the factory's counterfactual address was a second one\n // that never held anything.\n const mode = 'eip7702' as const;\n const account = await Account.fromLocalAccount(\n {\n chainId,\n apiKey,\n paymasterUrl: pm?.url,\n paymasterContext: pm?.context,\n },\n localAccount,\n { eip7702: true }\n );\n const sessionAddress = account.address;\n\n // 6. Open browser bridge to grant permissions\n if (!flags.quiet) {\n if (flags.x402) {\n // Which account gets connected in the browser decides everything\n // below, and it is the last moment the user can pick a different one.\n this.log(\n `Connect with an account that holds USDC on chain ${chainId}.\\n` +\n 'Payments pull from it through the permission, and the grant carries 0.1 USDC\\n' +\n 'to the session so it can pay for its own first transaction.\\n'\n );\n }\n this.log('Opening browser to approve permissions...');\n }\n\n const bridge = await getBridge({\n keysUrl: config.keysUrl,\n apiKey,\n chainId,\n ens: config.ens,\n });\n\n // Kept whole rather than narrowed on the way in. The response carries the\n // permission as the contract stores it, and every view on the permission\n // manager takes that struct: narrowing to the id here was what left the\n // CLI unable to ask the chain anything about its own permission.\n let granted: unknown;\n try {\n if (flags.x402) {\n const blocked = await whyOwnerCannotFundSession({ chainId, request: (m, p) => bridge.request(m, p) });\n if (blocked) this.error(blocked);\n }\n\n granted = await bridge.request('wallet_grantPermissions', [\n {\n spender: sessionAddress,\n expiry: expiryTimestamp,\n permissions,\n chainId,\n // The session account sends every op the permission authorises, and\n // the ERC-20 paymaster charges the sender, so its first one has\n // nothing to be charged. The wallet rides a small transfer along in\n // this same transaction; it decides the amount.\n capabilities: { prefundSpender: true },\n },\n ]);\n } finally {\n bridge.close();\n }\n\n const grantResponse = granted as { permissionId: string; account: string };\n // Undefined from a wallet whose response does not carry the struct, which\n // leaves the session behaving exactly as sessions did before this field.\n const permission = parseGrantedPermission(granted);\n\n // 7. Save keystore\n saveKeystore(privateKeyHex, sessionAddress);\n\n // 8. Save session config\n saveSessionConfig({\n ownerAddress: grantResponse.account,\n sessionAddress,\n permissionId: grantResponse.permissionId,\n chainId,\n expiry: expiryTimestamp,\n mode,\n ...(permission ? { permission } : {}),\n ...(orphaned.length > 0 ? { orphanedPermissions: orphaned } : {}),\n });\n\n // 8.5 The grant asked the wallet to seed the spender. Check that it did.\n //\n // An unsupported capability is ignored rather than refused, so a\n // wallet that does not implement `prefundSpender` leaves the session\n // unable to pay for anything, and says nothing about it. The failure\n // then surfaces at the first operation, in an error about sizing a\n // paymaster approval, long after the user has left this screen.\n // Only under --x402: the wallet seeds in whatever token the\n // permission names, and that preset is the one grant that always\n // names USDC. A calls-only permission is correctly seeded with\n // nothing, and warning there would send someone to move real funds\n // for no reason.\n if (flags.x402) {\n const unfunded = await whySpenderCannotPay({ chainId, spender: sessionAddress });\n if (unfunded) this.logToStderr(`\\nWarning: ${unfunded}`);\n }\n\n // 9. Output\n const summary = {\n ownerAddress: grantResponse.account,\n sessionAddress,\n permissionId: grantResponse.permissionId,\n expiry: expiryTimestamp,\n mode,\n };\n\n if (flags.quiet) {\n this.outputResult(summary, format);\n } else {\n this.log('\\nSession created successfully.\\n');\n this.log(` Session address: ${sessionAddress}`);\n this.log(' (the session key EOA, and the x402 payer)');\n this.log(` Owner address: ${grantResponse.account}`);\n if (flags.x402) {\n // Where the money stays. Sending it to the session address instead is\n // the easiest thing to get wrong, and getting it wrong looks like it\n // worked: payments succeed from there without ever exercising the\n // permission, so the cap the user granted applies to nothing.\n this.log(` (payments pull from here, capped at ${describeX402Grant(flags.limit)})`);\n }\n this.log(` Permission ID: ${grantResponse.permissionId}`);\n this.log(` Chain: ${chainId}`);\n this.log(` Expires: ${new Date(expiryTimestamp * 1000).toISOString()} (${expiryDays} days)`);\n this.log('\\nUse --session flag to execute RPC calls in auto mode.');\n }\n } catch (error) {\n if (oldPermissionRevoked) {\n this.logToStderr(\n 'Old permission was revoked on-chain but setup did not complete. ' +\n 'Local session-config still references the revoked permission; ' +\n 'run `jaw session setup` again to create a new session.'\n );\n }\n throw error;\n }\n }\n\n private resolvePermissions(\n flagValue: string | undefined,\n configValue: PermissionsConfig | undefined,\n preset: { x402: boolean; limit?: string; chainId: number }\n ): PermissionsConfig {\n let raw: unknown;\n\n // --x402 derives the scope instead of asking for it. Checked first: it is\n // mutually exclusive with --permissions at the flag level, and it should\n // win over a config block the user is deliberately bypassing.\n if (preset.x402) {\n try {\n raw = buildX402Permissions(preset.chainId, preset.limit);\n } catch (err) {\n this.error(err instanceof Error ? err.message : String(err));\n }\n } else if (flagValue) {\n if (flagValue.trimStart().startsWith('{')) {\n try {\n raw = JSON.parse(flagValue);\n } catch {\n this.error(`--permissions is not valid JSON: ${flagValue}`);\n }\n } else {\n const content = fs.readFileSync(flagValue, 'utf-8');\n try {\n raw = JSON.parse(content);\n } catch {\n this.error(`Permissions file at ${flagValue} is not valid JSON.`);\n }\n }\n } else if (configValue) {\n raw = configValue;\n } else {\n this.error(\n 'Permissions required. For x402 payments run `jaw session setup --x402` and the scope is ' +\n 'built for you. Otherwise pass --permissions or add \"permissions\" to ~/.jaw/config.json.'\n );\n }\n\n return parsePermissionsConfig(raw);\n }\n}\n\n/** The part of a replaced session worth keeping: enough to revoke it later. */\nfunction orphanOf(session: { permissionId: string; chainId: number; expiry: number }): OrphanedPermission {\n return { id: session.permissionId, chainId: session.chainId, expiry: session.expiry };\n}\n"]}