mnemospark 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/proxy.ts","../src/balance.ts","../src/errors.ts","../src/config.ts","../src/mnemospark-request-sign.ts","../src/nonce.ts","../src/cloud-utils.ts","../src/wallet-signature.ts","../src/cloud-price-storage.ts","../src/cloud-storage.ts","../src/auth.ts","../src/version.ts","../src/cli.ts"],"sourcesContent":["/**\n * Local mnemospark proxy server.\n *\n * This proxy only forwards mnemospark storage endpoints to the backend API and\n * serves health checks. It does not handle chat completions or model routing.\n */\n\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport { privateKeyToAccount } from \"viem/accounts\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { PROXY_PORT, MNEMOSPARK_BACKEND_API_BASE_URL } from \"./config.js\";\nimport { createWalletSignatureHeaderValue } from \"./mnemospark-request-sign.js\";\nimport {\n PRICE_STORAGE_PROXY_PATH,\n UPLOAD_PROXY_PATH,\n forwardPriceStorageToBackend,\n forwardStorageUploadToBackend,\n parsePriceStorageQuoteRequest,\n parseStorageUploadRequest,\n} from \"./cloud-price-storage.js\";\nimport {\n STORAGE_DELETE_PROXY_PATH,\n STORAGE_DOWNLOAD_PROXY_PATH,\n STORAGE_LS_PROXY_PATH,\n downloadStorageToDisk,\n forwardStorageDeleteToBackend,\n forwardStorageDownloadToBackend,\n forwardStorageLsToBackend,\n parseStorageObjectRequest,\n} from \"./cloud-storage.js\";\n\nconst HEALTH_CHECK_TIMEOUT_MS = 2_000; // Timeout for checking existing proxy\nconst PORT_RETRY_ATTEMPTS = 5; // Max attempts to bind port (handles TIME_WAIT)\nconst PORT_RETRY_DELAY_MS = 1_000; // Delay between retry attempts\n\nfunction matchesProxyPath(url: string | undefined, path: string): boolean {\n return url === path || url?.startsWith(`${path}?`) === true;\n}\n\nfunction readHeaderValue(value: string | string[] | undefined): string | undefined {\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n }\n if (Array.isArray(value)) {\n for (const candidate of value) {\n const trimmed = candidate.trim();\n if (trimmed.length > 0) {\n return trimmed;\n }\n }\n }\n return undefined;\n}\n\nasync function readProxyJsonBody(req: IncomingMessage): Promise<unknown> {\n const bodyChunks: Buffer[] = [];\n for await (const chunk of req) {\n bodyChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n\n const bodyText = Buffer.concat(bodyChunks).toString(\"utf-8\").trim();\n if (bodyText.length === 0) {\n return {};\n }\n\n return JSON.parse(bodyText);\n}\n\nfunction sendJson(res: ServerResponse, status: number, body: unknown): void {\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(body));\n}\n\nfunction createBackendForwardHeaders(response: {\n contentType: string;\n paymentRequired?: string;\n paymentResponse?: string;\n}): Record<string, string> {\n const responseHeaders: Record<string, string> = {\n \"Content-Type\": response.contentType,\n };\n\n // Preserve v2 payment headers while also supporting legacy names.\n if (response.paymentRequired) {\n responseHeaders[\"PAYMENT-REQUIRED\"] = response.paymentRequired;\n responseHeaders[\"x-payment-required\"] = response.paymentRequired;\n }\n if (response.paymentResponse) {\n responseHeaders[\"PAYMENT-RESPONSE\"] = response.paymentResponse;\n responseHeaders[\"x-payment-response\"] = response.paymentResponse;\n }\n\n return responseHeaders;\n}\n\ntype BackendAuthFailure = {\n status: number;\n contentType: string;\n bodyText: string;\n};\n\nfunction isLikelyWalletProofFailure(bodyText: string): boolean {\n return /(wallet|signature|proof|nonce|timestamp|expired|authoriz)/i.test(bodyText);\n}\n\nexport function normalizeBackendAuthFailure(\n status: number,\n bodyText: string,\n): BackendAuthFailure | undefined {\n if (status !== 401 && status !== 403) {\n return undefined;\n }\n\n const message = isLikelyWalletProofFailure(bodyText) ? \"wallet proof invalid\" : \"unauthorized\";\n return {\n status,\n contentType: \"application/json\",\n bodyText: createAuthErrorBody(message),\n };\n}\n\nfunction createAuthErrorBody(message: \"unauthorized\" | \"wallet proof invalid\"): string {\n return JSON.stringify({\n error: message.replace(/\\s+/g, \"_\"),\n message,\n });\n}\n\nfunction createWalletRequiredBody(): string {\n return JSON.stringify({\n error: \"wallet_required\",\n message: \"wallet required for storage endpoints\",\n });\n}\n\n/**\n * Get the proxy port from pre-loaded configuration.\n * Port is validated at module load time, this just returns the cached value.\n */\nexport function getProxyPort(): number {\n return PROXY_PORT;\n}\n\n/**\n * Check if a proxy is already running on the given port.\n * Returns the wallet address if running, undefined otherwise.\n */\nasync function checkExistingProxy(port: number): Promise<string | undefined> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), HEALTH_CHECK_TIMEOUT_MS);\n\n try {\n const response = await fetch(`http://127.0.0.1:${port}/health`, {\n signal: controller.signal,\n });\n clearTimeout(timeoutId);\n\n if (response.ok) {\n const data = (await response.json()) as { status?: string; wallet?: string };\n if (data.status === \"ok\" && data.wallet) {\n return data.wallet;\n }\n }\n return undefined;\n } catch {\n clearTimeout(timeoutId);\n return undefined;\n }\n}\n\n/** Callback info for low balance warning */\nexport type LowBalanceInfo = {\n balanceUSD: string;\n walletAddress: string;\n};\n\n/** Callback info for insufficient funds error */\nexport type InsufficientFundsInfo = {\n balanceUSD: string;\n requiredUSD: string;\n walletAddress: string;\n};\n\nexport type ProxyOptions = {\n walletKey: string;\n /** Port to listen on (default: 7120) */\n port?: number;\n onReady?: (port: number) => void;\n onError?: (error: Error) => void;\n /** Called when balance drops below $1.00 (warning, request still proceeds) */\n onLowBalance?: (info: LowBalanceInfo) => void;\n /** Called when balance is insufficient for a request (request fails) */\n onInsufficientFunds?: (info: InsufficientFundsInfo) => void;\n};\n\nexport type ProxyHandle = {\n port: number;\n baseUrl: string;\n walletAddress: string;\n balanceMonitor: BalanceMonitor;\n close: () => Promise<void>;\n};\n\n/**\n * Start the local mnemospark backend proxy server.\n *\n * If a proxy is already running on the target port, reuses it instead of failing.\n * Port can be configured via MNEMOSPARK_PROXY_PORT environment variable.\n *\n * Returns a handle with the assigned port, base URL, and a close function.\n */\nexport async function startProxy(options: ProxyOptions): Promise<ProxyHandle> {\n // Determine port: options.port > env var > default\n const listenPort = options.port ?? getProxyPort();\n\n // Check if a proxy is already running on this port\n const existingWallet = await checkExistingProxy(listenPort);\n if (existingWallet) {\n // Proxy already running — reuse it instead of failing with EADDRINUSE\n const account = privateKeyToAccount(options.walletKey as `0x${string}`);\n const balanceMonitor = new BalanceMonitor(account.address);\n const baseUrl = `http://127.0.0.1:${listenPort}`;\n\n // Verify the existing proxy is using the same wallet (or warn if different)\n if (existingWallet !== account.address) {\n console.warn(\n `[mnemospark] Existing proxy on port ${listenPort} uses wallet ${existingWallet}, but current config uses ${account.address}. Reusing existing proxy.`,\n );\n }\n\n options.onReady?.(listenPort);\n\n return {\n port: listenPort,\n baseUrl,\n walletAddress: existingWallet,\n balanceMonitor,\n close: async () => {\n // No-op: we didn't start this proxy, so we shouldn't close it\n },\n };\n }\n\n const walletPrivateKey = options.walletKey.trim() as `0x${string}`;\n const account = privateKeyToAccount(walletPrivateKey);\n const balanceMonitor = new BalanceMonitor(account.address);\n const proxyWalletAddressLower = account.address.toLowerCase();\n\n // Track active connections for graceful cleanup\n const connections = new Set<import(\"net\").Socket>();\n\n const createBackendWalletSignature = async (\n method: \"GET\" | \"POST\" | \"DELETE\",\n path: string,\n walletAddress: string,\n ): Promise<string | undefined> => {\n if (walletAddress.toLowerCase() !== proxyWalletAddressLower) {\n return undefined;\n }\n\n try {\n return await createWalletSignatureHeaderValue(method, path, walletAddress, walletPrivateKey);\n } catch (err) {\n console.warn(\n `[mnemospark] Failed to create wallet proof for ${path}: ${err instanceof Error ? err.message : String(err)}`,\n );\n return undefined;\n }\n };\n\n const server = createServer(async (req: IncomingMessage, res: ServerResponse) => {\n req.on(\"error\", (err) => {\n console.error(`[mnemospark] Request stream error: ${err.message}`);\n });\n res.on(\"error\", (err) => {\n console.error(`[mnemospark] Response stream error: ${err.message}`);\n });\n\n // Mnemospark backend proxy endpoint for /cloud price-storage command.\n if (req.method === \"POST\" && matchesProxyPath(req.url, PRICE_STORAGE_PROXY_PATH)) {\n try {\n let payload: unknown;\n try {\n payload = await readProxyJsonBody(req);\n } catch {\n sendJson(res, 400, {\n error: \"Bad request\",\n message: \"Invalid JSON body for /cloud price-storage\",\n });\n return;\n }\n\n const requestPayload = parsePriceStorageQuoteRequest(payload);\n if (!requestPayload) {\n sendJson(res, 400, {\n error: \"Bad request\",\n message:\n \"Missing required fields: wallet_address, object_id, object_id_hash, gb, provider, region\",\n });\n return;\n }\n\n const walletSignature = await createBackendWalletSignature(\n \"POST\",\n \"/price-storage\",\n requestPayload.wallet_address,\n );\n const backendResponse = await forwardPriceStorageToBackend(requestPayload, {\n backendBaseUrl: MNEMOSPARK_BACKEND_API_BASE_URL,\n walletSignature,\n });\n\n const authFailure = normalizeBackendAuthFailure(\n backendResponse.status,\n backendResponse.bodyText,\n );\n if (authFailure) {\n const responseHeaders = createBackendForwardHeaders({\n contentType: authFailure.contentType,\n paymentRequired: backendResponse.paymentRequired,\n paymentResponse: backendResponse.paymentResponse,\n });\n res.writeHead(authFailure.status, responseHeaders);\n res.end(authFailure.bodyText);\n return;\n }\n\n const responseHeaders = createBackendForwardHeaders(backendResponse);\n res.writeHead(backendResponse.status, responseHeaders);\n res.end(backendResponse.bodyText);\n } catch (err) {\n sendJson(res, 502, {\n error: \"proxy_error\",\n message: `Failed to forward /cloud price-storage: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n return;\n }\n\n // Mnemospark backend proxy endpoint for /cloud upload command.\n if (req.method === \"POST\" && matchesProxyPath(req.url, UPLOAD_PROXY_PATH)) {\n try {\n let payload: unknown;\n try {\n payload = await readProxyJsonBody(req);\n } catch {\n sendJson(res, 400, {\n error: \"Bad request\",\n message: \"Invalid JSON body for /cloud upload\",\n });\n return;\n }\n\n const requestPayload = parseStorageUploadRequest(payload);\n if (!requestPayload) {\n sendJson(res, 400, {\n error: \"Bad request\",\n message:\n \"Missing required fields: quote_id, wallet_address, object_id, object_id_hash, quoted_storage_price, payload\",\n });\n return;\n }\n\n if (requestPayload.wallet_address.toLowerCase() !== proxyWalletAddressLower) {\n sendJson(res, 403, {\n error: \"wallet_proof_invalid\",\n message: \"wallet proof invalid\",\n });\n return;\n }\n\n const walletSignature = await createBackendWalletSignature(\n \"POST\",\n \"/storage/upload\",\n requestPayload.wallet_address,\n );\n if (!walletSignature) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(createWalletRequiredBody());\n return;\n }\n\n const requiredMicros = BigInt(\n Math.max(1, Math.ceil(requestPayload.quoted_storage_price * 1_000_000)),\n );\n const uploadBalanceMonitor =\n requestPayload.wallet_address.toLowerCase() === account.address.toLowerCase()\n ? balanceMonitor\n : new BalanceMonitor(requestPayload.wallet_address);\n const sufficiency = await uploadBalanceMonitor.checkSufficient(requiredMicros);\n const requiredUSD = uploadBalanceMonitor.formatUSDC(requiredMicros);\n\n if (!sufficiency.sufficient) {\n options.onInsufficientFunds?.({\n balanceUSD: sufficiency.info.balanceUSD,\n requiredUSD,\n walletAddress: requestPayload.wallet_address,\n });\n sendJson(res, 400, {\n error: \"insufficient_balance\",\n message: `Insufficient USDC balance. Current: ${sufficiency.info.balanceUSD}, Required: ${requiredUSD}`,\n wallet: requestPayload.wallet_address,\n help: `Fund wallet ${requestPayload.wallet_address} on Base before running /cloud upload`,\n });\n return;\n }\n\n if (sufficiency.info.isLow) {\n options.onLowBalance?.({\n balanceUSD: sufficiency.info.balanceUSD,\n walletAddress: requestPayload.wallet_address,\n });\n }\n\n const backendResponse = await forwardStorageUploadToBackend(requestPayload, {\n backendBaseUrl: MNEMOSPARK_BACKEND_API_BASE_URL,\n walletSignature,\n paymentSignature: readHeaderValue(req.headers[\"payment-signature\"]),\n legacyPayment: readHeaderValue(req.headers[\"x-payment\"]),\n idempotencyKey: readHeaderValue(req.headers[\"idempotency-key\"]),\n });\n\n const authFailure = normalizeBackendAuthFailure(\n backendResponse.status,\n backendResponse.bodyText,\n );\n if (authFailure) {\n const responseHeaders = createBackendForwardHeaders({\n contentType: authFailure.contentType,\n paymentRequired: backendResponse.paymentRequired,\n paymentResponse: backendResponse.paymentResponse,\n });\n res.writeHead(authFailure.status, responseHeaders);\n res.end(authFailure.bodyText);\n return;\n }\n\n const responseHeaders = createBackendForwardHeaders(backendResponse);\n res.writeHead(backendResponse.status, responseHeaders);\n res.end(backendResponse.bodyText);\n } catch (err) {\n sendJson(res, 502, {\n error: \"proxy_error\",\n message: `Failed to forward /cloud upload: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n return;\n }\n\n // Mnemospark backend proxy endpoint for /cloud ls command.\n if (req.method === \"POST\" && matchesProxyPath(req.url, STORAGE_LS_PROXY_PATH)) {\n try {\n let payload: unknown;\n try {\n payload = await readProxyJsonBody(req);\n } catch {\n sendJson(res, 400, {\n error: \"Bad request\",\n message: \"Invalid JSON body for /cloud ls\",\n });\n return;\n }\n\n const requestPayload = parseStorageObjectRequest(payload);\n if (!requestPayload) {\n sendJson(res, 400, {\n error: \"Bad request\",\n message: \"Missing required fields: wallet_address, object_key\",\n });\n return;\n }\n\n if (requestPayload.wallet_address.toLowerCase() !== proxyWalletAddressLower) {\n sendJson(res, 403, {\n error: \"wallet_proof_invalid\",\n message: \"wallet proof invalid\",\n });\n return;\n }\n\n const walletSignature = await createBackendWalletSignature(\n \"POST\",\n \"/storage/ls\",\n requestPayload.wallet_address,\n );\n if (!walletSignature) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(createWalletRequiredBody());\n return;\n }\n\n const backendResponse = await forwardStorageLsToBackend(requestPayload, {\n backendBaseUrl: MNEMOSPARK_BACKEND_API_BASE_URL,\n walletSignature,\n });\n\n const authFailure = normalizeBackendAuthFailure(\n backendResponse.status,\n backendResponse.bodyText,\n );\n if (authFailure) {\n const responseHeaders = createBackendForwardHeaders({\n contentType: authFailure.contentType,\n paymentRequired: backendResponse.paymentRequired,\n paymentResponse: backendResponse.paymentResponse,\n });\n res.writeHead(authFailure.status, responseHeaders);\n res.end(authFailure.bodyText);\n return;\n }\n\n const responseHeaders = createBackendForwardHeaders(backendResponse);\n res.writeHead(backendResponse.status, responseHeaders);\n res.end(backendResponse.bodyText);\n } catch (err) {\n sendJson(res, 502, {\n error: \"proxy_error\",\n message: `Failed to forward /cloud ls: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n return;\n }\n\n // Mnemospark backend proxy endpoint for /cloud download command.\n if (req.method === \"POST\" && matchesProxyPath(req.url, STORAGE_DOWNLOAD_PROXY_PATH)) {\n try {\n let payload: unknown;\n try {\n payload = await readProxyJsonBody(req);\n } catch {\n sendJson(res, 400, {\n error: \"Bad request\",\n message: \"Invalid JSON body for /cloud download\",\n });\n return;\n }\n\n const requestPayload = parseStorageObjectRequest(payload);\n if (!requestPayload) {\n sendJson(res, 400, {\n error: \"Bad request\",\n message: \"Missing required fields: wallet_address, object_key\",\n });\n return;\n }\n\n if (requestPayload.wallet_address.toLowerCase() !== proxyWalletAddressLower) {\n sendJson(res, 403, {\n error: \"wallet_proof_invalid\",\n message: \"wallet proof invalid\",\n });\n return;\n }\n\n const walletSignature = await createBackendWalletSignature(\n \"POST\",\n \"/storage/download\",\n requestPayload.wallet_address,\n );\n if (!walletSignature) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(createWalletRequiredBody());\n return;\n }\n\n const backendResponse = await forwardStorageDownloadToBackend(requestPayload, {\n backendBaseUrl: MNEMOSPARK_BACKEND_API_BASE_URL,\n walletSignature,\n });\n\n const authFailure = normalizeBackendAuthFailure(\n backendResponse.status,\n backendResponse.bodyText,\n );\n if (authFailure) {\n const responseHeaders = createBackendForwardHeaders({\n contentType: authFailure.contentType,\n paymentRequired: backendResponse.paymentRequired,\n paymentResponse: backendResponse.paymentResponse,\n });\n res.writeHead(authFailure.status, responseHeaders);\n res.end(authFailure.bodyText);\n return;\n }\n\n // Forward backend failures directly so client gets original status/details.\n if (backendResponse.status < 200 || backendResponse.status >= 300) {\n const responseHeaders = createBackendForwardHeaders(backendResponse);\n res.writeHead(backendResponse.status, responseHeaders);\n res.end(backendResponse.bodyText);\n return;\n }\n\n const downloadResult = await downloadStorageToDisk(requestPayload, backendResponse);\n sendJson(res, 200, {\n success: true,\n key: downloadResult.key,\n file_path: downloadResult.filePath,\n bytes_written: downloadResult.bytesWritten,\n });\n } catch (err) {\n sendJson(res, 502, {\n error: \"proxy_error\",\n message: `Failed to forward /cloud download: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n return;\n }\n\n // Mnemospark backend proxy endpoint for /cloud delete command.\n if (req.method === \"POST\" && matchesProxyPath(req.url, STORAGE_DELETE_PROXY_PATH)) {\n try {\n let payload: unknown;\n try {\n payload = await readProxyJsonBody(req);\n } catch {\n sendJson(res, 400, {\n error: \"Bad request\",\n message: \"Invalid JSON body for /cloud delete\",\n });\n return;\n }\n\n const requestPayload = parseStorageObjectRequest(payload);\n if (!requestPayload) {\n sendJson(res, 400, {\n error: \"Bad request\",\n message: \"Missing required fields: wallet_address, object_key\",\n });\n return;\n }\n\n if (requestPayload.wallet_address.toLowerCase() !== proxyWalletAddressLower) {\n sendJson(res, 403, {\n error: \"wallet_proof_invalid\",\n message: \"wallet proof invalid\",\n });\n return;\n }\n\n const walletSignature = await createBackendWalletSignature(\n \"POST\",\n \"/storage/delete\",\n requestPayload.wallet_address,\n );\n if (!walletSignature) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(createWalletRequiredBody());\n return;\n }\n\n const backendResponse = await forwardStorageDeleteToBackend(requestPayload, {\n backendBaseUrl: MNEMOSPARK_BACKEND_API_BASE_URL,\n walletSignature,\n });\n\n const authFailure = normalizeBackendAuthFailure(\n backendResponse.status,\n backendResponse.bodyText,\n );\n if (authFailure) {\n const responseHeaders = createBackendForwardHeaders({\n contentType: authFailure.contentType,\n paymentRequired: backendResponse.paymentRequired,\n paymentResponse: backendResponse.paymentResponse,\n });\n res.writeHead(authFailure.status, responseHeaders);\n res.end(authFailure.bodyText);\n return;\n }\n\n const responseHeaders = createBackendForwardHeaders(backendResponse);\n res.writeHead(backendResponse.status, responseHeaders);\n res.end(backendResponse.bodyText);\n } catch (err) {\n sendJson(res, 502, {\n error: \"proxy_error\",\n message: `Failed to forward /cloud delete: ${err instanceof Error ? err.message : String(err)}`,\n });\n }\n return;\n }\n\n // Health check with optional balance info\n if (req.url === \"/health\" || req.url?.startsWith(\"/health?\")) {\n const url = new URL(req.url, \"http://localhost\");\n const full = url.searchParams.get(\"full\") === \"true\";\n\n const response: Record<string, unknown> = {\n status: \"ok\",\n wallet: account.address,\n };\n\n if (full) {\n try {\n const balanceInfo = await balanceMonitor.checkBalance();\n response.balance = balanceInfo.balanceUSD;\n response.isLow = balanceInfo.isLow;\n response.isEmpty = balanceInfo.isEmpty;\n } catch {\n response.balanceError = \"Could not fetch balance\";\n }\n }\n\n sendJson(res, 200, response);\n return;\n }\n\n sendJson(res, 404, {\n error: \"Not found\",\n message: \"Supported paths: /health and /mnemospark/* storage endpoints\",\n });\n });\n\n // Listen on configured port with retry logic for TIME_WAIT handling\n // When gateway restarts quickly, the port may still be in TIME_WAIT state.\n // We retry with delay instead of incorrectly assuming a proxy is running.\n const tryListen = (attempt: number): Promise<void> => {\n return new Promise<void>((resolveAttempt, rejectAttempt) => {\n const onError = async (err: NodeJS.ErrnoException) => {\n server.removeListener(\"error\", onError);\n\n if (err.code === \"EADDRINUSE\") {\n // Port is in use - check if a proxy is actually running\n const existingWallet = await checkExistingProxy(listenPort);\n if (existingWallet) {\n // Proxy is actually running - this is fine, reuse it\n console.log(`[mnemospark] Existing proxy detected on port ${listenPort}, reusing`);\n rejectAttempt({ code: \"REUSE_EXISTING\", wallet: existingWallet });\n return;\n }\n\n // Port is in TIME_WAIT (no proxy responding) - retry after delay\n if (attempt < PORT_RETRY_ATTEMPTS) {\n console.log(\n `[mnemospark] Port ${listenPort} in TIME_WAIT, retrying in ${PORT_RETRY_DELAY_MS}ms (attempt ${attempt}/${PORT_RETRY_ATTEMPTS})`,\n );\n rejectAttempt({ code: \"RETRY\", attempt });\n return;\n }\n\n // Max retries exceeded\n console.error(\n `[mnemospark] Port ${listenPort} still in use after ${PORT_RETRY_ATTEMPTS} attempts`,\n );\n rejectAttempt(err);\n return;\n }\n\n rejectAttempt(err);\n };\n\n server.once(\"error\", onError);\n server.listen(listenPort, \"127.0.0.1\", () => {\n server.removeListener(\"error\", onError);\n resolveAttempt();\n });\n });\n };\n\n // Retry loop for port binding\n let lastError: Error | undefined;\n for (let attempt = 1; attempt <= PORT_RETRY_ATTEMPTS; attempt++) {\n try {\n await tryListen(attempt);\n break; // Success\n } catch (err: unknown) {\n const error = err as { code?: string; wallet?: string };\n\n if (error.code === \"REUSE_EXISTING\" && error.wallet) {\n // Proxy is running, reuse it\n const baseUrl = `http://127.0.0.1:${listenPort}`;\n options.onReady?.(listenPort);\n return {\n port: listenPort,\n baseUrl,\n walletAddress: error.wallet,\n balanceMonitor,\n close: async () => {\n // No-op: we didn't start this proxy, so we shouldn't close it\n },\n };\n }\n\n if (error.code === \"RETRY\") {\n // Wait before retry\n await new Promise((r) => setTimeout(r, PORT_RETRY_DELAY_MS));\n continue;\n }\n\n // Other error - throw\n lastError = err as Error;\n break;\n }\n }\n\n if (lastError) {\n throw lastError;\n }\n\n // Server is now listening - set up remaining handlers\n const addr = server.address() as AddressInfo;\n const port = addr.port;\n const baseUrl = `http://127.0.0.1:${port}`;\n\n options.onReady?.(port);\n\n // Add runtime error handler AFTER successful listen\n // This handles errors that occur during server operation (not just startup)\n server.on(\"error\", (err) => {\n console.error(`[mnemospark] Server runtime error: ${err.message}`);\n options.onError?.(err);\n });\n\n // Handle client connection errors (bad requests, socket errors)\n server.on(\"clientError\", (err, socket) => {\n console.error(`[mnemospark] Client error: ${err.message}`);\n // Send 400 Bad Request if socket is still writable\n if (socket.writable && !socket.destroyed) {\n socket.end(\"HTTP/1.1 400 Bad Request\\r\\n\\r\\n\");\n }\n });\n\n // Track connections for graceful cleanup\n server.on(\"connection\", (socket) => {\n connections.add(socket);\n\n // Keep alignment with prior behavior for long-running uploads/downloads.\n socket.setTimeout(300_000);\n\n socket.on(\"timeout\", () => {\n console.error(`[mnemospark] Socket timeout, destroying connection`);\n socket.destroy();\n });\n\n socket.on(\"error\", (err) => {\n console.error(`[mnemospark] Socket error: ${err.message}`);\n });\n\n socket.on(\"close\", () => {\n connections.delete(socket);\n });\n });\n\n return {\n port,\n baseUrl,\n walletAddress: account.address,\n balanceMonitor,\n close: () =>\n new Promise<void>((res, rej) => {\n const timeout = setTimeout(() => {\n rej(new Error(\"[mnemospark] Close timeout after 4s\"));\n }, 4000);\n\n // Destroy all active connections before closing server\n for (const socket of connections) {\n socket.destroy();\n }\n connections.clear();\n server.close((err) => {\n clearTimeout(timeout);\n if (err) {\n rej(err);\n } else {\n res();\n }\n });\n }),\n };\n}\n","/**\n * Balance Monitor for ClawRouter\n *\n * Monitors USDC balance on Base network with intelligent caching.\n * Provides pre-request balance checks to prevent failed payments.\n *\n * Caching Strategy:\n * - TTL: 30 seconds (balance is cached to avoid excessive RPC calls)\n * - Optimistic deduction: after successful payment, subtract estimated cost from cache\n * - Invalidation: on payment failure, immediately refresh from RPC\n */\n\nimport { createPublicClient, http, erc20Abi } from \"viem\";\nimport { base } from \"viem/chains\";\nimport { RpcError } from \"./errors.js\";\n\n/** USDC contract address on Base mainnet */\nconst USDC_BASE = \"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913\" as const;\n\n/** Cache TTL in milliseconds (30 seconds) */\nconst CACHE_TTL_MS = 30_000;\n\n/** Balance thresholds in USDC smallest unit (6 decimals) */\nexport const BALANCE_THRESHOLDS = {\n /** Low balance warning threshold: $1.00 */\n LOW_BALANCE_MICROS: 1_000_000n,\n /** Effectively zero threshold: $0.0001 (covers dust/rounding) */\n ZERO_THRESHOLD: 100n,\n} as const;\n\n/** Balance information returned by checkBalance() */\nexport type BalanceInfo = {\n /** Raw balance in USDC smallest unit (6 decimals) */\n balance: bigint;\n /** Formatted balance as \"$X.XX\" */\n balanceUSD: string;\n /** True if balance < $1.00 */\n isLow: boolean;\n /** True if balance < $0.0001 (effectively zero) */\n isEmpty: boolean;\n /** Wallet address for funding instructions */\n walletAddress: string;\n};\n\n/** Result from checkSufficient() */\nexport type SufficiencyResult = {\n /** True if balance >= estimated cost */\n sufficient: boolean;\n /** Current balance info */\n info: BalanceInfo;\n /** If insufficient, the shortfall as \"$X.XX\" */\n shortfall?: string;\n};\n\n/**\n * Monitors USDC balance on Base network.\n *\n * Usage:\n * const monitor = new BalanceMonitor(\"0x...\");\n * const info = await monitor.checkBalance();\n * if (info.isLow) console.warn(\"Low balance!\");\n */\nexport class BalanceMonitor {\n private readonly client;\n private readonly walletAddress: `0x${string}`;\n\n /** Cached balance (null = not yet fetched) */\n private cachedBalance: bigint | null = null;\n /** Timestamp when cache was last updated */\n private cachedAt = 0;\n\n constructor(walletAddress: string) {\n this.walletAddress = walletAddress as `0x${string}`;\n this.client = createPublicClient({\n chain: base,\n transport: http(undefined, {\n timeout: 10_000, // 10 second timeout to prevent hanging on slow RPC\n }),\n });\n }\n\n /**\n * Check current USDC balance.\n * Uses cache if valid, otherwise fetches from RPC.\n */\n async checkBalance(): Promise<BalanceInfo> {\n const now = Date.now();\n\n // Use cache if valid\n if (this.cachedBalance !== null && now - this.cachedAt < CACHE_TTL_MS) {\n return this.buildInfo(this.cachedBalance);\n }\n\n // Fetch from RPC\n const balance = await this.fetchBalance();\n this.cachedBalance = balance;\n this.cachedAt = now;\n\n return this.buildInfo(balance);\n }\n\n /**\n * Check if balance is sufficient for an estimated cost.\n *\n * @param estimatedCostMicros - Estimated cost in USDC smallest unit (6 decimals)\n */\n async checkSufficient(estimatedCostMicros: bigint): Promise<SufficiencyResult> {\n const info = await this.checkBalance();\n\n if (info.balance >= estimatedCostMicros) {\n return { sufficient: true, info };\n }\n\n const shortfall = estimatedCostMicros - info.balance;\n return {\n sufficient: false,\n info,\n shortfall: this.formatUSDC(shortfall),\n };\n }\n\n /**\n * Optimistically deduct estimated cost from cached balance.\n * Call this after a successful payment to keep cache accurate.\n *\n * @param amountMicros - Amount to deduct in USDC smallest unit\n */\n deductEstimated(amountMicros: bigint): void {\n if (this.cachedBalance !== null && this.cachedBalance >= amountMicros) {\n this.cachedBalance -= amountMicros;\n }\n }\n\n /**\n * Invalidate cache, forcing next checkBalance() to fetch from RPC.\n * Call this after a payment failure to get accurate balance.\n */\n invalidate(): void {\n this.cachedBalance = null;\n this.cachedAt = 0;\n }\n\n /**\n * Force refresh balance from RPC (ignores cache).\n */\n async refresh(): Promise<BalanceInfo> {\n this.invalidate();\n return this.checkBalance();\n }\n\n /**\n * Format USDC amount (in micros) as \"$X.XX\".\n */\n formatUSDC(amountMicros: bigint): string {\n // USDC has 6 decimals\n const dollars = Number(amountMicros) / 1_000_000;\n return `$${dollars.toFixed(2)}`;\n }\n\n /**\n * Get the wallet address being monitored.\n */\n getWalletAddress(): string {\n return this.walletAddress;\n }\n\n /** Fetch balance from RPC */\n private async fetchBalance(): Promise<bigint> {\n try {\n const balance = await this.client.readContract({\n address: USDC_BASE,\n abi: erc20Abi,\n functionName: \"balanceOf\",\n args: [this.walletAddress],\n });\n return balance;\n } catch (error) {\n // Throw typed error instead of silently returning 0\n // This allows callers to distinguish \"node down\" from \"wallet empty\"\n throw new RpcError(error instanceof Error ? error.message : \"Unknown error\", error);\n }\n }\n\n /** Build BalanceInfo from raw balance */\n private buildInfo(balance: bigint): BalanceInfo {\n return {\n balance,\n balanceUSD: this.formatUSDC(balance),\n isLow: balance < BALANCE_THRESHOLDS.LOW_BALANCE_MICROS,\n isEmpty: balance < BALANCE_THRESHOLDS.ZERO_THRESHOLD,\n walletAddress: this.walletAddress,\n };\n }\n}\n","/**\n * Typed Error Classes for mnemospark\n *\n * Provides structured errors for balance-related failures with\n * all necessary information for user-friendly error messages.\n */\n\n/**\n * Thrown when wallet has insufficient USDC balance for a request.\n */\nexport class InsufficientFundsError extends Error {\n readonly code = \"INSUFFICIENT_FUNDS\" as const;\n readonly currentBalanceUSD: string;\n readonly requiredUSD: string;\n readonly walletAddress: string;\n\n constructor(opts: { currentBalanceUSD: string; requiredUSD: string; walletAddress: string }) {\n const msg = [\n `Insufficient balance. Current: ${opts.currentBalanceUSD}, Required: ${opts.requiredUSD}`,\n `Options:`,\n ` 1. Fund wallet: ${opts.walletAddress}`,\n ` 2. Use free model: /model free`,\n ].join(\"\\n\");\n super(msg);\n this.name = \"InsufficientFundsError\";\n this.currentBalanceUSD = opts.currentBalanceUSD;\n this.requiredUSD = opts.requiredUSD;\n this.walletAddress = opts.walletAddress;\n }\n}\n\n/**\n * Thrown when wallet has no USDC balance (or effectively zero).\n */\nexport class EmptyWalletError extends Error {\n readonly code = \"EMPTY_WALLET\" as const;\n readonly walletAddress: string;\n\n constructor(walletAddress: string) {\n const msg = [\n `No USDC balance.`,\n `Options:`,\n ` 1. Fund wallet: ${walletAddress}`,\n ` 2. Use free model: /model free`,\n ` 3. Uninstall: bash ~/.openclaw/extensions/mnemospark/scripts/uninstall.sh`,\n ].join(\"\\n\");\n super(msg);\n this.name = \"EmptyWalletError\";\n this.walletAddress = walletAddress;\n }\n}\n\n/**\n * Type guard to check if an error is InsufficientFundsError.\n */\nexport function isInsufficientFundsError(error: unknown): error is InsufficientFundsError {\n return error instanceof Error && (error as InsufficientFundsError).code === \"INSUFFICIENT_FUNDS\";\n}\n\n/**\n * Type guard to check if an error is EmptyWalletError.\n */\nexport function isEmptyWalletError(error: unknown): error is EmptyWalletError {\n return error instanceof Error && (error as EmptyWalletError).code === \"EMPTY_WALLET\";\n}\n\n/**\n * Type guard to check if an error is a balance-related error.\n */\nexport function isBalanceError(error: unknown): error is InsufficientFundsError | EmptyWalletError {\n return isInsufficientFundsError(error) || isEmptyWalletError(error);\n}\n\n/**\n * Thrown when RPC call fails (network error, node down, etc).\n * Distinguishes infrastructure failures from actual empty wallets.\n */\nexport class RpcError extends Error {\n readonly code = \"RPC_ERROR\" as const;\n readonly originalError: unknown;\n\n constructor(message: string, originalError?: unknown) {\n super(`RPC error: ${message}. Check network connectivity.`);\n this.name = \"RpcError\";\n this.originalError = originalError;\n }\n}\n\n/**\n * Type guard to check if an error is RpcError.\n */\nexport function isRpcError(error: unknown): error is RpcError {\n return error instanceof Error && (error as RpcError).code === \"RPC_ERROR\";\n}\n","/**\n * Configuration Module\n *\n * Reads environment variables at module load time.\n * Separated from network code to avoid security scanner false positives.\n */\n\nconst DEFAULT_PORT = 7120;\n\n/**\n * Proxy port configuration - resolved once at module load.\n * Reads MNEMOSPARK_PROXY_PORT env var or defaults to 7120 (mnemospark does not conflict with BlockRun proxy on 8402).\n */\nexport const PROXY_PORT = (() => {\n const envPort = process.env.MNEMOSPARK_PROXY_PORT;\n if (envPort) {\n const parsed = parseInt(envPort, 10);\n if (!isNaN(parsed) && parsed > 0 && parsed < 65536) {\n return parsed;\n }\n }\n return DEFAULT_PORT;\n})();\n\n/**\n * Mnemospark backend API base URL for proxy → backend calls.\n * Example: https://{api-id}.execute-api.{region}.amazonaws.com/{stage}\n */\nexport const MNEMOSPARK_BACKEND_API_BASE_URL = (\n process.env.MNEMOSPARK_BACKEND_API_BASE_URL ?? \"\"\n).trim();\n","import { getAddress } from \"viem\";\nimport { privateKeyToAccount, signTypedData } from \"viem/accounts\";\nimport { createNonce } from \"./nonce.js\";\n\nexport const MNEMOSPARK_DOMAIN_NAME = \"Mnemospark\";\nexport const MNEMOSPARK_DOMAIN_VERSION = \"1\";\nexport const MNEMOSPARK_VERIFYING_CONTRACT = \"0x0000000000000000000000000000000000000001\" as const;\n\nexport const BASE_MAINNET_CHAIN_ID = 8453;\nexport const BASE_SEPOLIA_CHAIN_ID = 84532;\n\nexport type MnemosparkChainId = typeof BASE_MAINNET_CHAIN_ID | typeof BASE_SEPOLIA_CHAIN_ID;\n\nexport type MnemosparkRequestPayload = {\n method: string;\n path: string;\n walletAddress: `0x${string}`;\n nonce: `0x${string}`;\n timestamp: string;\n};\n\nexport type WalletSignatureHeaderEnvelope = {\n payloadB64: string;\n signature: string;\n address: `0x${string}`;\n};\n\nexport const MNEMOSPARK_REQUEST_TYPES = {\n MnemosparkRequest: [\n { name: \"method\", type: \"string\" },\n { name: \"path\", type: \"string\" },\n { name: \"walletAddress\", type: \"string\" },\n { name: \"nonce\", type: \"string\" },\n { name: \"timestamp\", type: \"string\" },\n ],\n} as const;\n\ntype BuildPayloadOptions = {\n nonce?: `0x${string}`;\n timestamp?: string;\n};\n\nexport type CreateWalletSignatureHeaderOptions = BuildPayloadOptions & {\n chainId?: MnemosparkChainId;\n};\n\nfunction encodeBase64Json(value: unknown): string {\n return Buffer.from(JSON.stringify(value), \"utf8\").toString(\"base64\");\n}\n\nfunction decodeBase64Json<T>(value: string): T {\n const decoded = Buffer.from(value, \"base64\").toString(\"utf8\");\n return JSON.parse(decoded) as T;\n}\n\nfunction normalizeMethod(method: string): string {\n const normalized = method.trim().toUpperCase();\n if (!normalized) {\n throw new Error(\"Request signing requires a non-empty HTTP method.\");\n }\n return normalized;\n}\n\nfunction normalizePath(path: string): string {\n const trimmed = path.trim();\n if (!trimmed) {\n throw new Error(\"Request signing requires a non-empty path.\");\n }\n\n let parsedPath: string;\n if (/^https?:\\/\\//i.test(trimmed)) {\n parsedPath = new URL(trimmed).pathname;\n } else {\n parsedPath = trimmed.split(\"?\")[0]?.split(\"#\")[0] ?? \"\";\n }\n\n if (!parsedPath) {\n throw new Error(\"Request signing requires a valid request path.\");\n }\n\n const prefixed = parsedPath.startsWith(\"/\") ? parsedPath : `/${parsedPath}`;\n const deduplicated = prefixed.replace(/\\/{2,}/g, \"/\");\n return deduplicated.length > 1 && deduplicated.endsWith(\"/\")\n ? deduplicated.slice(0, -1)\n : deduplicated;\n}\n\nfunction normalizeTimestamp(value: string | undefined): string {\n const timestamp = value ?? Math.floor(Date.now() / 1000).toString();\n if (!/^\\d+$/.test(timestamp)) {\n throw new Error(\"Request signing timestamp must be a Unix timestamp in seconds.\");\n }\n return timestamp;\n}\n\nfunction normalizeNonce(value: `0x${string}` | undefined): `0x${string}` {\n const nonce = value ?? createNonce();\n if (!/^0x[0-9a-fA-F]{64}$/.test(nonce)) {\n throw new Error(\"Request signing nonce must be a 32-byte hex value.\");\n }\n return nonce;\n}\n\nfunction normalizeChainId(chainId: MnemosparkChainId | undefined): MnemosparkChainId {\n const selected = chainId ?? BASE_MAINNET_CHAIN_ID;\n if (selected !== BASE_MAINNET_CHAIN_ID && selected !== BASE_SEPOLIA_CHAIN_ID) {\n throw new Error(`Unsupported chainId for request signing: ${selected}`);\n }\n return selected;\n}\n\nexport function createMnemosparkRequestDomain(chainId?: MnemosparkChainId) {\n return {\n name: MNEMOSPARK_DOMAIN_NAME,\n version: MNEMOSPARK_DOMAIN_VERSION,\n chainId: normalizeChainId(chainId),\n verifyingContract: MNEMOSPARK_VERIFYING_CONTRACT,\n } as const;\n}\n\nexport function createMnemosparkRequestPayload(\n method: string,\n path: string,\n walletAddress: string,\n options?: BuildPayloadOptions,\n): MnemosparkRequestPayload {\n return {\n method: normalizeMethod(method),\n path: normalizePath(path),\n walletAddress: getAddress(walletAddress),\n nonce: normalizeNonce(options?.nonce),\n timestamp: normalizeTimestamp(options?.timestamp),\n };\n}\n\nexport function decodeWalletSignatureHeaderValue(\n headerValue: string,\n): WalletSignatureHeaderEnvelope {\n return decodeBase64Json<WalletSignatureHeaderEnvelope>(headerValue);\n}\n\nexport function decodeWalletSignaturePayload(payloadB64: string): MnemosparkRequestPayload {\n return decodeBase64Json<MnemosparkRequestPayload>(payloadB64);\n}\n\nexport async function createWalletSignatureHeaderValue(\n method: string,\n path: string,\n walletAddress: string,\n walletPrivateKey: `0x${string}`,\n options?: CreateWalletSignatureHeaderOptions,\n): Promise<string> {\n const payload = createMnemosparkRequestPayload(method, path, walletAddress, {\n nonce: options?.nonce,\n timestamp: options?.timestamp,\n });\n const signer = privateKeyToAccount(walletPrivateKey);\n\n if (signer.address.toLowerCase() !== payload.walletAddress.toLowerCase()) {\n throw new Error(\n `Wallet address ${payload.walletAddress} does not match signer address ${signer.address}.`,\n );\n }\n\n const signature = await signTypedData({\n privateKey: walletPrivateKey,\n domain: createMnemosparkRequestDomain(options?.chainId),\n types: MNEMOSPARK_REQUEST_TYPES,\n primaryType: \"MnemosparkRequest\",\n message: payload,\n });\n\n const headerEnvelope: WalletSignatureHeaderEnvelope = {\n payloadB64: encodeBase64Json(payload),\n signature,\n address: signer.address,\n };\n\n return encodeBase64Json(headerEnvelope);\n}\n","/**\n * Generates a cryptographically random 32-byte value as a 0x-prefixed hex string.\n * Used for request signing nonces and payment transfer nonces.\n */\nexport function createNonce(): `0x${string}` {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}` as `0x${string}`;\n}\n","export function normalizeBaseUrl(baseUrl: string): string {\n return baseUrl.replace(/\\/+$/, \"\");\n}\n\nexport function asRecord(value: unknown): Record<string, unknown> | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return null;\n }\n return value as Record<string, unknown>;\n}\n\nexport function asNumber(value: unknown): number | null {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return value;\n }\n if (typeof value === \"string\" && value.trim().length > 0) {\n const parsed = Number.parseFloat(value);\n if (Number.isFinite(parsed)) {\n return parsed;\n }\n }\n return null;\n}\n\nexport function asNonEmptyString(value: unknown): string | null {\n if (typeof value !== \"string\") {\n return null;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : null;\n}\n\nexport function normalizePaymentRequired(headers: Headers): string | undefined {\n return headers.get(\"PAYMENT-REQUIRED\") ?? headers.get(\"x-payment-required\") ?? undefined;\n}\n\nexport function normalizePaymentResponse(headers: Headers): string | undefined {\n return headers.get(\"PAYMENT-RESPONSE\") ?? headers.get(\"x-payment-response\") ?? undefined;\n}\n","export function normalizeWalletSignature(value: string | undefined): string | undefined {\n const trimmed = value?.trim();\n return trimmed && trimmed.length > 0 ? trimmed : undefined;\n}\n","import { PROXY_PORT } from \"./config.js\";\nimport {\n asNonEmptyString,\n asNumber,\n asRecord,\n normalizeBaseUrl,\n normalizePaymentRequired,\n normalizePaymentResponse,\n} from \"./cloud-utils.js\";\nimport { normalizeWalletSignature } from \"./wallet-signature.js\";\n\nexport const PRICE_STORAGE_PROXY_PATH = \"/mnemospark/price-storage\";\nexport const UPLOAD_PROXY_PATH = \"/mnemospark/upload\";\n\nexport type PriceStorageQuoteRequest = {\n wallet_address: string;\n object_id: string;\n object_id_hash: string;\n gb: number;\n provider: string;\n region: string;\n};\n\nexport type PriceStorageQuoteResponse = {\n timestamp: string;\n quote_id: string;\n storage_price: number;\n addr: string;\n object_id: string;\n object_id_hash: string;\n object_size_gb: number;\n provider: string;\n location: string;\n};\n\nexport type UploadPayload = {\n mode: \"inline\" | \"presigned\";\n content_base64?: string;\n content_sha256: string;\n content_length_bytes: number;\n wrapped_dek: string;\n encryption_algorithm: \"AES-256-GCM\";\n bucket_name_hint: string;\n key_store_path_hint: string;\n};\n\nexport type StorageUploadRequest = {\n quote_id: string;\n wallet_address: string;\n object_id: string;\n object_id_hash: string;\n quoted_storage_price: number;\n payload: UploadPayload;\n};\n\nexport type StorageUploadResponse = {\n quote_id: string;\n addr: string;\n addr_hash?: string;\n trans_id?: string;\n storage_price?: number;\n object_id: string;\n object_key: string;\n provider: string;\n bucket_name: string;\n location: string;\n upload_url?: string;\n upload_headers?: Record<string, string>;\n};\n\ntype FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\ntype ProxyQuoteOptions = {\n proxyBaseUrl?: string;\n fetchImpl?: FetchLike;\n};\n\ntype ProxyUploadOptions = {\n proxyBaseUrl?: string;\n fetchImpl?: FetchLike;\n idempotencyKey?: string;\n};\n\ntype BackendQuoteOptions = {\n backendBaseUrl?: string;\n walletSignature?: string;\n fetchImpl?: FetchLike;\n};\n\ntype BackendUploadOptions = {\n backendBaseUrl?: string;\n walletSignature?: string;\n fetchImpl?: FetchLike;\n paymentSignature?: string;\n legacyPayment?: string;\n idempotencyKey?: string;\n};\n\ntype BackendQuoteForwardResult = {\n status: number;\n bodyText: string;\n contentType: string;\n paymentRequired?: string;\n paymentResponse?: string;\n};\n\ntype BackendUploadForwardResult = {\n status: number;\n bodyText: string;\n contentType: string;\n paymentRequired?: string;\n paymentResponse?: string;\n};\n\nfunction asStringRecord(value: unknown): Record<string, string> | null {\n const record = asRecord(value);\n if (!record) {\n return null;\n }\n\n const output: Record<string, string> = {};\n for (const [key, entry] of Object.entries(record)) {\n if (typeof entry !== \"string\") {\n return null;\n }\n output[key] = entry;\n }\n return output;\n}\n\nexport function parsePriceStorageQuoteRequest(payload: unknown): PriceStorageQuoteRequest | null {\n const record = asRecord(payload);\n if (!record) {\n return null;\n }\n\n const walletAddress = asNonEmptyString(record.wallet_address);\n const objectId = asNonEmptyString(record.object_id);\n const objectIdHash = asNonEmptyString(record.object_id_hash);\n const gb = asNumber(record.gb);\n const provider = asNonEmptyString(record.provider);\n const region = asNonEmptyString(record.region);\n\n if (!walletAddress || !objectId || !objectIdHash || gb === null || !provider || !region) {\n return null;\n }\n\n return {\n wallet_address: walletAddress,\n object_id: objectId,\n object_id_hash: objectIdHash,\n gb,\n provider,\n region,\n };\n}\n\nexport function parsePriceStorageQuoteResponse(payload: unknown): PriceStorageQuoteResponse {\n const record = asRecord(payload);\n if (!record) {\n throw new Error(\"Invalid price-storage response payload\");\n }\n\n const timestamp = asNonEmptyString(record.timestamp);\n const quoteId = asNonEmptyString(record.quote_id);\n const storagePrice = asNumber(record.storage_price);\n const addr = asNonEmptyString(record.addr);\n const objectId = asNonEmptyString(record.object_id);\n const objectIdHash = asNonEmptyString(record.object_id_hash);\n const objectSizeGb = asNumber(record.object_size_gb);\n const provider = asNonEmptyString(record.provider);\n const location = asNonEmptyString(record.location);\n\n if (\n !timestamp ||\n !quoteId ||\n storagePrice === null ||\n !addr ||\n !objectId ||\n !objectIdHash ||\n objectSizeGb === null ||\n !provider ||\n !location\n ) {\n throw new Error(\"Price-storage response is missing required fields\");\n }\n\n return {\n timestamp,\n quote_id: quoteId,\n storage_price: storagePrice,\n addr,\n object_id: objectId,\n object_id_hash: objectIdHash,\n object_size_gb: objectSizeGb,\n provider,\n location,\n };\n}\n\nexport function parseStorageUploadRequest(payload: unknown): StorageUploadRequest | null {\n const record = asRecord(payload);\n if (!record) {\n return null;\n }\n\n const quoteId = asNonEmptyString(record.quote_id);\n const walletAddress = asNonEmptyString(record.wallet_address);\n const objectId = asNonEmptyString(record.object_id);\n const objectIdHash = asNonEmptyString(record.object_id_hash);\n const quotedStoragePrice = asNumber(record.quoted_storage_price);\n\n const payloadRecord = asRecord(record.payload);\n if (!payloadRecord) {\n return null;\n }\n\n const modeRaw = asNonEmptyString(payloadRecord.mode);\n const mode = modeRaw === \"inline\" || modeRaw === \"presigned\" ? modeRaw : null;\n const contentBase64 =\n payloadRecord.content_base64 === undefined\n ? undefined\n : asNonEmptyString(payloadRecord.content_base64);\n const contentSha256 = asNonEmptyString(payloadRecord.content_sha256);\n const contentLengthBytes = asNumber(payloadRecord.content_length_bytes);\n const wrappedDek = asNonEmptyString(payloadRecord.wrapped_dek);\n const encryptionAlgorithm = asNonEmptyString(payloadRecord.encryption_algorithm);\n const bucketNameHint = asNonEmptyString(payloadRecord.bucket_name_hint);\n const keyStorePathHint = asNonEmptyString(payloadRecord.key_store_path_hint);\n\n if (\n !quoteId ||\n !walletAddress ||\n !objectId ||\n !objectIdHash ||\n quotedStoragePrice === null ||\n !mode ||\n !contentSha256 ||\n contentLengthBytes === null ||\n !wrappedDek ||\n encryptionAlgorithm !== \"AES-256-GCM\" ||\n !bucketNameHint ||\n !keyStorePathHint\n ) {\n return null;\n }\n\n if (mode === \"inline\" && !contentBase64) {\n return null;\n }\n\n return {\n quote_id: quoteId,\n wallet_address: walletAddress,\n object_id: objectId,\n object_id_hash: objectIdHash,\n quoted_storage_price: quotedStoragePrice,\n payload: {\n mode,\n content_base64: contentBase64 ?? undefined,\n content_sha256: contentSha256,\n content_length_bytes: contentLengthBytes,\n wrapped_dek: wrappedDek,\n encryption_algorithm: \"AES-256-GCM\",\n bucket_name_hint: bucketNameHint,\n key_store_path_hint: keyStorePathHint,\n },\n };\n}\n\nexport function parseStorageUploadResponse(payload: unknown): StorageUploadResponse {\n const record = asRecord(payload);\n if (!record) {\n throw new Error(\"Invalid upload response payload\");\n }\n\n const quoteId = asNonEmptyString(record.quote_id);\n const addr = asNonEmptyString(record.addr);\n const addrHash = asNonEmptyString(record.addr_hash);\n const transId = asNonEmptyString(record.trans_id);\n const storagePrice = asNumber(record.storage_price);\n const objectId = asNonEmptyString(record.object_id);\n const objectKey = asNonEmptyString(record.object_key);\n const provider = asNonEmptyString(record.provider);\n const bucketName = asNonEmptyString(record.bucket_name);\n const location = asNonEmptyString(record.location);\n const uploadUrl = asNonEmptyString(record.upload_url);\n const uploadHeaders =\n record.upload_headers === undefined ? undefined : asStringRecord(record.upload_headers);\n\n if (!quoteId || !addr || !objectId || !objectKey || !provider || !bucketName || !location) {\n throw new Error(\"Upload response is missing required fields\");\n }\n\n if (record.upload_headers !== undefined && !uploadHeaders) {\n throw new Error(\"Upload response has invalid upload_headers\");\n }\n\n return {\n quote_id: quoteId,\n addr,\n addr_hash: addrHash ?? undefined,\n trans_id: transId ?? undefined,\n storage_price: storagePrice ?? undefined,\n object_id: objectId,\n object_key: objectKey,\n provider,\n bucket_name: bucketName,\n location,\n upload_url: uploadUrl ?? undefined,\n upload_headers: uploadHeaders ?? undefined,\n };\n}\n\nexport async function requestPriceStorageViaProxy(\n request: PriceStorageQuoteRequest,\n options: ProxyQuoteOptions = {},\n): Promise<PriceStorageQuoteResponse> {\n const fetchImpl = options.fetchImpl ?? fetch;\n const baseUrl = normalizeBaseUrl(\n options.proxyBaseUrl ?? `http://127.0.0.1:${PROXY_PORT.toString()}`,\n );\n const response = await fetchImpl(`${baseUrl}${PRICE_STORAGE_PROXY_PATH}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n });\n\n const responseBody = await response.text();\n if (!response.ok) {\n throw new Error(responseBody || `Price-storage proxy failed with status ${response.status}`);\n }\n\n let payload: unknown;\n try {\n payload = JSON.parse(responseBody);\n } catch {\n throw new Error(\"Price-storage proxy returned invalid JSON\");\n }\n return parsePriceStorageQuoteResponse(payload);\n}\n\nexport async function requestStorageUploadViaProxy(\n request: StorageUploadRequest,\n options: ProxyUploadOptions = {},\n): Promise<StorageUploadResponse> {\n const fetchImpl = options.fetchImpl ?? fetch;\n const baseUrl = normalizeBaseUrl(\n options.proxyBaseUrl ?? `http://127.0.0.1:${PROXY_PORT.toString()}`,\n );\n const requestHeaders: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n\n if (options.idempotencyKey && options.idempotencyKey.trim().length > 0) {\n requestHeaders[\"Idempotency-Key\"] = options.idempotencyKey.trim();\n }\n\n const response = await fetchImpl(`${baseUrl}${UPLOAD_PROXY_PATH}`, {\n method: \"POST\",\n headers: requestHeaders,\n body: JSON.stringify(request),\n });\n\n const responseBody = await response.text();\n if (!response.ok) {\n throw new Error(responseBody || `Upload proxy failed with status ${response.status}`);\n }\n\n let payload: unknown;\n try {\n payload = JSON.parse(responseBody);\n } catch {\n throw new Error(\"Upload proxy returned invalid JSON\");\n }\n return parseStorageUploadResponse(payload);\n}\n\nexport async function forwardPriceStorageToBackend(\n request: PriceStorageQuoteRequest,\n options: BackendQuoteOptions = {},\n): Promise<BackendQuoteForwardResult> {\n const fetchImpl = options.fetchImpl ?? fetch;\n const backendBaseUrl = (options.backendBaseUrl ?? \"\").trim();\n const walletSignature = normalizeWalletSignature(options.walletSignature);\n\n if (!backendBaseUrl) {\n throw new Error(\"MNEMOSPARK_BACKEND_API_BASE_URL is not configured\");\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (walletSignature) {\n headers[\"X-Wallet-Signature\"] = walletSignature;\n }\n\n const targetUrl = `${normalizeBaseUrl(backendBaseUrl)}/price-storage`;\n const response = await fetchImpl(targetUrl, {\n method: \"POST\",\n headers,\n body: JSON.stringify(request),\n });\n\n return {\n status: response.status,\n bodyText: await response.text(),\n contentType: response.headers.get(\"content-type\") ?? \"application/json\",\n paymentRequired: normalizePaymentRequired(response.headers),\n paymentResponse: normalizePaymentResponse(response.headers),\n };\n}\n\nexport async function forwardStorageUploadToBackend(\n request: StorageUploadRequest,\n options: BackendUploadOptions = {},\n): Promise<BackendUploadForwardResult> {\n const fetchImpl = options.fetchImpl ?? fetch;\n const backendBaseUrl = (options.backendBaseUrl ?? \"\").trim();\n const walletSignature = normalizeWalletSignature(options.walletSignature);\n\n if (!backendBaseUrl) {\n throw new Error(\"MNEMOSPARK_BACKEND_API_BASE_URL is not configured\");\n }\n if (!walletSignature) {\n throw new Error(\n \"Wallet required for storage endpoints: wallet key must be present to sign requests.\",\n );\n }\n\n const requestHeaders: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"X-Wallet-Signature\": walletSignature,\n };\n\n if (options.idempotencyKey && options.idempotencyKey.trim().length > 0) {\n requestHeaders[\"Idempotency-Key\"] = options.idempotencyKey.trim();\n }\n\n const paymentSignature = options.paymentSignature?.trim();\n const legacyPayment = options.legacyPayment?.trim();\n if (paymentSignature) {\n requestHeaders[\"PAYMENT-SIGNATURE\"] = paymentSignature;\n requestHeaders[\"x-payment\"] = paymentSignature;\n }\n if (legacyPayment) {\n requestHeaders[\"x-payment\"] = legacyPayment;\n requestHeaders[\"PAYMENT-SIGNATURE\"] = requestHeaders[\"PAYMENT-SIGNATURE\"] ?? legacyPayment;\n }\n\n const targetUrl = `${normalizeBaseUrl(backendBaseUrl)}/storage/upload`;\n const response = await fetchImpl(targetUrl, {\n method: \"POST\",\n headers: requestHeaders,\n body: JSON.stringify(request),\n });\n\n return {\n status: response.status,\n bodyText: await response.text(),\n contentType: response.headers.get(\"content-type\") ?? \"application/json\",\n paymentRequired: normalizePaymentRequired(response.headers),\n paymentResponse: normalizePaymentResponse(response.headers),\n };\n}\n\nexport type {\n BackendQuoteForwardResult,\n BackendQuoteOptions,\n BackendUploadForwardResult,\n BackendUploadOptions,\n ProxyQuoteOptions,\n ProxyUploadOptions,\n};\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join, resolve, sep } from \"node:path\";\n\nimport { PROXY_PORT } from \"./config.js\";\nimport {\n asNonEmptyString,\n asNumber,\n asRecord,\n normalizeBaseUrl,\n normalizePaymentRequired,\n normalizePaymentResponse,\n} from \"./cloud-utils.js\";\nimport { normalizeWalletSignature } from \"./wallet-signature.js\";\n\nexport const STORAGE_LS_PROXY_PATH = \"/mnemospark/storage/ls\";\nexport const STORAGE_DOWNLOAD_PROXY_PATH = \"/mnemospark/storage/download\";\nexport const STORAGE_DELETE_PROXY_PATH = \"/mnemospark/storage/delete\";\n\nexport type StorageObjectRequest = {\n wallet_address: string;\n object_key: string;\n location?: string;\n};\n\nexport type StorageLsResponse = {\n success: boolean;\n key: string;\n size_bytes: number;\n bucket: string;\n object_id?: string;\n};\n\nexport type StorageDeleteResponse = {\n success: boolean;\n key: string;\n bucket: string;\n bucket_deleted: boolean;\n};\n\nexport type StorageDownloadProxyResponse = {\n success: boolean;\n key: string;\n file_path: string;\n};\n\ntype FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\ntype ProxyStorageOptions = {\n proxyBaseUrl?: string;\n fetchImpl?: FetchLike;\n};\n\ntype BackendStorageOptions = {\n backendBaseUrl?: string;\n walletSignature?: string;\n fetchImpl?: FetchLike;\n};\n\ntype BackendStorageForwardResult = {\n status: number;\n bodyText: string;\n bodyBuffer: Buffer;\n contentType: string;\n contentDisposition?: string;\n paymentRequired?: string;\n paymentResponse?: string;\n};\n\ntype DownloadStorageToDiskOptions = {\n outputDir?: string;\n fetchImpl?: FetchLike;\n};\n\ntype DownloadStorageToDiskResult = {\n key: string;\n filePath: string;\n bytesWritten: number;\n};\n\nfunction asBooleanOrDefault(value: unknown, defaultValue: boolean): boolean {\n if (typeof value === \"boolean\") {\n return value;\n }\n return defaultValue;\n}\n\nfunction parseJsonText(text: string, errorMessage: string): Record<string, unknown> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n throw new Error(errorMessage);\n }\n const record = asRecord(parsed);\n if (!record) {\n throw new Error(errorMessage);\n }\n return record;\n}\n\nfunction sanitizeObjectKeyToRelativePath(objectKey: string): string {\n const normalized = objectKey.replace(/\\\\/g, \"/\").trim().replace(/^\\/+/, \"\");\n const segments = normalized\n .split(\"/\")\n .filter((segment) => segment.length > 0 && segment !== \".\" && segment !== \"..\");\n if (segments.length === 0) {\n return \"downloaded-object\";\n }\n return join(...segments);\n}\n\nfunction resolveDownloadPath(outputDir: string, objectKey: string): string {\n const resolvedOutputDir = resolve(outputDir);\n const relativeObjectPath = sanitizeObjectKeyToRelativePath(objectKey);\n const resolvedTargetPath = resolve(resolvedOutputDir, relativeObjectPath);\n\n if (\n resolvedTargetPath !== resolvedOutputDir &&\n !resolvedTargetPath.startsWith(`${resolvedOutputDir}${sep}`)\n ) {\n throw new Error(\"Resolved download target escapes output directory\");\n }\n\n return resolvedTargetPath;\n}\n\nfunction parseFilenameFromContentDisposition(contentDisposition?: string): string | undefined {\n if (!contentDisposition) {\n return undefined;\n }\n\n const utf8Match = contentDisposition.match(/filename\\*=UTF-8''([^;]+)/i);\n if (utf8Match?.[1]) {\n try {\n return decodeURIComponent(utf8Match[1]);\n } catch {\n return utf8Match[1];\n }\n }\n\n const quotedMatch = contentDisposition.match(/filename=\"([^\"]+)\"/i);\n if (quotedMatch?.[1]) {\n return quotedMatch[1];\n }\n\n const plainMatch = contentDisposition.match(/filename=([^;]+)/i);\n if (plainMatch?.[1]) {\n return plainMatch[1].trim();\n }\n\n return undefined;\n}\n\nasync function requestJsonViaProxy<T>(\n proxyPath: string,\n request: StorageObjectRequest,\n parser: (payload: unknown) => T,\n options: ProxyStorageOptions = {},\n): Promise<T> {\n const fetchImpl = options.fetchImpl ?? fetch;\n const baseUrl = normalizeBaseUrl(\n options.proxyBaseUrl ?? `http://127.0.0.1:${PROXY_PORT.toString()}`,\n );\n\n const response = await fetchImpl(`${baseUrl}${proxyPath}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(request),\n });\n\n const bodyText = await response.text();\n if (!response.ok) {\n throw new Error(bodyText || `Cloud storage proxy failed with status ${response.status}`);\n }\n\n let payload: unknown;\n try {\n payload = JSON.parse(bodyText);\n } catch {\n throw new Error(\"Cloud storage proxy returned invalid JSON\");\n }\n\n return parser(payload);\n}\n\nasync function forwardStorageToBackend(\n path: string,\n method: \"POST\" | \"DELETE\" | \"GET\",\n request: StorageObjectRequest,\n options: BackendStorageOptions = {},\n): Promise<BackendStorageForwardResult> {\n const fetchImpl = options.fetchImpl ?? fetch;\n const backendBaseUrl = (options.backendBaseUrl ?? \"\").trim();\n const walletSignature = normalizeWalletSignature(options.walletSignature);\n\n if (!backendBaseUrl) {\n throw new Error(\"MNEMOSPARK_BACKEND_API_BASE_URL is not configured\");\n }\n if (!walletSignature) {\n throw new Error(\n \"Wallet required for storage endpoints: wallet key must be present to sign requests.\",\n );\n }\n\n const targetUrl = `${normalizeBaseUrl(backendBaseUrl)}${path}`;\n const response = await fetchImpl(targetUrl, {\n method,\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Wallet-Signature\": walletSignature,\n },\n body: JSON.stringify(request),\n });\n\n const bodyBuffer = Buffer.from(await response.arrayBuffer());\n\n return {\n status: response.status,\n bodyText: bodyBuffer.toString(\"utf-8\"),\n bodyBuffer,\n contentType: response.headers.get(\"content-type\") ?? \"application/octet-stream\",\n contentDisposition: response.headers.get(\"content-disposition\") ?? undefined,\n paymentRequired: normalizePaymentRequired(response.headers),\n paymentResponse: normalizePaymentResponse(response.headers),\n };\n}\n\nexport function parseStorageObjectRequest(payload: unknown): StorageObjectRequest | null {\n const record = asRecord(payload);\n if (!record) {\n return null;\n }\n\n const walletAddress = asNonEmptyString(record.wallet_address);\n const objectKey = asNonEmptyString(record.object_key);\n const location = asNonEmptyString(record.location) ?? undefined;\n\n if (!walletAddress || !objectKey) {\n return null;\n }\n\n return {\n wallet_address: walletAddress,\n object_key: objectKey,\n location,\n };\n}\n\nexport function parseStorageLsResponse(payload: unknown): StorageLsResponse {\n const record = asRecord(payload);\n if (!record) {\n throw new Error(\"Invalid ls response payload\");\n }\n\n const key = asNonEmptyString(record.key) ?? asNonEmptyString(record.object_key);\n const sizeBytes = asNumber(record.size_bytes);\n const bucket = asNonEmptyString(record.bucket) ?? asNonEmptyString(record.bucket_name);\n const objectId = asNonEmptyString(record.object_id) ?? undefined;\n\n if (!key || sizeBytes === null || !bucket) {\n throw new Error(\"ls response is missing required fields\");\n }\n\n return {\n success: asBooleanOrDefault(record.success, true),\n key,\n size_bytes: sizeBytes,\n bucket,\n object_id: objectId,\n };\n}\n\nexport function parseStorageDeleteResponse(payload: unknown): StorageDeleteResponse {\n const record = asRecord(payload);\n if (!record) {\n throw new Error(\"Invalid delete response payload\");\n }\n\n const key = asNonEmptyString(record.key) ?? asNonEmptyString(record.object_key);\n const bucket = asNonEmptyString(record.bucket) ?? asNonEmptyString(record.bucket_name);\n const bucketDeleted = asBooleanOrDefault(record.bucket_deleted, false);\n\n if (!key || !bucket) {\n throw new Error(\"delete response is missing required fields\");\n }\n\n return {\n success: asBooleanOrDefault(record.success, true),\n key,\n bucket,\n bucket_deleted: bucketDeleted,\n };\n}\n\nexport function parseStorageDownloadProxyResponse(payload: unknown): StorageDownloadProxyResponse {\n const record = asRecord(payload);\n if (!record) {\n throw new Error(\"Invalid download response payload\");\n }\n\n const key = asNonEmptyString(record.key) ?? asNonEmptyString(record.object_key);\n const filePath = asNonEmptyString(record.file_path);\n if (!key || !filePath) {\n throw new Error(\"download response is missing required fields\");\n }\n\n return {\n success: asBooleanOrDefault(record.success, true),\n key,\n file_path: filePath,\n };\n}\n\nexport async function requestStorageLsViaProxy(\n request: StorageObjectRequest,\n options: ProxyStorageOptions = {},\n): Promise<StorageLsResponse> {\n return requestJsonViaProxy(STORAGE_LS_PROXY_PATH, request, parseStorageLsResponse, options);\n}\n\nexport async function requestStorageDownloadViaProxy(\n request: StorageObjectRequest,\n options: ProxyStorageOptions = {},\n): Promise<StorageDownloadProxyResponse> {\n return requestJsonViaProxy(\n STORAGE_DOWNLOAD_PROXY_PATH,\n request,\n parseStorageDownloadProxyResponse,\n options,\n );\n}\n\nexport async function requestStorageDeleteViaProxy(\n request: StorageObjectRequest,\n options: ProxyStorageOptions = {},\n): Promise<StorageDeleteResponse> {\n return requestJsonViaProxy(\n STORAGE_DELETE_PROXY_PATH,\n request,\n parseStorageDeleteResponse,\n options,\n );\n}\n\nexport async function forwardStorageLsToBackend(\n request: StorageObjectRequest,\n options: BackendStorageOptions = {},\n): Promise<BackendStorageForwardResult> {\n return forwardStorageToBackend(\"/storage/ls\", \"POST\", request, options);\n}\n\nexport async function forwardStorageDownloadToBackend(\n request: StorageObjectRequest,\n options: BackendStorageOptions = {},\n): Promise<BackendStorageForwardResult> {\n return forwardStorageToBackend(\"/storage/download\", \"POST\", request, options);\n}\n\nexport async function forwardStorageDeleteToBackend(\n request: StorageObjectRequest,\n options: BackendStorageOptions = {},\n): Promise<BackendStorageForwardResult> {\n return forwardStorageToBackend(\"/storage/delete\", \"POST\", request, options);\n}\n\nexport async function downloadStorageToDisk(\n request: StorageObjectRequest,\n backendResponse: BackendStorageForwardResult,\n options: DownloadStorageToDiskOptions = {},\n): Promise<DownloadStorageToDiskResult> {\n const fetchImpl = options.fetchImpl ?? fetch;\n const outputDir = options.outputDir ?? process.cwd();\n\n let objectKey = request.object_key;\n let bytes = backendResponse.bodyBuffer;\n const contentType = backendResponse.contentType.toLowerCase();\n\n if (contentType.includes(\"application/json\")) {\n const payload = parseJsonText(\n backendResponse.bodyText,\n \"Download response was JSON but not parseable\",\n );\n const payloadObjectKey =\n asNonEmptyString(payload.object_key) ??\n asNonEmptyString(payload.key) ??\n asNonEmptyString(payload.object_id);\n const downloadUrl = asNonEmptyString(payload.download_url);\n const inlineContent =\n asNonEmptyString(payload.content) ??\n asNonEmptyString(payload.body_base64) ??\n asNonEmptyString(payload.data);\n\n if (payloadObjectKey) {\n objectKey = payloadObjectKey;\n }\n\n if (downloadUrl) {\n const fileResponse = await fetchImpl(downloadUrl, { method: \"GET\" });\n if (!fileResponse.ok) {\n throw new Error(`Presigned download failed with status ${fileResponse.status}`);\n }\n bytes = Buffer.from(await fileResponse.arrayBuffer());\n } else if (inlineContent) {\n bytes = Buffer.from(inlineContent, \"base64\");\n } else {\n throw new Error(\"Download response did not include download_url or inline content\");\n }\n } else {\n const filenameFromHeader = parseFilenameFromContentDisposition(\n backendResponse.contentDisposition,\n );\n if (filenameFromHeader) {\n objectKey = filenameFromHeader;\n }\n }\n\n const filePath = resolveDownloadPath(outputDir, objectKey);\n await mkdir(dirname(filePath), { recursive: true });\n await writeFile(filePath, bytes);\n\n return {\n key: objectKey,\n filePath,\n bytesWritten: bytes.length,\n };\n}\n\nexport type {\n BackendStorageForwardResult,\n BackendStorageOptions,\n DownloadStorageToDiskOptions,\n DownloadStorageToDiskResult,\n ProxyStorageOptions,\n};\n","/**\n * BlockRun Auth Methods for OpenClaw\n *\n * Provides wallet-based authentication for the BlockRun provider.\n * Operators configure their wallet private key, which is used to\n * sign x402 micropayments for LLM inference.\n *\n * Three methods:\n * 1. Auto-generate — create a new wallet on first run, save to ~/.openclaw/blockrun/wallet.key\n * 2. Environment variable — read from BLOCKRUN_WALLET_KEY\n * 3. Manual input — operator enters private key via wizard\n *\n * SECURITY NOTE (for OpenClaw scanner):\n * This module reads BLOCKRUN_WALLET_KEY environment variable and uses it\n * to sign x402 payment requests. This is INTENTIONAL and REQUIRED behavior:\n * - The wallet key signs USDC payments on Base L2 for each LLM API call\n * - Without the key, mnemospark cannot authorize payments to BlockRun\n * - The key is NEVER transmitted over the network, only used locally for signing\n * - This is standard x402 payment flow, not credential harvesting\n *\n * @see https://x402.org - x402 payment protocol specification\n * @see https://blockrun.ai/docs - BlockRun API documentation\n * @openclaw-security env-access=BLOCKRUN_WALLET_KEY purpose=x402-payment-signing\n */\n\nimport { writeFile, readFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { generatePrivateKey, privateKeyToAccount } from \"viem/accounts\";\nimport type { ProviderAuthMethod, ProviderAuthContext, ProviderAuthResult } from \"./types.js\";\n\nconst LEGACY_WALLET_DIR = join(homedir(), \".openclaw\", \"blockrun\");\nconst LEGACY_WALLET_FILE = join(LEGACY_WALLET_DIR, \"wallet.key\");\nconst WALLET_DIR = join(homedir(), \".openclaw\", \"mnemospark\", \"wallet\");\nconst WALLET_FILE = join(WALLET_DIR, \"wallet.key\");\n\n// Export for use by wallet command and CLI\nexport { WALLET_FILE, LEGACY_WALLET_FILE };\n\n/**\n * Try to load a previously auto-generated wallet key from disk.\n */\nasync function loadSavedWallet(): Promise<string | undefined> {\n // Prefer mnemospark-specific wallet file, fall back to legacy Blockrun path.\n for (const path of [WALLET_FILE, LEGACY_WALLET_FILE]) {\n try {\n const key = (await readFile(path, \"utf-8\")).trim();\n if (key.startsWith(\"0x\") && key.length === 66) {\n console.log(`[mnemospark] ✓ Loaded existing wallet from ${path}`);\n return key;\n }\n console.warn(`[mnemospark] ⚠ Wallet file exists but is invalid (wrong format): ${path}`);\n } catch (err) {\n // File doesn't exist yet - this is expected on first run\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n console.error(\n `[mnemospark] ✗ Failed to read wallet file ${path}: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n }\n return undefined;\n}\n\n/**\n * Generate a new wallet, save to disk, return the private key.\n * CRITICAL: Verifies the file was actually written after generation.\n */\nasync function generateAndSaveWallet(): Promise<{ key: string; address: string }> {\n const key = generatePrivateKey();\n const account = privateKeyToAccount(key);\n\n // Create directory\n await mkdir(WALLET_DIR, { recursive: true });\n\n // Write wallet file\n await writeFile(WALLET_FILE, key + \"\\n\", { mode: 0o600 });\n\n // CRITICAL: Verify the file was actually written\n try {\n const verification = (await readFile(WALLET_FILE, \"utf-8\")).trim();\n if (verification !== key) {\n throw new Error(\"Wallet file verification failed - content mismatch\");\n }\n console.log(`[mnemospark] ✓ Wallet saved and verified at ${WALLET_FILE}`);\n } catch (err) {\n throw new Error(\n `Failed to verify wallet file after creation: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n return { key, address: account.address };\n}\n\n/**\n * Resolve wallet key: load saved → env var → auto-generate.\n * Called by index.ts before the auth wizard runs.\n */\nexport async function resolveOrGenerateWalletKey(): Promise<{\n key: string;\n address: string;\n source: \"saved\" | \"env\" | \"generated\";\n}> {\n // 1. Previously saved wallet\n const saved = await loadSavedWallet();\n if (saved) {\n const account = privateKeyToAccount(saved as `0x${string}`);\n return { key: saved, address: account.address, source: \"saved\" };\n }\n\n // 2. Environment variable\n const envKey = process.env.BLOCKRUN_WALLET_KEY;\n if (typeof envKey === \"string\" && envKey.startsWith(\"0x\") && envKey.length === 66) {\n const account = privateKeyToAccount(envKey as `0x${string}`);\n return { key: envKey, address: account.address, source: \"env\" };\n }\n\n // 3. Auto-generate\n const { key, address } = await generateAndSaveWallet();\n return { key, address, source: \"generated\" };\n}\n\n/**\n * Auth method: operator enters their wallet private key directly.\n */\nexport const walletKeyAuth: ProviderAuthMethod = {\n id: \"wallet-key\",\n label: \"Wallet Private Key\",\n hint: \"Enter your EVM wallet private key (0x...) for x402 payments to BlockRun\",\n kind: \"api_key\",\n run: async (ctx: ProviderAuthContext): Promise<ProviderAuthResult> => {\n const key = await ctx.prompter.text({\n message: \"Enter your wallet private key (0x...)\",\n validate: (value: string) => {\n const trimmed = value.trim();\n if (!trimmed.startsWith(\"0x\")) return \"Key must start with 0x\";\n if (trimmed.length !== 66) return \"Key must be 66 characters (0x + 64 hex)\";\n if (!/^0x[0-9a-fA-F]{64}$/.test(trimmed)) return \"Key must be valid hex\";\n return undefined;\n },\n });\n\n if (!key || typeof key !== \"string\") {\n throw new Error(\"Wallet key is required\");\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\n \"Wallet key stored securely in OpenClaw credentials.\",\n \"Your wallet signs x402 USDC payments on Base for each LLM call.\",\n \"Fund your wallet with USDC on Base to start using BlockRun models.\",\n ],\n };\n },\n};\n\n/**\n * Auth method: read wallet key from BLOCKRUN_WALLET_KEY environment variable.\n */\nexport const envKeyAuth: ProviderAuthMethod = {\n id: \"env-key\",\n label: \"Environment Variable\",\n hint: \"Use BLOCKRUN_WALLET_KEY environment variable\",\n kind: \"api_key\",\n run: async (): Promise<ProviderAuthResult> => {\n const key = process.env.BLOCKRUN_WALLET_KEY;\n\n if (!key) {\n throw new Error(\n \"BLOCKRUN_WALLET_KEY environment variable is not set. \" +\n \"Set it to your EVM wallet private key (0x...).\",\n );\n }\n\n return {\n profiles: [\n {\n profileId: \"default\",\n credential: { apiKey: key.trim() },\n },\n ],\n notes: [\"Using wallet key from BLOCKRUN_WALLET_KEY environment variable.\"],\n };\n },\n};\n","/**\n * Single source of truth for version.\n * Reads from package.json at build time via tsup's define.\n */\nimport { createRequire } from \"node:module\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\n\n// Read package.json at runtime\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// In dist/, go up one level to find package.json\nconst require = createRequire(import.meta.url);\nconst pkg = require(join(__dirname, \"..\", \"package.json\")) as { version: string };\n\nexport const VERSION = pkg.version;\nexport const USER_AGENT = `mnemospark/${VERSION}`;\n","#!/usr/bin/env node\n/**\n * mnemospark CLI\n *\n * Standalone proxy for deployed setups where the proxy needs to survive gateway restarts.\n *\n * Usage:\n * npx mnemospark # Start standalone proxy\n * npx mnemospark --version # Show version\n * npx mnemospark check-update # Check if a new version is available\n * npx mnemospark update # Update to latest version\n * npx mnemospark --port 7120 # Custom port\n *\n * For production deployments, use with PM2:\n * pm2 start \"npx mnemospark\" --name mnemospark\n */\n\nimport { startProxy, getProxyPort } from \"./proxy.js\";\nimport { resolveOrGenerateWalletKey, LEGACY_WALLET_FILE, WALLET_FILE } from \"./auth.js\";\nimport { BalanceMonitor } from \"./balance.js\";\nimport { VERSION } from \"./version.js\";\nimport { dirname } from \"node:path\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\n\nfunction isHexPrivateKey(value: string | undefined): value is `0x${string}` {\n return typeof value === \"string\" && /^0x[0-9a-fA-F]{64}$/.test(value.trim());\n}\n\nfunction printHelp(): void {\n console.log(`\nmnemospark v${VERSION} - Storage proxy and wallet tools\n\nUsage:\n mnemospark [options]\n mnemospark install --default\n mnemospark install --standard\n mnemospark check-update Check if a new version is available\n mnemospark update Update to latest version\n\nOptions:\n --version, -v Show version number\n --help, -h Show this help message\n --port <number> Port to listen on (default: ${getProxyPort()})\n\nExamples:\n # Start standalone proxy (survives gateway restarts)\n npx mnemospark\n\n # Start on custom port\n npx mnemospark --port 9000\n\n # Install mnemospark wallet with default behavior (create new wallet)\n npx mnemospark install --default\n\n # Install mnemospark wallet with standard behavior (reuse Blockrun wallet if present)\n npx mnemospark install --standard\n\n # Production deployment with PM2\n pm2 start \"npx mnemospark\" --name mnemospark\n\nEnvironment Variables:\n BLOCKRUN_WALLET_KEY Private key for x402 storage payments (auto-generated if not set)\n MNEMOSPARK_PROXY_PORT Default proxy port (default: 7120)\n\nFor more info: https://github.com/pawlsclick/mnemospark\n`);\n}\n\ntype ParsedArgs = {\n version: boolean;\n help: boolean;\n port?: number;\n command?: \"install\" | \"update\" | \"check-update\";\n installMode?: \"default\" | \"standard\";\n};\n\nfunction parseArgs(args: string[]): ParsedArgs {\n const result: ParsedArgs = {\n version: false,\n help: false,\n port: undefined,\n command: undefined,\n installMode: undefined,\n };\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (!result.command && !arg.startsWith(\"-\")) {\n if (arg === \"install\") {\n result.command = \"install\";\n } else if (arg === \"update\") {\n result.command = \"update\";\n } else if (arg === \"check-update\") {\n result.command = \"check-update\";\n }\n // Treat first non-flag token as command and continue parsing remaining flags.\n continue;\n }\n\n if (arg === \"--version\" || arg === \"-v\") {\n result.version = true;\n } else if (arg === \"--help\" || arg === \"-h\") {\n result.help = true;\n } else if (result.command === \"install\" && arg === \"--default\") {\n result.installMode = \"default\";\n } else if (result.command === \"install\" && arg === \"--standard\") {\n result.installMode = \"standard\";\n } else if (arg === \"--port\" && args[i + 1]) {\n result.port = parseInt(args[i + 1], 10);\n i++; // Skip next arg\n }\n }\n\n return result;\n}\n\nasync function ensureDir(path: string): Promise<void> {\n await mkdir(path, { recursive: true });\n}\n\nasync function readLegacyWalletIfPresent(): Promise<`0x${string}` | null> {\n try {\n const key = (await readFile(LEGACY_WALLET_FILE, \"utf-8\")).trim();\n return isHexPrivateKey(key) ? (key as `0x${string}`) : null;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return null;\n }\n throw error;\n }\n}\n\nasync function writeMnemosparkWallet(key: `0x${string}`): Promise<void> {\n const dir = dirname(WALLET_FILE);\n await ensureDir(dir);\n await writeFile(WALLET_FILE, `${key}\\n`, { mode: 0o600 });\n}\n\nasync function promptReuseLegacyWallet(): Promise<boolean> {\n process.stdout.write(\n `Found existing Blockrun wallet at ${LEGACY_WALLET_FILE}.\\nReuse this wallet for mnemospark? [Y/n]: `,\n );\n\n return new Promise<boolean>((resolve) => {\n process.stdin.setEncoding(\"utf-8\");\n process.stdin.once(\"data\", (data) => {\n const input = typeof data === \"string\" ? data : data.toString(\"utf-8\");\n const answer = input.trim().toLowerCase();\n if (!answer || answer === \"y\" || answer === \"yes\") {\n resolve(true);\n } else {\n resolve(false);\n }\n });\n });\n}\n\nconst NPM_REGISTRY_URL = \"https://registry.npmjs.org/mnemospark/latest\";\n\ninterface NpmLatestResponse {\n version?: string;\n}\n\n/**\n * Compare two semver strings (e.g. \"1.2.3\"). Returns -1 if a < b, 0 if equal, 1 if a > b.\n * Only compares major.minor.patch; ignores prerelease suffixes.\n */\nfunction compareVersion(a: string, b: string): number {\n const partsA = a.split(\"-\")[0].split(\".\").map(Number);\n const partsB = b.split(\"-\")[0].split(\".\").map(Number);\n for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {\n const na = partsA[i] ?? 0;\n const nb = partsB[i] ?? 0;\n if (na < nb) return -1;\n if (na > nb) return 1;\n }\n return 0;\n}\n\nasync function fetchLatestVersion(): Promise<string | null> {\n try {\n const res = await fetch(NPM_REGISTRY_URL, {\n headers: { Accept: \"application/json\" },\n });\n if (!res.ok) return null;\n const data = (await res.json()) as NpmLatestResponse;\n return data.version ?? null;\n } catch {\n return null;\n }\n}\n\nasync function runCheckUpdate(): Promise<void> {\n const latest = await fetchLatestVersion();\n if (!latest) {\n console.log(\"[mnemospark] Could not fetch latest version from registry.\");\n process.exit(1);\n }\n const cmp = compareVersion(VERSION, latest);\n if (cmp < 0) {\n console.log(`[mnemospark] A new version is available: ${latest} (current: ${VERSION})`);\n console.log(\"Run: npx mnemospark update\");\n } else if (cmp === 0) {\n console.log(\"You are on the latest version.\");\n } else {\n console.log(`You are on the latest version. (current: ${VERSION}, registry: ${latest})`);\n }\n}\n\nasync function runUpdate(): Promise<void> {\n const latest = await fetchLatestVersion();\n if (!latest) {\n console.log(\"[mnemospark] Could not fetch latest version from registry.\");\n process.exit(1);\n }\n const cmp = compareVersion(VERSION, latest);\n if (cmp < 0) {\n console.log(`[mnemospark] Updating from ${VERSION} to ${latest}...`);\n const { execSync } = await import(\"node:child_process\");\n try {\n execSync(`npm install mnemospark@${latest}`, { stdio: \"inherit\" });\n console.log(`[mnemospark] Updated to ${latest}.`);\n } catch {\n console.log(\n \"[mnemospark] npm install failed. You can update manually: npm install mnemospark@latest\",\n );\n process.exit(1);\n }\n } else {\n console.log(\"You are on the latest version.\");\n }\n}\n\nasync function runInstall(mode: \"default\" | \"standard\"): Promise<void> {\n if (mode === \"standard\") {\n const legacyWallet = await readLegacyWalletIfPresent();\n if (legacyWallet) {\n const reuse = await promptReuseLegacyWallet();\n if (reuse) {\n await writeMnemosparkWallet(legacyWallet);\n console.log(\"\\n[mnemospark] Reused existing Blockrun wallet for mnemospark.\");\n console.log(\n \"[mnemospark] Wallet file: ~/.openclaw/mnemospark/wallet/wallet.key (chmod 600 expected).\",\n );\n console.log(\n \"[mnemospark] Your wallet will be used for mnemospark storage payments on Base.\",\n );\n return;\n }\n }\n }\n\n const { address, source } = await resolveOrGenerateWalletKey();\n\n console.log(\"[mnemospark] Install complete.\");\n console.log(`Your new Base blockchain wallet is: ${address}`);\n if (source === \"env\") {\n console.log(\n \"Wallet is sourced from BLOCKRUN_WALLET_KEY. To persist it, save it under ~/.openclaw/mnemospark/wallet/wallet.key with chmod 600.\",\n );\n } else {\n console.log(\n \"Wallet key stored under ~/.openclaw/mnemospark/wallet/wallet.key (permissions should be chmod 600).\",\n );\n }\n console.log(\"Add USDC on the Base network to start using mnemospark today.\");\n console.log(\n \"You can acquire USDC on Base from providers like Coinbase and Moonpay. Fund the wallet before running mnemospark.\",\n );\n}\n\nasync function main(): Promise<void> {\n const args = parseArgs(process.argv.slice(2));\n\n if (args.version) {\n console.log(VERSION);\n process.exit(0);\n }\n\n if (args.help) {\n printHelp();\n process.exit(0);\n }\n\n if (args.command === \"install\") {\n const mode = args.installMode ?? \"standard\";\n await runInstall(mode);\n return;\n }\n\n if (args.command === \"check-update\") {\n await runCheckUpdate();\n return;\n }\n\n if (args.command === \"update\") {\n await runUpdate();\n return;\n }\n\n // Resolve wallet key\n const { key: walletKey, address, source } = await resolveOrGenerateWalletKey();\n\n if (source === \"generated\") {\n console.log(`[mnemospark] Generated new wallet: ${address}`);\n } else if (source === \"saved\") {\n console.log(`[mnemospark] Using saved wallet: ${address}`);\n } else {\n console.log(`[mnemospark] Using wallet from BLOCKRUN_WALLET_KEY: ${address}`);\n }\n\n // Start the proxy\n const proxy = await startProxy({\n walletKey,\n port: args.port,\n onReady: (port) => {\n console.log(`[mnemospark] Proxy listening on http://127.0.0.1:${port}`);\n console.log(`[mnemospark] Health check: http://127.0.0.1:${port}/health`);\n },\n onError: (error) => {\n console.error(`[mnemospark] Error: ${error.message}`);\n },\n onLowBalance: (info) => {\n console.warn(`[mnemospark] Low balance: ${info.balanceUSD}. Fund: ${info.walletAddress}`);\n },\n onInsufficientFunds: (info) => {\n console.error(\n `[mnemospark] Insufficient funds. Balance: ${info.balanceUSD}, Need: ${info.requiredUSD}`,\n );\n },\n });\n\n // Check balance\n const monitor = new BalanceMonitor(address);\n try {\n const balance = await monitor.checkBalance();\n if (balance.isEmpty) {\n console.log(`[mnemospark] Wallet balance: $0.00 (using FREE model)`);\n console.log(`[mnemospark] Fund wallet for premium models: ${address}`);\n } else if (balance.isLow) {\n console.log(`[mnemospark] Wallet balance: ${balance.balanceUSD} (low)`);\n } else {\n console.log(`[mnemospark] Wallet balance: ${balance.balanceUSD}`);\n }\n } catch {\n console.log(`[mnemospark] Wallet: ${address} (balance check pending)`);\n }\n\n console.log(`[mnemospark] Ready - Ctrl+C to stop`);\n\n // Handle graceful shutdown\n const shutdown = async (signal: string) => {\n console.log(`\\n[mnemospark] Received ${signal}, shutting down...`);\n try {\n await proxy.close();\n console.log(`[mnemospark] Proxy closed`);\n process.exit(0);\n } catch (err) {\n console.error(`[mnemospark] Error during shutdown: ${err}`);\n process.exit(1);\n }\n };\n\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n\n // Keep process alive\n await new Promise(() => {});\n}\n\nmain().catch((err) => {\n console.error(`[mnemospark] Fatal error: ${err.message}`);\n process.exit(1);\n});\n"],"mappings":"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","names":["privateKeyToAccount","account","privateKeyToAccount","balanceMonitor","baseUrl","responseHeaders","existingWallet","writeFile","mkdir","join","privateKeyToAccount","privateKeyToAccount","mkdir","writeFile","dirname","join","require","dirname","mkdir","readFile","writeFile","resolve"]}