@ghostlytools/cli 1.2.3 → 1.2.4

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.
@@ -1,4 +1,4 @@
1
- import { Un as engineError, an as SEPOLIA_TEST_USDT_FAUCET, fn as validatePaymentTarget, in as SEPOLIA_TEST_USDT, on as TEST_USDT_FAUCET_AMOUNT, rn as PaymentPreflightError, sn as USDT_PUBLIC_RPC, tn as EVM_TEST_CHAINS } from "./src-_FzJkeAJ.js";
1
+ import { Un as engineError, an as SEPOLIA_TEST_USDT_FAUCET, fn as validatePaymentTarget, in as SEPOLIA_TEST_USDT, on as TEST_USDT_FAUCET_AMOUNT, rn as PaymentPreflightError, sn as USDT_PUBLIC_RPC, tn as EVM_TEST_CHAINS } from "./src-CbLkHfz8.js";
2
2
  import { F as sealSeed, I as unsealSeed, h as rpcHost, m as networkReason } from "../ghostly.mjs";
3
3
  import { mnemonicToSeedSync } from "@scure/bip39";
4
4
  import WalletManagerEvm from "@tetherto/wdk-wallet-evm";
@@ -407,4 +407,4 @@ var UsdtAdapter = class UsdtAdapter {
407
407
  //#endregion
408
408
  export { UsdtAdapter, wireProvider };
409
409
 
410
- //# sourceMappingURL=usdt-D0lO2pRR.js.map
410
+ //# sourceMappingURL=usdt-Qf4UuygS.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"usdt-D0lO2pRR.js","names":[],"sources":["../../../browser/src/engine/paymentAdapters/usdt.ts"],"sourcesContent":["import { mnemonicToSeedSync } from '@scure/bip39';\nimport WalletManagerEvm, { type WalletAccountEvm } from '@tetherto/wdk-wallet-evm';\nimport { Interface, Transaction, getAddress, keccak256 } from 'ethers';\nimport { ETHEREUM_USDT, EVM_TEST_CHAINS, USDT_PUBLIC_RPC, SEPOLIA_TEST_USDT, SEPOLIA_TEST_USDT_FAUCET, TEST_USDT_FAUCET_AMOUNT, PaymentPreflightError, engineError, validatePaymentTarget, type PaymentAdapter, type PaymentExecution, type PaymentReview, type PaymentTarget } from '@ghostly/core';\nimport { sealSeed, unsealSeed, type EncryptedSeed } from './persistence';\nimport { networkReason, rpcHost } from './networkReason';\n\nexport interface UsdtConfig {\n network: 'ethereum' | 'sepolia' | 'evm-local';\n provider: string;\n chainId: 1 | 11155111 | 31337;\n token: string;\n decimals: number;\n codeHash: string;\n}\nexport interface UsdtPrepared {\n from: string; to: string; data: string; value: string; chainId: number; nonce: number;\n gasLimit: string; maxFeePerGas: string; maxPriorityFeePerGas: string;\n signed?: EncryptedSeed; hash?: string;\n}\nconst faucet = new Interface(['function mint(address token,address to,uint256 amount) returns (uint256)']);\nconst erc20 = new Interface(['function decimals() view returns(uint8)', 'function balanceOf(address) view returns(uint256)', 'function transfer(address,uint256) returns(bool)', 'event Transfer(address indexed from,address indexed to,uint256 value)']);\nconst same = (a: string, b: string) => a.toLowerCase() === b.toLowerCase();\nconst CONFIRMATIONS = 2;\n/** The JSON-RPC methods that only read: asked again once when they fail (see `UsdtAdapter.rpc`). */\nconst RETRIED_READS = new Set(['eth_chainId', 'eth_getCode', 'eth_call', 'eth_getBalance', 'eth_blockNumber', 'eth_getLogs', 'eth_getTransactionCount', 'eth_estimateGas', 'eth_getBlockByNumber', 'eth_maxPriorityFeePerGas', 'eth_gasPrice', 'eth_feeHistory', 'eth_getTransactionByHash', 'eth_getTransactionReceipt']);\nconst RETRY_AFTER_MS = 1000;\n/** Failures that would fail the same way again at once: not retried. */\nconst FINAL = new WeakSet<object>();\nconst timedOut = (error: unknown) => error instanceof Error && (error.name === 'AbortError' || error.name === 'TimeoutError');\n\n/**\n * The `provider` a request carries to the contact. Which RPC pays is the payer's own choice, so it names none of\n * this wallet's: a typed RPC URL may hold an API key (`/v3/<key>`), and every contact would read it. Older apps\n * require a URL here and pay only when it equals their own RPC, so it is the chain's public RPC (the default both\n * start with), and a local test chain's origin, without its path.\n */\nexport function wireProvider(config: Pick<UsdtConfig, 'network' | 'provider'>): string {\n return config.network === 'evm-local' ? new URL(config.provider).origin : USDT_PUBLIC_RPC[config.network];\n}\n\n/** WDK signs locally. Every network call uses the configured RPC, never a peer-supplied URL. */\nexport class UsdtAdapter implements PaymentAdapter<UsdtPrepared> {\n readonly method = 'usdt' as const;\n private manager?: WalletManagerEvm;\n private account?: WalletAccountEvm;\n private mnemonic = '';\n private nextId = 0;\n private queue: Promise<unknown> = Promise.resolve();\n private constructor(readonly config: UsdtConfig) {}\n\n static async inspect(config: Omit<UsdtConfig, 'decimals' | 'codeHash'>): Promise<UsdtConfig> {\n if (config.network === 'ethereum' ? config.chainId !== 1 || !same(config.token, ETHEREUM_USDT) : !(config.network in EVM_TEST_CHAINS) || config.chainId !== EVM_TEST_CHAINS[config.network]) throw new Error('Unsupported USDT network or contract');\n const token = getAddress(config.token);\n const url = new URL(config.provider);\n if (url.username || url.password || url.search || url.hash || (url.protocol !== 'https:' && !(url.protocol === 'http:' && ['localhost','127.0.0.1','[::1]'].includes(url.hostname)))) throw new Error('Use HTTPS or a loopback test RPC');\n const adapter = new UsdtAdapter({...config, token, decimals: 6, codeHash: ''});\n await adapter.chain();\n const code = await adapter.rpc<string>('eth_getCode', [token, 'latest']);\n if (code === '0x') throw new Error('No token contract exists on this chain');\n const result = await adapter.rpc<string>('eth_call', [{to: token, data: erc20.encodeFunctionData('decimals')}, 'latest']);\n const decimals = Number(erc20.decodeFunctionResult('decimals', result)[0]);\n if (!Number.isInteger(decimals) || decimals < 0 || decimals > 18 || (config.chainId === 1 && decimals !== 6)) throw new Error('Unexpected token decimals');\n return {...config, token, decimals, codeHash: keccak256(code)};\n }\n static async connect(config: UsdtConfig, mnemonic: string): Promise<UsdtAdapter> {\n const inspected = await UsdtAdapter.inspect(config);\n if (inspected.decimals !== config.decimals || inspected.codeHash !== config.codeHash) throw new Error('Token metadata changed; do not use this wallet configuration');\n const adapter = new UsdtAdapter(config);\n adapter.mnemonic = mnemonic;\n // Pass standard BIP-39 seed bytes: WDK's string helper assumes a Node Buffer global.\n const seed = mnemonicToSeedSync(mnemonic);\n try { adapter.manager = new WalletManagerEvm(seed, {provider: {request: ({method, params}) => adapter.rpc(method, params as unknown[] ?? [])}, chainId: config.chainId}); } finally { seed.fill(0); }\n adapter.account = await adapter.manager.getAccount(0);\n return adapter;\n }\n /**\n * A read that fails is asked again, once, a moment later: a public RPC drops a request now and then, and a chain that\n * just made a block can refuse a read of \"latest\" it no longer holds. Without it a network switch, a restore or New\n * gave up on the first such answer. Never a broadcast or anything else that writes, nor a request that did not answer\n * in time (the person would wait twice as long), nor one the server refused as such (4xx).\n */\n async rpc<T>(method: string, params: unknown[] = []): Promise<T> {\n try { return await this.ask<T>(method, params); }\n catch (error) {\n if (!RETRIED_READS.has(method) || FINAL.has(error as object)) throw error;\n await new Promise((resolve) => setTimeout(resolve, RETRY_AFTER_MS));\n return this.ask<T>(method, params);\n }\n }\n private async ask<T>(method: string, params: unknown[]): Promise<T> {\n let response: Response;\n // The browser's words for a request that got no answer (\"Fetch is aborted\") say nothing: the RPC's host does.\n try { response = await fetch(this.config.provider, {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({jsonrpc:'2.0',id:++this.nextId,method,params}), signal:AbortSignal.timeout(15000)}); }\n catch (error) {\n const reason = networkReason(error, rpcHost(this.config.provider));\n const thrown = reason ? Object.assign(new Error(reason), {cause: error}) : error;\n if (timedOut(error) && thrown && typeof thrown === 'object') FINAL.add(thrown);\n throw thrown;\n }\n if (!response.ok) { const error = engineError('usdtRpcUnavailable'); if (response.status !== 429 && response.status < 500) FINAL.add(error); throw error; }\n const result = await response.json();\n if (result.error || !Object.prototype.hasOwnProperty.call(result, 'result')) throw new Error('USDT RPC rejected the operation');\n return result.result as T;\n }\n private async chain() {\n if (BigInt(await this.rpc<string>('eth_chainId')) !== BigInt(this.config.chainId)) throw new Error('RPC chain does not match this wallet');\n }\n private async assertToken() {\n await this.chain();\n const code = await this.rpc<string>('eth_getCode', [this.config.token, 'latest']);\n if (code === '0x' || keccak256(code) !== this.config.codeHash) throw new Error('Token contract changed');\n }\n /**\n * Sepolia only: asks Aave's public faucet for test USDT, to this wallet, paid with its own test ETH.\n * Everything is fixed here (chain, contract, token, amount, recipient): nothing comes from outside.\n */\n mintTestTokens(): Promise<string> { return this.serial(async () => {\n if (this.config.chainId !== EVM_TEST_CHAINS.sepolia || !same(this.config.token, SEPOLIA_TEST_USDT)) throw new Error('Test USDT comes from a faucet on Sepolia only');\n await this.chain();\n const account = this.current(), from = await account.getAddress();\n const data = faucet.encodeFunctionData('mint', [SEPOLIA_TEST_USDT, from, BigInt(TEST_USDT_FAUCET_AMOUNT)]);\n const nonce = Number(BigInt(await this.rpc<string>('eth_getTransactionCount', [from, 'pending'])));\n const estimate = BigInt(await this.rpc<string>('eth_estimateGas', [{ from, to: SEPOLIA_TEST_USDT_FAUCET, data, value: '0x0' }]));\n const block = await this.rpc<{ baseFeePerGas?: string }>('eth_getBlockByNumber', ['latest', false]);\n if (!block.baseFeePerGas) throw new Error('This wallet requires an EIP-1559 chain');\n const priority = BigInt(await this.rpc<string>('eth_maxPriorityFeePerGas'));\n const maxFeePerGas = BigInt(block.baseFeePerGas) * 2n + priority, gasLimit = (estimate * 120n + 99n) / 100n;\n if (BigInt((await this.balances()).gasBalance) < gasLimit * maxFeePerGas) throw engineError('usdtNeedsSepoliaGas');\n const raw = await account.signTransaction({ type: 2, to: SEPOLIA_TEST_USDT_FAUCET, data, value: 0n, chainId: this.config.chainId, nonce, gasLimit, maxFeePerGas, maxPriorityFeePerGas: priority });\n await account.sendTransaction(raw);\n return Transaction.from(raw).hash!;\n }); }\n private current(): WalletAccountEvm { if (!this.account) throw new Error('Unlock the USDT wallet first'); return this.account; }\n address() { return this.current().getAddress(); }\n async balances() {\n await this.assertToken();\n const address = await this.address();\n const [token, gas] = await Promise.all([this.rpc<string>('eth_call',[{to:this.config.token,data:erc20.encodeFunctionData('balanceOf',[address])},'latest']),this.rpc<string>('eth_getBalance',[address,'pending'])]);\n return {balance:erc20.decodeFunctionResult('balanceOf',token)[0].toString(),gasBalance:BigInt(gas).toString()};\n }\n async target(): Promise<PaymentTarget> {\n const now = Date.now();\n return {method:'usdt',network:this.config.network,provider:wireProvider(this.config),asset:this.config.chainId === 1 ? 'USDT':'TEST-USDT',unit:'token-base',address:await this.address(),chainId:this.config.chainId,token:this.config.token,decimals:this.config.decimals,issuedAt:now,expiresAt:now+15*60*1000};\n }\n /** The request is for this wallet's token on its chain. Its `provider` is not compared: this wallet's own RPC pays. */\n private matches(target: PaymentTarget) {\n validatePaymentTarget(target);\n if (target.method !== 'usdt' || target.network !== this.config.network || target.chainId !== this.config.chainId || !same(target.token!,this.config.token) || target.decimals !== this.config.decimals) throw new Error('Request does not match the configured token and network');\n }\n prepare(target: PaymentTarget, amount: number, feeCap: number) { return this.serial(async () => {\n this.matches(target);\n await this.assertToken();\n const from = await this.address(), to = this.config.token;\n if (same(target.address, from) || same(target.address, to)) throw new Error('Choose a different recipient address');\n const {balance,gasBalance} = await this.balances();\n if (BigInt(balance) < BigInt(amount)) throw engineError('usdtNotEnoughTokens');\n const data = erc20.encodeFunctionData('transfer', [getAddress(target.address),BigInt(amount)]);\n const nonce = Number(BigInt(await this.rpc<string>('eth_getTransactionCount',[from,'pending'])));\n if (!Number.isSafeInteger(nonce)) throw new Error('Invalid account nonce');\n const estimate = BigInt(await this.rpc<string>('eth_estimateGas',[{from,to,data,value:'0x0'}]));\n const block = await this.rpc<{baseFeePerGas?:string}>('eth_getBlockByNumber',['latest',false]);\n if (!block.baseFeePerGas) throw new Error('This wallet requires an EIP-1559 chain');\n const priority = BigInt(await this.rpc<string>('eth_maxPriorityFeePerGas'));\n const maxFee = BigInt(block.baseFeePerGas)*2n + priority;\n const gasLimit = (estimate*120n+99n)/100n;\n const maximum = gasLimit*maxFee;\n if (maximum > BigInt(feeCap) || maximum > BigInt(Number.MAX_SAFE_INTEGER)) throw engineError('usdtGasAboveLimit');\n if (BigInt(gasBalance) < maximum) throw engineError('usdtNotEnoughGas');\n const prepared:UsdtPrepared = {from,to,data,value:'0',chainId:this.config.chainId,nonce,gasLimit:gasLimit.toString(),maxFeePerGas:maxFee.toString(),maxPriorityFeePerGas:priority.toString()};\n return {fee:Number(maximum),prepared,evm:{from,nonce,gasLimit:prepared.gasLimit,maxFeePerGas:prepared.maxFeePerGas,maxPriorityFeePerGas:prepared.maxPriorityFeePerGas,confirmations:CONFIRMATIONS}};\n }); }\n private verifyPrepared(review: PaymentReview, tx: UsdtPrepared) {\n if (tx.chainId !== this.config.chainId || !same(tx.to,this.config.token) || tx.value !== '0' || tx.data !== erc20.encodeFunctionData('transfer',[getAddress(review.address),BigInt(review.amount)]) || BigInt(tx.gasLimit)*BigInt(tx.maxFeePerGas) !== BigInt(review.fee) || review.fee > review.feeCap || tx.nonce !== review.evm?.nonce || !same(tx.from,review.evm?.from ?? '')) throw new Error('Transaction no longer matches the approved review');\n }\n private verifySigned(raw: string, saved: UsdtPrepared) {\n const tx = Transaction.from(raw);\n if (!tx.hash || !tx.from || !same(tx.from,saved.from) || tx.chainId !== BigInt(saved.chainId) || !tx.to || !same(tx.to,saved.to) || tx.data !== saved.data || tx.value !== 0n || tx.nonce !== saved.nonce || tx.gasLimit !== BigInt(saved.gasLimit) || tx.maxFeePerGas !== BigInt(saved.maxFeePerGas) || tx.maxPriorityFeePerGas !== BigInt(saved.maxPriorityFeePerGas)) throw new Error('Signature does not match the approved transaction');\n return tx.hash;\n }\n execute(review: PaymentReview, prepared: UsdtPrepared, persist?:()=>Promise<void>) { return this.serial(async () => {\n let account:WalletAccountEvm;\n try {\n this.matches(review); this.verifyPrepared(review,prepared);\n await this.assertToken(); account=this.current();\n if (!same(await account.getAddress(),prepared.from)) throw new Error('Wrong wallet');\n const nonce = Number(BigInt(await this.rpc<string>('eth_getTransactionCount',[prepared.from,'pending'])));\n if (nonce !== prepared.nonce) throw new Error('Account nonce changed. Create a new review');\n const balances = await this.balances();\n if (BigInt(balances.balance)<BigInt(review.amount) || BigInt(balances.gasBalance)<BigInt(review.fee)) throw new Error('Token or gas balance changed. Create a new review');\n if (!persist) throw new Error('Durable payment journal required');\n } catch (error) { throw new PaymentPreflightError(error instanceof Error ? error.message : 'Could not validate payment'); }\n const raw = await account.signTransaction({type:2,to:prepared.to,data:prepared.data,value:0n,chainId:prepared.chainId,nonce:prepared.nonce,gasLimit:BigInt(prepared.gasLimit),maxFeePerGas:BigInt(prepared.maxFeePerGas),maxPriorityFeePerGas:BigInt(prepared.maxPriorityFeePerGas)});\n prepared.hash = this.verifySigned(raw,prepared);\n prepared.signed = await sealSeed(raw,this.mnemonic);\n await persist!(); // Nothing may broadcast before the encrypted bytes are durable.\n await account.sendTransaction(raw);\n return this.receipt(prepared.hash,review,prepared.from);\n }); }\n reconcile(review: PaymentReview, prepared: UsdtPrepared) { return this.serial(async () => {\n await this.assertToken(); this.verifyPrepared(review,prepared);\n if (!prepared.signed || !prepared.hash) return {settled:false,failed:true,error:'No signed transaction was submitted. Create a new review.'};\n const result = await this.receipt(prepared.hash,review,prepared.from);\n if (result.settled || result.failed || result.pending) return result;\n // An uncertain network response permits only replay of exactly the saved bytes.\n const nonce = Number(BigInt(await this.rpc<string>('eth_getTransactionCount',[prepared.from,'pending'])));\n if (nonce > prepared.nonce) return result;\n const raw = await unsealSeed(prepared.signed,this.mnemonic);\n if (this.verifySigned(raw,prepared) !== prepared.hash || !same(await this.address(),prepared.from)) throw new Error('Recovery wallet mismatch');\n await this.current().sendTransaction(raw);\n return this.receipt(prepared.hash,review,prepared.from);\n }); }\n async receipt(hash: string, target: PaymentTarget & {amount:number}, expectedFrom?:string): Promise<PaymentExecution> {\n if (!/^0x[0-9a-fA-F]{64}$/.test(hash) || target.chainId !== this.config.chainId || !same(target.token ?? '',this.config.token) || target.decimals !== this.config.decimals) throw new Error('Invalid receipt target');\n await this.assertToken();\n const tx = await this.rpc<{from:string;to:string;input:string;value:string;nonce:string}|null>('eth_getTransactionByHash',[hash]);\n if (!tx) return {txid:hash,settled:false};\n if (!same(tx.to,this.config.token) || (expectedFrom && !same(tx.from,expectedFrom)) || BigInt(tx.value)!==0n || tx.input !== erc20.encodeFunctionData('transfer',[getAddress(target.address),BigInt(target.amount)])) throw new Error('Transaction is not the requested token transfer');\n const receipt = await this.rpc<{status:string;blockNumber:string;blockHash:string;logs:Array<{address:string;topics:string[];data:string}>}|null>('eth_getTransactionReceipt',[hash]);\n if (!receipt) return {txid:hash,settled:false,pending:true};\n const block = await this.rpc<{hash:string;timestamp:string}>('eth_getBlockByNumber',[receipt.blockNumber,false]);\n if (!block || block.hash !== receipt.blockHash || BigInt(block.timestamp)*1000n < BigInt((target.issuedAt ?? 0)-1000)) return {txid:hash,settled:false};\n const height = BigInt(await this.rpc<string>('eth_blockNumber'));\n if (height-BigInt(receipt.blockNumber)+1n < BigInt(CONFIRMATIONS)) return {txid:hash,settled:false,pending:true};\n if (BigInt(receipt.status)!==1n) return {txid:hash,settled:false,failed:true,error:'Transaction reverted. Tokens were not sent; gas was spent.'};\n const transfer = receipt.logs.some(log=>{\n if (!same(log.address,this.config.token)) return false;\n try {const event=erc20.parseLog(log);return event?.name==='Transfer' && same(event.args[0],tx.from) && same(event.args[1],target.address) && event.args[2]===BigInt(target.amount);} catch {return false;}\n });\n if (!transfer) throw new Error('Receipt has no matching token Transfer');\n return {txid:hash,settled:true};\n }\n async dispose() { await this.queue.catch(()=>{}); this.account=undefined;this.manager?.dispose();this.manager=undefined;this.mnemonic=''; }\n private serial<T>(work:()=>Promise<T>):Promise<T> { const operation=this.queue.then(work,work);this.queue=operation.catch(()=>{});return operation; }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"usdt-Qf4UuygS.js","names":[],"sources":["../../../browser/src/engine/paymentAdapters/usdt.ts"],"sourcesContent":["import { mnemonicToSeedSync } from '@scure/bip39';\nimport WalletManagerEvm, { type WalletAccountEvm } from '@tetherto/wdk-wallet-evm';\nimport { Interface, Transaction, getAddress, keccak256 } from 'ethers';\nimport { ETHEREUM_USDT, EVM_TEST_CHAINS, USDT_PUBLIC_RPC, SEPOLIA_TEST_USDT, SEPOLIA_TEST_USDT_FAUCET, TEST_USDT_FAUCET_AMOUNT, PaymentPreflightError, engineError, validatePaymentTarget, type PaymentAdapter, type PaymentExecution, type PaymentReview, type PaymentTarget } from '@ghostly/core';\nimport { sealSeed, unsealSeed, type EncryptedSeed } from './persistence';\nimport { networkReason, rpcHost } from './networkReason';\n\nexport interface UsdtConfig {\n network: 'ethereum' | 'sepolia' | 'evm-local';\n provider: string;\n chainId: 1 | 11155111 | 31337;\n token: string;\n decimals: number;\n codeHash: string;\n}\nexport interface UsdtPrepared {\n from: string; to: string; data: string; value: string; chainId: number; nonce: number;\n gasLimit: string; maxFeePerGas: string; maxPriorityFeePerGas: string;\n signed?: EncryptedSeed; hash?: string;\n}\nconst faucet = new Interface(['function mint(address token,address to,uint256 amount) returns (uint256)']);\nconst erc20 = new Interface(['function decimals() view returns(uint8)', 'function balanceOf(address) view returns(uint256)', 'function transfer(address,uint256) returns(bool)', 'event Transfer(address indexed from,address indexed to,uint256 value)']);\nconst same = (a: string, b: string) => a.toLowerCase() === b.toLowerCase();\nconst CONFIRMATIONS = 2;\n/** The JSON-RPC methods that only read: asked again once when they fail (see `UsdtAdapter.rpc`). */\nconst RETRIED_READS = new Set(['eth_chainId', 'eth_getCode', 'eth_call', 'eth_getBalance', 'eth_blockNumber', 'eth_getLogs', 'eth_getTransactionCount', 'eth_estimateGas', 'eth_getBlockByNumber', 'eth_maxPriorityFeePerGas', 'eth_gasPrice', 'eth_feeHistory', 'eth_getTransactionByHash', 'eth_getTransactionReceipt']);\nconst RETRY_AFTER_MS = 1000;\n/** Failures that would fail the same way again at once: not retried. */\nconst FINAL = new WeakSet<object>();\nconst timedOut = (error: unknown) => error instanceof Error && (error.name === 'AbortError' || error.name === 'TimeoutError');\n\n/**\n * The `provider` a request carries to the contact. Which RPC pays is the payer's own choice, so it names none of\n * this wallet's: a typed RPC URL may hold an API key (`/v3/<key>`), and every contact would read it. Older apps\n * require a URL here and pay only when it equals their own RPC, so it is the chain's public RPC (the default both\n * start with), and a local test chain's origin, without its path.\n */\nexport function wireProvider(config: Pick<UsdtConfig, 'network' | 'provider'>): string {\n return config.network === 'evm-local' ? new URL(config.provider).origin : USDT_PUBLIC_RPC[config.network];\n}\n\n/** WDK signs locally. Every network call uses the configured RPC, never a peer-supplied URL. */\nexport class UsdtAdapter implements PaymentAdapter<UsdtPrepared> {\n readonly method = 'usdt' as const;\n private manager?: WalletManagerEvm;\n private account?: WalletAccountEvm;\n private mnemonic = '';\n private nextId = 0;\n private queue: Promise<unknown> = Promise.resolve();\n private constructor(readonly config: UsdtConfig) {}\n\n static async inspect(config: Omit<UsdtConfig, 'decimals' | 'codeHash'>): Promise<UsdtConfig> {\n if (config.network === 'ethereum' ? config.chainId !== 1 || !same(config.token, ETHEREUM_USDT) : !(config.network in EVM_TEST_CHAINS) || config.chainId !== EVM_TEST_CHAINS[config.network]) throw new Error('Unsupported USDT network or contract');\n const token = getAddress(config.token);\n const url = new URL(config.provider);\n if (url.username || url.password || url.search || url.hash || (url.protocol !== 'https:' && !(url.protocol === 'http:' && ['localhost','127.0.0.1','[::1]'].includes(url.hostname)))) throw new Error('Use HTTPS or a loopback test RPC');\n const adapter = new UsdtAdapter({...config, token, decimals: 6, codeHash: ''});\n await adapter.chain();\n const code = await adapter.rpc<string>('eth_getCode', [token, 'latest']);\n if (code === '0x') throw new Error('No token contract exists on this chain');\n const result = await adapter.rpc<string>('eth_call', [{to: token, data: erc20.encodeFunctionData('decimals')}, 'latest']);\n const decimals = Number(erc20.decodeFunctionResult('decimals', result)[0]);\n if (!Number.isInteger(decimals) || decimals < 0 || decimals > 18 || (config.chainId === 1 && decimals !== 6)) throw new Error('Unexpected token decimals');\n return {...config, token, decimals, codeHash: keccak256(code)};\n }\n static async connect(config: UsdtConfig, mnemonic: string): Promise<UsdtAdapter> {\n const inspected = await UsdtAdapter.inspect(config);\n if (inspected.decimals !== config.decimals || inspected.codeHash !== config.codeHash) throw new Error('Token metadata changed; do not use this wallet configuration');\n const adapter = new UsdtAdapter(config);\n adapter.mnemonic = mnemonic;\n // Pass standard BIP-39 seed bytes: WDK's string helper assumes a Node Buffer global.\n const seed = mnemonicToSeedSync(mnemonic);\n try { adapter.manager = new WalletManagerEvm(seed, {provider: {request: ({method, params}) => adapter.rpc(method, params as unknown[] ?? [])}, chainId: config.chainId}); } finally { seed.fill(0); }\n adapter.account = await adapter.manager.getAccount(0);\n return adapter;\n }\n /**\n * A read that fails is asked again, once, a moment later: a public RPC drops a request now and then, and a chain that\n * just made a block can refuse a read of \"latest\" it no longer holds. Without it a network switch, a restore or New\n * gave up on the first such answer. Never a broadcast or anything else that writes, nor a request that did not answer\n * in time (the person would wait twice as long), nor one the server refused as such (4xx).\n */\n async rpc<T>(method: string, params: unknown[] = []): Promise<T> {\n try { return await this.ask<T>(method, params); }\n catch (error) {\n if (!RETRIED_READS.has(method) || FINAL.has(error as object)) throw error;\n await new Promise((resolve) => setTimeout(resolve, RETRY_AFTER_MS));\n return this.ask<T>(method, params);\n }\n }\n private async ask<T>(method: string, params: unknown[]): Promise<T> {\n let response: Response;\n // The browser's words for a request that got no answer (\"Fetch is aborted\") say nothing: the RPC's host does.\n try { response = await fetch(this.config.provider, {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({jsonrpc:'2.0',id:++this.nextId,method,params}), signal:AbortSignal.timeout(15000)}); }\n catch (error) {\n const reason = networkReason(error, rpcHost(this.config.provider));\n const thrown = reason ? Object.assign(new Error(reason), {cause: error}) : error;\n if (timedOut(error) && thrown && typeof thrown === 'object') FINAL.add(thrown);\n throw thrown;\n }\n if (!response.ok) { const error = engineError('usdtRpcUnavailable'); if (response.status !== 429 && response.status < 500) FINAL.add(error); throw error; }\n const result = await response.json();\n if (result.error || !Object.prototype.hasOwnProperty.call(result, 'result')) throw new Error('USDT RPC rejected the operation');\n return result.result as T;\n }\n private async chain() {\n if (BigInt(await this.rpc<string>('eth_chainId')) !== BigInt(this.config.chainId)) throw new Error('RPC chain does not match this wallet');\n }\n private async assertToken() {\n await this.chain();\n const code = await this.rpc<string>('eth_getCode', [this.config.token, 'latest']);\n if (code === '0x' || keccak256(code) !== this.config.codeHash) throw new Error('Token contract changed');\n }\n /**\n * Sepolia only: asks Aave's public faucet for test USDT, to this wallet, paid with its own test ETH.\n * Everything is fixed here (chain, contract, token, amount, recipient): nothing comes from outside.\n */\n mintTestTokens(): Promise<string> { return this.serial(async () => {\n if (this.config.chainId !== EVM_TEST_CHAINS.sepolia || !same(this.config.token, SEPOLIA_TEST_USDT)) throw new Error('Test USDT comes from a faucet on Sepolia only');\n await this.chain();\n const account = this.current(), from = await account.getAddress();\n const data = faucet.encodeFunctionData('mint', [SEPOLIA_TEST_USDT, from, BigInt(TEST_USDT_FAUCET_AMOUNT)]);\n const nonce = Number(BigInt(await this.rpc<string>('eth_getTransactionCount', [from, 'pending'])));\n const estimate = BigInt(await this.rpc<string>('eth_estimateGas', [{ from, to: SEPOLIA_TEST_USDT_FAUCET, data, value: '0x0' }]));\n const block = await this.rpc<{ baseFeePerGas?: string }>('eth_getBlockByNumber', ['latest', false]);\n if (!block.baseFeePerGas) throw new Error('This wallet requires an EIP-1559 chain');\n const priority = BigInt(await this.rpc<string>('eth_maxPriorityFeePerGas'));\n const maxFeePerGas = BigInt(block.baseFeePerGas) * 2n + priority, gasLimit = (estimate * 120n + 99n) / 100n;\n if (BigInt((await this.balances()).gasBalance) < gasLimit * maxFeePerGas) throw engineError('usdtNeedsSepoliaGas');\n const raw = await account.signTransaction({ type: 2, to: SEPOLIA_TEST_USDT_FAUCET, data, value: 0n, chainId: this.config.chainId, nonce, gasLimit, maxFeePerGas, maxPriorityFeePerGas: priority });\n await account.sendTransaction(raw);\n return Transaction.from(raw).hash!;\n }); }\n private current(): WalletAccountEvm { if (!this.account) throw new Error('Unlock the USDT wallet first'); return this.account; }\n address() { return this.current().getAddress(); }\n async balances() {\n await this.assertToken();\n const address = await this.address();\n const [token, gas] = await Promise.all([this.rpc<string>('eth_call',[{to:this.config.token,data:erc20.encodeFunctionData('balanceOf',[address])},'latest']),this.rpc<string>('eth_getBalance',[address,'pending'])]);\n return {balance:erc20.decodeFunctionResult('balanceOf',token)[0].toString(),gasBalance:BigInt(gas).toString()};\n }\n async target(): Promise<PaymentTarget> {\n const now = Date.now();\n return {method:'usdt',network:this.config.network,provider:wireProvider(this.config),asset:this.config.chainId === 1 ? 'USDT':'TEST-USDT',unit:'token-base',address:await this.address(),chainId:this.config.chainId,token:this.config.token,decimals:this.config.decimals,issuedAt:now,expiresAt:now+15*60*1000};\n }\n /** The request is for this wallet's token on its chain. Its `provider` is not compared: this wallet's own RPC pays. */\n private matches(target: PaymentTarget) {\n validatePaymentTarget(target);\n if (target.method !== 'usdt' || target.network !== this.config.network || target.chainId !== this.config.chainId || !same(target.token!,this.config.token) || target.decimals !== this.config.decimals) throw new Error('Request does not match the configured token and network');\n }\n prepare(target: PaymentTarget, amount: number, feeCap: number) { return this.serial(async () => {\n this.matches(target);\n await this.assertToken();\n const from = await this.address(), to = this.config.token;\n if (same(target.address, from) || same(target.address, to)) throw new Error('Choose a different recipient address');\n const {balance,gasBalance} = await this.balances();\n if (BigInt(balance) < BigInt(amount)) throw engineError('usdtNotEnoughTokens');\n const data = erc20.encodeFunctionData('transfer', [getAddress(target.address),BigInt(amount)]);\n const nonce = Number(BigInt(await this.rpc<string>('eth_getTransactionCount',[from,'pending'])));\n if (!Number.isSafeInteger(nonce)) throw new Error('Invalid account nonce');\n const estimate = BigInt(await this.rpc<string>('eth_estimateGas',[{from,to,data,value:'0x0'}]));\n const block = await this.rpc<{baseFeePerGas?:string}>('eth_getBlockByNumber',['latest',false]);\n if (!block.baseFeePerGas) throw new Error('This wallet requires an EIP-1559 chain');\n const priority = BigInt(await this.rpc<string>('eth_maxPriorityFeePerGas'));\n const maxFee = BigInt(block.baseFeePerGas)*2n + priority;\n const gasLimit = (estimate*120n+99n)/100n;\n const maximum = gasLimit*maxFee;\n if (maximum > BigInt(feeCap) || maximum > BigInt(Number.MAX_SAFE_INTEGER)) throw engineError('usdtGasAboveLimit');\n if (BigInt(gasBalance) < maximum) throw engineError('usdtNotEnoughGas');\n const prepared:UsdtPrepared = {from,to,data,value:'0',chainId:this.config.chainId,nonce,gasLimit:gasLimit.toString(),maxFeePerGas:maxFee.toString(),maxPriorityFeePerGas:priority.toString()};\n return {fee:Number(maximum),prepared,evm:{from,nonce,gasLimit:prepared.gasLimit,maxFeePerGas:prepared.maxFeePerGas,maxPriorityFeePerGas:prepared.maxPriorityFeePerGas,confirmations:CONFIRMATIONS}};\n }); }\n private verifyPrepared(review: PaymentReview, tx: UsdtPrepared) {\n if (tx.chainId !== this.config.chainId || !same(tx.to,this.config.token) || tx.value !== '0' || tx.data !== erc20.encodeFunctionData('transfer',[getAddress(review.address),BigInt(review.amount)]) || BigInt(tx.gasLimit)*BigInt(tx.maxFeePerGas) !== BigInt(review.fee) || review.fee > review.feeCap || tx.nonce !== review.evm?.nonce || !same(tx.from,review.evm?.from ?? '')) throw new Error('Transaction no longer matches the approved review');\n }\n private verifySigned(raw: string, saved: UsdtPrepared) {\n const tx = Transaction.from(raw);\n if (!tx.hash || !tx.from || !same(tx.from,saved.from) || tx.chainId !== BigInt(saved.chainId) || !tx.to || !same(tx.to,saved.to) || tx.data !== saved.data || tx.value !== 0n || tx.nonce !== saved.nonce || tx.gasLimit !== BigInt(saved.gasLimit) || tx.maxFeePerGas !== BigInt(saved.maxFeePerGas) || tx.maxPriorityFeePerGas !== BigInt(saved.maxPriorityFeePerGas)) throw new Error('Signature does not match the approved transaction');\n return tx.hash;\n }\n execute(review: PaymentReview, prepared: UsdtPrepared, persist?:()=>Promise<void>) { return this.serial(async () => {\n let account:WalletAccountEvm;\n try {\n this.matches(review); this.verifyPrepared(review,prepared);\n await this.assertToken(); account=this.current();\n if (!same(await account.getAddress(),prepared.from)) throw new Error('Wrong wallet');\n const nonce = Number(BigInt(await this.rpc<string>('eth_getTransactionCount',[prepared.from,'pending'])));\n if (nonce !== prepared.nonce) throw new Error('Account nonce changed. Create a new review');\n const balances = await this.balances();\n if (BigInt(balances.balance)<BigInt(review.amount) || BigInt(balances.gasBalance)<BigInt(review.fee)) throw new Error('Token or gas balance changed. Create a new review');\n if (!persist) throw new Error('Durable payment journal required');\n } catch (error) { throw new PaymentPreflightError(error instanceof Error ? error.message : 'Could not validate payment'); }\n const raw = await account.signTransaction({type:2,to:prepared.to,data:prepared.data,value:0n,chainId:prepared.chainId,nonce:prepared.nonce,gasLimit:BigInt(prepared.gasLimit),maxFeePerGas:BigInt(prepared.maxFeePerGas),maxPriorityFeePerGas:BigInt(prepared.maxPriorityFeePerGas)});\n prepared.hash = this.verifySigned(raw,prepared);\n prepared.signed = await sealSeed(raw,this.mnemonic);\n await persist!(); // Nothing may broadcast before the encrypted bytes are durable.\n await account.sendTransaction(raw);\n return this.receipt(prepared.hash,review,prepared.from);\n }); }\n reconcile(review: PaymentReview, prepared: UsdtPrepared) { return this.serial(async () => {\n await this.assertToken(); this.verifyPrepared(review,prepared);\n if (!prepared.signed || !prepared.hash) return {settled:false,failed:true,error:'No signed transaction was submitted. Create a new review.'};\n const result = await this.receipt(prepared.hash,review,prepared.from);\n if (result.settled || result.failed || result.pending) return result;\n // An uncertain network response permits only replay of exactly the saved bytes.\n const nonce = Number(BigInt(await this.rpc<string>('eth_getTransactionCount',[prepared.from,'pending'])));\n if (nonce > prepared.nonce) return result;\n const raw = await unsealSeed(prepared.signed,this.mnemonic);\n if (this.verifySigned(raw,prepared) !== prepared.hash || !same(await this.address(),prepared.from)) throw new Error('Recovery wallet mismatch');\n await this.current().sendTransaction(raw);\n return this.receipt(prepared.hash,review,prepared.from);\n }); }\n async receipt(hash: string, target: PaymentTarget & {amount:number}, expectedFrom?:string): Promise<PaymentExecution> {\n if (!/^0x[0-9a-fA-F]{64}$/.test(hash) || target.chainId !== this.config.chainId || !same(target.token ?? '',this.config.token) || target.decimals !== this.config.decimals) throw new Error('Invalid receipt target');\n await this.assertToken();\n const tx = await this.rpc<{from:string;to:string;input:string;value:string;nonce:string}|null>('eth_getTransactionByHash',[hash]);\n if (!tx) return {txid:hash,settled:false};\n if (!same(tx.to,this.config.token) || (expectedFrom && !same(tx.from,expectedFrom)) || BigInt(tx.value)!==0n || tx.input !== erc20.encodeFunctionData('transfer',[getAddress(target.address),BigInt(target.amount)])) throw new Error('Transaction is not the requested token transfer');\n const receipt = await this.rpc<{status:string;blockNumber:string;blockHash:string;logs:Array<{address:string;topics:string[];data:string}>}|null>('eth_getTransactionReceipt',[hash]);\n if (!receipt) return {txid:hash,settled:false,pending:true};\n const block = await this.rpc<{hash:string;timestamp:string}>('eth_getBlockByNumber',[receipt.blockNumber,false]);\n if (!block || block.hash !== receipt.blockHash || BigInt(block.timestamp)*1000n < BigInt((target.issuedAt ?? 0)-1000)) return {txid:hash,settled:false};\n const height = BigInt(await this.rpc<string>('eth_blockNumber'));\n if (height-BigInt(receipt.blockNumber)+1n < BigInt(CONFIRMATIONS)) return {txid:hash,settled:false,pending:true};\n if (BigInt(receipt.status)!==1n) return {txid:hash,settled:false,failed:true,error:'Transaction reverted. Tokens were not sent; gas was spent.'};\n const transfer = receipt.logs.some(log=>{\n if (!same(log.address,this.config.token)) return false;\n try {const event=erc20.parseLog(log);return event?.name==='Transfer' && same(event.args[0],tx.from) && same(event.args[1],target.address) && event.args[2]===BigInt(target.amount);} catch {return false;}\n });\n if (!transfer) throw new Error('Receipt has no matching token Transfer');\n return {txid:hash,settled:true};\n }\n async dispose() { await this.queue.catch(()=>{}); this.account=undefined;this.manager?.dispose();this.manager=undefined;this.mnemonic=''; }\n private serial<T>(work:()=>Promise<T>):Promise<T> { const operation=this.queue.then(work,work);this.queue=operation.catch(()=>{});return operation; }\n}\n"],"mappings":"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"}
package/dist/ghostly.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as __exportAll } from "./assets/rolldown-runtime-8H4AJuhK.js";
3
- import { $n as readGroupHave, An as resolveLightningDestination, At as DidError, Ba as PR_CHECKS, Bo as extractParamsFromSdp, Bt as didWebHost, Ci as normalizeDomain, Cn as normalizePubkyKey, Ct as parseAtprotoDidDocument, Di as txtValue, Dn as homeserverWebEndpoint, Do as GhostlyHttpError, Dt as DID_DOCUMENT_MAX_BYTES$1, Ei as recordsName, En as pubkyProofPath, Et as verifyAtprotoRecordProof, Fo as RTC_CONFIG, Ft as didSignedMessages, Ga as cardLine, Gn as GROUP_FILE_LIMITS, Gt as signingKeys, Ha as RUN_RESULTS, Ho as signalHasVideo, Ht as parseDid, Ii as IdentityCheckUnavailable, Io as answersOffer, Ir as sanitizeTypingStatus, It as didWebDocumentUrl, Jn as GROUP_WANT_NO_FRAME, Ka as cardUrl, Kn as GROUP_HAVE_FRAME, Kt as staticDidDocument, La as replySnippet, Lo as buildSdpFromSignal, Lt as didWebFile, Mt as checkDidSignature, Nr as TYPING_KINDS, Nt as didGhostlyServiceEntry, Oi as wellKnownUrl, On as pubkyHomeserverOf, Ot as DID_FILE_MAX_BYTES, Po as CALL_SIGNAL_MAX_AGE_MS, Pr as TYPING_REFRESH_MS, Pt as didJwsAlg, Qi as irohRelayUrl, Qr as checkPushEndpoint, Qt as resolveDidDht, Ri as boundVerifiedIdentity, Ro as callRtcConfig, Rt as didWebFileNames, Si as nip05RootKey, Sn as newPubkyProofFolder, St as normalizeAtprotoHandle, Ti as recordsFromWellKnown, Tn as pubkyProofFile, Tt as AtprotoProofError, Ua as STATUS_CARD_LIMITS, Un as engineError, Ut as parseDidDocument, Va as PR_STATES, Vc as setLinkTraceSink, Vi as identityStatement, Vo as parseCallSignal, Vt as normalizeDid, Wa as buttonLabelClash, Wn as engineText, Wt as parseDidSignaturePaste, Xc as openRelayPayload, Xn as groupFileFallback, Yn as fetchesByItself, Zi as irohDescriptor, Zn as isGroupMessageId, _ as checkAppManifest, _i as dnsProofName, _t as atprotoDidMethod, aa as readImageMeta, ao as checkAppRevokeStatement, at as parseSshPublicKey, bi as encodeDnsQuery, bn as isPubkyKey, bt as checkAtprotoProofRecord, c as readAppStore, ca as sanitizeFileName, cl as toBase64Url, cn as WALLET_NETWORKS, ct as sshSignCommand, d as APP_BUNDLE_LIMITS, da as VOICE_LIMITS, dl as utf8Encode, do as signAppRevocation, dt as BitcoinAddressError, er as readGroupWant, fa as baseMime, fo as canonicalJson, ft as decodeAnyBitcoinAddress, g as assembleAppBundle, gi as decodeDnsResponse, gt as ATPROTO_PROOF_SCOPE, ha as voicePeaksOf, hi as DOMAIN_FILE_MAX_BYTES, ht as ATPROTO_PROOF_COLLECTION, il as sanitizeAvatar, io as appRef, it as SshSigError, jn as decodeBolt11, jo as LIMITS, jr as transferEnded, jt as checkDidJws, kn as requestLnurlInvoice, kr as ChatFiles, la as sanitizeMime, ll as toZ32, lo as readAppRevocations, lt as verifySshSignature, ma as parseVoiceMeta, mt as ATPROTO_FULL_SCOPE, n as appStoreDecision, no as APP_STATEMENT_LIMITS, ol as fromBase64Url$1, ot as parseSshSignature, pa as fileMessageText, pn as walletNetworkOf, po as canonicalJsonBytes, pt as ATPROTO_DECLARED_SCOPE, qa as checkStatusCard, qc as RELAY_PAYLOAD_MAX_BYTES, qt as strictBase64Url, ri as BUTTONS_CAPABILITY, rl as MAX_AVATAR_LENGTH, ro as appFingerprint, rt as SSHSIG_NAMESPACE, s as checkAppStoreIndex, sc as inviteLink, sl as randomBytes$1, st as sameSshKey, to as APP_PREFIXES, tr as readGroupWantNo, tt as groupName, u as signAppStore, ua as PLAYABLE_AUDIO, ul as utf8Decode, uo as signAppObject, ut as verifyBitcoinMessage, v as isAppUrl, vc as seedSigner, vi as domainTxtRecord, vt as atprotoProofRecord, wi as recordsFromTxt, wn as pubkyProofCapability, wt as shortAtprotoDid, xi as isPublicAddress, xn as isPubkyProofFolder, xt as isAtprotoDid, y as readAppBundle, ya as RateWindow, yi as domainWellKnownFile, yn as PUBKY_PROOF_MAX_BYTES, yt as atprotoProofRkey, za as ITEM_STATES, zo as callSignalHeardAt, zt as didWebFileUrl } from "./assets/src-_FzJkeAJ.js";
3
+ import { $n as readGroupHave, An as resolveLightningDestination, At as DidError, Ba as PR_CHECKS, Bo as extractParamsFromSdp, Bt as didWebHost, Ci as normalizeDomain, Cn as normalizePubkyKey, Ct as parseAtprotoDidDocument, Di as txtValue, Dn as homeserverWebEndpoint, Do as GhostlyHttpError, Dt as DID_DOCUMENT_MAX_BYTES$1, Ei as recordsName, En as pubkyProofPath, Et as verifyAtprotoRecordProof, Fo as RTC_CONFIG, Ft as didSignedMessages, Ga as cardLine, Gn as GROUP_FILE_LIMITS, Gt as signingKeys, Ha as RUN_RESULTS, Ho as signalHasVideo, Ht as parseDid, Ii as IdentityCheckUnavailable, Io as answersOffer, Ir as sanitizeTypingStatus, It as didWebDocumentUrl, Jn as GROUP_WANT_NO_FRAME, Ka as cardUrl, Kn as GROUP_HAVE_FRAME, Kt as staticDidDocument, La as replySnippet, Lo as buildSdpFromSignal, Lt as didWebFile, Mt as checkDidSignature, Nr as TYPING_KINDS, Nt as didGhostlyServiceEntry, Oi as wellKnownUrl, On as pubkyHomeserverOf, Ot as DID_FILE_MAX_BYTES, Po as CALL_SIGNAL_MAX_AGE_MS, Pr as TYPING_REFRESH_MS, Pt as didJwsAlg, Qi as irohRelayUrl, Qr as checkPushEndpoint, Qt as resolveDidDht, Ri as boundVerifiedIdentity, Ro as callRtcConfig, Rt as didWebFileNames, Si as nip05RootKey, Sn as newPubkyProofFolder, St as normalizeAtprotoHandle, Ti as recordsFromWellKnown, Tn as pubkyProofFile, Tt as AtprotoProofError, Ua as STATUS_CARD_LIMITS, Un as engineError, Ut as parseDidDocument, Va as PR_STATES, Vc as setLinkTraceSink, Vi as identityStatement, Vo as parseCallSignal, Vt as normalizeDid, Wa as buttonLabelClash, Wn as engineText, Wt as parseDidSignaturePaste, Xc as openRelayPayload, Xn as groupFileFallback, Yn as fetchesByItself, Zi as irohDescriptor, Zn as isGroupMessageId, _ as checkAppManifest, _i as dnsProofName, _t as atprotoDidMethod, aa as readImageMeta, ao as checkAppRevokeStatement, at as parseSshPublicKey, bi as encodeDnsQuery, bn as isPubkyKey, bt as checkAtprotoProofRecord, c as readAppStore, ca as sanitizeFileName, cl as toBase64Url, cn as WALLET_NETWORKS, ct as sshSignCommand, d as APP_BUNDLE_LIMITS, da as VOICE_LIMITS, dl as utf8Encode, do as signAppRevocation, dt as BitcoinAddressError, er as readGroupWant, fa as baseMime, fo as canonicalJson, ft as decodeAnyBitcoinAddress, g as assembleAppBundle, gi as decodeDnsResponse, gt as ATPROTO_PROOF_SCOPE, ha as voicePeaksOf, hi as DOMAIN_FILE_MAX_BYTES, ht as ATPROTO_PROOF_COLLECTION, il as sanitizeAvatar, io as appRef, it as SshSigError, jn as decodeBolt11, jo as LIMITS, jr as transferEnded, jt as checkDidJws, kn as requestLnurlInvoice, kr as ChatFiles, la as sanitizeMime, ll as toZ32, lo as readAppRevocations, lt as verifySshSignature, ma as parseVoiceMeta, mt as ATPROTO_FULL_SCOPE, n as appStoreDecision, no as APP_STATEMENT_LIMITS, ol as fromBase64Url$1, ot as parseSshSignature, pa as fileMessageText, pn as walletNetworkOf, po as canonicalJsonBytes, pt as ATPROTO_DECLARED_SCOPE, qa as checkStatusCard, qc as RELAY_PAYLOAD_MAX_BYTES, qt as strictBase64Url, ri as BUTTONS_CAPABILITY, rl as MAX_AVATAR_LENGTH, ro as appFingerprint, rt as SSHSIG_NAMESPACE, s as checkAppStoreIndex, sc as inviteLink, sl as randomBytes$1, st as sameSshKey, to as APP_PREFIXES, tr as readGroupWantNo, tt as groupName, u as signAppStore, ua as PLAYABLE_AUDIO, ul as utf8Decode, uo as signAppObject, ut as verifyBitcoinMessage, v as isAppUrl, vc as seedSigner, vi as domainTxtRecord, vt as atprotoProofRecord, wi as recordsFromTxt, wn as pubkyProofCapability, wt as shortAtprotoDid, xi as isPublicAddress, xn as isPubkyProofFolder, xt as isAtprotoDid, y as readAppBundle, ya as RateWindow, yi as domainWellKnownFile, yn as PUBKY_PROOF_MAX_BYTES, yt as atprotoProofRkey, za as ITEM_STATES, zo as callSignalHeardAt, zt as didWebFileUrl } from "./assets/src-CbLkHfz8.js";
4
4
  import { c as fileStore, f as store$1, i as STORES, m as wrap, o as databaseName, p as transact, u as openDb } from "./assets/idb-CTF6LF5B.js";
5
5
  import { a as fileBytesOf, i as fileBytes, l as FILE_BYTES_STEP } from "./assets/fileBytes-BcYZhNgF.js";
6
6
  import { createRequire } from "node:module";
@@ -35,7 +35,7 @@ import { IDBFactory, IDBKeyRange as IDBKeyRange$1, IDBTransaction } from "fake-i
35
35
  import { format } from "node:util";
36
36
  var package_default = {
37
37
  name: "@ghostlytools/cli",
38
- version: "1.2.3",
38
+ version: "1.2.4",
39
39
  type: "module",
40
40
  description: "Ghostly for bots and terminals: the app's own engine, headless on Node, behind a daemon and a `ghostly` command with JSON output.",
41
41
  license: "MIT",
@@ -795,6 +795,14 @@ var SECRET_RESULTS = /* @__PURE__ */ new Set([
795
795
  //#region src/apiKit.ts
796
796
  var node = (ctx) => ctx.runtime.server.node;
797
797
  var state = (ctx) => node(ctx).getState();
798
+ /**
799
+ * The time of a send the engine names its row after (`me_<timestamp>`: a file, a payment, a request), its own even
800
+ * within one millisecond (a bot paying or sending several times at once over the socket, `file send` run in
801
+ * parallel), or the chat keeps only one. One clock for all of them: they share the row names. A file's resend after a
802
+ * drop finds its row by it, as a forward does.
803
+ */
804
+ var lastSentAt = 0;
805
+ var sentAt = () => lastSentAt = Math.max(Date.now(), lastSentAt + 1);
798
806
  function str(params, name, required = false) {
799
807
  const value = params[name];
800
808
  if (value === void 0 || value === null || value === "") {
@@ -804,10 +812,12 @@ function str(params, name, required = false) {
804
812
  if (typeof value !== "string") throw new CliError("bad_request", `${name} must be a string`);
805
813
  return value;
806
814
  }
807
- function num(params, name, fallback, { min = 0, max = Number.MAX_SAFE_INTEGER } = {}) {
815
+ /** A number in `[min, max]`; `whole` takes only whole ones (a count of messages), as the engine needs them. */
816
+ function num(params, name, fallback, { min = 0, max = Number.MAX_SAFE_INTEGER, whole = false } = {}) {
808
817
  const value = params[name];
809
818
  if (value === void 0 || value === null) return fallback;
810
- if (typeof value !== "number" || !Number.isFinite(value) || value < min || value > max) throw new CliError("bad_request", `${name} must be a number from ${min} to ${max}`);
819
+ if (typeof value !== "number" || !Number.isFinite(value) || value < min || value > max) throw new CliError("bad_request", `${name} must be a ${whole ? "whole " : ""}number from ${min} to ${max}`);
820
+ if (whole && !Number.isSafeInteger(value)) throw new CliError("bad_request", `${name} must be a whole number from ${min} to ${max}`);
811
821
  return value;
812
822
  }
813
823
  function bool(params, name) {
@@ -2723,7 +2733,7 @@ var FILE_METHODS = {
2723
2733
  ...voice ? { voice } : {},
2724
2734
  ...image ? { image } : {}
2725
2735
  };
2726
- const timestamp = Date.now();
2736
+ const timestamp = sentAt();
2727
2737
  const bytes = await fileBytes();
2728
2738
  const digest = await bytes.stage(file.id, source);
2729
2739
  await fileStore.put({
@@ -9412,10 +9422,6 @@ async function readBackupHeader(source) {
9412
9422
  line: start.slice(0, end + 1)
9413
9423
  };
9414
9424
  }
9415
- /** How a backup is protected, read from its clear header without opening it: version 1 is always sealed. */
9416
- async function backupProtection(source) {
9417
- return (await readBackupHeader(source))?.header.protection ?? "passphrase";
9418
- }
9419
9425
  var DAMAGED = "This backup is damaged: it was changed or cut short";
9420
9426
  /** Reads a version 2 backup record by record. Nothing of a frame is handed out before it passed its check. */
9421
9427
  var BackupReader = class BackupReader {
@@ -9536,15 +9542,21 @@ var keptInLight = (size, voice) => size <= (voice ? LIGHT_VOICE_BYTES : LIGHT_FI
9536
9542
  */
9537
9543
  var DEFAULT_PROFILE = "default";
9538
9544
  var NAME = /^[a-z0-9][a-z0-9._-]{0,63}$/i;
9545
+ /**
9546
+ * An empty `--home` or `--profile` (an unset variable in a script) is a usage error: taken as not given, it ran the
9547
+ * command in the current folder, or as the current profile. An empty variable of the environment counts as unset.
9548
+ */
9539
9549
  function ghostlyHome(option) {
9540
- return resolve(option ?? process.env.GHOSTLY_HOME ?? join(homedir(), ".ghostly"));
9550
+ if (option === "") throw new CliError("usage", "--home needs a folder");
9551
+ return resolve(option ?? (process.env.GHOSTLY_HOME || join(homedir(), ".ghostly")));
9541
9552
  }
9542
9553
  function checkProfileName(name) {
9543
9554
  if (!NAME.test(name) || name.includes("..")) throw new CliError("usage", `Not a profile name: ${JSON.stringify(name)} (letters, digits, ".", "_" and "-", up to 64)`);
9544
9555
  return name;
9545
9556
  }
9546
9557
  function currentProfile(home, option) {
9547
- if (option) return checkProfileName(option);
9558
+ if (option === "") throw new CliError("usage", "--profile needs a profile name");
9559
+ if (option !== void 0) return checkProfileName(option);
9548
9560
  if (process.env.GHOSTLY_PROFILE) return checkProfileName(process.env.GHOSTLY_PROFILE);
9549
9561
  const file = join(home, "current");
9550
9562
  if (existsSync(file)) {
@@ -9821,11 +9833,24 @@ async function fileSource(path) {
9821
9833
  close: () => handle.close()
9822
9834
  };
9823
9835
  }
9824
- /** Whether the backup at `file` is sealed with a passphrase or was made without one, read from its clear header. */
9836
+ /** A version 1 backup is one JSON object, and `seal` writes its format first. */
9837
+ var VERSION_1_START = /^\s*\{\s*"format"\s*:\s*"ghostly-backup"/;
9838
+ /**
9839
+ * Whether the backup at `file` is sealed with a passphrase or was made without one, read from its clear header.
9840
+ * A file that is neither version is refused here, before any passphrase is asked for: the path is what is wrong.
9841
+ */
9825
9842
  async function backupFileProtection(file) {
9826
9843
  const source = await fileSource(file);
9827
9844
  try {
9828
- return await backupProtection(source);
9845
+ let found;
9846
+ try {
9847
+ found = await readBackupHeader(source);
9848
+ } catch (error) {
9849
+ throw new CliError("refused", error instanceof Error ? error.message : String(error));
9850
+ }
9851
+ if (found) return found.header.protection;
9852
+ if (!VERSION_1_START.test(new TextDecoder().decode(await source.read(0, 256)))) throw new CliError("refused", "This is not a Ghostly backup");
9853
+ return "passphrase";
9829
9854
  } finally {
9830
9855
  await source.close();
9831
9856
  }
@@ -12329,6 +12354,15 @@ function paymentJson(p) {
12329
12354
  }
12330
12355
  var isInvoice = (text) => /^(lightning:)?ln(bc|tb|tbs|sb|bcrt)[0-9a-z]+$/i.test(text.trim());
12331
12356
  var isLnurl = (text) => /^(lightning:)?lnurl[0-9a-z]+$/i.test(text.trim()) || /^[a-z0-9._+-]+@[a-z0-9.-]+\.[a-z]{2,}$/i.test(text.trim());
12357
+ /**
12358
+ * The engine refusing the mint URL the person typed (not a URL, or not https): their value, so `bad_request`, as
12359
+ * `service add` says; before, it was `engine` (exit 1), which a bot reads as the engine failing and may retry. Read by
12360
+ * its shape: the engine's `EngineError` carries `engineCode`.
12361
+ */
12362
+ function badMintUrl(error) {
12363
+ const code = error instanceof Error ? error.engineCode : void 0;
12364
+ return code === "invalidMintUrl" || code === "mintNotHttps";
12365
+ }
12332
12366
  var WALLET_METHODS = {
12333
12367
  async "wallet.list"(ctx, params) {
12334
12368
  await federationsOpen(ctx);
@@ -12415,7 +12449,8 @@ var WALLET_METHODS = {
12415
12449
  const n = network(params);
12416
12450
  const limit = num(params, "limit", 50, {
12417
12451
  min: 1,
12418
- max: 1e4
12452
+ max: 1e4,
12453
+ whole: true
12419
12454
  });
12420
12455
  await federationsOpen(ctx);
12421
12456
  return {
@@ -12471,6 +12506,8 @@ var WALLET_METHODS = {
12471
12506
  return node(ctx).walletAddMint({
12472
12507
  url: str(params, "url", true),
12473
12508
  ...bool(params, "primary") ? { primary: true } : {}
12509
+ }).catch((error) => {
12510
+ throw badMintUrl(error) ? new CliError("bad_request", error.message) : error;
12474
12511
  });
12475
12512
  },
12476
12513
  async "lightning.default"(ctx, params) {
@@ -12555,7 +12592,7 @@ var WALLET_METHODS = {
12555
12592
  const { paymentId } = await node(ctx).sendPayment({
12556
12593
  linkId: link.id,
12557
12594
  amount,
12558
- timestamp: Date.now(),
12595
+ timestamp: sentAt(),
12559
12596
  network: n,
12560
12597
  ...str(params, "memo") ? { memo: str(params, "memo") } : {},
12561
12598
  ...real(params)
@@ -12576,7 +12613,7 @@ var WALLET_METHODS = {
12576
12613
  const { paymentId } = await node(ctx).requestPayment({
12577
12614
  linkId: link.id,
12578
12615
  amount,
12579
- timestamp: Date.now(),
12616
+ timestamp: sentAt(),
12580
12617
  network: network(params),
12581
12618
  ...str(params, "memo") ? { memo: str(params, "memo") } : {},
12582
12619
  ...method ? { method } : {},
@@ -12763,6 +12800,33 @@ function mentionsFor(text, refs, group) {
12763
12800
  }
12764
12801
  return out;
12765
12802
  }
12803
+ /** Per host: stops watching the invite it marked as the chat on screen. */
12804
+ var inviteShown = /* @__PURE__ */ new WeakMap();
12805
+ /**
12806
+ * Marks a new invite as the chat on screen (native listeners, the quick pace) only until it is paired: a paired chat
12807
+ * keeps its listeners anyway, and a daemon nobody looks at reads an away contact at the background pace, as its
12808
+ * other chats and the same chat after a restart do.
12809
+ */
12810
+ function showUntilPaired(ctx, linkId) {
12811
+ inviteShown.get(ctx)?.();
12812
+ node(ctx).setActiveLink({ linkId });
12813
+ let seen = false;
12814
+ const done = (s) => {
12815
+ const link = s.links.find((l) => l.id === linkId);
12816
+ if (link) seen = true;
12817
+ return link ? !!link.peerParticipationKey : seen;
12818
+ };
12819
+ const stop = () => {
12820
+ off();
12821
+ if (inviteShown.get(ctx) === stop) inviteShown.delete(ctx);
12822
+ };
12823
+ const off = ctx.hub.onState((s) => {
12824
+ if (!done(s)) return;
12825
+ stop();
12826
+ node(ctx).setActiveLink({ linkId: null });
12827
+ });
12828
+ inviteShown.set(ctx, stop);
12829
+ }
12766
12830
  var METHODS = {
12767
12831
  ...WALLET_METHODS,
12768
12832
  ...FILE_METHODS,
@@ -12839,7 +12903,7 @@ var METHODS = {
12839
12903
  linkId,
12840
12904
  label
12841
12905
  });
12842
- node(ctx).setActiveLink({ linkId });
12906
+ showUntilPaired(ctx, linkId);
12843
12907
  const progressOf = (s) => s.links.find((l) => l.id === linkId)?.pairingProgress;
12844
12908
  const progress = await waitForState(ctx, (s) => {
12845
12909
  const p = progressOf(s);
@@ -12873,7 +12937,7 @@ var METHODS = {
12873
12937
  linkId,
12874
12938
  label
12875
12939
  });
12876
- node(ctx).setActiveLink({ linkId });
12940
+ showUntilPaired(ctx, linkId);
12877
12941
  return { chat: linkId };
12878
12942
  },
12879
12943
  async "chat.list"(ctx, params) {
@@ -13425,6 +13489,7 @@ var METHODS = {
13425
13489
  if (args && "confirmedReal" in args && !bool(params, "confirmReal")) throw new CliError("confirm", `${method} spends real money: pass --confirm-real (confirmReal: true over the socket) to confirm it`);
13426
13490
  if (method === "getMessages") return node(ctx).getMessages(str(args ?? {}, "linkId", true));
13427
13491
  if (method === "getState") return state(ctx);
13492
+ if (method === "setActiveLink") inviteShown.get(ctx)?.();
13428
13493
  const target = node(ctx)[method];
13429
13494
  if (typeof target !== "function") throw new CliError("not_found", `The engine has no call ${method}`);
13430
13495
  if (args === void 0) args = void 0;
@@ -13515,7 +13580,8 @@ async function historyOf(ctx, chat, params, json = messageJson) {
13515
13580
  if (params.after !== void 0 && params.after !== null) return history(await node(ctx).getMessages(chat), params, json);
13516
13581
  const limit = num(params, "limit", 50, {
13517
13582
  min: 1,
13518
- max: 1e4
13583
+ max: 1e4,
13584
+ whole: true
13519
13585
  });
13520
13586
  const before = params.before ?? void 0;
13521
13587
  if (before !== void 0 && typeof before !== "number" && typeof before !== "string") throw new CliError("bad_request", "before must be a timestamp or a message id");
@@ -13534,7 +13600,8 @@ async function historyOf(ctx, chat, params, json = messageJson) {
13534
13600
  function history(messages, params, json = messageJson) {
13535
13601
  const limit = num(params, "limit", 50, {
13536
13602
  min: 1,
13537
- max: 1e4
13603
+ max: 1e4,
13604
+ whole: true
13538
13605
  });
13539
13606
  const before = params.before;
13540
13607
  const after = params.after;
@@ -14791,6 +14858,7 @@ function taskFields(options) {
14791
14858
  set("title", options.title);
14792
14859
  set("status", options.status);
14793
14860
  percent(options, "progress");
14861
+ if (options.progress !== void 0 && options.steps !== void 0) throw new CliError("usage", "--progress or --steps, not both");
14794
14862
  set("progress", options.progress);
14795
14863
  set("step", options.step);
14796
14864
  set("branch", options.branch);
@@ -14995,6 +15063,7 @@ function usageWindowOf(value) {
14995
15063
  function usageFields(options) {
14996
15064
  const fields = { ...cardJson(options.json) };
14997
15065
  percent(options, "left");
15066
+ if (options.left !== void 0 && (options.used !== void 0 || options.limit !== void 0)) throw new CliError("usage", "--left or --used with --limit, not both");
14998
15067
  for (const key of [
14999
15068
  "id",
15000
15069
  "left",
@@ -15802,6 +15871,7 @@ var commands$4 = {
15802
15871
  } },
15803
15872
  params: ({ options }, a) => {
15804
15873
  if (a.path === void 0 && options.clear !== true) throw new CliError("usage", "Missing <jpeg>: ghostly profile picture <jpeg> | --clear");
15874
+ if (a.path !== void 0 && options.clear === true) throw new CliError("usage", "--clear removes the picture: not with a <jpeg>");
15805
15875
  return {
15806
15876
  path: here(a.path),
15807
15877
  clear: options.clear === true
@@ -15918,12 +15988,20 @@ var commands$3 = {
15918
15988
  description: "A hub if their app stays online (the default)"
15919
15989
  }
15920
15990
  },
15921
- params: ({ options }, a) => ({
15922
- group: a.group,
15923
- member: a.member,
15924
- role: options.pin === true ? "pin" : options.exclude === true ? "exclude" : "auto",
15925
- ...secret(options)
15926
- })
15991
+ params: ({ options }, a) => {
15992
+ const roles = [
15993
+ "pin",
15994
+ "exclude",
15995
+ "auto"
15996
+ ].filter((role) => options[role] === true);
15997
+ if (roles.length > 1) throw new CliError("usage", "--pin, --exclude or --auto: one of them");
15998
+ return {
15999
+ group: a.group,
16000
+ member: a.member,
16001
+ role: roles[0] ?? "auto",
16002
+ ...secret(options)
16003
+ };
16004
+ }
15927
16005
  },
15928
16006
  "group invite": {
15929
16007
  method: "group.invite",
@@ -15966,11 +16044,14 @@ var commands$3 = {
15966
16044
  description: "Replace it: the old link stops working"
15967
16045
  }
15968
16046
  },
15969
- params: ({ options }, a) => ({
15970
- group: a.group,
15971
- on: options.off !== true,
15972
- reset: options.reset === true
15973
- })
16047
+ params: ({ options }, a) => {
16048
+ if (options.off === true && options.reset === true) throw new CliError("usage", "--off turns the link off: not with --reset");
16049
+ return {
16050
+ group: a.group,
16051
+ on: options.off !== true,
16052
+ reset: options.reset === true
16053
+ };
16054
+ }
15974
16055
  },
15975
16056
  "group list": {
15976
16057
  method: "group.list",
@@ -15990,6 +16071,7 @@ var commands$3 = {
15990
16071
  } },
15991
16072
  params: ({ options }, a) => {
15992
16073
  if (a.path === void 0 && options.clear !== true) throw new CliError("usage", "Missing <jpeg>: ghostly group picture <group> <jpeg> | --clear");
16074
+ if (a.path !== void 0 && options.clear === true) throw new CliError("usage", "--clear removes the picture: not with a <jpeg>");
15993
16075
  return {
15994
16076
  group: a.group,
15995
16077
  path: here(a.path),
@@ -20332,14 +20414,14 @@ async function startRuntime(paths, options = {}) {
20332
20414
  (await import("./assets/ghostly_iroh_web-Dvzh3Y6E.js")).initSync({ module: irohWasmBytes() });
20333
20415
  const [{ registerFileBytes }, { NodeFileBytes }] = await Promise.all([import("./assets/fileBytes-BcYZhNgF.js").then((n) => n.o), import("./assets/fileBytes-Dbifu5I5.js")]);
20334
20416
  registerFileBytes("native", async () => new NodeFileBytes(paths.files), true);
20335
- const [{ EngineServer }, { createHyperEndpoint }] = await Promise.all([import("./assets/server-DHMXMwNn.js").then((n) => n.t), import("./assets/endpoint-pgFkR2AS.js")]);
20417
+ const [{ EngineServer }, { createHyperEndpoint }] = await Promise.all([import("./assets/server-0zfNpABQ.js").then((n) => n.t), import("./assets/endpoint-pgFkR2AS.js")]);
20336
20418
  const network = hyperdhtNetwork();
20337
20419
  const dht = mainlineNetwork();
20338
- const mainline = dht.off ? null : new (await (import("./assets/mainline-DriRu_hb.js"))).Mainline({
20420
+ const mainline = dht.off ? null : new (await (import("./assets/mainline-BH6s8HVi.js"))).Mainline({
20339
20421
  bootstrap: dht.bootstrap,
20340
20422
  host: dht.host
20341
20423
  });
20342
- const transport = mainline || pinned ? new (await (import("./assets/mainline-DriRu_hb.js"))).RelaysAndDht(mainline, pinned ? { relays: pinned } : {}, !!pinned) : null;
20424
+ const transport = mainline || pinned ? new (await (import("./assets/mainline-BH6s8HVi.js"))).RelaysAndDht(mainline, pinned ? { relays: pinned } : {}, !!pinned) : null;
20343
20425
  const server = new EngineServer({
20344
20426
  ...transport ? { transport } : {},
20345
20427
  irohWeb: true,
@@ -21258,7 +21340,7 @@ async function profileCommand(sub, argv) {
21258
21340
  if (!file || !name) throw new CliError("usage", "ghostly profile restore <file> <new profile> [--passphrase-file f] [--use]");
21259
21341
  noMoreThan(2, parsed.positionals, "profile restore <file> <new profile> [--passphrase-file f] [--use]");
21260
21342
  const protection = await backupFileProtection(file);
21261
- const paths = await restoreProfile(g.home, checkProfileName(name), file, protection === "none" ? void 0 : backupPassphrase(parsed.options["passphrase-file"]));
21343
+ const paths = await restoreProfile(g.home, checkProfileName(name), file, protection === "none" ? void 0 : backupPassphrase(parsed.options["passphrase-file"], RESTORE_PASSPHRASE));
21262
21344
  if (parsed.options.use) selectProfile(g.home, name);
21263
21345
  print({
21264
21346
  restored: name,
@@ -21294,10 +21376,13 @@ function onStopSignals(stop) {
21294
21376
  "SIGHUP"
21295
21377
  ]) process.on(signal, stop);
21296
21378
  }
21379
+ var BACKUP_PASSPHRASE = "The backup passphrase comes from --passphrase-file or GHOSTLY_BACKUP_PASSPHRASE (at least 12 characters). For a backup that is not encrypted, say so with --no-passphrase";
21380
+ /** Restore takes no --no-passphrase: a backup made without one says so itself. */
21381
+ var RESTORE_PASSPHRASE = "This backup is encrypted: its passphrase comes from --passphrase-file or GHOSTLY_BACKUP_PASSPHRASE";
21297
21382
  /** The backup passphrase: from a file or the environment, never the command line (it would sit in shell history). */
21298
- function backupPassphrase(file) {
21383
+ function backupPassphrase(file, missing = BACKUP_PASSPHRASE) {
21299
21384
  const value = typeof file === "string" ? readFileSync(file, "utf8").replace(/\r?\n$/, "") : process.env.GHOSTLY_BACKUP_PASSPHRASE;
21300
- if (!value) throw new CliError("usage", "The backup passphrase comes from --passphrase-file or GHOSTLY_BACKUP_PASSPHRASE (at least 12 characters). For a backup that is not encrypted, say so with --no-passphrase");
21385
+ if (!value) throw new CliError("usage", missing);
21301
21386
  return value;
21302
21387
  }
21303
21388
  async function runDaemon(g) {