import { createRequire as __tmCreateRequire } from 'node:module'; import { fileURLToPath as __tmFileURLToPath } from 'node:url'; import { dirname as __tmDirname } from 'node:path'; const require = __tmCreateRequire(import.meta.url); const __tmFilename = __tmFileURLToPath(import.meta.url); const __tmDirnameValue = __tmDirname(__tmFilename); import { IDEMPOTENCY_KEY_HEADER, NetworkInfoSchema, apiErrorEnvelopeOf, buildLegalReceiptHeaders, getTaskmarketHome, isInFlightApiError, paymentProtocolFor, taskmarketChain, verifierProviderId } from "./chunk-RY4U7U45.js"; // src/lib/idempotency.ts import { randomUUID } from "crypto"; var pendingEnvKey = process.env.TASKMARKET_IDEMPOTENCY_KEY?.trim() || void 0; var keyByError = /* @__PURE__ */ new WeakMap(); function rememberIdempotencyKeyFor(error, key) { if (error === null || typeof error !== "object" && typeof error !== "function") return; if (keyByError.has(error)) return; keyByError.set(error, key); } function idempotencyKeyForError(error) { if (error === null || typeof error !== "object" && typeof error !== "function") return void 0; return keyByError.get(error); } function newIdempotencyKey() { return randomUUID(); } function resolveIdempotencyKey(explicit) { if (explicit !== void 0) { return explicit; } if (pendingEnvKey !== void 0) { const fromEnv = pendingEnvKey; pendingEnvKey = void 0; return fromEnv; } return newIdempotencyKey(); } async function withIdempotentWrite(key, fn) { try { return await fn(); } catch (error) { rememberIdempotencyKeyFor(error, key); throw error; } } function idempotencyHeaders(key) { return { [IDEMPOTENCY_KEY_HEADER]: key }; } // src/lib/keystore.ts import { createCipheriv, createDecipheriv, randomBytes } from "crypto"; import { promises as fs } from "fs"; import path from "path"; import { privateKeyToAccount } from "viem/accounts"; function getKeystorePath() { return path.join(getTaskmarketHome(), "keystore.json"); } function generateKeypair() { const keyBytes = randomBytes(32); const privateKey = "0x" + keyBytes.toString("hex"); const account = privateKeyToAccount(privateKey); return { privateKey, address: account.address }; } function encryptPrivateKey(deviceEncryptionKeyHex, privateKey) { const key = Buffer.from(deviceEncryptionKeyHex, "hex"); const iv = randomBytes(12); const cipher = createCipheriv("aes-256-gcm", key, iv); const plaintext = Buffer.from(privateKey, "utf8"); const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]); const tag = cipher.getAuthTag(); return Buffer.concat([iv, tag, encrypted]).toString("hex"); } function decryptPrivateKey(deviceEncryptionKeyHex, encryptedHex) { const key = Buffer.from(deviceEncryptionKeyHex, "hex"); const data = Buffer.from(encryptedHex, "hex"); const iv = data.subarray(0, 12); const tag = data.subarray(12, 28); const ciphertext = data.subarray(28); const decipher = createDecipheriv("aes-256-gcm", key, iv); decipher.setAuthTag(tag); const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]); return decrypted.toString("utf8"); } async function saveKeystore(keystore, keystorePath) { const p = keystorePath ?? getKeystorePath(); await fs.mkdir(path.dirname(p), { recursive: true }); await fs.writeFile(p, JSON.stringify(keystore, null, 2), { encoding: "utf8", mode: 384 }); await fs.chmod(p, 384); } var KeystoreExistsError = class extends Error { constructor(keystorePath) { super(`A keystore already exists at ${keystorePath}.`); this.name = "KeystoreExistsError"; } }; async function createKeystore(keystore, keystorePath) { const p = keystorePath ?? getKeystorePath(); await fs.mkdir(path.dirname(p), { recursive: true }); try { await fs.writeFile(p, JSON.stringify(keystore, null, 2), { encoding: "utf8", mode: 384, flag: "wx" }); } catch (error) { if (error.code === "EEXIST") throw new KeystoreExistsError(p); throw error; } } async function loadKeystore(keystorePath) { const p = keystorePath ?? getKeystorePath(); let data; try { data = await fs.readFile(p, "utf8"); } catch { throw new Error(`Keystore not found at ${p}. Run 'taskmarket init' first.`); } return JSON.parse(data); } async function keystoreExists(keystorePath) { const p = keystorePath ?? getKeystorePath(); try { await fs.access(p); return true; } catch { return false; } } async function readKeystoreNetwork(keystorePath) { try { const keystore = JSON.parse( await fs.readFile(keystorePath ?? getKeystorePath(), "utf8") ); return typeof keystore.network === "string" ? keystore.network : void 0; } catch { return void 0; } } // src/lib/network.ts var NETWORK_NAMES = [ "base", "base-sepolia", "tempo", "tempo-testnet", "robinhood", "robinhood-testnet", "solana", "solana-devnet" ]; var PRODUCTION_API_URL = "https://api.taskmarket.dev"; var TESTNET_API_URL = "https://testnet-api-market.daydreams.systems"; var NETWORKS = { base: { name: "base", apiUrl: PRODUCTION_API_URL, chainId: 8453, available: true }, "base-sepolia": { name: "base-sepolia", apiUrl: TESTNET_API_URL, chainId: 84532, available: true }, tempo: { name: "tempo", apiUrl: PRODUCTION_API_URL, chainId: 4217, available: true }, "tempo-testnet": { name: "tempo-testnet", apiUrl: TESTNET_API_URL, chainId: 42431, available: true }, // Robinhood Chain serves Sponsored Tasks only. Whether a chain is served is the API's own // per-chain setting (ADR-0327): `chainInfoFor` refuses one its network.info does not list. robinhood: { name: "robinhood", apiUrl: PRODUCTION_API_URL, chainId: 4663, available: true }, "robinhood-testnet": { name: "robinhood-testnet", apiUrl: TESTNET_API_URL, chainId: 46630, available: true }, // Solana runs Sponsored Tasks only; its API requests name the Base chain of the same network. solana: { name: "solana", apiUrl: PRODUCTION_API_URL, chainId: 8453, available: true, solana: { chainId: 101, cluster: "mainnet-beta" } }, "solana-devnet": { name: "solana-devnet", apiUrl: TESTNET_API_URL, chainId: 84532, available: true, solana: { chainId: 103, cluster: "devnet" } } }; var SPONSORED_ONLY_COMMANDS = ["sponsored-task", "wallet", "address"]; function coreNetworkNames() { return liveNetworkNames().filter( (name) => !NETWORKS[name].solana && taskmarketChain(NETWORKS[name].chainId).isCore ); } function assertNetworkServesCommand(network, command) { if (!network || !network.solana && taskmarketChain(network.chainId).isCore) return; if (SPONSORED_ONLY_COMMANDS.includes(command)) return; const name = network.solana ? `Solana (${network.name})` : taskmarketChain(network.chainId).name; throw new Error( `${name} serves Sponsored Tasks only: \`taskmarket ${command}\` needs a core network (${coreNetworkNames().join(", ")}). On --network ${network.name}, use: ${SPONSORED_ONLY_COMMANDS.join(", ")}.` ); } function networkNameForChain(chainId) { return NETWORK_NAMES.find( (name) => NETWORKS[name].solana ? NETWORKS[name].solana.chainId === chainId : NETWORKS[name].chainId === chainId ); } function taskmarketCommandFor(chainId) { const name = networkNameForChain(chainId); return name ? `taskmarket --network ${name}` : "taskmarket"; } function isNetworkName(value) { return NETWORK_NAMES.includes(value); } function getNetwork(nameOrChainId) { const raw = nameOrChainId.trim().toLowerCase(); const name = /^\d+$/.test(raw) ? networkNameForChain(Number(raw)) ?? raw : raw; if (!isNetworkName(name)) { throw new Error( `Unknown network '${name}'. Expected one of: ${NETWORK_NAMES.join(", ")}, or its chain id.` ); } const network = NETWORKS[name]; if (!network.available) { const live = liveNetworkNames().join(", "); throw new Error( `${network.unavailableMessage ?? `Network '${name}' is not available yet.`} Choose one of: ${live}.` ); } return network; } function liveNetworkNames() { return NETWORK_NAMES.filter((n) => NETWORKS[n].available); } var NetworkRequiredError = class extends Error { code = "network_required"; constructor() { super( `No network selected. The CLI has no default network: pass --network or set TASKMARKET_NETWORK (one of: ${liveNetworkNames().join(", ")}).` ); this.name = "NetworkRequiredError"; } }; function resolveNetwork(sources) { const name = sources.flag || sources.env || sources.keystore; return name ? getNetwork(name) : void 0; } var selected; function setSelectedNetwork(network) { selected = network; } function selectedNetworkOrUndefined() { return selected ?? resolveNetwork({ env: process.env.TASKMARKET_NETWORK }); } function selectedNetwork() { const network = selectedNetworkOrUndefined(); if (!network) throw new NetworkRequiredError(); return network; } function withChainId(path2, chainId = selectedNetwork().chainId) { return `${path2}${path2.includes("?") ? "&" : "?"}chainId=${chainId}`; } function apiUrl() { return process.env.TASKMARKET_API_URL || selectedNetwork().apiUrl; } function paymentProtocolOf(chainId) { return paymentProtocolFor(taskmarketChain(chainId).payment.method); } function apiOrigin() { return new URL(apiUrl()).origin; } function networkToStamp() { return process.env.TASKMARKET_API_URL ? void 0 : selectedNetwork().name; } function chainInfoFor(raw, chainId) { const full = NetworkInfoSchema.safeParse(raw); if (!full.success) return void 0; const chain = full.data.chains.find((entry) => entry.chainId === chainId); if (chain) return chain; const selected2 = selectedNetworkOrUndefined(); const subject = selected2?.chainId === chainId ? `network "${selected2.name}" (chain ${chainId})` : `chain ${chainId}`; const served = full.data.chains.map((entry) => entry.chainId).join(", "); throw new Error( `The selected ${subject} is not available: the API at ${process.env.TASKMARKET_API_URL || selected2?.apiUrl || "the selected URL"} does not serve it (it serves chain ${served}). Choose a network it serves with --network, or point TASKMARKET_API_URL at an API that serves this one.` ); } // src/lib/tap.ts import { constants, createPrivateKey, createHash, createPublicKey, generateKeyPairSync, randomBytes as randomBytes2, sign as cryptoSign } from "crypto"; // src/lib/signer.ts import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts"; async function fetchDeviceKey(deviceId, apiToken, keyServerUrl) { const base = keyServerUrl ?? apiUrl(); const res = await fetch(`${base}/api/devices/${deviceId}/key`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ deviceId, apiToken }) }); if (!res.ok) { const text = await res.text().catch(() => ""); throw new Error(`Failed to fetch device key (${res.status}): ${text}`); } const data = await res.json(); return data.deviceEncryptionKey; } async function signTypedData(typedData, keystore) { const account = await createWalletAccountFromKeystore(keystore); const sig = await account.signTypedData(typedData); return sig; } async function signMessage(message, keystore) { const account = await createWalletAccountFromKeystore(keystore); const sig = await account.signMessage({ message }); return sig; } async function createWalletAccountFromKeystore(keystore) { const dek = await fetchDeviceKey(keystore.deviceId, keystore.apiToken, keystore.keyServerUrl); const privateKey = decryptPrivateKey(dek, keystore.encryptedKey); return privateKeyToAccount2(privateKey); } async function getWalletAddress() { const keystore = await loadKeystore(); return keystore.walletAddress; } // src/lib/tap.ts var TAP_ALGORITHMS = ["ed25519", "rsa-pss-sha256", "rsa-pss-sha512"]; var TAP_MAX_LIFETIME_SECONDS = 8 * 60;