@routstr/sdk 0.3.11 → 0.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.d.mts +2 -1
- package/dist/browser.d.ts +2 -1
- package/dist/browser.js +360 -28
- package/dist/browser.js.map +1 -1
- package/dist/browser.mjs +355 -29
- package/dist/browser.mjs.map +1 -1
- package/dist/bun.d.mts +2 -1
- package/dist/bun.d.ts +2 -1
- package/dist/bun.js +367 -31
- package/dist/bun.js.map +1 -1
- package/dist/bun.mjs +362 -32
- package/dist/bun.mjs.map +1 -1
- package/dist/client/index.d.mts +85 -1
- package/dist/client/index.d.ts +85 -1
- package/dist/client/index.js +358 -27
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +353 -28
- package/dist/client/index.mjs.map +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +360 -28
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +355 -29
- package/dist/index.mjs.map +1 -1
- package/dist/node.d.mts +2 -1
- package/dist/node.d.ts +2 -1
- package/dist/node.js +367 -31
- package/dist/node.js.map +1 -1
- package/dist/node.mjs +362 -32
- package/dist/node.mjs.map +1 -1
- package/dist/storage/bun.js +6 -1
- package/dist/storage/bun.js.map +1 -1
- package/dist/storage/bun.mjs +6 -1
- package/dist/storage/bun.mjs.map +1 -1
- package/dist/storage/index.js +2 -1
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/index.mjs +2 -1
- package/dist/storage/index.mjs.map +1 -1
- package/dist/storage/node.js +6 -1
- package/dist/storage/node.js.map +1 -1
- package/dist/storage/node.mjs +6 -1
- package/dist/storage/node.mjs.map +1 -1
- package/dist/wallet/index.js +36 -8
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs +36 -8
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +9 -3
package/dist/wallet/index.js
CHANGED
|
@@ -901,15 +901,27 @@ var BalanceManager = class _BalanceManager {
|
|
|
901
901
|
clearTimeout(timeoutId);
|
|
902
902
|
const requestId = response.headers.get("x-routstr-request-id") || void 0;
|
|
903
903
|
if (!response.ok) {
|
|
904
|
-
const
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
904
|
+
const responseBody = await response.text().catch(() => void 0);
|
|
905
|
+
let errorData = {};
|
|
906
|
+
if (responseBody) {
|
|
907
|
+
try {
|
|
908
|
+
errorData = JSON.parse(responseBody);
|
|
909
|
+
} catch {
|
|
910
|
+
errorData = {};
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
this.logger.error("Upstream wallet refund error response", {
|
|
914
|
+
baseUrl,
|
|
915
|
+
url,
|
|
916
|
+
status: response.status,
|
|
917
|
+
statusText: response.statusText,
|
|
918
|
+
requestId,
|
|
919
|
+
body: responseBody ?? "<unable to read response body>"
|
|
920
|
+
});
|
|
909
921
|
return {
|
|
910
922
|
success: false,
|
|
911
923
|
requestId,
|
|
912
|
-
error: `API key refund failed: ${errorData?.detail || response.statusText}`
|
|
924
|
+
error: `API key refund failed: ${errorData?.detail || responseBody || response.statusText}`
|
|
913
925
|
};
|
|
914
926
|
}
|
|
915
927
|
const data = await response.json();
|
|
@@ -1245,11 +1257,27 @@ var BalanceManager = class _BalanceManager {
|
|
|
1245
1257
|
clearTimeout(timeoutId);
|
|
1246
1258
|
const requestId = response.headers.get("x-routstr-request-id") || void 0;
|
|
1247
1259
|
if (!response.ok) {
|
|
1248
|
-
const
|
|
1260
|
+
const responseBody = await response.text().catch(() => void 0);
|
|
1261
|
+
let errorData = {};
|
|
1262
|
+
if (responseBody) {
|
|
1263
|
+
try {
|
|
1264
|
+
errorData = JSON.parse(responseBody);
|
|
1265
|
+
} catch {
|
|
1266
|
+
errorData = {};
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
this.logger.error("Upstream wallet topup error response", {
|
|
1270
|
+
baseUrl,
|
|
1271
|
+
url,
|
|
1272
|
+
status: response.status,
|
|
1273
|
+
statusText: response.statusText,
|
|
1274
|
+
requestId,
|
|
1275
|
+
body: responseBody ?? "<unable to read response body>"
|
|
1276
|
+
});
|
|
1249
1277
|
return {
|
|
1250
1278
|
success: false,
|
|
1251
1279
|
requestId,
|
|
1252
|
-
error: errorData?.detail || `Top up failed with status ${response.status}`
|
|
1280
|
+
error: errorData?.detail || responseBody || `Top up failed with status ${response.status}`
|
|
1253
1281
|
};
|
|
1254
1282
|
}
|
|
1255
1283
|
return { success: true, requestId };
|
package/dist/wallet/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../core/types.ts","../../core/errors.ts","../../wallet/AuditLogger.ts","../../wallet/tokenUtils.ts","../../wallet/CashuSpender.ts","../../wallet/BalanceManager.ts"],"names":["amount","unit","getDecodedToken","mintUrl"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Core types for the Routstr SDK\n * These types are shared across wallet and client modules\n */\n\nexport interface SdkLogger {\n log(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n error(...args: unknown[]): void;\n debug(...args: unknown[]): void;\n child(prefix: string): SdkLogger;\n}\n\nfunction makeConsoleLogger(prefix?: string): SdkLogger {\n const fmt = (args: unknown[]) => (prefix ? [prefix, ...args] : args);\n return {\n log: (...args) => console.log(...fmt(args)),\n warn: (...args) => console.warn(...fmt(args)),\n error: (...args) => console.error(...fmt(args)),\n debug: (...args) => console.log(...fmt(args)),\n child: (p) => makeConsoleLogger(prefix ? `${prefix}:${p}` : p),\n };\n}\n\nexport const consoleLogger: SdkLogger = makeConsoleLogger();\n\nexport const noopLogger: SdkLogger = {\n log: () => {},\n warn: () => {},\n error: () => {},\n debug: () => {},\n child: () => noopLogger,\n};\n\nexport interface MessageContentType {\n type: \"text\" | \"image_url\" | \"file\";\n text?: string;\n image_url?: {\n url: string;\n storageId?: string;\n };\n file?: {\n url: string;\n name?: string;\n mimeType?: string;\n size?: number;\n };\n hidden?: boolean;\n thinking?: string;\n citations?: string[];\n}\n\nexport interface Message {\n role: string;\n content: string | MessageContentType[];\n _eventId?: string;\n _prevId?: string;\n _createdAt?: number;\n _modelId?: string;\n satsSpent?: number;\n}\n\nexport interface TransactionHistory {\n type: \"spent\" | \"mint\" | \"send\" | \"import\" | \"refund\";\n amount: number;\n timestamp: number;\n status: \"success\" | \"failed\";\n model?: string;\n message?: string;\n balance?: number;\n}\n\nexport interface ModelPricing {\n prompt: number;\n completion: number;\n request: number;\n image: number;\n web_search: number;\n internal_reasoning: number;\n}\n\nexport interface ModelSatsPricing extends ModelPricing {\n max_completion_cost: number;\n max_prompt_cost: number;\n max_cost: number;\n}\n\nexport interface ModelArchitecture {\n modality: string;\n input_modalities: readonly string[];\n output_modalities: readonly string[];\n tokenizer: string;\n instruct_type: string | null;\n}\n\nexport interface PerRequestLimits {\n readonly prompt_tokens?: number;\n readonly completion_tokens?: number;\n readonly requests_per_minute?: number;\n readonly images_per_minute?: number;\n readonly web_searches_per_minute?: number;\n readonly [key: string]: number | undefined;\n}\n\nexport interface Model {\n id: string;\n name: string;\n created?: number;\n description?: string;\n context_length?: number;\n architecture?: ModelArchitecture;\n pricing?: ModelPricing;\n sats_pricing: ModelSatsPricing;\n per_request_limits?: PerRequestLimits;\n}\n\n/**\n * Result from spending cashu tokens\n */\nexport interface SpendResult {\n token: string | null;\n status: \"success\" | \"failed\";\n balance: number;\n unit?: \"sat\" | \"msat\";\n error?: string;\n errorDetails?: {\n required: number;\n available: number;\n maxMintBalance: number;\n maxMintUrl: string;\n };\n}\n\n/**\n * Result from refund operations\n */\nexport interface RefundResult {\n success: boolean;\n refundedAmount?: number;\n message?: string;\n requestId?: string;\n}\n\n/**\n * Result from top up operations\n */\nexport interface TopUpResult {\n success: boolean;\n toppedUpAmount?: number;\n message?: string;\n requestId?: string;\n recoveredToken?: boolean;\n}\n\n/**\n * API error verdict for retry logic\n */\nexport interface APIErrorVerdict {\n retry: boolean;\n reason: string;\n newBaseUrl?: string; // New provider to retry with (for 50X errors)\n}\n\n/**\n * Image data from API response\n */\nexport interface ImageData {\n type: \"image_url\";\n image_url: {\n url: string;\n };\n index?: number;\n}\n\n/**\n * Annotation data from API response\n */\nexport interface AnnotationData {\n type: \"url_citation\";\n start_index: number;\n end_index: number;\n url: string;\n title: string;\n}\n\n/**\n * Usage statistics from API response\n */\nexport interface UsageStats {\n total_tokens?: number;\n prompt_tokens?: number;\n completion_tokens?: number;\n cost?: number;\n sats_cost?: number;\n}\n\n/**\n * Result from streaming response processing\n */\nexport interface StreamingResult {\n content: string;\n thinking?: string;\n images?: ImageData[];\n usage?: UsageStats;\n model?: string;\n responseId?: string;\n finish_reason?: string;\n citations?: string[];\n annotations?: AnnotationData[];\n}\n\n/**\n * Parameters for fetching AI response\n */\nexport interface FetchAIResponseParams {\n messageHistory: Message[];\n selectedModel: Model;\n baseUrl: string;\n mintUrl: string;\n balance: number;\n transactionHistory: TransactionHistory[];\n}\n\n/**\n * Candidate provider for failover\n */\nexport interface CandidateProvider {\n baseUrl: string;\n model: Model;\n cost: number;\n}\n\n/**\n * Mint selection result\n */\nexport interface MintSelection {\n selectedMintUrl: string | null;\n selectedMintBalance: number;\n}\n\n/**\n * Pending token entry\n */\nexport interface PendingTokenEntry {\n baseUrl: string;\n amount: number;\n}\n\n/**\n * Provider information from /v1/info endpoint\n */\nexport interface ProviderInfo {\n mints?: string[];\n [key: string]: any;\n}\n\n/**\n * Model discovery result\n */\nexport interface ModelDiscoveryResult {\n models: Model[];\n bestById: Map<string, { model: Model; base: string }>;\n totalProcessed: number;\n}\n\n/**\n * Mint discovery result\n */\nexport interface MintDiscoveryResult {\n mintsFromProviders: Record<string, string[]>;\n infoFromProviders: Record<string, ProviderInfo>;\n}\n","/**\n * Custom error classes for the Routstr SDK\n * Provides specific error types for different failure modes\n */\n\n/**\n * Error thrown when balance is insufficient for an operation\n */\nexport class InsufficientBalanceError extends Error {\n constructor(\n public required: number,\n public available: number,\n public maxMintBalance: number = 0,\n public maxMintUrl: string = \"\",\n customMessage?: string\n ) {\n super(\n customMessage ??\n (`Insufficient balance: need ${required} sats, have ${available} sats available. ` +\n (maxMintBalance > 0\n ? `Largest mint balance: ${maxMintBalance} sats from ${maxMintUrl}`\n : \"\"))\n );\n this.name = \"InsufficientBalanceError\";\n }\n}\n\n/**\n * Error thrown when a provider returns an error response\n */\nexport class ProviderError extends Error {\n constructor(\n public baseUrl: string,\n public statusCode: number,\n message: string,\n public requestId?: string\n ) {\n super(\n `Provider ${baseUrl} returned ${statusCode}: ${message}` +\n (requestId ? ` (Request ID: ${requestId})` : \"\")\n );\n this.name = \"ProviderError\";\n }\n}\n\n/**\n * Error thrown when a mint is unreachable\n */\nexport class MintUnreachableError extends Error {\n constructor(public mintUrl: string) {\n super(\n `Your mint ${mintUrl} is unreachable or is blocking your IP. Please try again later or switch mints.`\n );\n this.name = \"MintUnreachableError\";\n }\n}\n\n/**\n * Error thrown when a token operation fails\n */\nexport class TokenOperationError extends Error {\n constructor(\n message: string,\n public operation: \"send\" | \"receive\" | \"refund\",\n public mintUrl?: string\n ) {\n super(message);\n this.name = \"TokenOperationError\";\n }\n}\n\n/**\n * Error thrown when provider failover fails\n */\nexport class FailoverError extends Error {\n constructor(\n public originalProvider: string,\n public failedProviders: string[],\n message?: string\n ) {\n super(\n message ||\n `All providers failed. Original: ${originalProvider}, Failed: ${failedProviders.join(\", \")}`\n );\n this.name = \"FailoverError\";\n }\n}\n\n/**\n * Error thrown when streaming response processing fails\n */\nexport class StreamingError extends Error {\n constructor(\n message: string,\n public finishReason?: string,\n public accumulatedContent?: string\n ) {\n super(message);\n this.name = \"StreamingError\";\n }\n}\n\n/**\n * Error thrown when model is not found on a provider\n */\nexport class ModelNotFoundError extends Error {\n constructor(public modelId: string, public baseUrl: string) {\n super(`Model '${modelId}' not found on provider ${baseUrl}`);\n this.name = \"ModelNotFoundError\";\n }\n}\n\n/**\n * Error thrown when provider bootstrap fails\n */\nexport class ProviderBootstrapError extends Error {\n constructor(\n public failedProviders: string[],\n message?: string\n ) {\n super(\n message || `Failed to bootstrap providers. Tried: ${failedProviders.join(\", \")}`\n );\n this.name = \"ProviderBootstrapError\";\n }\n}\n\n/**\n * Error thrown when no providers are available\n */\nexport class NoProvidersAvailableError extends Error {\n constructor() {\n super(\"No providers are available for model discovery\");\n this.name = \"NoProvidersAvailableError\";\n }\n}\n\n/**\n * Error thrown when mint discovery fails\n */\nexport class MintDiscoveryError extends Error {\n constructor(\n public baseUrl: string,\n message?: string\n ) {\n super(message || `Failed to discover mints from provider ${baseUrl}`);\n this.name = \"MintDiscoveryError\";\n }\n}\n","/**\n * AuditLogger - Transaction audit logging utility\n * Writes JSON-formatted transaction logs to audit.log\n */\n\nexport interface AuditLogEntry {\n timestamp: string;\n action: \"spend\" | \"topup\" | \"refund\" | \"receive\" | \"balance_check\";\n totalBalance: number;\n providerBalances: Record<string, number>;\n mintBalances: Record<string, number>;\n amount?: number;\n mintUrl?: string;\n baseUrl?: string;\n status: \"success\" | \"failed\";\n details?: string;\n}\n\nexport class AuditLogger {\n private static instance: AuditLogger | null = null;\n\n static getInstance(): AuditLogger {\n if (!AuditLogger.instance) {\n AuditLogger.instance = new AuditLogger();\n }\n return AuditLogger.instance;\n }\n\n async log(entry: Omit<AuditLogEntry, \"timestamp\">): Promise<void> {\n const fullEntry: AuditLogEntry = {\n ...entry,\n timestamp: new Date().toISOString(),\n };\n\n const logLine = JSON.stringify(fullEntry) + \"\\n\";\n\n if (typeof window === \"undefined\") {\n try {\n const fs = await import(\"fs\");\n const path = await import(\"path\");\n const logPath = path.join(process.cwd(), \"audit.log\");\n fs.appendFileSync(logPath, logLine);\n } catch (error) {\n console.error(\"[AuditLogger] Failed to write to file:\", error);\n }\n } else {\n console.log(\"[AUDIT]\", logLine.trim());\n }\n }\n\n async logBalanceSnapshot(\n action: AuditLogEntry[\"action\"],\n amounts: {\n totalBalance: number;\n providerBalances: Record<string, number>;\n mintBalances: Record<string, number>;\n },\n options?: {\n amount?: number;\n mintUrl?: string;\n baseUrl?: string;\n status?: \"success\" | \"failed\";\n details?: string;\n }\n ): Promise<void> {\n await this.log({\n action,\n totalBalance: amounts.totalBalance,\n providerBalances: amounts.providerBalances,\n mintBalances: amounts.mintBalances,\n amount: options?.amount,\n mintUrl: options?.mintUrl,\n baseUrl: options?.baseUrl,\n status: options?.status ?? \"success\",\n details: options?.details,\n });\n }\n}\n\nexport const auditLogger = AuditLogger.getInstance();\n","import type { MintSelection } from \"../core/types\";\n\nexport function isNetworkErrorMessage(message: string): boolean {\n return (\n message.includes(\"NetworkError when attempting to fetch resource\") ||\n message.includes(\"Failed to fetch\") ||\n message.includes(\"Load failed\") ||\n message.includes(\"ERR_TLS_CERT_ALTNAME_INVALID\") ||\n message.includes(\"ERR_TLS_CERT_NOT_YET_VALID\") ||\n message.includes(\"ERR_TLS_CERT_EXPIRED\") ||\n message.includes(\"UNABLE_TO_VERIFY_LEAF_SIGNATURE\") ||\n message.includes(\"SELF_SIGNED_CERT_IN_CHAIN\")\n );\n}\n\nexport function getBalanceInSats(\n balance: number,\n unit: \"sat\" | \"msat\" | string | undefined\n): number {\n return unit === \"msat\" ? balance / 1000 : balance;\n}\n\nexport function getTotalMintBalanceInSats(\n balances: Record<string, number>,\n units: Record<string, \"sat\" | \"msat\">\n): number {\n let total = 0;\n for (const mintUrl in balances) {\n total += getBalanceInSats(balances[mintUrl], units[mintUrl]);\n }\n return total;\n}\n\nexport function selectMintWithBalance(\n balances: Record<string, number>,\n units: Record<string, string>,\n amount: number,\n excludeMints: string[] = []\n): MintSelection {\n for (const mintUrl in balances) {\n if (excludeMints.includes(mintUrl)) {\n continue;\n }\n\n const balanceInSats = getBalanceInSats(balances[mintUrl], units[mintUrl]);\n if (balanceInSats >= amount) {\n return { selectedMintUrl: mintUrl, selectedMintBalance: balanceInSats };\n }\n }\n\n return { selectedMintUrl: null, selectedMintBalance: 0 };\n}\n","/**\n * CashuSpender - Core spending logic for Cashu tokens\n *\n * Handles:\n * - Mint selection with sufficient balance\n * - Provider mint compatibility checks\n * - Retry logic with alternate mints\n * - Critical section management (busy state)\n *\n * Extracted from hooks/useCashuWithXYZ.ts\n */\n\nimport type { WalletAdapter, StorageAdapter } from \"./interfaces\";\nimport type { SpendResult, SdkLogger } from \"../core/types\";\nimport { consoleLogger } from \"../core/types\";\nimport { InsufficientBalanceError } from \"../core/errors\";\nimport { BalanceManager } from \"./BalanceManager\";\nimport { auditLogger } from \"./AuditLogger\";\nimport { getBalanceInSats, isNetworkErrorMessage } from \"./tokenUtils\";\nimport { getDecodedToken } from \"@cashu/cashu-ts\";\n\n/**\n * Options for spending cashu tokens\n */\nexport interface SpendOptions {\n /** The mint URL to send from (can be overridden if insufficient balance) */\n mintUrl: string;\n\n /** The amount to spend in sats */\n amount: number;\n\n /** The provider base URL (for token storage and provider mint checks) */\n baseUrl: string;\n\n /** Whether to reuse an existing token if available */\n reuseToken?: boolean;\n\n /** Optional P2PK public key */\n p2pkPubkey?: string;\n\n /** Array of mint URLs to exclude (for retry logic) */\n excludeMints?: string[];\n\n /** Current retry count (for internal recursion) */\n retryCount?: number;\n\n /** Specific provider baseUrls to refund (if not provided, refunds all except current) */\n refundBaseUrls?: string[];\n}\n\ntype DebugLevel = \"DEBUG\" | \"WARN\" | \"ERROR\";\n\n/**\n * CashuSpender manages the spending of Cashu tokens\n */\nexport class CashuSpender {\n private _isBusy = false;\n private debugLevel: DebugLevel = \"WARN\";\n private readonly logger: SdkLogger;\n\n constructor(\n private walletAdapter: WalletAdapter,\n private storageAdapter: StorageAdapter,\n private _providerRegistry?: unknown,\n private balanceManager?: BalanceManager,\n logger?: SdkLogger\n ) {\n this.logger = (logger ?? consoleLogger).child(\"CashuSpender\");\n }\n\n async receiveToken(token: string): Promise<{\n success: boolean;\n amount: number;\n unit: \"sat\" | \"msat\";\n message?: string;\n }> {\n try {\n const result = await this.walletAdapter.receiveToken(token);\n return result;\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n\n if (errorMessage.includes(\"Failed to fetch mint\")) {\n const cachedTokens = this.storageAdapter.getCachedReceiveTokens();\n const existingIndex = cachedTokens.findIndex((t) => t.token === token);\n if (existingIndex === -1) {\n const { amount, unit } = this._decodeTokenAmount(token);\n this.storageAdapter.setCachedReceiveTokens([\n ...cachedTokens,\n {\n token,\n amount,\n unit,\n createdAt: Date.now(),\n },\n ]);\n }\n }\n\n const { amount, unit } = this._decodeTokenAmount(token);\n return { success: false, amount, unit, message: errorMessage };\n }\n }\n\n private _decodeTokenAmount(token: string): {\n amount: number;\n unit: \"sat\" | \"msat\";\n } {\n try {\n const decoded = getDecodedToken(token);\n const amount = decoded.proofs.reduce(\n (acc, proof) => acc + proof.amount,\n 0\n );\n const unit = (decoded.unit as \"sat\" | \"msat\") || \"sat\";\n return { amount, unit };\n } catch {\n return { amount: 0, unit: \"sat\" };\n }\n }\n\n private async _getBalanceState(): Promise<{\n totalBalance: number;\n providerBalances: Record<string, number>;\n mintBalances: Record<string, number>;\n }> {\n if (this.balanceManager) {\n return this.balanceManager.getBalanceState();\n }\n\n const mintBalances = await this.walletAdapter.getBalances();\n const units = this.walletAdapter.getMintUnits();\n\n let totalMintBalance = 0;\n const normalizedMintBalances: Record<string, number> = {};\n for (const url in mintBalances) {\n const balance = mintBalances[url];\n const unit = units[url];\n const balanceInSats = getBalanceInSats(balance, unit);\n normalizedMintBalances[url] = balanceInSats;\n totalMintBalance += balanceInSats;\n }\n\n const providerBalances: Record<string, number> = {};\n let totalProviderBalance = 0;\n\n const apiKeys = this.storageAdapter.getAllApiKeys();\n for (const apiKey of apiKeys) {\n if (!providerBalances[apiKey.baseUrl]) {\n providerBalances[apiKey.baseUrl] = 0;\n }\n providerBalances[apiKey.baseUrl] += apiKey.balance;\n totalProviderBalance += apiKey.balance;\n }\n\n return {\n totalBalance: totalMintBalance + totalProviderBalance,\n providerBalances,\n mintBalances: normalizedMintBalances,\n };\n }\n\n private async _logTransaction(\n action: \"spend\" | \"topup\" | \"refund\" | \"receive\" | \"balance_check\",\n options?: {\n amount?: number;\n mintUrl?: string;\n baseUrl?: string;\n status?: \"success\" | \"failed\";\n details?: string;\n }\n ): Promise<void> {\n const balanceState = await this._getBalanceState();\n await auditLogger.logBalanceSnapshot(action, balanceState, options);\n }\n\n /**\n * Check if the spender is currently in a critical operation\n */\n get isBusy(): boolean {\n return this._isBusy;\n }\n\n getDebugLevel(): DebugLevel {\n return this.debugLevel;\n }\n\n setDebugLevel(level: DebugLevel): void {\n this.debugLevel = level;\n }\n\n private _log(level: \"DEBUG\" | \"WARN\" | \"ERROR\", ...args: unknown[]): void {\n const levelPriority: Record<DebugLevel, number> = {\n DEBUG: 0,\n WARN: 1,\n ERROR: 2,\n };\n\n if (levelPriority[level] >= levelPriority[this.debugLevel]) {\n switch (level) {\n case \"DEBUG\":\n this.logger.log(...args);\n break;\n case \"WARN\":\n this.logger.warn(...args);\n break;\n case \"ERROR\":\n this.logger.error(...args);\n break;\n }\n }\n }\n\n /**\n * Spend Cashu tokens with automatic mint selection and retry logic\n * Throws errors on failure instead of returning failed SpendResult\n */\n async spend(options: SpendOptions): Promise<SpendResult> {\n const {\n mintUrl,\n amount,\n baseUrl,\n reuseToken = false,\n p2pkPubkey,\n excludeMints = [],\n retryCount = 0,\n } = options;\n\n this._isBusy = true;\n\n try {\n const result = await this._spendInternal({\n mintUrl,\n amount,\n baseUrl,\n reuseToken,\n p2pkPubkey,\n excludeMints,\n retryCount,\n });\n\n if (result.status === \"failed\" || !result.token) {\n const errorMsg =\n result.error || `Insufficient balance. Need ${amount} sats.`;\n\n if (this._isNetworkError(errorMsg)) {\n throw new Error(\n `Your mint ${mintUrl} is unreachable or is blocking your IP. Please try again later or switch mints.`\n );\n }\n\n if (result.errorDetails) {\n throw new InsufficientBalanceError(\n result.errorDetails.required,\n result.errorDetails.available,\n result.errorDetails.maxMintBalance,\n result.errorDetails.maxMintUrl\n );\n }\n\n throw new Error(errorMsg);\n }\n\n return result;\n } finally {\n this._isBusy = false;\n }\n }\n\n /**\n * Check if error message indicates a network error\n */\n private _isNetworkError(message: string): boolean {\n return (\n isNetworkErrorMessage(message) ||\n (message.includes(\"Your mint\") && message.includes(\"unreachable\"))\n );\n }\n\n /**\n * Internal spending logic\n */\n private async _spendInternal(options: SpendOptions): Promise<SpendResult> {\n let {\n mintUrl,\n amount,\n baseUrl,\n reuseToken,\n p2pkPubkey,\n excludeMints,\n retryCount,\n } = options;\n\n this._log(\n \"DEBUG\",\n `[CashuSpender] _spendInternal: amount=${amount}, mintUrl=${mintUrl}, baseUrl=${baseUrl}, reuseToken=${reuseToken}`\n );\n\n // Validate amount\n let adjustedAmount = Math.ceil(amount);\n if (!adjustedAmount || isNaN(adjustedAmount)) {\n this._log(\n \"ERROR\",\n `[CashuSpender] _spendInternal: Invalid amount: ${amount}`\n );\n return {\n token: null,\n status: \"failed\",\n balance: 0,\n error: \"Please enter a valid amount\",\n };\n }\n\n // Try to get existing token for reuse\n if (reuseToken && baseUrl) {\n this._log(\n \"DEBUG\",\n `[CashuSpender] _spendInternal: Attempting to reuse token for ${baseUrl}`\n );\n const existingResult = await this._tryReuseToken(\n baseUrl,\n adjustedAmount,\n mintUrl\n );\n if (existingResult) {\n this._log(\n \"DEBUG\",\n `[CashuSpender] _spendInternal: Successfully reused token, balance: ${existingResult.balance}`\n );\n return existingResult;\n }\n this._log(\n \"DEBUG\",\n `[CashuSpender] _spendInternal: Could not reuse token, will create new token`\n );\n }\n\n // Get current balance state\n const balanceState = await this._getBalanceState();\n const totalAvailableBalance = balanceState.totalBalance;\n\n this._log(\n \"DEBUG\",\n `[CashuSpender] _spendInternal: totalAvailableBalance=${totalAvailableBalance}, adjustedAmount=${adjustedAmount}`\n );\n\n // Check total balance\n if (totalAvailableBalance < adjustedAmount) {\n this._log(\n \"ERROR\",\n `[CashuSpender] _spendInternal: Insufficient balance, have=${totalAvailableBalance}, need=${adjustedAmount}`\n );\n return this._createInsufficientBalanceError(\n adjustedAmount,\n balanceState.mintBalances,\n totalAvailableBalance\n );\n }\n\n let token: string | null = null;\n let selectedMintUrl: string | undefined;\n let spentAmount = adjustedAmount;\n\n if (this.balanceManager) {\n const tokenResult = await this.balanceManager.createProviderToken({\n mintUrl,\n baseUrl,\n amount: adjustedAmount,\n p2pkPubkey,\n excludeMints,\n retryCount,\n });\n\n if (!tokenResult.success || !tokenResult.token) {\n if ((tokenResult.error || \"\").includes(\"Insufficient balance\")) {\n return this._createInsufficientBalanceError(\n adjustedAmount,\n balanceState.mintBalances,\n totalAvailableBalance\n );\n }\n\n return {\n token: null,\n status: \"failed\",\n balance: 0,\n error: tokenResult.error || \"Failed to create token\",\n };\n }\n\n token = tokenResult.token;\n selectedMintUrl = tokenResult.selectedMintUrl;\n spentAmount = tokenResult.amountSpent || adjustedAmount;\n } else {\n try {\n token = await this.walletAdapter.sendToken(\n mintUrl,\n adjustedAmount,\n p2pkPubkey\n );\n selectedMintUrl = mintUrl;\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n return {\n token: null,\n status: \"failed\",\n balance: 0,\n error: `Error generating token: ${errorMsg}`,\n };\n }\n }\n\n // Store token and return\n if (token) {\n this._log(\n \"DEBUG\",\n `[CashuSpender] _spendInternal: Successfully spent ${spentAmount}, returning token with balance=${spentAmount}`\n );\n }\n\n this._logTransaction(\"spend\", {\n amount: spentAmount,\n mintUrl: selectedMintUrl || mintUrl,\n baseUrl,\n status: \"success\",\n });\n\n this._log(\n \"DEBUG\",\n `[CashuSpender] _spendInternal: Successfully spent ${spentAmount}, returning token with balance=${spentAmount}`\n );\n\n const units = this.walletAdapter.getMintUnits();\n\n return {\n token,\n status: \"success\",\n balance: spentAmount,\n unit:\n (selectedMintUrl ? units[selectedMintUrl] : units[mintUrl]) || \"sat\",\n };\n }\n\n /**\n * Try to reuse an existing API key\n */\n private async _tryReuseToken(\n baseUrl: string,\n amount: number,\n mintUrl: string\n ): Promise<SpendResult | null> {\n const apiKeyEntry = this.storageAdapter.getApiKey(baseUrl);\n if (!apiKeyEntry) return null;\n\n // Get pending distribution to check balance\n const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();\n const balanceForBaseUrl =\n apiKeyDistribution.find((b) => b.baseUrl === baseUrl)?.amount || 0;\n\n this._log(\"DEBUG\", \"Reusing API key\", balanceForBaseUrl, amount);\n\n if (balanceForBaseUrl > amount) {\n const units = this.walletAdapter.getMintUnits();\n const unit = units[mintUrl] || \"sat\";\n return {\n token: apiKeyEntry.key,\n status: \"success\",\n balance: balanceForBaseUrl,\n unit,\n };\n }\n\n // API key exists but insufficient balance - attempt topup\n if (this.balanceManager) {\n const topUpAmount = Math.ceil(amount * 1.2 - balanceForBaseUrl);\n const topUpResult = await this.balanceManager.topUp({\n mintUrl,\n baseUrl,\n amount: topUpAmount,\n token: apiKeyEntry.key,\n });\n this._log(\"DEBUG\", \"TOPUP \", topUpResult);\n\n if (topUpResult.success && topUpResult.toppedUpAmount) {\n const newBalance = balanceForBaseUrl + topUpResult.toppedUpAmount;\n const units = this.walletAdapter.getMintUnits();\n const unit = units[mintUrl] || \"sat\";\n\n this._logTransaction(\"topup\", {\n amount: topUpResult.toppedUpAmount,\n mintUrl,\n baseUrl,\n status: \"success\",\n });\n\n return {\n token: apiKeyEntry.key,\n status: \"success\",\n balance: newBalance,\n unit,\n };\n }\n\n const providerBalance = await this._getProviderTokenBalance(\n baseUrl,\n apiKeyEntry.key\n );\n this._log(\"DEBUG\", providerBalance);\n if (providerBalance <= 0) {\n this.storageAdapter.removeApiKey(baseUrl);\n }\n }\n\n return null;\n }\n\n /**\n * Refund all xcashu tokens from storage by calling the provider's refund endpoint.\n * The xcashu token acts as an API key to claim the refund, and the response contains\n * the actual refunded Cashu token which is then received into the wallet.\n * @param mintUrl - The mint URL for receiving tokens\n * @param excludeBaseUrls - Base URLs to exclude from refund (optional)\n * @returns Results for each xcashu token refund attempt\n */\n async refundXcashuTokens(\n mintUrl: string,\n excludeBaseUrls?: string[]\n ): Promise<\n { baseUrl: string; token: string; success: boolean; error?: string }[]\n > {\n const results: {\n baseUrl: string;\n token: string;\n success: boolean;\n error?: string;\n }[] = [];\n const xcashuTokens = this.storageAdapter.getXcashuTokens();\n const excludedUrls = new Set(excludeBaseUrls || []);\n\n for (const [baseUrl, tokens] of Object.entries(xcashuTokens)) {\n if (excludedUrls.has(baseUrl)) continue;\n\n for (const xcashuToken of tokens) {\n try {\n // XCashu tokens need to be sent to the provider's refund endpoint\n // The xcashu token acts as an API key, and the response contains the actual refunded token\n if (!this.balanceManager) {\n throw new Error(\"BalanceManager not available for xcashu refund\");\n }\n\n // Call the refund endpoint using the xcashu token as the API key\n const fetchResult = await this.balanceManager.fetchRefundToken(\n baseUrl,\n xcashuToken.token,\n true\n );\n\n if (!fetchResult.success || !fetchResult.token) {\n throw new Error(\n fetchResult.error || \"Failed to fetch refund token from provider\"\n );\n }\n\n // Receive the refunded Cashu token into the wallet\n const receiveResult = await this.receiveToken(fetchResult.token);\n\n if (receiveResult.success) {\n // Remove successfully refunded token from storage\n this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);\n results.push({\n baseUrl,\n token: xcashuToken.token,\n success: true,\n });\n this._log(\n \"DEBUG\",\n `[CashuSpender] refundXcashuTokens: Successfully refunded xcashu token for ${baseUrl}, amount=${receiveResult.amount}`\n );\n } else {\n // Refund failed - increment tryCount\n const currentTryCount = xcashuToken.tryCount ?? 0;\n const newTryCount = currentTryCount + 1;\n this.storageAdapter.updateXcashuTokenTryCount(\n xcashuToken.token,\n newTryCount\n );\n results.push({\n baseUrl,\n token: xcashuToken.token,\n success: false,\n error: receiveResult.message ?? \"Refund failed\",\n });\n this._log(\n \"DEBUG\",\n `[CashuSpender] refundXcashuTokens: Failed to receive refund token for ${baseUrl}, incremented tryCount to ${newTryCount}: ${receiveResult.message}`\n );\n }\n } catch (error) {\n // Exception occurred - increment tryCount\n const currentTryCount = xcashuToken.tryCount ?? 0;\n const newTryCount = currentTryCount + 1;\n this.storageAdapter.updateXcashuTokenTryCount(\n xcashuToken.token,\n newTryCount\n );\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n results.push({\n baseUrl,\n token: xcashuToken.token,\n success: false,\n error: errorMessage,\n });\n this._log(\n \"ERROR\",\n `[CashuSpender] refundXcashuTokens: Exception during refund for ${baseUrl}: ${errorMessage}, incremented tryCount to ${newTryCount}`\n );\n }\n }\n }\n\n return results;\n }\n\n /**\n * Refund specific providers without retrying spend\n */\n async refundProviders(\n mintUrl: string,\n forceRefund?: boolean\n ): Promise<{ baseUrl: string; success: boolean }[]> {\n const results: { baseUrl: string; success: boolean }[] = [];\n\n const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();\n\n // Refresh balances from providers before refunding\n for (const apiKeyEntry of apiKeyDistribution) {\n const apiKeyEntryFull = this.storageAdapter.getApiKey(\n apiKeyEntry.baseUrl\n );\n\n if (apiKeyEntryFull && this.balanceManager) {\n try {\n const balanceResult = await this.balanceManager.getTokenBalance(\n apiKeyEntryFull.key,\n apiKeyEntry.baseUrl\n );\n\n if (balanceResult.isInvalidApiKey) {\n // Key is invalid/expired on the provider side — clean it up\n this.logger.warn(\n `refundProviders: ${apiKeyEntry.baseUrl} returned invalid API key; removing local key and treating as success`\n );\n this.storageAdapter.removeApiKey(apiKeyEntry.baseUrl);\n results.push({\n baseUrl: apiKeyEntry.baseUrl,\n success: true,\n });\n continue;\n }\n\n if (balanceResult.amount >= 0 && !balanceResult.balanceUnknown) {\n const balanceSat = balanceResult.unit === \"msat\"\n ? Math.floor(balanceResult.amount / 1000)\n : balanceResult.amount;\n this.storageAdapter.updateApiKeyBalance(\n apiKeyEntry.baseUrl,\n balanceSat\n );\n } else {\n this.logger.warn(\n `refundProviders: balance refresh for ${apiKeyEntry.baseUrl} returned negative amount; keeping stale local balance=${apiKeyEntryFull.balance}`\n );\n }\n } catch (error) {\n // Balance check failed — proceed with stale local balance\n this.logger.warn(\n `refundProviders: balance refresh threw for ${apiKeyEntry.baseUrl}; proceeding with stale local balance`,\n error\n );\n }\n\n // Re-read the entry after balance refresh (may have been removed above)\n const refreshedEntry = this.storageAdapter.getApiKey(\n apiKeyEntry.baseUrl\n );\n if (!refreshedEntry) {\n continue;\n }\n\n const refundResult = await this.balanceManager.refundApiKey({\n mintUrl,\n baseUrl: apiKeyEntry.baseUrl,\n apiKey: refreshedEntry.key,\n forceRefund,\n });\n\n if (refundResult.success) {\n this.storageAdapter.removeApiKey(apiKeyEntry.baseUrl);\n } else {\n const currentEntry = this.storageAdapter.getApiKey(\n apiKeyEntry.baseUrl\n );\n this.logger.warn(\n `refundProviders: refund failed for ${apiKeyEntry.baseUrl}; currentEntry=${Boolean(currentEntry)} balance=${currentEntry?.balance ?? \"none\"}. Touching lastUsed to rate-limit retries.`\n );\n if (currentEntry) {\n this.storageAdapter.updateApiKeyBalance(\n apiKeyEntry.baseUrl,\n currentEntry.balance\n ); // update lastUsed so we only try to refund every 5 mins.\n }\n }\n\n results.push({\n baseUrl: apiKeyEntry.baseUrl,\n success: refundResult.success,\n });\n } else {\n this.logger.warn(\n `refundProviders: cannot refund ${apiKeyEntry.baseUrl}; apiKeyEntryFull=${Boolean(apiKeyEntryFull)} balanceManager=${Boolean(this.balanceManager)}`\n );\n results.push({\n baseUrl: apiKeyEntry.baseUrl,\n success: false,\n });\n }\n }\n\n return results;\n }\n\n /**\n * Create an insufficient balance error result\n */\n private _createInsufficientBalanceError(\n required: number,\n normalizedBalances: Record<string, number>,\n availableBalance?: number\n ): SpendResult {\n let maxBalance = 0;\n let maxMintUrl = \"\";\n\n for (const mintUrl in normalizedBalances) {\n const balanceInSats = normalizedBalances[mintUrl];\n\n if (balanceInSats > maxBalance) {\n maxBalance = balanceInSats;\n maxMintUrl = mintUrl;\n }\n }\n\n const error = new InsufficientBalanceError(\n required,\n availableBalance ?? maxBalance,\n maxBalance,\n maxMintUrl\n );\n\n return {\n token: null,\n status: \"failed\",\n balance: 0,\n error: error.message,\n errorDetails: {\n required,\n available: availableBalance ?? maxBalance,\n maxMintBalance: maxBalance,\n maxMintUrl,\n },\n };\n }\n\n private async _getProviderTokenBalance(\n baseUrl: string,\n token: string\n ): Promise<number> {\n try {\n const response = await fetch(`${baseUrl}v1/wallet/info`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (response.ok) {\n const data = await response.json();\n return data.balance / 1000;\n }\n } catch {\n return 0;\n }\n return 0;\n }\n}\n","/**\n * BalanceManager - Handles refunding and topping up tokens from providers\n *\n * Handles:\n * - Fetching refund tokens from provider API\n * - Receiving/storing refunded tokens\n * - Topping up API key balances with cashu tokens\n * - Error handling for various refund/topup failure modes\n *\n * Extracted from utils/cashuUtils.ts\n */\n\nimport type {\n WalletAdapter,\n StorageAdapter,\n ProviderRegistry,\n} from \"./interfaces\";\nimport type { RefundResult, TopUpResult, SdkLogger } from \"../core/types\";\nimport { consoleLogger } from \"../core/types\";\nimport { InsufficientBalanceError } from \"../core/errors\";\nimport { CashuSpender } from \"./CashuSpender\";\nimport {\n getBalanceInSats,\n isNetworkErrorMessage,\n selectMintWithBalance,\n} from \"./tokenUtils\";\n\n/**\n * Options for refunding API key balance\n */\nexport interface RefundApiKeyOptions {\n /** The mint URL (for NIP-60 wallet operations) */\n mintUrl: string;\n\n /** The provider base URL */\n baseUrl: string;\n\n /** The API key to use for authentication */\n apiKey: string;\n\n /** If true, forces refund even if the API key was used recently */\n forceRefund?: boolean;\n}\n\n/**\n * Options for topping up API key balance\n */\nexport interface TopUpOptions {\n /** The mint URL to spend from */\n mintUrl: string;\n\n /** The provider base URL */\n baseUrl: string;\n\n /** Amount to top up in sats */\n amount: number;\n\n /** Optional specific API key to top up (if not provided, uses stored token) */\n token?: string;\n}\n\nexport interface CreateProviderTokenOptions {\n mintUrl: string;\n baseUrl: string;\n amount: number;\n p2pkPubkey?: string;\n excludeMints?: string[];\n retryCount?: number;\n}\n\nexport interface ProviderTokenResult {\n success: boolean;\n token?: string;\n error?: string;\n selectedMintUrl?: string;\n amountSpent?: number;\n}\n\nexport interface BalanceState {\n totalBalance: number;\n providerBalances: Record<string, number>;\n mintBalances: Record<string, number>;\n}\n\n/**\n * BalanceManager handles token refunds and topups from providers\n */\nexport class BalanceManager {\n private cashuSpender: CashuSpender;\n /** In-memory guard for per-provider wallet mutations (topup / refund) */\n private providerWalletOps: Map<\n string,\n { type: \"topup\" | \"refund\"; startTime: number; endTime?: number }\n > = new Map();\n /** Cooldown (ms) between opposite operations on the same provider */\n private static readonly PROVIDER_WALLET_COOLDOWN_MS = 10_000;\n private readonly logger: SdkLogger;\n\n constructor(\n private walletAdapter: WalletAdapter,\n private storageAdapter: StorageAdapter,\n private providerRegistry?: ProviderRegistry,\n cashuSpender?: CashuSpender,\n logger?: SdkLogger\n ) {\n this.logger = (logger ?? consoleLogger).child(\"BalanceManager\");\n if (cashuSpender) {\n this.cashuSpender = cashuSpender;\n } else {\n this.cashuSpender = new CashuSpender(\n walletAdapter,\n storageAdapter,\n providerRegistry,\n this,\n this.logger\n );\n }\n }\n\n /**\n * Check whether a wallet operation (topup/refund) may run for a provider.\n * Returns the reason when blocked.\n */\n private _canRunProviderWalletOperation(\n baseUrl: string,\n type: \"topup\" | \"refund\"\n ): { allowed: boolean; reason?: string } {\n const existing = this.providerWalletOps.get(baseUrl);\n if (!existing) {\n return { allowed: true };\n }\n if (existing.type === type) {\n return { allowed: true };\n }\n // Opposite type in progress or recently completed\n if (!existing.endTime) {\n return {\n allowed: false,\n reason: `Provider wallet operation locked; ${existing.type} in progress`,\n };\n }\n const elapsed = Date.now() - existing.endTime;\n if (elapsed < BalanceManager.PROVIDER_WALLET_COOLDOWN_MS) {\n return {\n allowed: false,\n reason: `Provider wallet operation locked; recent ${existing.type} completed ${Math.round(elapsed / 1000)}s ago`,\n };\n }\n // Cooldown expired — clean up stale entry\n this.providerWalletOps.delete(baseUrl);\n return { allowed: true };\n }\n\n private _beginProviderWalletOperation(\n baseUrl: string,\n type: \"topup\" | \"refund\"\n ): void {\n this.providerWalletOps.set(baseUrl, { type, startTime: Date.now() });\n }\n\n private _endProviderWalletOperation(\n baseUrl: string,\n type: \"topup\" | \"refund\"\n ): void {\n const existing = this.providerWalletOps.get(baseUrl);\n if (existing && existing.type === type) {\n existing.endTime = Date.now();\n }\n }\n\n async getBalanceState(): Promise<BalanceState> {\n const mintBalances = await this.walletAdapter.getBalances();\n const units = this.walletAdapter.getMintUnits();\n\n let totalMintBalance = 0;\n const normalizedMintBalances: Record<string, number> = {};\n for (const url in mintBalances) {\n const balance = mintBalances[url];\n const unit = units[url];\n const balanceInSats = getBalanceInSats(balance, unit);\n normalizedMintBalances[url] = balanceInSats;\n totalMintBalance += balanceInSats;\n }\n\n const providerBalances: Record<string, number> = {};\n let totalProviderBalance = 0;\n\n const apiKeys = this.storageAdapter.getAllApiKeys();\n for (const apiKey of apiKeys) {\n if (!providerBalances[apiKey.baseUrl]) {\n providerBalances[apiKey.baseUrl] = 0;\n }\n providerBalances[apiKey.baseUrl] += apiKey.balance;\n totalProviderBalance += apiKey.balance;\n }\n\n return {\n totalBalance: totalMintBalance + totalProviderBalance,\n providerBalances,\n mintBalances: normalizedMintBalances,\n };\n }\n\n /**\n * Refund API key balance - convert remaining API key balance to cashu token\n * @param options - Refund options including forceRefund flag\n * @returns Refund result\n */\n async refundApiKey(options: RefundApiKeyOptions): Promise<RefundResult> {\n const { mintUrl, baseUrl, apiKey, forceRefund } = options;\n\n const guard = this._canRunProviderWalletOperation(baseUrl, \"refund\");\n if (!guard.allowed) {\n this.logger.log(`Skipping refund for ${baseUrl} - ${guard.reason}`);\n return { success: false, message: guard.reason };\n }\n\n this._beginProviderWalletOperation(baseUrl, \"refund\");\n\n try {\n return await this._refundApiKeyImpl({ mintUrl, baseUrl, apiKey, forceRefund });\n } finally {\n this._endProviderWalletOperation(baseUrl, \"refund\");\n }\n }\n\n private async _refundApiKeyImpl(options: RefundApiKeyOptions): Promise<RefundResult> {\n const { mintUrl, baseUrl, apiKey, forceRefund } = options;\n\n if (!apiKey) {\n this.logger.warn(`refundApiKey: aborting for ${baseUrl} - no API key`);\n return { success: false, message: \"No API key to refund\" };\n }\n\n // If forceRefund is not true, skip refund if the API key was used in the last 5 minutes\n if (!forceRefund) {\n const apiKeyEntry = this.storageAdapter.getApiKey(baseUrl);\n if (apiKeyEntry?.lastUsed) {\n const fiveMinutesAgo = Date.now() - 5 * 60 * 1000;\n if (apiKeyEntry.lastUsed > fiveMinutesAgo) {\n this.logger.log(\n `refundApiKey: skipping ${baseUrl} - used ${Math.round((Date.now() - apiKeyEntry.lastUsed) / 1000)}s ago`\n );\n return {\n success: false,\n message: \"API key was used recently, skipping refund\",\n };\n }\n }\n }\n\n let fetchResult:\n | { success: boolean; token?: string; requestId?: string; error?: string }\n | undefined;\n\n try {\n fetchResult = await this.fetchRefundToken(baseUrl, apiKey);\n\n if (fetchResult.error === \"No balance to refund\") {\n this.logger.log(`refundApiKey: provider says no balance for ${baseUrl}; removing API key`);\n this.storageAdapter.removeApiKey(baseUrl);\n return { success: true, message: \"No balance to refund, key cleaned up\" };\n }\n\n if (!fetchResult.success) {\n this.logger.warn(\n `refundApiKey: fetch failed for ${baseUrl}: ${fetchResult.error || \"API key refund failed\"}`\n );\n return {\n success: false,\n message: fetchResult.error || \"API key refund failed\",\n requestId: fetchResult.requestId,\n };\n }\n\n if (!fetchResult.token) {\n this.logger.warn(`refundApiKey: no token received for ${baseUrl}`);\n return {\n success: false,\n message: \"No token received from API key refund\",\n requestId: fetchResult.requestId,\n };\n }\n\n const receiveResult = await this.cashuSpender.receiveToken(\n fetchResult.token\n );\n const totalAmountMsat =\n receiveResult.unit === \"msat\"\n ? receiveResult.amount\n : receiveResult.amount * 1000;\n\n if (receiveResult.success) {\n this.storageAdapter.removeApiKey(baseUrl);\n } else {\n this.logger.warn(\n `refundApiKey: receive failed for ${baseUrl}; keeping API key. message=${receiveResult.message ?? \"none\"}`\n );\n }\n\n return {\n success: receiveResult.success,\n refundedAmount: totalAmountMsat,\n message: receiveResult.message,\n requestId: fetchResult.requestId,\n };\n } catch (error) {\n this.logger.error(\"API key refund error\", error);\n return this._handleRefundError(error, mintUrl, fetchResult?.requestId);\n }\n }\n\n /**\n * Fetch refund token from provider API using API key (or xcashu token) authentication\n */\n async fetchRefundToken(\n baseUrl: string,\n apiKeyOrToken: string,\n xCashu: boolean = false\n ): Promise<{\n success: boolean;\n token?: string;\n requestId?: string;\n error?: string;\n }> {\n if (!baseUrl) {\n return {\n success: false,\n error: \"No base URL configured\",\n };\n }\n\n const normalizedBaseUrl = baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`;\n const url = `${normalizedBaseUrl}v1/wallet/refund`;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => {\n controller.abort();\n }, 60000);\n\n try {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (xCashu) {\n headers[\"X-Cashu\"] = apiKeyOrToken;\n } else {\n headers[\"Authorization\"] = `Bearer ${apiKeyOrToken}`;\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n const requestId =\n response.headers.get(\"x-routstr-request-id\") || undefined;\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n this.logger.warn(\n `fetchRefundToken: non-ok response for ${url} status=${response.status} statusText=${response.statusText}`,\n errorData\n );\n return {\n success: false,\n requestId,\n error: `API key refund failed: ${\n errorData?.detail || response.statusText\n }`,\n };\n }\n\n const data = await response.json();\n return {\n success: true,\n token: data.token,\n requestId,\n };\n } catch (error) {\n clearTimeout(timeoutId);\n this.logger.error(\"fetchRefundToken fetch error\", error);\n\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n return {\n success: false,\n error: \"Request timed out after 1 minute\",\n };\n }\n return {\n success: false,\n error: error.message,\n };\n }\n\n return {\n success: false,\n error: \"Unknown error occurred during API key refund request\",\n };\n }\n }\n\n /**\n * Top up API key balance with a cashu token\n */\n async topUp(options: TopUpOptions): Promise<TopUpResult> {\n const { mintUrl, baseUrl, amount, token: providedToken } = options;\n\n const guard = this._canRunProviderWalletOperation(baseUrl, \"topup\");\n if (!guard.allowed) {\n this.logger.log(`Skipping topup for ${baseUrl} - ${guard.reason}`);\n return { success: false, message: guard.reason };\n }\n\n this._beginProviderWalletOperation(baseUrl, \"topup\");\n\n try {\n return await this._topUpImpl({ mintUrl, baseUrl, amount, token: providedToken });\n } finally {\n this._endProviderWalletOperation(baseUrl, \"topup\");\n }\n }\n\n private async _topUpImpl(options: TopUpOptions): Promise<TopUpResult> {\n const { mintUrl, baseUrl, amount, token: providedToken } = options;\n\n if (!amount || amount <= 0) {\n return { success: false, message: \"Invalid top up amount\" };\n }\n\n const apiKeyEntry = providedToken\n ? null // providedToken is now the apiKey for apikeys mode\n : this.storageAdapter.getApiKey(baseUrl);\n const apiKey = providedToken || apiKeyEntry?.key;\n\n if (!apiKey) {\n return { success: false, message: \"No API key available for top up\" };\n }\n\n let cashuToken: string | null = null;\n let requestId: string | undefined;\n\n try {\n const tokenResult = await this.createProviderToken({\n mintUrl,\n baseUrl,\n amount,\n });\n\n if (!tokenResult.success || !tokenResult.token) {\n return {\n success: false,\n message: tokenResult.error || \"Unable to create top up token\",\n };\n }\n\n cashuToken = tokenResult.token;\n\n const topUpResult = await this._postTopUp(baseUrl, apiKey, cashuToken);\n requestId = topUpResult.requestId;\n this.logger.log(\"topUpResult:\", topUpResult);\n\n if (!topUpResult.success) {\n await this._recoverFailedTopUp(cashuToken);\n return {\n success: false,\n message: topUpResult.error || \"Top up failed\",\n requestId,\n recoveredToken: true,\n };\n }\n\n return {\n success: true,\n toppedUpAmount: amount,\n requestId,\n };\n } catch (error) {\n this.logger.log(`topup error for ${baseUrl}: ${error}`);\n if (cashuToken) {\n await this._recoverFailedTopUp(cashuToken);\n }\n\n return this._handleTopUpError(error, mintUrl, requestId);\n }\n }\n\n async createProviderToken(\n options: CreateProviderTokenOptions\n ): Promise<ProviderTokenResult> {\n const {\n mintUrl,\n baseUrl,\n amount,\n retryCount = 0,\n excludeMints = [],\n p2pkPubkey,\n } = options;\n\n const adjustedAmount = Math.ceil(amount);\n this.logger.log(`createProviderToken: baseUrl=${baseUrl} mintUrl=${mintUrl} amount=${amount} adjustedAmount=${adjustedAmount} retryCount=${retryCount}`);\n if (!adjustedAmount || isNaN(adjustedAmount)) {\n this.logger.error(`createProviderToken: invalid amount=${amount}`);\n return { success: false, error: \"Invalid top up amount\" };\n }\n\n const balanceState = await this.getBalanceState();\n const balances = await this.walletAdapter.getBalances();\n const units = this.walletAdapter.getMintUnits();\n\n const totalMintBalance = Object.values(balanceState.mintBalances).reduce(\n (sum, value) => sum + value,\n 0\n );\n const targetProviderBalance = balanceState.providerBalances[baseUrl] || 0;\n const refundableProviderBalance = Object.entries(\n balanceState.providerBalances\n )\n .filter(([providerBaseUrl]) => providerBaseUrl !== baseUrl)\n .reduce((sum, [, value]) => sum + value, 0);\n\n if (\n totalMintBalance + targetProviderBalance < adjustedAmount &&\n totalMintBalance + targetProviderBalance + refundableProviderBalance >=\n adjustedAmount &&\n retryCount < 3\n ) {\n await this._refundOtherProvidersForTopUp(baseUrl, mintUrl, retryCount, adjustedAmount);\n return this.createProviderToken({\n ...options,\n retryCount: retryCount + 1,\n });\n }\n\n if (totalMintBalance + targetProviderBalance < adjustedAmount) {\n const error = new InsufficientBalanceError(\n adjustedAmount,\n totalMintBalance + targetProviderBalance,\n totalMintBalance,\n Object.entries(balanceState.mintBalances).reduce(\n (max, [url, balance]) =>\n balance > max.balance ? { url, balance } : max,\n { url: \"\", balance: 0 }\n ).url\n );\n this.logger.error(`createProviderToken: insufficient balance required=${adjustedAmount} available=${totalMintBalance + targetProviderBalance} totalMint=${totalMintBalance} targetProvider=${targetProviderBalance}`);\n return { success: false, error: error.message };\n }\n\n const providerMints =\n baseUrl && this.providerRegistry\n ? this.providerRegistry.getProviderMints(baseUrl)\n : [];\n\n let requiredAmount = adjustedAmount;\n const supportedMintsOnly = providerMints.length > 0;\n\n let candidates = this._selectCandidateMints({\n balances,\n units,\n amount: requiredAmount,\n preferredMintUrl: mintUrl,\n excludeMints,\n allowedMints: supportedMintsOnly ? providerMints : undefined,\n });\n\n if (candidates.length === 0 && supportedMintsOnly) {\n requiredAmount += 2;\n candidates = this._selectCandidateMints({\n balances,\n units,\n amount: requiredAmount,\n preferredMintUrl: mintUrl,\n excludeMints,\n });\n }\n\n if (candidates.length === 0) {\n let maxBalance = 0;\n let maxMintUrl = \"\";\n for (const mintUrl in balances) {\n const balance = balances[mintUrl];\n const unit = units[mintUrl];\n const balanceInSats = getBalanceInSats(balance, unit);\n if (balanceInSats > maxBalance) {\n maxBalance = balanceInSats;\n maxMintUrl = mintUrl;\n }\n }\n\n this.logger.error(`createProviderToken: no candidate mints required=${requiredAmount} totalMint=${totalMintBalance} maxBalance=${maxBalance} maxMint=${maxMintUrl}`);\n const error = new InsufficientBalanceError(\n adjustedAmount,\n totalMintBalance,\n maxBalance,\n maxMintUrl\n );\n\n return { success: false, error: error.message };\n }\n\n let lastError: string | undefined;\n for (const candidateMint of candidates) {\n try {\n this.logger.log(`createProviderToken: attempting mint=${candidateMint} amount=${requiredAmount}`);\n const token = await this.walletAdapter.sendToken(\n candidateMint,\n requiredAmount,\n p2pkPubkey\n );\n this.logger.log(`createProviderToken: success from mint=${candidateMint}`);\n return {\n success: true,\n token,\n selectedMintUrl: candidateMint,\n amountSpent: requiredAmount,\n };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.logger.error(`createProviderToken: mint=${candidateMint} failed: ${errorMsg}`);\n if (error instanceof Error) {\n lastError = errorMsg;\n\n if (isNetworkErrorMessage(error.message)) {\n this.logger.warn(`createProviderToken: network error from ${candidateMint}, trying next mint...`);\n continue;\n }\n }\n\n return {\n success: false,\n error: lastError || \"Failed to create top up token\",\n };\n }\n }\n\n this.logger.error(`createProviderToken: all candidate mints exhausted lastError=${lastError}`);\n return {\n success: false,\n error:\n lastError || \"All candidate mints failed while creating top up token\",\n };\n }\n\n private _selectCandidateMints(options: {\n balances: Record<string, number>;\n units: Record<string, \"sat\" | \"msat\">;\n amount: number;\n preferredMintUrl: string;\n excludeMints: string[];\n allowedMints?: string[];\n }): string[] {\n const {\n balances,\n units,\n amount,\n preferredMintUrl,\n excludeMints,\n allowedMints,\n } = options;\n\n const candidates: string[] = [];\n\n const { selectedMintUrl: firstMint } = selectMintWithBalance(\n balances,\n units,\n amount,\n excludeMints\n );\n\n if (\n firstMint &&\n (!allowedMints ||\n allowedMints.length === 0 ||\n allowedMints.includes(firstMint))\n ) {\n candidates.push(firstMint);\n }\n\n const canUseMint = (mint: string): boolean => {\n if (excludeMints.includes(mint)) return false;\n if (\n allowedMints &&\n allowedMints.length > 0 &&\n !allowedMints.includes(mint)\n ) {\n return false;\n }\n const rawBalance = balances[mint] || 0;\n const unit = units[mint];\n const balanceInSats = getBalanceInSats(rawBalance, unit);\n return balanceInSats >= amount;\n };\n\n if (\n preferredMintUrl &&\n canUseMint(preferredMintUrl) &&\n !candidates.includes(preferredMintUrl)\n ) {\n candidates.push(preferredMintUrl);\n }\n\n for (const mint in balances) {\n if (mint === preferredMintUrl || candidates.includes(mint)) continue;\n if (canUseMint(mint)) {\n candidates.push(mint);\n }\n }\n\n return candidates;\n }\n\n private async _refundOtherProvidersForTopUp(\n baseUrl: string,\n mintUrl: string,\n retryCount: number,\n requiredAmount: number\n ): Promise<void> {\n const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();\n\n // If retryCount >= 2, force refund even if API keys were used recently\n const forceRefund = retryCount >= 2;\n\n // Build full candidate list sorted by lastUsed, oldest first.\n // This way providers outside the 5-min window are tried first (natural\n // refund succeeds), and if we must force-refund, we target the oldest\n // (closest to expiring) locked providers first.\n const candidates = apiKeyDistribution\n .filter((apiKey) => apiKey.baseUrl !== baseUrl && apiKey.amount > 0)\n .map((apiKey) => {\n const full = this.storageAdapter.getApiKey(apiKey.baseUrl);\n return {\n baseUrl: apiKey.baseUrl,\n amount: apiKey.amount,\n lastUsed: full?.lastUsed ?? 0,\n key: full?.key,\n } as const;\n })\n .filter((c) => c.key != null)\n .sort((a, b) => a.lastUsed - b.lastUsed); // oldest first\n\n if (candidates.length === 0) return;\n\n if (forceRefund) {\n // Sequential: refund one at a time until we have enough liquid balance\n // for the target provider, so we only force-refund as few providers as\n // necessary.\n //\n // NOTE: refundApiKey() already calls removeApiKey() on success, so we\n // don't need to update the balance here — the key is gone.\n for (const candidate of candidates) {\n await this.refundApiKey({\n mintUrl,\n baseUrl: candidate.baseUrl,\n apiKey: candidate.key!,\n forceRefund: true,\n });\n\n // Check if we've freed enough balance for the target provider\n const newState = await this.getBalanceState();\n const newAvailable =\n (newState.mintBalances[mintUrl] || 0) +\n (newState.providerBalances[baseUrl] || 0);\n\n if (newAvailable >= requiredAmount) {\n this.logger.log(\n `_refundOtherProvidersForTopUp: freed enough balance (${newAvailable} >= ${requiredAmount}), stopping early`\n );\n return;\n }\n }\n } else {\n // Non-force: try all in parallel (existing behavior, now sorted by\n // lastUsed for determinism). Providers outside the 5-min window will\n // succeed and be cleaned up by refundApiKey; recently-used ones are\n // skipped without side effects.\n await Promise.allSettled(\n candidates.map((candidate) =>\n this.refundApiKey({\n mintUrl,\n baseUrl: candidate.baseUrl,\n apiKey: candidate.key!,\n forceRefund: false,\n })\n )\n );\n }\n }\n\n /**\n * Post topup request to provider API\n */\n private async _postTopUp(\n baseUrl: string,\n storedToken: string,\n cashuToken: string\n ): Promise<{\n success: boolean;\n requestId?: string;\n error?: string;\n }> {\n if (!baseUrl) {\n return {\n success: false,\n error: \"No base URL configured\",\n };\n }\n\n const normalizedBaseUrl = baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`;\n const url = `${normalizedBaseUrl}v1/wallet/topup?cashu_token=${encodeURIComponent(\n cashuToken\n )}`;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => {\n controller.abort();\n }, 60000);\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${storedToken}`,\n \"Content-Type\": \"application/json\",\n },\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n const requestId =\n response.headers.get(\"x-routstr-request-id\") || undefined;\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n return {\n success: false,\n requestId,\n error:\n errorData?.detail || `Top up failed with status ${response.status}`,\n };\n }\n\n return { success: true, requestId };\n } catch (error) {\n clearTimeout(timeoutId);\n this.logger.error(\"_postTopUp fetch error\", error);\n\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n return {\n success: false,\n error: \"Request timed out after 1 minute\",\n };\n }\n return {\n success: false,\n error: error.message,\n };\n }\n\n return {\n success: false,\n error: \"Unknown error occurred during top up request\",\n };\n }\n }\n\n /**\n * Attempt to receive token back after failed top up\n */\n private async _recoverFailedTopUp(cashuToken: string): Promise<void> {\n try {\n await this.cashuSpender.receiveToken(cashuToken);\n } catch (error) {\n this.logger.error(\"_recoverFailedTopUp: failed to recover token\", error);\n }\n }\n\n /**\n * Handle refund errors with specific error types\n */\n private _handleRefundError(\n error: unknown,\n mintUrl: string,\n requestId?: string\n ): RefundResult {\n if (error instanceof Error) {\n // Network errors\n if (isNetworkErrorMessage(error.message)) {\n return {\n success: false,\n message: `Failed to connect to the mint: ${mintUrl}`,\n requestId,\n };\n }\n\n // Wallet not found error\n if (error.message.includes(\"Wallet not found\")) {\n return {\n success: false,\n message: `Wallet couldn't be loaded. Please save this refunded cashu token manually.`,\n requestId,\n };\n }\n\n return {\n success: false,\n message: error.message,\n requestId,\n };\n }\n\n return {\n success: false,\n message: \"Refund failed\",\n requestId,\n };\n }\n\n /**\n * Get token balance from provider\n */\n async getTokenBalance(\n token: string,\n baseUrl: string\n ): Promise<{\n amount: number;\n reserved: number;\n unit: \"sat\" | \"msat\";\n apiKey: string;\n isInvalidApiKey?: boolean;\n /** True when the balance could not be determined (network error, non-OK\n * response, etc.). Callers MUST NOT use `amount` in arithmetic when\n * this flag is set — it is 0, not a real balance. */\n balanceUnknown?: boolean;\n }> {\n try {\n const response = await fetch(`${baseUrl}v1/wallet/info`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (response.ok) {\n const data = await response.json();\n return {\n amount: data.balance,\n reserved: data.reserved ?? 0,\n unit: \"msat\",\n apiKey: data.api_key,\n };\n } else {\n this.logger.warn(`getTokenBalance: status=${response.status}`);\n const data = await response.json();\n this.logger.warn(\"getTokenBalance: FAILED\", data);\n\n // Check for invalid/expired API key error (proofs already spent)\n const isInvalidApiKey =\n response.status === 401 &&\n data?.detail?.error?.code === \"invalid_api_key\" &&\n data?.detail?.error?.message?.includes(\"proofs already spent\");\n\n return {\n amount: 0,\n reserved: data.reserved ?? 0,\n unit: \"msat\",\n apiKey: data.api_key,\n isInvalidApiKey,\n balanceUnknown: true,\n };\n }\n } catch (error) {\n this.logger.error(\"getTokenBalance error\", error);\n }\n\n return {\n amount: 0,\n reserved: 0,\n unit: \"sat\",\n apiKey: \"\",\n balanceUnknown: true,\n };\n }\n\n /**\n * Handle topup errors with specific error types\n */\n private _handleTopUpError(\n error: unknown,\n mintUrl: string,\n requestId?: string\n ): TopUpResult {\n if (error instanceof Error) {\n if (isNetworkErrorMessage(error.message)) {\n return {\n success: false,\n message: `Failed to connect to the mint: ${mintUrl}`,\n requestId,\n };\n }\n\n if (error.message.includes(\"Wallet not found\")) {\n return {\n success: false,\n message:\n \"Wallet couldn't be loaded. The cashu token was recovered locally.\",\n requestId,\n };\n }\n\n return {\n success: false,\n message: error.message,\n requestId,\n };\n }\n\n return {\n success: false,\n message: \"Top up failed\",\n requestId,\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../core/types.ts","../../core/errors.ts","../../wallet/AuditLogger.ts","../../wallet/tokenUtils.ts","../../wallet/CashuSpender.ts","../../wallet/BalanceManager.ts"],"names":["amount","unit","getDecodedToken","mintUrl"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Core types for the Routstr SDK\n * These types are shared across wallet and client modules\n */\n\nexport interface SdkLogger {\n log(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n error(...args: unknown[]): void;\n debug(...args: unknown[]): void;\n child(prefix: string): SdkLogger;\n}\n\nfunction makeConsoleLogger(prefix?: string): SdkLogger {\n const fmt = (args: unknown[]) => (prefix ? [prefix, ...args] : args);\n return {\n log: (...args) => console.log(...fmt(args)),\n warn: (...args) => console.warn(...fmt(args)),\n error: (...args) => console.error(...fmt(args)),\n debug: (...args) => console.log(...fmt(args)),\n child: (p) => makeConsoleLogger(prefix ? `${prefix}:${p}` : p),\n };\n}\n\nexport const consoleLogger: SdkLogger = makeConsoleLogger();\n\nexport const noopLogger: SdkLogger = {\n log: () => {},\n warn: () => {},\n error: () => {},\n debug: () => {},\n child: () => noopLogger,\n};\n\nexport interface MessageContentType {\n type: \"text\" | \"image_url\" | \"file\";\n text?: string;\n image_url?: {\n url: string;\n storageId?: string;\n };\n file?: {\n url: string;\n name?: string;\n mimeType?: string;\n size?: number;\n };\n hidden?: boolean;\n thinking?: string;\n citations?: string[];\n}\n\nexport interface Message {\n role: string;\n content: string | MessageContentType[];\n _eventId?: string;\n _prevId?: string;\n _createdAt?: number;\n _modelId?: string;\n satsSpent?: number;\n}\n\nexport interface TransactionHistory {\n type: \"spent\" | \"mint\" | \"send\" | \"import\" | \"refund\";\n amount: number;\n timestamp: number;\n status: \"success\" | \"failed\";\n model?: string;\n message?: string;\n balance?: number;\n}\n\nexport interface ModelPricing {\n prompt: number;\n completion: number;\n request: number;\n image: number;\n web_search: number;\n internal_reasoning: number;\n}\n\nexport interface ModelSatsPricing extends ModelPricing {\n max_completion_cost: number;\n max_prompt_cost: number;\n max_cost: number;\n}\n\nexport interface ModelArchitecture {\n modality: string;\n input_modalities: readonly string[];\n output_modalities: readonly string[];\n tokenizer: string;\n instruct_type: string | null;\n}\n\nexport interface PerRequestLimits {\n readonly prompt_tokens?: number;\n readonly completion_tokens?: number;\n readonly requests_per_minute?: number;\n readonly images_per_minute?: number;\n readonly web_searches_per_minute?: number;\n readonly [key: string]: number | undefined;\n}\n\nexport interface Model {\n id: string;\n name: string;\n created?: number;\n description?: string;\n context_length?: number;\n architecture?: ModelArchitecture;\n pricing?: ModelPricing;\n sats_pricing: ModelSatsPricing;\n per_request_limits?: PerRequestLimits;\n}\n\n/**\n * Result from spending cashu tokens\n */\nexport interface SpendResult {\n token: string | null;\n status: \"success\" | \"failed\";\n balance: number;\n unit?: \"sat\" | \"msat\";\n error?: string;\n errorDetails?: {\n required: number;\n available: number;\n maxMintBalance: number;\n maxMintUrl: string;\n };\n}\n\n/**\n * Result from refund operations\n */\nexport interface RefundResult {\n success: boolean;\n refundedAmount?: number;\n message?: string;\n requestId?: string;\n}\n\n/**\n * Result from top up operations\n */\nexport interface TopUpResult {\n success: boolean;\n toppedUpAmount?: number;\n message?: string;\n requestId?: string;\n recoveredToken?: boolean;\n}\n\n/**\n * API error verdict for retry logic\n */\nexport interface APIErrorVerdict {\n retry: boolean;\n reason: string;\n newBaseUrl?: string; // New provider to retry with (for 50X errors)\n}\n\n/**\n * Image data from API response\n */\nexport interface ImageData {\n type: \"image_url\";\n image_url: {\n url: string;\n };\n index?: number;\n}\n\n/**\n * Annotation data from API response\n */\nexport interface AnnotationData {\n type: \"url_citation\";\n start_index: number;\n end_index: number;\n url: string;\n title: string;\n}\n\n/**\n * Usage statistics from API response\n */\nexport interface UsageStats {\n total_tokens?: number;\n prompt_tokens?: number;\n completion_tokens?: number;\n cost?: number;\n sats_cost?: number;\n}\n\n/**\n * Result from streaming response processing\n */\nexport interface StreamingResult {\n content: string;\n thinking?: string;\n images?: ImageData[];\n usage?: UsageStats;\n model?: string;\n responseId?: string;\n finish_reason?: string;\n citations?: string[];\n annotations?: AnnotationData[];\n}\n\n/**\n * Parameters for fetching AI response\n */\nexport interface FetchAIResponseParams {\n messageHistory: Message[];\n selectedModel: Model;\n baseUrl: string;\n mintUrl: string;\n balance: number;\n transactionHistory: TransactionHistory[];\n}\n\n/**\n * Candidate provider for failover\n */\nexport interface CandidateProvider {\n baseUrl: string;\n model: Model;\n cost: number;\n}\n\n/**\n * Mint selection result\n */\nexport interface MintSelection {\n selectedMintUrl: string | null;\n selectedMintBalance: number;\n}\n\n/**\n * Pending token entry\n */\nexport interface PendingTokenEntry {\n baseUrl: string;\n amount: number;\n}\n\n/**\n * Provider information from /v1/info endpoint\n */\nexport interface ProviderInfo {\n mints?: string[];\n [key: string]: any;\n}\n\n/**\n * Model discovery result\n */\nexport interface ModelDiscoveryResult {\n models: Model[];\n bestById: Map<string, { model: Model; base: string }>;\n totalProcessed: number;\n}\n\n/**\n * Mint discovery result\n */\nexport interface MintDiscoveryResult {\n mintsFromProviders: Record<string, string[]>;\n infoFromProviders: Record<string, ProviderInfo>;\n}\n","/**\n * Custom error classes for the Routstr SDK\n * Provides specific error types for different failure modes\n */\n\n/**\n * Error thrown when balance is insufficient for an operation\n */\nexport class InsufficientBalanceError extends Error {\n constructor(\n public required: number,\n public available: number,\n public maxMintBalance: number = 0,\n public maxMintUrl: string = \"\",\n customMessage?: string\n ) {\n super(\n customMessage ??\n (`Insufficient balance: need ${required} sats, have ${available} sats available. ` +\n (maxMintBalance > 0\n ? `Largest mint balance: ${maxMintBalance} sats from ${maxMintUrl}`\n : \"\"))\n );\n this.name = \"InsufficientBalanceError\";\n }\n}\n\n/**\n * Error thrown when a provider returns an error response\n */\nexport class ProviderError extends Error {\n constructor(\n public baseUrl: string,\n public statusCode: number,\n message: string,\n public requestId?: string\n ) {\n super(\n `Provider ${baseUrl} returned ${statusCode}: ${message}` +\n (requestId ? ` (Request ID: ${requestId})` : \"\")\n );\n this.name = \"ProviderError\";\n }\n}\n\n/**\n * Error thrown when a mint is unreachable\n */\nexport class MintUnreachableError extends Error {\n constructor(public mintUrl: string) {\n super(\n `Your mint ${mintUrl} is unreachable or is blocking your IP. Please try again later or switch mints.`\n );\n this.name = \"MintUnreachableError\";\n }\n}\n\n/**\n * Error thrown when a token operation fails\n */\nexport class TokenOperationError extends Error {\n constructor(\n message: string,\n public operation: \"send\" | \"receive\" | \"refund\",\n public mintUrl?: string\n ) {\n super(message);\n this.name = \"TokenOperationError\";\n }\n}\n\n/**\n * Error thrown when provider failover fails\n */\nexport class FailoverError extends Error {\n constructor(\n public originalProvider: string,\n public failedProviders: string[],\n message?: string\n ) {\n super(\n message ||\n `All providers failed. Original: ${originalProvider}, Failed: ${failedProviders.join(\", \")}`\n );\n this.name = \"FailoverError\";\n }\n}\n\n/**\n * Error thrown when streaming response processing fails\n */\nexport class StreamingError extends Error {\n constructor(\n message: string,\n public finishReason?: string,\n public accumulatedContent?: string\n ) {\n super(message);\n this.name = \"StreamingError\";\n }\n}\n\n/**\n * Error thrown when model is not found on a provider\n */\nexport class ModelNotFoundError extends Error {\n constructor(public modelId: string, public baseUrl: string) {\n super(`Model '${modelId}' not found on provider ${baseUrl}`);\n this.name = \"ModelNotFoundError\";\n }\n}\n\n/**\n * Error thrown when provider bootstrap fails\n */\nexport class ProviderBootstrapError extends Error {\n constructor(\n public failedProviders: string[],\n message?: string\n ) {\n super(\n message || `Failed to bootstrap providers. Tried: ${failedProviders.join(\", \")}`\n );\n this.name = \"ProviderBootstrapError\";\n }\n}\n\n/**\n * Error thrown when no providers are available\n */\nexport class NoProvidersAvailableError extends Error {\n constructor() {\n super(\"No providers are available for model discovery\");\n this.name = \"NoProvidersAvailableError\";\n }\n}\n\n/**\n * Error thrown when mint discovery fails\n */\nexport class MintDiscoveryError extends Error {\n constructor(\n public baseUrl: string,\n message?: string\n ) {\n super(message || `Failed to discover mints from provider ${baseUrl}`);\n this.name = \"MintDiscoveryError\";\n }\n}\n","/**\n * AuditLogger - Transaction audit logging utility\n * Writes JSON-formatted transaction logs to audit.log\n */\n\nexport interface AuditLogEntry {\n timestamp: string;\n action: \"spend\" | \"topup\" | \"refund\" | \"receive\" | \"balance_check\";\n totalBalance: number;\n providerBalances: Record<string, number>;\n mintBalances: Record<string, number>;\n amount?: number;\n mintUrl?: string;\n baseUrl?: string;\n status: \"success\" | \"failed\";\n details?: string;\n}\n\nexport class AuditLogger {\n private static instance: AuditLogger | null = null;\n\n static getInstance(): AuditLogger {\n if (!AuditLogger.instance) {\n AuditLogger.instance = new AuditLogger();\n }\n return AuditLogger.instance;\n }\n\n async log(entry: Omit<AuditLogEntry, \"timestamp\">): Promise<void> {\n const fullEntry: AuditLogEntry = {\n ...entry,\n timestamp: new Date().toISOString(),\n };\n\n const logLine = JSON.stringify(fullEntry) + \"\\n\";\n\n if (typeof window === \"undefined\") {\n try {\n const fs = await import(\"fs\");\n const path = await import(\"path\");\n const logPath = path.join(process.cwd(), \"audit.log\");\n fs.appendFileSync(logPath, logLine);\n } catch (error) {\n console.error(\"[AuditLogger] Failed to write to file:\", error);\n }\n } else {\n console.log(\"[AUDIT]\", logLine.trim());\n }\n }\n\n async logBalanceSnapshot(\n action: AuditLogEntry[\"action\"],\n amounts: {\n totalBalance: number;\n providerBalances: Record<string, number>;\n mintBalances: Record<string, number>;\n },\n options?: {\n amount?: number;\n mintUrl?: string;\n baseUrl?: string;\n status?: \"success\" | \"failed\";\n details?: string;\n }\n ): Promise<void> {\n await this.log({\n action,\n totalBalance: amounts.totalBalance,\n providerBalances: amounts.providerBalances,\n mintBalances: amounts.mintBalances,\n amount: options?.amount,\n mintUrl: options?.mintUrl,\n baseUrl: options?.baseUrl,\n status: options?.status ?? \"success\",\n details: options?.details,\n });\n }\n}\n\nexport const auditLogger = AuditLogger.getInstance();\n","import type { MintSelection } from \"../core/types\";\n\nexport function isNetworkErrorMessage(message: string): boolean {\n return (\n message.includes(\"NetworkError when attempting to fetch resource\") ||\n message.includes(\"Failed to fetch\") ||\n message.includes(\"Load failed\") ||\n message.includes(\"ERR_TLS_CERT_ALTNAME_INVALID\") ||\n message.includes(\"ERR_TLS_CERT_NOT_YET_VALID\") ||\n message.includes(\"ERR_TLS_CERT_EXPIRED\") ||\n message.includes(\"UNABLE_TO_VERIFY_LEAF_SIGNATURE\") ||\n message.includes(\"SELF_SIGNED_CERT_IN_CHAIN\")\n );\n}\n\nexport function getBalanceInSats(\n balance: number,\n unit: \"sat\" | \"msat\" | string | undefined\n): number {\n return unit === \"msat\" ? balance / 1000 : balance;\n}\n\nexport function getTotalMintBalanceInSats(\n balances: Record<string, number>,\n units: Record<string, \"sat\" | \"msat\">\n): number {\n let total = 0;\n for (const mintUrl in balances) {\n total += getBalanceInSats(balances[mintUrl], units[mintUrl]);\n }\n return total;\n}\n\nexport function selectMintWithBalance(\n balances: Record<string, number>,\n units: Record<string, string>,\n amount: number,\n excludeMints: string[] = []\n): MintSelection {\n for (const mintUrl in balances) {\n if (excludeMints.includes(mintUrl)) {\n continue;\n }\n\n const balanceInSats = getBalanceInSats(balances[mintUrl], units[mintUrl]);\n if (balanceInSats >= amount) {\n return { selectedMintUrl: mintUrl, selectedMintBalance: balanceInSats };\n }\n }\n\n return { selectedMintUrl: null, selectedMintBalance: 0 };\n}\n","/**\n * CashuSpender - Core spending logic for Cashu tokens\n *\n * Handles:\n * - Mint selection with sufficient balance\n * - Provider mint compatibility checks\n * - Retry logic with alternate mints\n * - Critical section management (busy state)\n *\n * Extracted from hooks/useCashuWithXYZ.ts\n */\n\nimport type { WalletAdapter, StorageAdapter } from \"./interfaces\";\nimport type { SpendResult, SdkLogger } from \"../core/types\";\nimport { consoleLogger } from \"../core/types\";\nimport { InsufficientBalanceError } from \"../core/errors\";\nimport { BalanceManager } from \"./BalanceManager\";\nimport { auditLogger } from \"./AuditLogger\";\nimport { getBalanceInSats, isNetworkErrorMessage } from \"./tokenUtils\";\nimport { getDecodedToken } from \"@cashu/cashu-ts\";\n\n/**\n * Options for spending cashu tokens\n */\nexport interface SpendOptions {\n /** The mint URL to send from (can be overridden if insufficient balance) */\n mintUrl: string;\n\n /** The amount to spend in sats */\n amount: number;\n\n /** The provider base URL (for token storage and provider mint checks) */\n baseUrl: string;\n\n /** Whether to reuse an existing token if available */\n reuseToken?: boolean;\n\n /** Optional P2PK public key */\n p2pkPubkey?: string;\n\n /** Array of mint URLs to exclude (for retry logic) */\n excludeMints?: string[];\n\n /** Current retry count (for internal recursion) */\n retryCount?: number;\n\n /** Specific provider baseUrls to refund (if not provided, refunds all except current) */\n refundBaseUrls?: string[];\n}\n\ntype DebugLevel = \"DEBUG\" | \"WARN\" | \"ERROR\";\n\n/**\n * CashuSpender manages the spending of Cashu tokens\n */\nexport class CashuSpender {\n private _isBusy = false;\n private debugLevel: DebugLevel = \"WARN\";\n private readonly logger: SdkLogger;\n\n constructor(\n private walletAdapter: WalletAdapter,\n private storageAdapter: StorageAdapter,\n private _providerRegistry?: unknown,\n private balanceManager?: BalanceManager,\n logger?: SdkLogger\n ) {\n this.logger = (logger ?? consoleLogger).child(\"CashuSpender\");\n }\n\n async receiveToken(token: string): Promise<{\n success: boolean;\n amount: number;\n unit: \"sat\" | \"msat\";\n message?: string;\n }> {\n try {\n const result = await this.walletAdapter.receiveToken(token);\n return result;\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n\n if (errorMessage.includes(\"Failed to fetch mint\")) {\n const cachedTokens = this.storageAdapter.getCachedReceiveTokens();\n const existingIndex = cachedTokens.findIndex((t) => t.token === token);\n if (existingIndex === -1) {\n const { amount, unit } = this._decodeTokenAmount(token);\n this.storageAdapter.setCachedReceiveTokens([\n ...cachedTokens,\n {\n token,\n amount,\n unit,\n createdAt: Date.now(),\n },\n ]);\n }\n }\n\n const { amount, unit } = this._decodeTokenAmount(token);\n return { success: false, amount, unit, message: errorMessage };\n }\n }\n\n private _decodeTokenAmount(token: string): {\n amount: number;\n unit: \"sat\" | \"msat\";\n } {\n try {\n const decoded = getDecodedToken(token);\n const amount = decoded.proofs.reduce(\n (acc, proof) => acc + proof.amount,\n 0\n );\n const unit = (decoded.unit as \"sat\" | \"msat\") || \"sat\";\n return { amount, unit };\n } catch {\n return { amount: 0, unit: \"sat\" };\n }\n }\n\n private async _getBalanceState(): Promise<{\n totalBalance: number;\n providerBalances: Record<string, number>;\n mintBalances: Record<string, number>;\n }> {\n if (this.balanceManager) {\n return this.balanceManager.getBalanceState();\n }\n\n const mintBalances = await this.walletAdapter.getBalances();\n const units = this.walletAdapter.getMintUnits();\n\n let totalMintBalance = 0;\n const normalizedMintBalances: Record<string, number> = {};\n for (const url in mintBalances) {\n const balance = mintBalances[url];\n const unit = units[url];\n const balanceInSats = getBalanceInSats(balance, unit);\n normalizedMintBalances[url] = balanceInSats;\n totalMintBalance += balanceInSats;\n }\n\n const providerBalances: Record<string, number> = {};\n let totalProviderBalance = 0;\n\n const apiKeys = this.storageAdapter.getAllApiKeys();\n for (const apiKey of apiKeys) {\n if (!providerBalances[apiKey.baseUrl]) {\n providerBalances[apiKey.baseUrl] = 0;\n }\n providerBalances[apiKey.baseUrl] += apiKey.balance;\n totalProviderBalance += apiKey.balance;\n }\n\n return {\n totalBalance: totalMintBalance + totalProviderBalance,\n providerBalances,\n mintBalances: normalizedMintBalances,\n };\n }\n\n private async _logTransaction(\n action: \"spend\" | \"topup\" | \"refund\" | \"receive\" | \"balance_check\",\n options?: {\n amount?: number;\n mintUrl?: string;\n baseUrl?: string;\n status?: \"success\" | \"failed\";\n details?: string;\n }\n ): Promise<void> {\n const balanceState = await this._getBalanceState();\n await auditLogger.logBalanceSnapshot(action, balanceState, options);\n }\n\n /**\n * Check if the spender is currently in a critical operation\n */\n get isBusy(): boolean {\n return this._isBusy;\n }\n\n getDebugLevel(): DebugLevel {\n return this.debugLevel;\n }\n\n setDebugLevel(level: DebugLevel): void {\n this.debugLevel = level;\n }\n\n private _log(level: \"DEBUG\" | \"WARN\" | \"ERROR\", ...args: unknown[]): void {\n const levelPriority: Record<DebugLevel, number> = {\n DEBUG: 0,\n WARN: 1,\n ERROR: 2,\n };\n\n if (levelPriority[level] >= levelPriority[this.debugLevel]) {\n switch (level) {\n case \"DEBUG\":\n this.logger.log(...args);\n break;\n case \"WARN\":\n this.logger.warn(...args);\n break;\n case \"ERROR\":\n this.logger.error(...args);\n break;\n }\n }\n }\n\n /**\n * Spend Cashu tokens with automatic mint selection and retry logic\n * Throws errors on failure instead of returning failed SpendResult\n */\n async spend(options: SpendOptions): Promise<SpendResult> {\n const {\n mintUrl,\n amount,\n baseUrl,\n reuseToken = false,\n p2pkPubkey,\n excludeMints = [],\n retryCount = 0,\n } = options;\n\n this._isBusy = true;\n\n try {\n const result = await this._spendInternal({\n mintUrl,\n amount,\n baseUrl,\n reuseToken,\n p2pkPubkey,\n excludeMints,\n retryCount,\n });\n\n if (result.status === \"failed\" || !result.token) {\n const errorMsg =\n result.error || `Insufficient balance. Need ${amount} sats.`;\n\n if (this._isNetworkError(errorMsg)) {\n throw new Error(\n `Your mint ${mintUrl} is unreachable or is blocking your IP. Please try again later or switch mints.`\n );\n }\n\n if (result.errorDetails) {\n throw new InsufficientBalanceError(\n result.errorDetails.required,\n result.errorDetails.available,\n result.errorDetails.maxMintBalance,\n result.errorDetails.maxMintUrl\n );\n }\n\n throw new Error(errorMsg);\n }\n\n return result;\n } finally {\n this._isBusy = false;\n }\n }\n\n /**\n * Check if error message indicates a network error\n */\n private _isNetworkError(message: string): boolean {\n return (\n isNetworkErrorMessage(message) ||\n (message.includes(\"Your mint\") && message.includes(\"unreachable\"))\n );\n }\n\n /**\n * Internal spending logic\n */\n private async _spendInternal(options: SpendOptions): Promise<SpendResult> {\n let {\n mintUrl,\n amount,\n baseUrl,\n reuseToken,\n p2pkPubkey,\n excludeMints,\n retryCount,\n } = options;\n\n this._log(\n \"DEBUG\",\n `[CashuSpender] _spendInternal: amount=${amount}, mintUrl=${mintUrl}, baseUrl=${baseUrl}, reuseToken=${reuseToken}`\n );\n\n // Validate amount\n let adjustedAmount = Math.ceil(amount);\n if (!adjustedAmount || isNaN(adjustedAmount)) {\n this._log(\n \"ERROR\",\n `[CashuSpender] _spendInternal: Invalid amount: ${amount}`\n );\n return {\n token: null,\n status: \"failed\",\n balance: 0,\n error: \"Please enter a valid amount\",\n };\n }\n\n // Try to get existing token for reuse\n if (reuseToken && baseUrl) {\n this._log(\n \"DEBUG\",\n `[CashuSpender] _spendInternal: Attempting to reuse token for ${baseUrl}`\n );\n const existingResult = await this._tryReuseToken(\n baseUrl,\n adjustedAmount,\n mintUrl\n );\n if (existingResult) {\n this._log(\n \"DEBUG\",\n `[CashuSpender] _spendInternal: Successfully reused token, balance: ${existingResult.balance}`\n );\n return existingResult;\n }\n this._log(\n \"DEBUG\",\n `[CashuSpender] _spendInternal: Could not reuse token, will create new token`\n );\n }\n\n // Get current balance state\n const balanceState = await this._getBalanceState();\n const totalAvailableBalance = balanceState.totalBalance;\n\n this._log(\n \"DEBUG\",\n `[CashuSpender] _spendInternal: totalAvailableBalance=${totalAvailableBalance}, adjustedAmount=${adjustedAmount}`\n );\n\n // Check total balance\n if (totalAvailableBalance < adjustedAmount) {\n this._log(\n \"ERROR\",\n `[CashuSpender] _spendInternal: Insufficient balance, have=${totalAvailableBalance}, need=${adjustedAmount}`\n );\n return this._createInsufficientBalanceError(\n adjustedAmount,\n balanceState.mintBalances,\n totalAvailableBalance\n );\n }\n\n let token: string | null = null;\n let selectedMintUrl: string | undefined;\n let spentAmount = adjustedAmount;\n\n if (this.balanceManager) {\n const tokenResult = await this.balanceManager.createProviderToken({\n mintUrl,\n baseUrl,\n amount: adjustedAmount,\n p2pkPubkey,\n excludeMints,\n retryCount,\n });\n\n if (!tokenResult.success || !tokenResult.token) {\n if ((tokenResult.error || \"\").includes(\"Insufficient balance\")) {\n return this._createInsufficientBalanceError(\n adjustedAmount,\n balanceState.mintBalances,\n totalAvailableBalance\n );\n }\n\n return {\n token: null,\n status: \"failed\",\n balance: 0,\n error: tokenResult.error || \"Failed to create token\",\n };\n }\n\n token = tokenResult.token;\n selectedMintUrl = tokenResult.selectedMintUrl;\n spentAmount = tokenResult.amountSpent || adjustedAmount;\n } else {\n try {\n token = await this.walletAdapter.sendToken(\n mintUrl,\n adjustedAmount,\n p2pkPubkey\n );\n selectedMintUrl = mintUrl;\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n return {\n token: null,\n status: \"failed\",\n balance: 0,\n error: `Error generating token: ${errorMsg}`,\n };\n }\n }\n\n // Store token and return\n if (token) {\n this._log(\n \"DEBUG\",\n `[CashuSpender] _spendInternal: Successfully spent ${spentAmount}, returning token with balance=${spentAmount}`\n );\n }\n\n this._logTransaction(\"spend\", {\n amount: spentAmount,\n mintUrl: selectedMintUrl || mintUrl,\n baseUrl,\n status: \"success\",\n });\n\n this._log(\n \"DEBUG\",\n `[CashuSpender] _spendInternal: Successfully spent ${spentAmount}, returning token with balance=${spentAmount}`\n );\n\n const units = this.walletAdapter.getMintUnits();\n\n return {\n token,\n status: \"success\",\n balance: spentAmount,\n unit:\n (selectedMintUrl ? units[selectedMintUrl] : units[mintUrl]) || \"sat\",\n };\n }\n\n /**\n * Try to reuse an existing API key\n */\n private async _tryReuseToken(\n baseUrl: string,\n amount: number,\n mintUrl: string\n ): Promise<SpendResult | null> {\n const apiKeyEntry = this.storageAdapter.getApiKey(baseUrl);\n if (!apiKeyEntry) return null;\n\n // Get pending distribution to check balance\n const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();\n const balanceForBaseUrl =\n apiKeyDistribution.find((b) => b.baseUrl === baseUrl)?.amount || 0;\n\n this._log(\"DEBUG\", \"Reusing API key\", balanceForBaseUrl, amount);\n\n if (balanceForBaseUrl > amount) {\n const units = this.walletAdapter.getMintUnits();\n const unit = units[mintUrl] || \"sat\";\n return {\n token: apiKeyEntry.key,\n status: \"success\",\n balance: balanceForBaseUrl,\n unit,\n };\n }\n\n // API key exists but insufficient balance - attempt topup\n if (this.balanceManager) {\n const topUpAmount = Math.ceil(amount * 1.2 - balanceForBaseUrl);\n const topUpResult = await this.balanceManager.topUp({\n mintUrl,\n baseUrl,\n amount: topUpAmount,\n token: apiKeyEntry.key,\n });\n this._log(\"DEBUG\", \"TOPUP \", topUpResult);\n\n if (topUpResult.success && topUpResult.toppedUpAmount) {\n const newBalance = balanceForBaseUrl + topUpResult.toppedUpAmount;\n const units = this.walletAdapter.getMintUnits();\n const unit = units[mintUrl] || \"sat\";\n\n this._logTransaction(\"topup\", {\n amount: topUpResult.toppedUpAmount,\n mintUrl,\n baseUrl,\n status: \"success\",\n });\n\n return {\n token: apiKeyEntry.key,\n status: \"success\",\n balance: newBalance,\n unit,\n };\n }\n\n const providerBalance = await this._getProviderTokenBalance(\n baseUrl,\n apiKeyEntry.key\n );\n this._log(\"DEBUG\", providerBalance);\n if (providerBalance <= 0) {\n this.storageAdapter.removeApiKey(baseUrl);\n }\n }\n\n return null;\n }\n\n /**\n * Refund all xcashu tokens from storage by calling the provider's refund endpoint.\n * The xcashu token acts as an API key to claim the refund, and the response contains\n * the actual refunded Cashu token which is then received into the wallet.\n * @param mintUrl - The mint URL for receiving tokens\n * @param excludeBaseUrls - Base URLs to exclude from refund (optional)\n * @returns Results for each xcashu token refund attempt\n */\n async refundXcashuTokens(\n mintUrl: string,\n excludeBaseUrls?: string[]\n ): Promise<\n { baseUrl: string; token: string; success: boolean; error?: string }[]\n > {\n const results: {\n baseUrl: string;\n token: string;\n success: boolean;\n error?: string;\n }[] = [];\n const xcashuTokens = this.storageAdapter.getXcashuTokens();\n const excludedUrls = new Set(excludeBaseUrls || []);\n\n for (const [baseUrl, tokens] of Object.entries(xcashuTokens)) {\n if (excludedUrls.has(baseUrl)) continue;\n\n for (const xcashuToken of tokens) {\n try {\n // XCashu tokens need to be sent to the provider's refund endpoint\n // The xcashu token acts as an API key, and the response contains the actual refunded token\n if (!this.balanceManager) {\n throw new Error(\"BalanceManager not available for xcashu refund\");\n }\n\n // Call the refund endpoint using the xcashu token as the API key\n const fetchResult = await this.balanceManager.fetchRefundToken(\n baseUrl,\n xcashuToken.token,\n true\n );\n\n if (!fetchResult.success || !fetchResult.token) {\n throw new Error(\n fetchResult.error || \"Failed to fetch refund token from provider\"\n );\n }\n\n // Receive the refunded Cashu token into the wallet\n const receiveResult = await this.receiveToken(fetchResult.token);\n\n if (receiveResult.success) {\n // Remove successfully refunded token from storage\n this.storageAdapter.removeXcashuToken(baseUrl, xcashuToken.token);\n results.push({\n baseUrl,\n token: xcashuToken.token,\n success: true,\n });\n this._log(\n \"DEBUG\",\n `[CashuSpender] refundXcashuTokens: Successfully refunded xcashu token for ${baseUrl}, amount=${receiveResult.amount}`\n );\n } else {\n // Refund failed - increment tryCount\n const currentTryCount = xcashuToken.tryCount ?? 0;\n const newTryCount = currentTryCount + 1;\n this.storageAdapter.updateXcashuTokenTryCount(\n xcashuToken.token,\n newTryCount\n );\n results.push({\n baseUrl,\n token: xcashuToken.token,\n success: false,\n error: receiveResult.message ?? \"Refund failed\",\n });\n this._log(\n \"DEBUG\",\n `[CashuSpender] refundXcashuTokens: Failed to receive refund token for ${baseUrl}, incremented tryCount to ${newTryCount}: ${receiveResult.message}`\n );\n }\n } catch (error) {\n // Exception occurred - increment tryCount\n const currentTryCount = xcashuToken.tryCount ?? 0;\n const newTryCount = currentTryCount + 1;\n this.storageAdapter.updateXcashuTokenTryCount(\n xcashuToken.token,\n newTryCount\n );\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n results.push({\n baseUrl,\n token: xcashuToken.token,\n success: false,\n error: errorMessage,\n });\n this._log(\n \"ERROR\",\n `[CashuSpender] refundXcashuTokens: Exception during refund for ${baseUrl}: ${errorMessage}, incremented tryCount to ${newTryCount}`\n );\n }\n }\n }\n\n return results;\n }\n\n /**\n * Refund specific providers without retrying spend\n */\n async refundProviders(\n mintUrl: string,\n forceRefund?: boolean\n ): Promise<{ baseUrl: string; success: boolean }[]> {\n const results: { baseUrl: string; success: boolean }[] = [];\n\n const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();\n\n // Refresh balances from providers before refunding\n for (const apiKeyEntry of apiKeyDistribution) {\n const apiKeyEntryFull = this.storageAdapter.getApiKey(\n apiKeyEntry.baseUrl\n );\n\n if (apiKeyEntryFull && this.balanceManager) {\n try {\n const balanceResult = await this.balanceManager.getTokenBalance(\n apiKeyEntryFull.key,\n apiKeyEntry.baseUrl\n );\n\n if (balanceResult.isInvalidApiKey) {\n // Key is invalid/expired on the provider side — clean it up\n this.logger.warn(\n `refundProviders: ${apiKeyEntry.baseUrl} returned invalid API key; removing local key and treating as success`\n );\n this.storageAdapter.removeApiKey(apiKeyEntry.baseUrl);\n results.push({\n baseUrl: apiKeyEntry.baseUrl,\n success: true,\n });\n continue;\n }\n\n if (balanceResult.amount >= 0 && !balanceResult.balanceUnknown) {\n const balanceSat = balanceResult.unit === \"msat\"\n ? Math.floor(balanceResult.amount / 1000)\n : balanceResult.amount;\n this.storageAdapter.updateApiKeyBalance(\n apiKeyEntry.baseUrl,\n balanceSat\n );\n } else {\n this.logger.warn(\n `refundProviders: balance refresh for ${apiKeyEntry.baseUrl} returned negative amount; keeping stale local balance=${apiKeyEntryFull.balance}`\n );\n }\n } catch (error) {\n // Balance check failed — proceed with stale local balance\n this.logger.warn(\n `refundProviders: balance refresh threw for ${apiKeyEntry.baseUrl}; proceeding with stale local balance`,\n error\n );\n }\n\n // Re-read the entry after balance refresh (may have been removed above)\n const refreshedEntry = this.storageAdapter.getApiKey(\n apiKeyEntry.baseUrl\n );\n if (!refreshedEntry) {\n continue;\n }\n\n const refundResult = await this.balanceManager.refundApiKey({\n mintUrl,\n baseUrl: apiKeyEntry.baseUrl,\n apiKey: refreshedEntry.key,\n forceRefund,\n });\n\n if (refundResult.success) {\n this.storageAdapter.removeApiKey(apiKeyEntry.baseUrl);\n } else {\n const currentEntry = this.storageAdapter.getApiKey(\n apiKeyEntry.baseUrl\n );\n this.logger.warn(\n `refundProviders: refund failed for ${apiKeyEntry.baseUrl}; currentEntry=${Boolean(currentEntry)} balance=${currentEntry?.balance ?? \"none\"}. Touching lastUsed to rate-limit retries.`\n );\n if (currentEntry) {\n this.storageAdapter.updateApiKeyBalance(\n apiKeyEntry.baseUrl,\n currentEntry.balance\n ); // update lastUsed so we only try to refund every 5 mins.\n }\n }\n\n results.push({\n baseUrl: apiKeyEntry.baseUrl,\n success: refundResult.success,\n });\n } else {\n this.logger.warn(\n `refundProviders: cannot refund ${apiKeyEntry.baseUrl}; apiKeyEntryFull=${Boolean(apiKeyEntryFull)} balanceManager=${Boolean(this.balanceManager)}`\n );\n results.push({\n baseUrl: apiKeyEntry.baseUrl,\n success: false,\n });\n }\n }\n\n return results;\n }\n\n /**\n * Create an insufficient balance error result\n */\n private _createInsufficientBalanceError(\n required: number,\n normalizedBalances: Record<string, number>,\n availableBalance?: number\n ): SpendResult {\n let maxBalance = 0;\n let maxMintUrl = \"\";\n\n for (const mintUrl in normalizedBalances) {\n const balanceInSats = normalizedBalances[mintUrl];\n\n if (balanceInSats > maxBalance) {\n maxBalance = balanceInSats;\n maxMintUrl = mintUrl;\n }\n }\n\n const error = new InsufficientBalanceError(\n required,\n availableBalance ?? maxBalance,\n maxBalance,\n maxMintUrl\n );\n\n return {\n token: null,\n status: \"failed\",\n balance: 0,\n error: error.message,\n errorDetails: {\n required,\n available: availableBalance ?? maxBalance,\n maxMintBalance: maxBalance,\n maxMintUrl,\n },\n };\n }\n\n private async _getProviderTokenBalance(\n baseUrl: string,\n token: string\n ): Promise<number> {\n try {\n const response = await fetch(`${baseUrl}v1/wallet/info`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (response.ok) {\n const data = await response.json();\n return data.balance / 1000;\n }\n } catch {\n return 0;\n }\n return 0;\n }\n}\n","/**\n * BalanceManager - Handles refunding and topping up tokens from providers\n *\n * Handles:\n * - Fetching refund tokens from provider API\n * - Receiving/storing refunded tokens\n * - Topping up API key balances with cashu tokens\n * - Error handling for various refund/topup failure modes\n *\n * Extracted from utils/cashuUtils.ts\n */\n\nimport type {\n WalletAdapter,\n StorageAdapter,\n ProviderRegistry,\n} from \"./interfaces\";\nimport type { RefundResult, TopUpResult, SdkLogger } from \"../core/types\";\nimport { consoleLogger } from \"../core/types\";\nimport { InsufficientBalanceError } from \"../core/errors\";\nimport { CashuSpender } from \"./CashuSpender\";\nimport {\n getBalanceInSats,\n isNetworkErrorMessage,\n selectMintWithBalance,\n} from \"./tokenUtils\";\n\n/**\n * Options for refunding API key balance\n */\nexport interface RefundApiKeyOptions {\n /** The mint URL (for NIP-60 wallet operations) */\n mintUrl: string;\n\n /** The provider base URL */\n baseUrl: string;\n\n /** The API key to use for authentication */\n apiKey: string;\n\n /** If true, forces refund even if the API key was used recently */\n forceRefund?: boolean;\n}\n\n/**\n * Options for topping up API key balance\n */\nexport interface TopUpOptions {\n /** The mint URL to spend from */\n mintUrl: string;\n\n /** The provider base URL */\n baseUrl: string;\n\n /** Amount to top up in sats */\n amount: number;\n\n /** Optional specific API key to top up (if not provided, uses stored token) */\n token?: string;\n}\n\nexport interface CreateProviderTokenOptions {\n mintUrl: string;\n baseUrl: string;\n amount: number;\n p2pkPubkey?: string;\n excludeMints?: string[];\n retryCount?: number;\n}\n\nexport interface ProviderTokenResult {\n success: boolean;\n token?: string;\n error?: string;\n selectedMintUrl?: string;\n amountSpent?: number;\n}\n\nexport interface BalanceState {\n totalBalance: number;\n providerBalances: Record<string, number>;\n mintBalances: Record<string, number>;\n}\n\n/**\n * BalanceManager handles token refunds and topups from providers\n */\nexport class BalanceManager {\n private cashuSpender: CashuSpender;\n /** In-memory guard for per-provider wallet mutations (topup / refund) */\n private providerWalletOps: Map<\n string,\n { type: \"topup\" | \"refund\"; startTime: number; endTime?: number }\n > = new Map();\n /** Cooldown (ms) between opposite operations on the same provider */\n private static readonly PROVIDER_WALLET_COOLDOWN_MS = 10_000;\n private readonly logger: SdkLogger;\n\n constructor(\n private walletAdapter: WalletAdapter,\n private storageAdapter: StorageAdapter,\n private providerRegistry?: ProviderRegistry,\n cashuSpender?: CashuSpender,\n logger?: SdkLogger\n ) {\n this.logger = (logger ?? consoleLogger).child(\"BalanceManager\");\n if (cashuSpender) {\n this.cashuSpender = cashuSpender;\n } else {\n this.cashuSpender = new CashuSpender(\n walletAdapter,\n storageAdapter,\n providerRegistry,\n this,\n this.logger\n );\n }\n }\n\n /**\n * Check whether a wallet operation (topup/refund) may run for a provider.\n * Returns the reason when blocked.\n */\n private _canRunProviderWalletOperation(\n baseUrl: string,\n type: \"topup\" | \"refund\"\n ): { allowed: boolean; reason?: string } {\n const existing = this.providerWalletOps.get(baseUrl);\n if (!existing) {\n return { allowed: true };\n }\n if (existing.type === type) {\n return { allowed: true };\n }\n // Opposite type in progress or recently completed\n if (!existing.endTime) {\n return {\n allowed: false,\n reason: `Provider wallet operation locked; ${existing.type} in progress`,\n };\n }\n const elapsed = Date.now() - existing.endTime;\n if (elapsed < BalanceManager.PROVIDER_WALLET_COOLDOWN_MS) {\n return {\n allowed: false,\n reason: `Provider wallet operation locked; recent ${existing.type} completed ${Math.round(elapsed / 1000)}s ago`,\n };\n }\n // Cooldown expired — clean up stale entry\n this.providerWalletOps.delete(baseUrl);\n return { allowed: true };\n }\n\n private _beginProviderWalletOperation(\n baseUrl: string,\n type: \"topup\" | \"refund\"\n ): void {\n this.providerWalletOps.set(baseUrl, { type, startTime: Date.now() });\n }\n\n private _endProviderWalletOperation(\n baseUrl: string,\n type: \"topup\" | \"refund\"\n ): void {\n const existing = this.providerWalletOps.get(baseUrl);\n if (existing && existing.type === type) {\n existing.endTime = Date.now();\n }\n }\n\n async getBalanceState(): Promise<BalanceState> {\n const mintBalances = await this.walletAdapter.getBalances();\n const units = this.walletAdapter.getMintUnits();\n\n let totalMintBalance = 0;\n const normalizedMintBalances: Record<string, number> = {};\n for (const url in mintBalances) {\n const balance = mintBalances[url];\n const unit = units[url];\n const balanceInSats = getBalanceInSats(balance, unit);\n normalizedMintBalances[url] = balanceInSats;\n totalMintBalance += balanceInSats;\n }\n\n const providerBalances: Record<string, number> = {};\n let totalProviderBalance = 0;\n\n const apiKeys = this.storageAdapter.getAllApiKeys();\n for (const apiKey of apiKeys) {\n if (!providerBalances[apiKey.baseUrl]) {\n providerBalances[apiKey.baseUrl] = 0;\n }\n providerBalances[apiKey.baseUrl] += apiKey.balance;\n totalProviderBalance += apiKey.balance;\n }\n\n return {\n totalBalance: totalMintBalance + totalProviderBalance,\n providerBalances,\n mintBalances: normalizedMintBalances,\n };\n }\n\n /**\n * Refund API key balance - convert remaining API key balance to cashu token\n * @param options - Refund options including forceRefund flag\n * @returns Refund result\n */\n async refundApiKey(options: RefundApiKeyOptions): Promise<RefundResult> {\n const { mintUrl, baseUrl, apiKey, forceRefund } = options;\n\n const guard = this._canRunProviderWalletOperation(baseUrl, \"refund\");\n if (!guard.allowed) {\n this.logger.log(`Skipping refund for ${baseUrl} - ${guard.reason}`);\n return { success: false, message: guard.reason };\n }\n\n this._beginProviderWalletOperation(baseUrl, \"refund\");\n\n try {\n return await this._refundApiKeyImpl({ mintUrl, baseUrl, apiKey, forceRefund });\n } finally {\n this._endProviderWalletOperation(baseUrl, \"refund\");\n }\n }\n\n private async _refundApiKeyImpl(options: RefundApiKeyOptions): Promise<RefundResult> {\n const { mintUrl, baseUrl, apiKey, forceRefund } = options;\n\n if (!apiKey) {\n this.logger.warn(`refundApiKey: aborting for ${baseUrl} - no API key`);\n return { success: false, message: \"No API key to refund\" };\n }\n\n // If forceRefund is not true, skip refund if the API key was used in the last 5 minutes\n if (!forceRefund) {\n const apiKeyEntry = this.storageAdapter.getApiKey(baseUrl);\n if (apiKeyEntry?.lastUsed) {\n const fiveMinutesAgo = Date.now() - 5 * 60 * 1000;\n if (apiKeyEntry.lastUsed > fiveMinutesAgo) {\n this.logger.log(\n `refundApiKey: skipping ${baseUrl} - used ${Math.round((Date.now() - apiKeyEntry.lastUsed) / 1000)}s ago`\n );\n return {\n success: false,\n message: \"API key was used recently, skipping refund\",\n };\n }\n }\n }\n\n let fetchResult:\n | { success: boolean; token?: string; requestId?: string; error?: string }\n | undefined;\n\n try {\n fetchResult = await this.fetchRefundToken(baseUrl, apiKey);\n\n if (fetchResult.error === \"No balance to refund\") {\n this.logger.log(`refundApiKey: provider says no balance for ${baseUrl}; removing API key`);\n this.storageAdapter.removeApiKey(baseUrl);\n return { success: true, message: \"No balance to refund, key cleaned up\" };\n }\n\n if (!fetchResult.success) {\n this.logger.warn(\n `refundApiKey: fetch failed for ${baseUrl}: ${fetchResult.error || \"API key refund failed\"}`\n );\n return {\n success: false,\n message: fetchResult.error || \"API key refund failed\",\n requestId: fetchResult.requestId,\n };\n }\n\n if (!fetchResult.token) {\n this.logger.warn(`refundApiKey: no token received for ${baseUrl}`);\n return {\n success: false,\n message: \"No token received from API key refund\",\n requestId: fetchResult.requestId,\n };\n }\n\n const receiveResult = await this.cashuSpender.receiveToken(\n fetchResult.token\n );\n const totalAmountMsat =\n receiveResult.unit === \"msat\"\n ? receiveResult.amount\n : receiveResult.amount * 1000;\n\n if (receiveResult.success) {\n this.storageAdapter.removeApiKey(baseUrl);\n } else {\n this.logger.warn(\n `refundApiKey: receive failed for ${baseUrl}; keeping API key. message=${receiveResult.message ?? \"none\"}`\n );\n }\n\n return {\n success: receiveResult.success,\n refundedAmount: totalAmountMsat,\n message: receiveResult.message,\n requestId: fetchResult.requestId,\n };\n } catch (error) {\n this.logger.error(\"API key refund error\", error);\n return this._handleRefundError(error, mintUrl, fetchResult?.requestId);\n }\n }\n\n /**\n * Fetch refund token from provider API using API key (or xcashu token) authentication\n */\n async fetchRefundToken(\n baseUrl: string,\n apiKeyOrToken: string,\n xCashu: boolean = false\n ): Promise<{\n success: boolean;\n token?: string;\n requestId?: string;\n error?: string;\n }> {\n if (!baseUrl) {\n return {\n success: false,\n error: \"No base URL configured\",\n };\n }\n\n const normalizedBaseUrl = baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`;\n const url = `${normalizedBaseUrl}v1/wallet/refund`;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => {\n controller.abort();\n }, 60000);\n\n try {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (xCashu) {\n headers[\"X-Cashu\"] = apiKeyOrToken;\n } else {\n headers[\"Authorization\"] = `Bearer ${apiKeyOrToken}`;\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n const requestId =\n response.headers.get(\"x-routstr-request-id\") || undefined;\n\n if (!response.ok) {\n const responseBody = await response.text().catch(() => undefined);\n let errorData: any = {};\n if (responseBody) {\n try {\n errorData = JSON.parse(responseBody);\n } catch {\n errorData = {};\n }\n }\n this.logger.error(\"Upstream wallet refund error response\", {\n baseUrl,\n url,\n status: response.status,\n statusText: response.statusText,\n requestId,\n body: responseBody ?? \"<unable to read response body>\",\n });\n return {\n success: false,\n requestId,\n error: `API key refund failed: ${\n errorData?.detail || responseBody || response.statusText\n }`,\n };\n }\n\n const data = await response.json();\n return {\n success: true,\n token: data.token,\n requestId,\n };\n } catch (error) {\n clearTimeout(timeoutId);\n this.logger.error(\"fetchRefundToken fetch error\", error);\n\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n return {\n success: false,\n error: \"Request timed out after 1 minute\",\n };\n }\n return {\n success: false,\n error: error.message,\n };\n }\n\n return {\n success: false,\n error: \"Unknown error occurred during API key refund request\",\n };\n }\n }\n\n /**\n * Top up API key balance with a cashu token\n */\n async topUp(options: TopUpOptions): Promise<TopUpResult> {\n const { mintUrl, baseUrl, amount, token: providedToken } = options;\n\n const guard = this._canRunProviderWalletOperation(baseUrl, \"topup\");\n if (!guard.allowed) {\n this.logger.log(`Skipping topup for ${baseUrl} - ${guard.reason}`);\n return { success: false, message: guard.reason };\n }\n\n this._beginProviderWalletOperation(baseUrl, \"topup\");\n\n try {\n return await this._topUpImpl({ mintUrl, baseUrl, amount, token: providedToken });\n } finally {\n this._endProviderWalletOperation(baseUrl, \"topup\");\n }\n }\n\n private async _topUpImpl(options: TopUpOptions): Promise<TopUpResult> {\n const { mintUrl, baseUrl, amount, token: providedToken } = options;\n\n if (!amount || amount <= 0) {\n return { success: false, message: \"Invalid top up amount\" };\n }\n\n const apiKeyEntry = providedToken\n ? null // providedToken is now the apiKey for apikeys mode\n : this.storageAdapter.getApiKey(baseUrl);\n const apiKey = providedToken || apiKeyEntry?.key;\n\n if (!apiKey) {\n return { success: false, message: \"No API key available for top up\" };\n }\n\n let cashuToken: string | null = null;\n let requestId: string | undefined;\n\n try {\n const tokenResult = await this.createProviderToken({\n mintUrl,\n baseUrl,\n amount,\n });\n\n if (!tokenResult.success || !tokenResult.token) {\n return {\n success: false,\n message: tokenResult.error || \"Unable to create top up token\",\n };\n }\n\n cashuToken = tokenResult.token;\n\n const topUpResult = await this._postTopUp(baseUrl, apiKey, cashuToken);\n requestId = topUpResult.requestId;\n this.logger.log(\"topUpResult:\", topUpResult);\n\n if (!topUpResult.success) {\n await this._recoverFailedTopUp(cashuToken);\n return {\n success: false,\n message: topUpResult.error || \"Top up failed\",\n requestId,\n recoveredToken: true,\n };\n }\n\n return {\n success: true,\n toppedUpAmount: amount,\n requestId,\n };\n } catch (error) {\n this.logger.log(`topup error for ${baseUrl}: ${error}`);\n if (cashuToken) {\n await this._recoverFailedTopUp(cashuToken);\n }\n\n return this._handleTopUpError(error, mintUrl, requestId);\n }\n }\n\n async createProviderToken(\n options: CreateProviderTokenOptions\n ): Promise<ProviderTokenResult> {\n const {\n mintUrl,\n baseUrl,\n amount,\n retryCount = 0,\n excludeMints = [],\n p2pkPubkey,\n } = options;\n\n const adjustedAmount = Math.ceil(amount);\n this.logger.log(`createProviderToken: baseUrl=${baseUrl} mintUrl=${mintUrl} amount=${amount} adjustedAmount=${adjustedAmount} retryCount=${retryCount}`);\n if (!adjustedAmount || isNaN(adjustedAmount)) {\n this.logger.error(`createProviderToken: invalid amount=${amount}`);\n return { success: false, error: \"Invalid top up amount\" };\n }\n\n const balanceState = await this.getBalanceState();\n const balances = await this.walletAdapter.getBalances();\n const units = this.walletAdapter.getMintUnits();\n\n const totalMintBalance = Object.values(balanceState.mintBalances).reduce(\n (sum, value) => sum + value,\n 0\n );\n const targetProviderBalance = balanceState.providerBalances[baseUrl] || 0;\n const refundableProviderBalance = Object.entries(\n balanceState.providerBalances\n )\n .filter(([providerBaseUrl]) => providerBaseUrl !== baseUrl)\n .reduce((sum, [, value]) => sum + value, 0);\n\n if (\n totalMintBalance + targetProviderBalance < adjustedAmount &&\n totalMintBalance + targetProviderBalance + refundableProviderBalance >=\n adjustedAmount &&\n retryCount < 3\n ) {\n await this._refundOtherProvidersForTopUp(baseUrl, mintUrl, retryCount, adjustedAmount);\n return this.createProviderToken({\n ...options,\n retryCount: retryCount + 1,\n });\n }\n\n if (totalMintBalance + targetProviderBalance < adjustedAmount) {\n const error = new InsufficientBalanceError(\n adjustedAmount,\n totalMintBalance + targetProviderBalance,\n totalMintBalance,\n Object.entries(balanceState.mintBalances).reduce(\n (max, [url, balance]) =>\n balance > max.balance ? { url, balance } : max,\n { url: \"\", balance: 0 }\n ).url\n );\n this.logger.error(`createProviderToken: insufficient balance required=${adjustedAmount} available=${totalMintBalance + targetProviderBalance} totalMint=${totalMintBalance} targetProvider=${targetProviderBalance}`);\n return { success: false, error: error.message };\n }\n\n const providerMints =\n baseUrl && this.providerRegistry\n ? this.providerRegistry.getProviderMints(baseUrl)\n : [];\n\n let requiredAmount = adjustedAmount;\n const supportedMintsOnly = providerMints.length > 0;\n\n let candidates = this._selectCandidateMints({\n balances,\n units,\n amount: requiredAmount,\n preferredMintUrl: mintUrl,\n excludeMints,\n allowedMints: supportedMintsOnly ? providerMints : undefined,\n });\n\n if (candidates.length === 0 && supportedMintsOnly) {\n requiredAmount += 2;\n candidates = this._selectCandidateMints({\n balances,\n units,\n amount: requiredAmount,\n preferredMintUrl: mintUrl,\n excludeMints,\n });\n }\n\n if (candidates.length === 0) {\n let maxBalance = 0;\n let maxMintUrl = \"\";\n for (const mintUrl in balances) {\n const balance = balances[mintUrl];\n const unit = units[mintUrl];\n const balanceInSats = getBalanceInSats(balance, unit);\n if (balanceInSats > maxBalance) {\n maxBalance = balanceInSats;\n maxMintUrl = mintUrl;\n }\n }\n\n this.logger.error(`createProviderToken: no candidate mints required=${requiredAmount} totalMint=${totalMintBalance} maxBalance=${maxBalance} maxMint=${maxMintUrl}`);\n const error = new InsufficientBalanceError(\n adjustedAmount,\n totalMintBalance,\n maxBalance,\n maxMintUrl\n );\n\n return { success: false, error: error.message };\n }\n\n let lastError: string | undefined;\n for (const candidateMint of candidates) {\n try {\n this.logger.log(`createProviderToken: attempting mint=${candidateMint} amount=${requiredAmount}`);\n const token = await this.walletAdapter.sendToken(\n candidateMint,\n requiredAmount,\n p2pkPubkey\n );\n this.logger.log(`createProviderToken: success from mint=${candidateMint}`);\n return {\n success: true,\n token,\n selectedMintUrl: candidateMint,\n amountSpent: requiredAmount,\n };\n } catch (error) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.logger.error(`createProviderToken: mint=${candidateMint} failed: ${errorMsg}`);\n if (error instanceof Error) {\n lastError = errorMsg;\n\n if (isNetworkErrorMessage(error.message)) {\n this.logger.warn(`createProviderToken: network error from ${candidateMint}, trying next mint...`);\n continue;\n }\n }\n\n return {\n success: false,\n error: lastError || \"Failed to create top up token\",\n };\n }\n }\n\n this.logger.error(`createProviderToken: all candidate mints exhausted lastError=${lastError}`);\n return {\n success: false,\n error:\n lastError || \"All candidate mints failed while creating top up token\",\n };\n }\n\n private _selectCandidateMints(options: {\n balances: Record<string, number>;\n units: Record<string, \"sat\" | \"msat\">;\n amount: number;\n preferredMintUrl: string;\n excludeMints: string[];\n allowedMints?: string[];\n }): string[] {\n const {\n balances,\n units,\n amount,\n preferredMintUrl,\n excludeMints,\n allowedMints,\n } = options;\n\n const candidates: string[] = [];\n\n const { selectedMintUrl: firstMint } = selectMintWithBalance(\n balances,\n units,\n amount,\n excludeMints\n );\n\n if (\n firstMint &&\n (!allowedMints ||\n allowedMints.length === 0 ||\n allowedMints.includes(firstMint))\n ) {\n candidates.push(firstMint);\n }\n\n const canUseMint = (mint: string): boolean => {\n if (excludeMints.includes(mint)) return false;\n if (\n allowedMints &&\n allowedMints.length > 0 &&\n !allowedMints.includes(mint)\n ) {\n return false;\n }\n const rawBalance = balances[mint] || 0;\n const unit = units[mint];\n const balanceInSats = getBalanceInSats(rawBalance, unit);\n return balanceInSats >= amount;\n };\n\n if (\n preferredMintUrl &&\n canUseMint(preferredMintUrl) &&\n !candidates.includes(preferredMintUrl)\n ) {\n candidates.push(preferredMintUrl);\n }\n\n for (const mint in balances) {\n if (mint === preferredMintUrl || candidates.includes(mint)) continue;\n if (canUseMint(mint)) {\n candidates.push(mint);\n }\n }\n\n return candidates;\n }\n\n private async _refundOtherProvidersForTopUp(\n baseUrl: string,\n mintUrl: string,\n retryCount: number,\n requiredAmount: number\n ): Promise<void> {\n const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();\n\n // If retryCount >= 2, force refund even if API keys were used recently\n const forceRefund = retryCount >= 2;\n\n // Build full candidate list sorted by lastUsed, oldest first.\n // This way providers outside the 5-min window are tried first (natural\n // refund succeeds), and if we must force-refund, we target the oldest\n // (closest to expiring) locked providers first.\n const candidates = apiKeyDistribution\n .filter((apiKey) => apiKey.baseUrl !== baseUrl && apiKey.amount > 0)\n .map((apiKey) => {\n const full = this.storageAdapter.getApiKey(apiKey.baseUrl);\n return {\n baseUrl: apiKey.baseUrl,\n amount: apiKey.amount,\n lastUsed: full?.lastUsed ?? 0,\n key: full?.key,\n } as const;\n })\n .filter((c) => c.key != null)\n .sort((a, b) => a.lastUsed - b.lastUsed); // oldest first\n\n if (candidates.length === 0) return;\n\n if (forceRefund) {\n // Sequential: refund one at a time until we have enough liquid balance\n // for the target provider, so we only force-refund as few providers as\n // necessary.\n //\n // NOTE: refundApiKey() already calls removeApiKey() on success, so we\n // don't need to update the balance here — the key is gone.\n for (const candidate of candidates) {\n await this.refundApiKey({\n mintUrl,\n baseUrl: candidate.baseUrl,\n apiKey: candidate.key!,\n forceRefund: true,\n });\n\n // Check if we've freed enough balance for the target provider\n const newState = await this.getBalanceState();\n const newAvailable =\n (newState.mintBalances[mintUrl] || 0) +\n (newState.providerBalances[baseUrl] || 0);\n\n if (newAvailable >= requiredAmount) {\n this.logger.log(\n `_refundOtherProvidersForTopUp: freed enough balance (${newAvailable} >= ${requiredAmount}), stopping early`\n );\n return;\n }\n }\n } else {\n // Non-force: try all in parallel (existing behavior, now sorted by\n // lastUsed for determinism). Providers outside the 5-min window will\n // succeed and be cleaned up by refundApiKey; recently-used ones are\n // skipped without side effects.\n await Promise.allSettled(\n candidates.map((candidate) =>\n this.refundApiKey({\n mintUrl,\n baseUrl: candidate.baseUrl,\n apiKey: candidate.key!,\n forceRefund: false,\n })\n )\n );\n }\n }\n\n /**\n * Post topup request to provider API\n */\n private async _postTopUp(\n baseUrl: string,\n storedToken: string,\n cashuToken: string\n ): Promise<{\n success: boolean;\n requestId?: string;\n error?: string;\n }> {\n if (!baseUrl) {\n return {\n success: false,\n error: \"No base URL configured\",\n };\n }\n\n const normalizedBaseUrl = baseUrl.endsWith(\"/\") ? baseUrl : `${baseUrl}/`;\n const url = `${normalizedBaseUrl}v1/wallet/topup?cashu_token=${encodeURIComponent(\n cashuToken\n )}`;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => {\n controller.abort();\n }, 60000);\n\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${storedToken}`,\n \"Content-Type\": \"application/json\",\n },\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n const requestId =\n response.headers.get(\"x-routstr-request-id\") || undefined;\n\n if (!response.ok) {\n const responseBody = await response.text().catch(() => undefined);\n let errorData: any = {};\n if (responseBody) {\n try {\n errorData = JSON.parse(responseBody);\n } catch {\n errorData = {};\n }\n }\n this.logger.error(\"Upstream wallet topup error response\", {\n baseUrl,\n url,\n status: response.status,\n statusText: response.statusText,\n requestId,\n body: responseBody ?? \"<unable to read response body>\",\n });\n return {\n success: false,\n requestId,\n error:\n errorData?.detail || responseBody || `Top up failed with status ${response.status}`,\n };\n }\n\n return { success: true, requestId };\n } catch (error) {\n clearTimeout(timeoutId);\n this.logger.error(\"_postTopUp fetch error\", error);\n\n if (error instanceof Error) {\n if (error.name === \"AbortError\") {\n return {\n success: false,\n error: \"Request timed out after 1 minute\",\n };\n }\n return {\n success: false,\n error: error.message,\n };\n }\n\n return {\n success: false,\n error: \"Unknown error occurred during top up request\",\n };\n }\n }\n\n /**\n * Attempt to receive token back after failed top up\n */\n private async _recoverFailedTopUp(cashuToken: string): Promise<void> {\n try {\n await this.cashuSpender.receiveToken(cashuToken);\n } catch (error) {\n this.logger.error(\"_recoverFailedTopUp: failed to recover token\", error);\n }\n }\n\n /**\n * Handle refund errors with specific error types\n */\n private _handleRefundError(\n error: unknown,\n mintUrl: string,\n requestId?: string\n ): RefundResult {\n if (error instanceof Error) {\n // Network errors\n if (isNetworkErrorMessage(error.message)) {\n return {\n success: false,\n message: `Failed to connect to the mint: ${mintUrl}`,\n requestId,\n };\n }\n\n // Wallet not found error\n if (error.message.includes(\"Wallet not found\")) {\n return {\n success: false,\n message: `Wallet couldn't be loaded. Please save this refunded cashu token manually.`,\n requestId,\n };\n }\n\n return {\n success: false,\n message: error.message,\n requestId,\n };\n }\n\n return {\n success: false,\n message: \"Refund failed\",\n requestId,\n };\n }\n\n /**\n * Get token balance from provider\n */\n async getTokenBalance(\n token: string,\n baseUrl: string\n ): Promise<{\n amount: number;\n reserved: number;\n unit: \"sat\" | \"msat\";\n apiKey: string;\n isInvalidApiKey?: boolean;\n /** True when the balance could not be determined (network error, non-OK\n * response, etc.). Callers MUST NOT use `amount` in arithmetic when\n * this flag is set — it is 0, not a real balance. */\n balanceUnknown?: boolean;\n }> {\n try {\n const response = await fetch(`${baseUrl}v1/wallet/info`, {\n headers: {\n Authorization: `Bearer ${token}`,\n },\n });\n\n if (response.ok) {\n const data = await response.json();\n return {\n amount: data.balance,\n reserved: data.reserved ?? 0,\n unit: \"msat\",\n apiKey: data.api_key,\n };\n } else {\n this.logger.warn(`getTokenBalance: status=${response.status}`);\n const data = await response.json();\n this.logger.warn(\"getTokenBalance: FAILED\", data);\n\n // Check for invalid/expired API key error (proofs already spent)\n const isInvalidApiKey =\n response.status === 401 &&\n data?.detail?.error?.code === \"invalid_api_key\" &&\n data?.detail?.error?.message?.includes(\"proofs already spent\");\n\n return {\n amount: 0,\n reserved: data.reserved ?? 0,\n unit: \"msat\",\n apiKey: data.api_key,\n isInvalidApiKey,\n balanceUnknown: true,\n };\n }\n } catch (error) {\n this.logger.error(\"getTokenBalance error\", error);\n }\n\n return {\n amount: 0,\n reserved: 0,\n unit: \"sat\",\n apiKey: \"\",\n balanceUnknown: true,\n };\n }\n\n /**\n * Handle topup errors with specific error types\n */\n private _handleTopUpError(\n error: unknown,\n mintUrl: string,\n requestId?: string\n ): TopUpResult {\n if (error instanceof Error) {\n if (isNetworkErrorMessage(error.message)) {\n return {\n success: false,\n message: `Failed to connect to the mint: ${mintUrl}`,\n requestId,\n };\n }\n\n if (error.message.includes(\"Wallet not found\")) {\n return {\n success: false,\n message:\n \"Wallet couldn't be loaded. The cashu token was recovered locally.\",\n requestId,\n };\n }\n\n return {\n success: false,\n message: error.message,\n requestId,\n };\n }\n\n return {\n success: false,\n message: \"Top up failed\",\n requestId,\n };\n }\n}\n"]}
|