@ghostlytools/cli 1.1.2 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/SKILL.md +1 -1
- package/dist/assets/argon2id-088uQfnH.js.map +1 -1
- package/dist/assets/bark_ffi_wasm_bg-EY2uc0Bx.js.map +1 -1
- package/dist/assets/bitcoindevkit_bg-B-iLWrmX.js.map +1 -1
- package/dist/assets/breez_sdk_spark_wasm_bg.wasm +0 -0
- package/dist/assets/fedimint_client_wasm_bg-BtHHlFpp.js.map +1 -1
- package/dist/assets/{hyperdhtRelay-CVLCuqVr.js → hyperdhtRelay-BoxPHp7v.js} +3 -3
- package/dist/assets/{hyperdhtRelay-CVLCuqVr.js.map → hyperdhtRelay-BoxPHp7v.js.map} +1 -1
- package/dist/assets/legacy_ciphers-JJOu0JXL.js.map +1 -1
- package/dist/assets/{mainline-CKFpwXcB.js → mainline-dkA94eh2.js} +2 -2
- package/dist/assets/{mainline-CKFpwXcB.js.map → mainline-dkA94eh2.js.map} +1 -1
- package/dist/assets/nacl-fast-CDhNCYHs.js.map +1 -1
- package/dist/assets/noble_curves-DDWn5AH0.js.map +1 -1
- package/dist/assets/noble_hashes-B7AZyFyS.js.map +1 -1
- package/dist/assets/openpgp-BBFr-zHQ.js.map +1 -1
- package/dist/assets/{server-vGoe9MET.js → server-CXFTDnFI.js} +285 -99
- package/dist/assets/server-CXFTDnFI.js.map +1 -0
- package/dist/assets/sha512-BYId-G-T.js.map +1 -1
- package/dist/assets/{src-CJdPTl7Q.js → src-K3NijMq-.js} +455 -87
- package/dist/assets/src-K3NijMq-.js.map +1 -0
- package/dist/assets/storage-Bya5b2Xt.js.map +1 -1
- package/dist/assets/tree-store-N362nuzZ.js.map +1 -1
- package/dist/assets/unbzip2-stream-B1C-JX9L.js.map +1 -1
- package/dist/assets/{web-OUQl4Q7L.js → web-DwgdhfcY.js} +16 -16
- package/dist/assets/{web-OUQl4Q7L.js.map → web-DwgdhfcY.js.map} +1 -1
- package/dist/ghostly.mjs +55 -40
- package/dist/ghostly.mjs.map +1 -1
- package/examples/call-echo.mjs +1 -1
- package/package.json +7 -7
- package/dist/assets/server-vGoe9MET.js.map +0 -1
- package/dist/assets/src-CJdPTl7Q.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-Bya5b2Xt.js","names":[],"sources":["../../../../node_modules/@breeztech/breez-sdk-spark/web/storage/index.js"],"sourcesContent":["/**\n * ES6 module for Web IndexedDB Storage Implementation\n * This provides an ES6 interface to IndexedDB storage for web browsers\n */\n\nclass MigrationManager {\n constructor(db, StorageError, logger = null) {\n this.db = db;\n this.StorageError = StorageError;\n this.logger = logger;\n this.migrations = this._getMigrations();\n }\n\n /**\n * Handle IndexedDB upgrade event - called during database opening\n */\n handleUpgrade(event, oldVersion, newVersion) {\n const db = event.target.result;\n const transaction = event.target.transaction;\n\n this._log(\n \"info\",\n `Upgrading IndexedDB from version ${oldVersion} to ${newVersion}`\n );\n\n try {\n for (let i = oldVersion; i < newVersion; i++) {\n const migration = this.migrations[i];\n if (migration) {\n this._log(\"debug\", `Running migration ${i + 1}: ${migration.name}`);\n migration.upgrade(db, transaction);\n }\n }\n this._log(\"info\", `Database migration completed successfully`);\n } catch (error) {\n this._log(\n \"error\",\n `Migration failed at version ${oldVersion}: ${error.message}`\n );\n throw new this.StorageError(\n `Migration failed at version ${oldVersion}: ${error.message}`,\n error\n );\n }\n }\n\n _log(level, message) {\n if (this.logger && typeof this.logger.log === \"function\") {\n this.logger.log({\n line: message,\n level: level,\n });\n } else if (level === \"error\") {\n console.error(`[MigrationManager] ${message}`);\n }\n }\n\n /**\n * Define all database migrations for IndexedDB\n *\n * Each migration is an object with:\n * - name: Description of the migration\n * - upgrade: Function that takes (db, transaction) and creates/modifies object stores\n */\n _getMigrations() {\n return [\n {\n name: \"Create initial object stores\",\n upgrade: (db) => {\n // Settings store (key-value cache)\n if (!db.objectStoreNames.contains(\"settings\")) {\n db.createObjectStore(\"settings\", { keyPath: \"key\" });\n }\n\n // Payments store\n if (!db.objectStoreNames.contains(\"payments\")) {\n const paymentStore = db.createObjectStore(\"payments\", {\n keyPath: \"id\",\n });\n paymentStore.createIndex(\"timestamp\", \"timestamp\", {\n unique: false,\n });\n paymentStore.createIndex(\"paymentType\", \"paymentType\", {\n unique: false,\n });\n paymentStore.createIndex(\"status\", \"status\", { unique: false });\n }\n\n // Payment metadata store\n if (!db.objectStoreNames.contains(\"payment_metadata\")) {\n db.createObjectStore(\"payment_metadata\", { keyPath: \"paymentId\" });\n }\n\n // Unclaimed deposits store\n if (!db.objectStoreNames.contains(\"unclaimed_deposits\")) {\n const depositStore = db.createObjectStore(\"unclaimed_deposits\", {\n keyPath: [\"txid\", \"vout\"],\n });\n depositStore.createIndex(\"txid\", \"txid\", { unique: false });\n }\n },\n },\n {\n name: \"Create invoice index\",\n upgrade: (db, transaction) => {\n const paymentStore = transaction.objectStore(\"payments\");\n if (!paymentStore.indexNames.contains(\"invoice\")) {\n paymentStore.createIndex(\"invoice\", \"details.invoice\", {\n unique: false,\n });\n }\n },\n },\n {\n name: \"Convert amount and fees from Number to BigInt for u128 support\",\n upgrade: (db, transaction) => {\n const store = transaction.objectStore(\"payments\");\n const getAllRequest = store.getAll();\n\n getAllRequest.onsuccess = () => {\n const payments = getAllRequest.result;\n let updated = 0;\n\n payments.forEach((payment) => {\n // Convert amount and fees from Number to BigInt if they're numbers\n let needsUpdate = false;\n\n if (typeof payment.amount === \"number\") {\n payment.amount = BigInt(Math.round(payment.amount));\n needsUpdate = true;\n }\n\n if (typeof payment.fees === \"number\") {\n payment.fees = BigInt(Math.round(payment.fees));\n needsUpdate = true;\n }\n\n if (needsUpdate) {\n store.put(payment);\n updated++;\n }\n });\n\n console.log(`Migrated ${updated} payment records to BigInt format`);\n };\n },\n },\n {\n name: \"Add sync tables\",\n upgrade: (db, transaction) => {\n // sync_revision: tracks the last committed revision (from server-acknowledged\n // or server-received records). Does NOT include pending outgoing revisions.\n if (!db.objectStoreNames.contains(\"sync_revision\")) {\n const syncRevisionStore = db.createObjectStore(\"sync_revision\", {\n keyPath: \"id\",\n });\n transaction\n .objectStore(\"sync_revision\")\n .add({ id: 1, revision: \"0\" });\n }\n\n if (!db.objectStoreNames.contains(\"sync_outgoing\")) {\n db.createObjectStore(\"sync_outgoing\", {\n keyPath: [\"type\", \"dataId\", \"revision\"],\n });\n transaction\n .objectStore(\"sync_outgoing\")\n .createIndex(\"revision\", \"revision\");\n }\n\n if (!db.objectStoreNames.contains(\"sync_incoming\")) {\n db.createObjectStore(\"sync_incoming\", {\n keyPath: [\"type\", \"dataId\", \"revision\"],\n });\n transaction\n .objectStore(\"sync_incoming\")\n .createIndex(\"revision\", \"revision\");\n }\n\n if (!db.objectStoreNames.contains(\"sync_state\")) {\n db.createObjectStore(\"sync_state\", { keyPath: [\"type\", \"dataId\"] });\n }\n },\n },\n {\n name: \"Create lnurl_receive_metadata store\",\n upgrade: (db) => {\n if (!db.objectStoreNames.contains(\"lnurl_receive_metadata\")) {\n db.createObjectStore(\"lnurl_receive_metadata\", {\n keyPath: \"paymentHash\",\n });\n }\n },\n },\n {\n // Delete all unclaimed deposits to clear old claim_error JSON format.\n // Deposits will be recovered on next sync.\n name: \"Clear unclaimed deposits for claim_error format change\",\n upgrade: (db, transaction) => {\n if (db.objectStoreNames.contains(\"unclaimed_deposits\")) {\n const store = transaction.objectStore(\"unclaimed_deposits\");\n store.clear();\n }\n },\n },\n {\n name: \"Clear sync tables for BreezSigner backward compatibility\",\n upgrade: (db, transaction) => {\n // Clear all sync tables due to BreezSigner signature change.\n // This forces users to sync from scratch to the sync server.\n // Also delete the sync_initial_complete flag to force re-populating\n // all payment metadata for outgoing sync using the new key.\n\n // Clear sync tables (only if they exist)\n if (db.objectStoreNames.contains(\"sync_outgoing\")) {\n const syncOutgoing = transaction.objectStore(\"sync_outgoing\");\n syncOutgoing.clear();\n }\n\n if (db.objectStoreNames.contains(\"sync_incoming\")) {\n const syncIncoming = transaction.objectStore(\"sync_incoming\");\n syncIncoming.clear();\n }\n\n if (db.objectStoreNames.contains(\"sync_state\")) {\n const syncState = transaction.objectStore(\"sync_state\");\n syncState.clear();\n }\n\n // Reset revision to 0 (only if store exists)\n if (db.objectStoreNames.contains(\"sync_revision\")) {\n const syncRevision = transaction.objectStore(\"sync_revision\");\n syncRevision.clear();\n syncRevision.put({ id: 1, revision: \"0\" });\n }\n\n // Delete sync_initial_complete setting (only if store exists)\n if (db.objectStoreNames.contains(\"settings\")) {\n const settings = transaction.objectStore(\"settings\");\n settings.delete(\"sync_initial_complete\");\n }\n }\n },\n {\n name: \"Create parentPaymentId index for related payments lookup\",\n upgrade: (db, transaction) => {\n if (db.objectStoreNames.contains(\"payment_metadata\")) {\n const metadataStore = transaction.objectStore(\"payment_metadata\");\n if (!metadataStore.indexNames.contains(\"parentPaymentId\")) {\n metadataStore.createIndex(\"parentPaymentId\", \"parentPaymentId\", { unique: false });\n }\n }\n }\n },\n {\n name: \"Add tx_type to token payments and trigger token re-sync\",\n upgrade: (db, transaction) => {\n // Update all existing token payments to have a default txType\n if (db.objectStoreNames.contains(\"payments\")) {\n const paymentStore = transaction.objectStore(\"payments\");\n const getAllRequest = paymentStore.getAll();\n\n getAllRequest.onsuccess = () => {\n const payments = getAllRequest.result;\n\n payments.forEach((payment) => {\n // Parse details if it's a string\n let details = null;\n if (payment.details && typeof payment.details === \"string\") {\n try {\n details = JSON.parse(payment.details);\n } catch (e) {\n return; // Skip this payment if parsing fails\n }\n } else {\n details = payment.details;\n }\n\n // Add default txType to token payments\n if (details && details.type === \"token\" && !details.txType) {\n details.txType = \"transfer\";\n payment.details = JSON.stringify(details);\n paymentStore.put(payment);\n }\n });\n };\n }\n\n // Reset sync cache to trigger token re-sync\n if (db.objectStoreNames.contains(\"settings\")) {\n const settingsStore = transaction.objectStore(\"settings\");\n const getRequest = settingsStore.get(\"sync_offset\");\n\n getRequest.onsuccess = () => {\n const syncCache = getRequest.result;\n if (syncCache && syncCache.value) {\n try {\n const syncInfo = JSON.parse(syncCache.value);\n // Reset only the token sync position, keep the bitcoin offset\n syncInfo.last_synced_final_token_payment_id = null;\n settingsStore.put({\n key: \"sync_offset\",\n value: JSON.stringify(syncInfo),\n });\n } catch (e) {\n // If parsing fails, just continue\n }\n }\n };\n }\n },\n },\n {\n name: \"Clear sync tables to force re-sync\",\n upgrade: (db, transaction) => {\n if (db.objectStoreNames.contains(\"sync_outgoing\")) {\n transaction.objectStore(\"sync_outgoing\").clear();\n }\n if (db.objectStoreNames.contains(\"sync_incoming\")) {\n transaction.objectStore(\"sync_incoming\").clear();\n }\n if (db.objectStoreNames.contains(\"sync_state\")) {\n transaction.objectStore(\"sync_state\").clear();\n }\n if (db.objectStoreNames.contains(\"sync_revision\")) {\n const syncRevision = transaction.objectStore(\"sync_revision\");\n syncRevision.clear();\n syncRevision.put({ id: 1, revision: \"0\" });\n }\n if (db.objectStoreNames.contains(\"settings\")) {\n transaction.objectStore(\"settings\").delete(\"sync_initial_complete\");\n }\n },\n },\n {\n name: \"Add preimage to lnurl_receive_metadata for LUD-21 and NIP-57\",\n upgrade: (db, transaction) => {\n // IndexedDB doesn't need schema changes for new fields on existing stores.\n // Just clear the lnurl_metadata_updated_after setting to force re-sync.\n if (db.objectStoreNames.contains(\"settings\")) {\n const settings = transaction.objectStore(\"settings\");\n settings.delete(\"lnurl_metadata_updated_after\");\n }\n }\n },\n {\n name: \"Backfill htlc_details for existing Lightning payments\",\n upgrade: (db, transaction) => {\n if (db.objectStoreNames.contains(\"payments\")) {\n const paymentStore = transaction.objectStore(\"payments\");\n const getAllRequest = paymentStore.getAll();\n\n getAllRequest.onsuccess = () => {\n const payments = getAllRequest.result;\n payments.forEach((payment) => {\n let details;\n if (typeof payment.details === \"string\") {\n try {\n details = JSON.parse(payment.details);\n } catch (e) {\n return;\n }\n } else {\n details = payment.details;\n }\n\n if (details && details.type === \"lightning\" && !details.htlcDetails) {\n let htlcStatus;\n if (payment.status === \"completed\") {\n htlcStatus = \"preimageShared\";\n } else if (payment.status === \"pending\") {\n htlcStatus = \"waitingForPreimage\";\n } else {\n htlcStatus = \"returned\";\n }\n details.htlcDetails = {\n paymentHash: details.paymentHash,\n preimage: details.preimage || null,\n expiryTime: 0,\n status: htlcStatus,\n };\n payment.details = JSON.stringify(details);\n paymentStore.put(payment);\n }\n });\n };\n }\n\n // Reset sync offset to trigger resync\n if (db.objectStoreNames.contains(\"settings\")) {\n const settingsStore = transaction.objectStore(\"settings\");\n const getRequest = settingsStore.get(\"sync_offset\");\n\n getRequest.onsuccess = () => {\n const syncCache = getRequest.result;\n if (syncCache && syncCache.value) {\n try {\n const syncInfo = JSON.parse(syncCache.value);\n syncInfo.offset = 0;\n settingsStore.put({\n key: \"sync_offset\",\n value: JSON.stringify(syncInfo),\n });\n } catch (e) {\n // If parsing fails, just continue\n }\n }\n };\n }\n },\n },\n {\n name: \"Create contacts store\",\n upgrade: (db) => {\n if (!db.objectStoreNames.contains(\"contacts\")) {\n const contactsStore = db.createObjectStore(\"contacts\", { keyPath: \"id\" });\n contactsStore.createIndex(\"name_identifier\", [\"name\", \"paymentIdentifier\"], { unique: false });\n contactsStore.createIndex(\"name\", \"name\", { unique: false });\n }\n }\n },\n {\n name: \"Clear cached lightning address for LnurlInfo schema change\",\n upgrade: (db, transaction) => {\n if (db.objectStoreNames.contains(\"settings\")) {\n const settings = transaction.objectStore(\"settings\");\n settings.delete(\"lightning_address\");\n }\n }\n },\n {\n name: \"Drop preimage from lnurl_receive_metadata records\",\n upgrade: (db, transaction) => {\n if (db.objectStoreNames.contains(\"lnurl_receive_metadata\")) {\n const store = transaction.objectStore(\"lnurl_receive_metadata\");\n const request = store.openCursor();\n request.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor) {\n const record = cursor.value;\n if (\"preimage\" in record) {\n delete record.preimage;\n cursor.update(record);\n }\n cursor.continue();\n }\n };\n }\n }\n },\n {\n name: \"Clear cached lightning address for CachedLightningAddress format change\",\n upgrade: (db, transaction) => {\n if (db.objectStoreNames.contains(\"settings\")) {\n const settings = transaction.objectStore(\"settings\");\n settings.delete(\"lightning_address\");\n }\n }\n },\n {\n // Recovery migration for the missing \"contacts\" object store.\n //\n // The original \"Create contacts store\" migration above was INSERTED into\n // the middle of this array (at index 12) instead of being appended, in\n // SDK 0.11.0. That index was already occupied by the \"Clear cached\n // lightning address for LnurlInfo schema change\" migration, which had\n // shipped one release earlier in SDK 0.10.0 (dbVersion 13).\n //\n // Migration array indices map 1:1 to DB version transitions, so any\n // database that ran 0.10.0 reached version 13 and, on upgrading to\n // 0.11.0+ (dbVersion 14), ran only migrations[13] — permanently skipping\n // the newly-inserted migrations[12]. Those databases never got a\n // \"contacts\" object store, so every contact operation fails with\n // NotFoundError.\n //\n // This migration is correctly appended and idempotently (re)creates the\n // store, so affected databases recover on their next upgrade while\n // unaffected databases treat it as a no-op. Keep the original migration\n // in place; do not delete or reorder it.\n name: \"Create contacts store (recovery for skipped migration)\",\n upgrade: (db) => {\n if (!db.objectStoreNames.contains(\"contacts\")) {\n const contactsStore = db.createObjectStore(\"contacts\", { keyPath: \"id\" });\n contactsStore.createIndex(\"name_identifier\", [\"name\", \"paymentIdentifier\"], { unique: false });\n contactsStore.createIndex(\"name\", \"name\", { unique: false });\n }\n }\n },\n {\n // Add deposit_vout to distinguish deposits sharing a funding tx. The\n // new field is carried inside the JSON `details` blob. We can't safely\n // backfill vout on the existing blobs: we never stored the original SSP\n // output_index, and vout=0 is a valid output index, so defaulting would\n // silently mislabel. Instead we clear `details` on legacy deposit blobs\n // so the read path returns `details: None` (matches what the SQL\n // backends do by leaving the payments row but having no matching\n // payment_details_deposit row). Reset the bitcoin sync offset so the\n // resync re-fetches the SSP user_request and the upsert rewrites the\n // blob with the proper vout.\n name: \"Clear legacy deposit details and reset sync offset for vout\",\n upgrade: (db, transaction) => {\n if (db.objectStoreNames.contains(\"payments\")) {\n const paymentStore = transaction.objectStore(\"payments\");\n const cursorRequest = paymentStore.openCursor();\n cursorRequest.onsuccess = (event) => {\n const cursor = event.target.result;\n if (!cursor) return;\n const payment = cursor.value;\n let details = null;\n if (payment.details && typeof payment.details === \"string\") {\n try {\n details = JSON.parse(payment.details);\n } catch (e) {\n details = null;\n }\n } else {\n details = payment.details;\n }\n if (details && details.type === \"deposit\") {\n payment.details = null;\n cursor.update(payment);\n }\n cursor.continue();\n };\n }\n if (db.objectStoreNames.contains(\"settings\")) {\n const settingsStore = transaction.objectStore(\"settings\");\n const getRequest = settingsStore.get(\"sync_offset\");\n\n getRequest.onsuccess = () => {\n const syncCache = getRequest.result;\n if (syncCache && syncCache.value) {\n try {\n const syncInfo = JSON.parse(syncCache.value);\n syncInfo.offset = 0;\n settingsStore.put({\n key: \"sync_offset\",\n value: JSON.stringify(syncInfo),\n });\n } catch (e) {\n // If parsing fails, just continue\n }\n }\n };\n }\n },\n },\n {\n name: \"Backfill conversion_info type discriminator for serde tagged enum\",\n upgrade: (db, transaction) => {\n if (db.objectStoreNames.contains(\"payment_metadata\")) {\n const store = transaction.objectStore(\"payment_metadata\");\n const request = store.openCursor();\n request.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor) {\n const record = cursor.value;\n if (record.conversionInfo) {\n try {\n const ci = typeof record.conversionInfo === \"string\"\n ? JSON.parse(record.conversionInfo)\n : record.conversionInfo;\n if (!ci.type) {\n ci.type = \"amm\";\n record.conversionInfo = JSON.stringify(ci);\n cursor.update(record);\n }\n } catch (e) {\n // Skip unparseable records\n }\n }\n cursor.continue();\n }\n };\n }\n },\n },\n {\n // listActiveCrossChainSwaps scans and filters.\n name: \"Create cross_chain_swaps store\",\n upgrade: (db) => {\n if (!db.objectStoreNames.contains(\"cross_chain_swaps\")) {\n db.createObjectStore(\"cross_chain_swaps\", {\n keyPath: [\"provider\", \"id\"],\n });\n }\n },\n },\n {\n // Only the Declined shape changed, and clearing it costs at most one extra\n // quote. Submitted entries are left alone: their shape is unchanged and\n // they are the only guard against re-claiming a UTXO whose earlier claim\n // is still settling.\n name: \"Clear declined instant claim status after its shape changed\",\n upgrade: (db, transaction) => {\n if (!db.objectStoreNames.contains(\"unclaimed_deposits\")) return;\n const store = transaction.objectStore(\"unclaimed_deposits\");\n const cursorRequest = store.openCursor();\n cursorRequest.onsuccess = (event) => {\n const cursor = event.target.result;\n if (!cursor) return;\n const deposit = cursor.value;\n if (\n deposit.instantClaimStatus &&\n String(deposit.instantClaimStatus).toLowerCase().includes(\"declined\")\n ) {\n deposit.instantClaimStatus = null;\n cursor.update(deposit);\n }\n cursor.continue();\n };\n },\n },\n {\n // Deposit addresses polled on-chain for deposits still in the mempool.\n // Entries are removed once watching them can no longer lead to an early\n // claim, so the store holds only the live watch set.\n name: \"Create watched_deposit_addresses store\",\n upgrade: (db) => {\n if (!db.objectStoreNames.contains(\"watched_deposit_addresses\")) {\n db.createObjectStore(\"watched_deposit_addresses\", {\n keyPath: \"address\",\n });\n }\n },\n },\n ];\n }\n}\n\nclass StorageError extends Error {\n constructor(message, cause = null) {\n super(message);\n this.name = \"StorageError\";\n this.cause = cause;\n\n // Maintain proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, StorageError);\n }\n }\n}\n\nclass IndexedDBStorage {\n constructor(dbName = \"BreezSDK\", logger = null) {\n this.dbName = dbName;\n this.db = null;\n this.migrationManager = null;\n this.logger = logger;\n // IMPORTANT: the migrations array in MigrationManager is append-only. The\n // migration at array index N is the upgrade step from DB version N to N+1,\n // so existing databases depend on indices never shifting. Never insert,\n // reorder, or delete a migration — only append. dbVersion MUST equal the\n // number of migrations (enforced by the guard in initialize()).\n this.dbVersion = 22; // Current schema version (= migration count)\n }\n\n /**\n * Initialize the storage - must be called before using other methods\n */\n async initialize() {\n if (this.db) {\n return this;\n }\n\n if (typeof window === \"undefined\" || !window.indexedDB) {\n throw new StorageError(\"IndexedDB is not available in this environment\");\n }\n\n // Guard: dbVersion must equal the migration count. If they drift apart, the\n // upgrade loop either skips the trailing migration(s) or requests a version\n // no migration fills in. Fail fast — this is a programming error.\n const migrationCount = new MigrationManager(null, StorageError).migrations.length;\n if (this.dbVersion !== migrationCount) {\n throw new StorageError(\n `dbVersion (${this.dbVersion}) must equal the migration count (${migrationCount}). ` +\n `Migrations are append-only: append a new migration and bump dbVersion to match.`\n );\n }\n\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(this.dbName, this.dbVersion);\n\n request.onerror = () => {\n const error = new StorageError(\n `Failed to open IndexedDB: ${request.error?.message || \"Unknown error\"\n }`,\n request.error\n );\n reject(error);\n };\n\n request.onsuccess = () => {\n this.db = request.result;\n this.migrationManager = new MigrationManager(\n this.db,\n StorageError,\n this.logger\n );\n\n // Handle unexpected version changes\n this.db.onversionchange = () => {\n this.db.close();\n this.db = null;\n };\n\n resolve(this);\n };\n\n request.onupgradeneeded = (event) => {\n this.db = event.target.result;\n this.migrationManager = new MigrationManager(\n this.db,\n StorageError,\n this.logger\n );\n\n try {\n this.migrationManager.handleUpgrade(\n event,\n event.oldVersion,\n event.newVersion\n );\n } catch (error) {\n reject(error);\n }\n };\n });\n }\n\n /**\n * Close the database connection\n */\n close() {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n }\n\n // ===== Cache Operations =====\n\n async getCachedItem(key) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"settings\", \"readonly\");\n const store = transaction.objectStore(\"settings\");\n const request = store.get(key);\n\n request.onsuccess = () => {\n const result = request.result;\n resolve(result ? result.value : null);\n };\n\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to get cached item '${key}': ${request.error?.message || \"Unknown error\"\n }`,\n request.error\n )\n );\n };\n });\n }\n\n async setCachedItem(key, value) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"settings\", \"readwrite\");\n const store = transaction.objectStore(\"settings\");\n const request = store.put({ key, value });\n\n request.onsuccess = () => resolve();\n\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to set cached item '${key}': ${request.error?.message || \"Unknown error\"\n }`,\n request.error\n )\n );\n };\n });\n }\n\n async deleteCachedItem(key) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"settings\", \"readwrite\");\n const store = transaction.objectStore(\"settings\");\n const request = store.delete(key);\n\n request.onsuccess = () => resolve();\n\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to delete cached item '${key}': ${request.error?.message || \"Unknown error\"\n }`,\n request.error\n )\n );\n };\n });\n }\n\n // ===== Payment Operations =====\n\n /**\n * Gets the set of payment IDs that are related payments (have a parentPaymentId).\n * Uses the parentPaymentId index for efficient lookup.\n * @param {IDBObjectStore} metadataStore - The payment_metadata object store\n * @returns {Promise<Set<string>>} Set of payment IDs that are related payments\n */\n _getRelatedPaymentIds(metadataStore) {\n return new Promise((resolve) => {\n const relatedPaymentIds = new Set();\n\n // Check if the parentPaymentId index exists (added in migration)\n if (!metadataStore.indexNames.contains(\"parentPaymentId\")) {\n // Index doesn't exist yet, fall back to scanning all metadata\n const cursorRequest = metadataStore.openCursor();\n cursorRequest.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor) {\n if (cursor.value.parentPaymentId) {\n relatedPaymentIds.add(cursor.value.paymentId);\n }\n cursor.continue();\n } else {\n resolve(relatedPaymentIds);\n }\n };\n cursorRequest.onerror = () => resolve(new Set());\n return;\n }\n\n // Use the parentPaymentId index to find all metadata entries with a parent\n const index = metadataStore.index(\"parentPaymentId\");\n const cursorRequest = index.openCursor();\n\n cursorRequest.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor) {\n // Only add if parentPaymentId is truthy (not null/undefined)\n if (cursor.value.parentPaymentId) {\n relatedPaymentIds.add(cursor.value.paymentId);\n }\n cursor.continue();\n } else {\n resolve(relatedPaymentIds);\n }\n };\n\n cursorRequest.onerror = () => {\n // If index lookup fails, return empty set and fall back to per-payment lookup\n resolve(new Set());\n };\n });\n }\n\n async listPayments(request) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n // Handle null values by using default values\n const actualOffset = request.offset !== null ? request.offset : 0;\n const actualLimit = request.limit !== null ? request.limit : 4294967295; // u32::MAX\n\n const transaction = this.db.transaction(\n [\"payments\", \"payment_metadata\", \"lnurl_receive_metadata\"],\n \"readonly\"\n );\n const paymentStore = transaction.objectStore(\"payments\");\n const metadataStore = transaction.objectStore(\"payment_metadata\");\n const lnurlReceiveMetadataStore = transaction.objectStore(\"lnurl_receive_metadata\");\n\n // Build set of related payment IDs upfront for O(1) filtering\n const relatedPaymentIds = await this._getRelatedPaymentIds(metadataStore);\n\n return new Promise((resolve, reject) => {\n const payments = [];\n let count = 0;\n let skipped = 0;\n\n // Determine sort order - \"prev\" for descending (default), \"next\" for ascending\n const cursorDirection = request.sortAscending ? \"next\" : \"prev\";\n\n // Use cursor to iterate through payments ordered by timestamp\n const cursorRequest = paymentStore\n .index(\"timestamp\")\n .openCursor(null, cursorDirection);\n\n cursorRequest.onsuccess = (event) => {\n const cursor = event.target.result;\n\n if (!cursor || count >= actualLimit) {\n resolve(payments);\n return;\n }\n\n const payment = cursor.value;\n\n // Skip related payments (those with a parentPaymentId)\n if (relatedPaymentIds.has(payment.id)) {\n cursor.continue();\n return;\n }\n\n if (skipped < actualOffset) {\n skipped++;\n cursor.continue();\n return;\n }\n\n // Get metadata for this payment (now only for non-related payments)\n const metadataRequest = metadataStore.get(payment.id);\n metadataRequest.onsuccess = () => {\n const metadata = metadataRequest.result;\n\n const paymentWithMetadata = this._mergePaymentMetadata(\n payment,\n metadata\n );\n\n // Fetch lnurl receive metadata before filtering, so Lightning\n // filters can check lnurlReceiveMetadata fields\n this._fetchLnurlReceiveMetadata(\n paymentWithMetadata,\n lnurlReceiveMetadataStore\n )\n .then((mergedPayment) => {\n // Apply filters after lnurl metadata is populated\n if (!this._matchesFilters(mergedPayment, request)) {\n cursor.continue();\n return;\n }\n payments.push(mergedPayment);\n count++;\n cursor.continue();\n })\n .catch(() => {\n // Apply filters even if lnurl metadata fetch fails\n if (!this._matchesFilters(paymentWithMetadata, request)) {\n cursor.continue();\n return;\n }\n payments.push(paymentWithMetadata);\n count++;\n cursor.continue();\n });\n };\n metadataRequest.onerror = () => {\n // Continue without metadata if it fails\n if (this._matchesFilters(payment, request)) {\n payments.push(payment);\n count++;\n }\n\n cursor.continue();\n };\n };\n\n cursorRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to list payments (request: ${JSON.stringify(request)}: ${cursorRequest.error?.message || \"Unknown error\"\n }`,\n cursorRequest.error\n )\n );\n };\n });\n }\n\n async applyPaymentUpdate(payment) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n let shouldEmit = false;\n let settled = false;\n const transaction = this.db.transaction(\"payments\", \"readwrite\");\n const store = transaction.objectStore(\"payments\");\n\n const rejectOnce = (message, error) => {\n if (settled) {\n return;\n }\n settled = true;\n reject(new StorageError(message, error));\n };\n\n transaction.oncomplete = () => {\n if (settled) {\n return;\n }\n settled = true;\n resolve(shouldEmit);\n };\n\n transaction.onerror = () => {\n rejectOnce(\n `Failed to apply payment update '${payment.id}': ${transaction.error?.message || \"Unknown error\"\n }`,\n transaction.error\n );\n };\n\n transaction.onabort = () => {\n rejectOnce(\n `Payment update transaction aborted for '${payment.id}': ${transaction.error?.message || \"Unknown error\"\n }`,\n transaction.error\n );\n };\n\n const getRequest = store.get(payment.id);\n\n getRequest.onsuccess = () => {\n const storedPayment = getRequest.result;\n const stored = storedPayment\n ? this._normalizePaymentStatus(storedPayment.status)\n : null;\n const next = this._normalizePaymentStatus(payment.status);\n\n let shouldPersist;\n if (stored == null) {\n shouldPersist = true;\n shouldEmit = true;\n } else if (stored === next) {\n console.debug(\n `Skipping redundant payment event: id=${payment.id} status=${next}`\n );\n shouldPersist = true;\n shouldEmit = false;\n } else if (this._isFinalPaymentStatus(stored)) {\n console.warn(\n `Skipping payment update (would replace terminal status): id=${payment.id} stored=${stored} new=${next}`\n );\n shouldPersist = false;\n shouldEmit = false;\n } else {\n shouldPersist = true;\n shouldEmit = true;\n }\n\n if (!shouldPersist) {\n return;\n }\n\n const putRequest = store.put(this._paymentToStore(payment));\n putRequest.onerror = () => {\n rejectOnce(\n `Failed to persist payment update '${payment.id}': ${putRequest.error?.message || \"Unknown error\"\n }`,\n putRequest.error\n );\n };\n };\n\n getRequest.onerror = () => {\n rejectOnce(\n `Failed to read payment '${payment.id}' before update: ${getRequest.error?.message || \"Unknown error\"\n }`,\n getRequest.error\n );\n };\n });\n }\n\n async getPaymentById(id) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n [\"payments\", \"payment_metadata\", \"lnurl_receive_metadata\"],\n \"readonly\"\n );\n const paymentStore = transaction.objectStore(\"payments\");\n const metadataStore = transaction.objectStore(\"payment_metadata\");\n const lnurlReceiveMetadataStore = transaction.objectStore(\n \"lnurl_receive_metadata\"\n );\n\n const paymentRequest = paymentStore.get(id);\n\n paymentRequest.onsuccess = () => {\n const payment = paymentRequest.result;\n if (!payment) {\n reject(new StorageError(`Payment with id '${id}' not found`));\n return;\n }\n\n // Get metadata for this payment\n const metadataRequest = metadataStore.get(id);\n metadataRequest.onsuccess = () => {\n const metadata = metadataRequest.result;\n const paymentWithMetadata = this._mergePaymentMetadata(\n payment,\n metadata\n );\n\n // Fetch lnurl receive metadata if it's a lightning payment\n this._fetchLnurlReceiveMetadata(\n paymentWithMetadata,\n lnurlReceiveMetadataStore\n )\n .then(resolve)\n .catch(() => {\n // Continue without lnurl receive metadata if fetch fails\n resolve(paymentWithMetadata);\n });\n };\n metadataRequest.onerror = () => {\n // Return payment without metadata if metadata fetch fails\n resolve(payment);\n };\n };\n\n paymentRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to get payment by id '${id}': ${paymentRequest.error?.message || \"Unknown error\"\n }`,\n paymentRequest.error\n )\n );\n };\n });\n }\n\n async getPaymentByInvoice(invoice) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n [\"payments\", \"payment_metadata\", \"lnurl_receive_metadata\"],\n \"readonly\"\n );\n const paymentStore = transaction.objectStore(\"payments\");\n const invoiceIndex = paymentStore.index(\"invoice\");\n const metadataStore = transaction.objectStore(\"payment_metadata\");\n const lnurlReceiveMetadataStore = transaction.objectStore(\n \"lnurl_receive_metadata\"\n );\n\n const paymentRequest = invoiceIndex.get(invoice);\n\n paymentRequest.onsuccess = () => {\n const payment = paymentRequest.result;\n if (!payment) {\n resolve(null);\n return;\n }\n\n // Get metadata for this payment\n const metadataRequest = metadataStore.get(payment.id);\n metadataRequest.onsuccess = () => {\n const metadata = metadataRequest.result;\n const paymentWithMetadata = this._mergePaymentMetadata(\n payment,\n metadata\n );\n\n // Fetch lnurl receive metadata if it's a lightning payment\n this._fetchLnurlReceiveMetadata(\n paymentWithMetadata,\n lnurlReceiveMetadataStore\n )\n .then(resolve)\n .catch(() => {\n // Continue without lnurl receive metadata if fetch fails\n resolve(paymentWithMetadata);\n });\n };\n metadataRequest.onerror = () => {\n // Return payment without metadata if metadata fetch fails\n resolve(payment);\n };\n };\n\n paymentRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to get payment by invoice '${invoice}': ${paymentRequest.error?.message || \"Unknown error\"\n }`,\n paymentRequest.error\n )\n );\n };\n });\n }\n\n /**\n * Checks if any related payments exist (payments with a parentPaymentId).\n * Uses the parentPaymentId index for efficient lookup.\n * @param {IDBObjectStore} metadataStore - The payment_metadata object store\n * @returns {Promise<boolean>} True if any related payments exist\n */\n _hasRelatedPayments(metadataStore) {\n return new Promise((resolve) => {\n // Check if the parentPaymentId index exists (added in migration)\n if (!metadataStore.indexNames.contains(\"parentPaymentId\")) {\n // Index doesn't exist yet, fall back to scanning all metadata\n const cursorRequest = metadataStore.openCursor();\n cursorRequest.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor) {\n if (cursor.value.parentPaymentId) {\n resolve(true);\n return;\n }\n cursor.continue();\n } else {\n resolve(false);\n }\n };\n cursorRequest.onerror = () => resolve(true); // Assume there might be related payments on error\n return;\n }\n\n const index = metadataStore.index(\"parentPaymentId\");\n const cursorRequest = index.openCursor();\n\n cursorRequest.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor && cursor.value.parentPaymentId) {\n // Found at least one related payment\n resolve(true);\n } else if (cursor) {\n // Entry with null parentPaymentId, continue searching\n cursor.continue();\n } else {\n // No more entries\n resolve(false);\n }\n };\n\n cursorRequest.onerror = () => {\n // If index lookup fails, assume there might be related payments\n resolve(true);\n };\n });\n }\n\n /**\n * Gets payments that have any of the specified parent payment IDs.\n * @param {string[]} parentPaymentIds - Array of parent payment IDs\n * @returns {Promise<Object>} Map of parentPaymentId -> array of RelatedPayment objects\n */\n async getPaymentsByParentIds(parentPaymentIds) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n if (!parentPaymentIds || parentPaymentIds.length === 0) {\n return {};\n }\n\n const transaction = this.db.transaction(\n [\"payments\", \"payment_metadata\", \"lnurl_receive_metadata\"],\n \"readonly\"\n );\n const metadataStore = transaction.objectStore(\"payment_metadata\");\n\n // Early exit if no related payments exist\n const hasRelated = await this._hasRelatedPayments(metadataStore);\n if (!hasRelated) {\n return {};\n }\n\n const parentIdSet = new Set(parentPaymentIds);\n const paymentStore = transaction.objectStore(\"payments\");\n const lnurlReceiveMetadataStore = transaction.objectStore(\"lnurl_receive_metadata\");\n\n return new Promise((resolve, reject) => {\n const result = {};\n const fetchedMetadata = [];\n\n // Query all metadata records and filter by parentPaymentId\n const cursorRequest = metadataStore.openCursor();\n\n cursorRequest.onsuccess = (event) => {\n const cursor = event.target.result;\n if (!cursor) {\n // All metadata processed, now fetch payment details\n if (fetchedMetadata.length === 0) {\n resolve(result);\n return;\n }\n\n let processed = 0;\n for (const metadata of fetchedMetadata) {\n const parentId = metadata.parentPaymentId;\n const paymentRequest = paymentStore.get(metadata.paymentId);\n paymentRequest.onsuccess = () => {\n const payment = paymentRequest.result;\n if (payment) {\n const paymentWithMetadata = this._mergePaymentMetadata(payment, metadata);\n\n if (!result[parentId]) {\n result[parentId] = [];\n }\n\n // Fetch lnurl receive metadata if applicable\n this._fetchLnurlReceiveMetadata(paymentWithMetadata, lnurlReceiveMetadataStore)\n .then((mergedPayment) => {\n result[parentId].push(mergedPayment);\n })\n .catch(() => {\n result[parentId].push(paymentWithMetadata);\n })\n .finally(() => {\n processed++;\n if (processed === fetchedMetadata.length) {\n // Sort each parent's children by timestamp\n for (const parentId of Object.keys(result)) {\n result[parentId].sort((a, b) => a.timestamp - b.timestamp);\n }\n resolve(result);\n }\n });\n } else {\n processed++;\n if (processed === fetchedMetadata.length) {\n resolve(result);\n }\n }\n };\n paymentRequest.onerror = () => {\n processed++;\n if (processed === fetchedMetadata.length) {\n resolve(result);\n }\n };\n }\n return;\n }\n\n const metadata = cursor.value;\n if (metadata.parentPaymentId && parentIdSet.has(metadata.parentPaymentId)) {\n fetchedMetadata.push(metadata);\n }\n cursor.continue();\n };\n\n cursorRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to get payments by parent ids: ${cursorRequest.error?.message || \"Unknown error\"\n }`,\n cursorRequest.error\n )\n );\n };\n });\n }\n\n async insertPaymentMetadata(paymentId, metadata) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"payment_metadata\", \"readwrite\");\n const store = transaction.objectStore(\"payment_metadata\");\n\n // First get existing record to merge with\n const getRequest = store.get(paymentId);\n getRequest.onsuccess = () => {\n const existing = getRequest.result || {};\n\n // Use COALESCE-like behavior: new value if non-null, otherwise keep existing\n const metadataToStore = {\n paymentId,\n parentPaymentId: metadata.parentPaymentId ?? existing.parentPaymentId ?? null,\n lnurlPayInfo: metadata.lnurlPayInfo\n ? JSON.stringify(metadata.lnurlPayInfo)\n : existing.lnurlPayInfo ?? null,\n lnurlWithdrawInfo: metadata.lnurlWithdrawInfo\n ? JSON.stringify(metadata.lnurlWithdrawInfo)\n : existing.lnurlWithdrawInfo ?? null,\n lnurlDescription: metadata.lnurlDescription ?? existing.lnurlDescription ?? null,\n conversionInfo: metadata.conversionInfo\n ? JSON.stringify(metadata.conversionInfo)\n : existing.conversionInfo ?? null,\n conversionStatus: metadata.conversionStatus ?? existing.conversionStatus ?? null,\n };\n\n const putRequest = store.put(metadataToStore);\n putRequest.onsuccess = () => resolve();\n putRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to set payment metadata for '${paymentId}': ${putRequest.error?.message || \"Unknown error\"\n }`,\n putRequest.error\n )\n );\n };\n };\n getRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to get existing payment metadata for '${paymentId}': ${getRequest.error?.message || \"Unknown error\"\n }`,\n getRequest.error\n )\n );\n };\n });\n }\n\n // ===== Deposit Operations =====\n\n async addDeposit(txid, vout, amountSats, isMature) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n \"unclaimed_deposits\",\n \"readwrite\"\n );\n const store = transaction.objectStore(\"unclaimed_deposits\");\n\n // Get existing deposit first to preserve fields on upsert\n const getRequest = store.get([txid, vout]);\n\n getRequest.onsuccess = () => {\n const existing = getRequest.result;\n const depositToStore = {\n txid,\n vout,\n amountSats,\n isMature: isMature ?? true,\n claimError: existing?.claimError ?? null,\n refundTx: existing?.refundTx ?? null,\n refundTxId: existing?.refundTxId ?? null,\n instantClaimStatus: existing?.instantClaimStatus ?? null,\n refundState: existing?.refundState ?? null,\n maxClaimFee: existing?.maxClaimFee ?? null,\n };\n\n const putRequest = store.put(depositToStore);\n putRequest.onsuccess = () => resolve();\n putRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to add deposit '${txid}:${vout}': ${putRequest.error?.message || \"Unknown error\"\n }`,\n putRequest.error\n )\n );\n };\n };\n\n getRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to add deposit '${txid}:${vout}': ${getRequest.error?.message || \"Unknown error\"\n }`,\n getRequest.error\n )\n );\n };\n });\n }\n\n async deleteDeposit(txid, vout) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n \"unclaimed_deposits\",\n \"readwrite\"\n );\n const store = transaction.objectStore(\"unclaimed_deposits\");\n const request = store.delete([txid, vout]);\n\n request.onsuccess = () => resolve();\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to delete deposit '${txid}:${vout}': ${request.error?.message || \"Unknown error\"\n }`,\n request.error\n )\n );\n };\n });\n }\n\n async listDeposits() {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"unclaimed_deposits\", \"readonly\");\n const store = transaction.objectStore(\"unclaimed_deposits\");\n const request = store.getAll();\n\n request.onsuccess = () => {\n const deposits = request.result.map((row) => ({\n txid: row.txid,\n vout: row.vout,\n amountSats: row.amountSats,\n isMature: row.isMature ?? true,\n claimError: row.claimError ? JSON.parse(row.claimError) : null,\n refundTx: row.refundTx,\n refundTxId: row.refundTxId,\n instantClaimStatus: row.instantClaimStatus\n ? JSON.parse(row.instantClaimStatus)\n : null,\n refundState: row.refundState ? JSON.parse(row.refundState) : null,\n maxClaimFee: row.maxClaimFee ? JSON.parse(row.maxClaimFee) : null,\n }));\n resolve(deposits);\n };\n\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to list deposits: ${request.error?.message || \"Unknown error\"\n }`,\n request.error\n )\n );\n };\n });\n }\n\n async updateDeposit(txid, vout, payload) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n \"unclaimed_deposits\",\n \"readwrite\"\n );\n const store = transaction.objectStore(\"unclaimed_deposits\");\n\n // First get the existing deposit\n const getRequest = store.get([txid, vout]);\n\n getRequest.onsuccess = () => {\n const existingDeposit = getRequest.result;\n if (!existingDeposit) {\n // Deposit doesn't exist, just resolve (matches SQLite behavior)\n resolve();\n return;\n }\n\n let updatedDeposit = { ...existingDeposit };\n\n if (payload.type === \"claimError\") {\n updatedDeposit.claimError = JSON.stringify(payload.error);\n } else if (payload.type === \"refund\") {\n updatedDeposit.refundTx = payload.refundTx;\n updatedDeposit.refundTxId = payload.refundTxid;\n updatedDeposit.refundState = JSON.stringify(payload.state);\n updatedDeposit.claimError = null;\n } else if (payload.type === \"instantClaim\") {\n updatedDeposit.instantClaimStatus = JSON.stringify(payload.status);\n } else if (payload.type === \"refundBroadcastState\") {\n // Only while this is still the stored refund.\n if (existingDeposit.refundTxId === payload.refundTxid) {\n updatedDeposit.refundState = JSON.stringify(payload.state);\n }\n } else if (payload.type === \"maxClaimFee\") {\n updatedDeposit.maxClaimFee = payload.maxFee\n ? JSON.stringify(payload.maxFee)\n : null;\n } else {\n reject(new StorageError(`Unknown payload type: ${payload.type}`));\n return;\n }\n\n const putRequest = store.put(updatedDeposit);\n putRequest.onsuccess = () => resolve();\n putRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to update deposit '${txid}:${vout}': ${putRequest.error?.message || \"Unknown error\"\n }`,\n putRequest.error\n )\n );\n };\n };\n\n getRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to get deposit '${txid}:${vout}' for update: ${getRequest.error?.message || \"Unknown error\"\n }`,\n getRequest.error\n )\n );\n };\n });\n }\n\n async listWatchedDepositAddresses() {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n \"watched_deposit_addresses\",\n \"readonly\"\n );\n const store = transaction.objectStore(\"watched_deposit_addresses\");\n const request = store.getAll();\n\n request.onsuccess = () => {\n const watched = (request.result || []).map((entry) => ({\n address: entry.address,\n issuedAt: entry.issuedAt,\n seen: Boolean(entry.seen),\n }));\n // The store is keyed by address, so ordering is applied here rather\n // than by an index.\n watched.sort((a, b) => Number(b.issuedAt) - Number(a.issuedAt));\n resolve(watched);\n };\n request.onerror = () =>\n reject(\n new StorageError(\n `Failed to list watched deposit addresses: ${request.error}`\n )\n );\n });\n }\n\n async updateWatchedDepositAddress(address, payload) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n \"watched_deposit_addresses\",\n \"readwrite\"\n );\n const store = transaction.objectStore(\"watched_deposit_addresses\");\n\n if (payload.type === \"watch\") {\n const request = store.put({\n address,\n issuedAt: payload.issuedAt,\n seen: false,\n });\n request.onsuccess = () => resolve();\n request.onerror = () =>\n reject(\n new StorageError(\n `Failed to watch deposit address '${address}': ${request.error}`\n )\n );\n return;\n }\n\n if (payload.type === \"unwatch\") {\n // Conditional on issuedAt, so an address handed out again since the\n // caller read it is not retired by a decision taken before that. The\n // get and the delete share one readwrite transaction, so nothing can\n // interleave between them.\n const getRequest = store.get(address);\n getRequest.onsuccess = () => {\n const existing = getRequest.result;\n const stale =\n !existing || String(existing.issuedAt) !== String(payload.issuedAt);\n if (stale) {\n resolve();\n return;\n }\n const request = store.delete(address);\n request.onsuccess = () => resolve();\n request.onerror = () =>\n reject(\n new StorageError(\n `Failed to unwatch deposit address '${address}': ${request.error}`\n )\n );\n };\n getRequest.onerror = () =>\n reject(\n new StorageError(\n `Failed to read watched deposit address '${address}': ${getRequest.error}`\n )\n );\n return;\n }\n\n if (payload.type === \"seen\") {\n const getRequest = store.get(address);\n getRequest.onsuccess = () => {\n const existing = getRequest.result;\n if (!existing) {\n // Not watched, so there is nothing to mark (matches the SQL stores,\n // whose UPDATE affects no rows).\n resolve();\n return;\n }\n const request = store.put({ ...existing, seen: true });\n request.onsuccess = () => resolve();\n request.onerror = () =>\n reject(\n new StorageError(\n `Failed to mark deposit address '${address}' seen: ${request.error}`\n )\n );\n };\n getRequest.onerror = () =>\n reject(\n new StorageError(\n `Failed to read watched deposit address '${address}': ${getRequest.error}`\n )\n );\n return;\n }\n\n reject(new StorageError(`Unknown payload type: ${payload.type}`));\n });\n }\n\n async setLnurlMetadata(metadata) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n \"lnurl_receive_metadata\",\n \"readwrite\"\n );\n const store = transaction.objectStore(\"lnurl_receive_metadata\");\n\n let completed = 0;\n const total = metadata.length;\n\n if (total === 0) {\n resolve();\n return;\n }\n\n for (const item of metadata) {\n const request = store.put({\n paymentHash: item.paymentHash,\n nostrZapRequest: item.nostrZapRequest || null,\n nostrZapReceipt: item.nostrZapReceipt || null,\n senderComment: item.senderComment || null,\n });\n\n request.onsuccess = () => {\n completed++;\n if (completed === total) {\n resolve();\n }\n };\n\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to add lnurl metadata for payment hash '${item.paymentHash\n }': ${request.error?.message || \"Unknown error\"}`,\n request.error\n )\n );\n };\n }\n });\n }\n\n async syncAddOutgoingChange(record) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction([\"sync_outgoing\"], \"readwrite\");\n\n // This revision is a local queue id for pending rows, not a server revision.\n const outgoingStore = transaction.objectStore(\"sync_outgoing\");\n const getAllOutgoingRequest = outgoingStore.getAll();\n\n getAllOutgoingRequest.onsuccess = () => {\n const records = getAllOutgoingRequest.result;\n let maxOutgoingRevision = BigInt(0);\n for (const storeRecord of records) {\n const rev = BigInt(\n storeRecord.record.localRevision ?? storeRecord.record.revision\n );\n if (rev > maxOutgoingRevision) {\n maxOutgoingRevision = rev;\n }\n }\n const nextRevision = maxOutgoingRevision + BigInt(1);\n\n const storeRecord = {\n type: record.id.type,\n dataId: record.id.dataId,\n revision: Number(nextRevision),\n record: {\n ...record,\n localRevision: nextRevision,\n },\n };\n\n const addRequest = outgoingStore.add(storeRecord);\n\n addRequest.onsuccess = () => {\n transaction.oncomplete = () => {\n resolve(nextRevision);\n };\n };\n\n addRequest.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to add outgoing change: ${event.target.error.message}`\n )\n );\n };\n };\n\n getAllOutgoingRequest.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to get outgoing records: ${event.target.error.message}`\n )\n );\n };\n\n transaction.onerror = (event) => {\n reject(\n new StorageError(`Transaction failed: ${event.target.error.message}`)\n );\n };\n });\n }\n\n async syncCompleteOutgoingSync(record, localRevision) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n [\"sync_outgoing\", \"sync_state\", \"sync_revision\"],\n \"readwrite\"\n );\n const outgoingStore = transaction.objectStore(\"sync_outgoing\");\n const stateStore = transaction.objectStore(\"sync_state\");\n const revisionStore = transaction.objectStore(\"sync_revision\");\n\n const deleteRequest = outgoingStore.delete([\n record.id.type,\n record.id.dataId,\n Number(localRevision),\n ]);\n\n deleteRequest.onsuccess = () => {\n const stateRecord = {\n type: record.id.type,\n dataId: record.id.dataId,\n record: record,\n };\n stateStore.put(stateRecord);\n\n // Update sync_revision to track the highest known revision\n const getRevisionRequest = revisionStore.get(1);\n getRevisionRequest.onsuccess = () => {\n const current = getRevisionRequest.result || { id: 1, revision: \"0\" };\n const currentRevision = BigInt(current.revision);\n const recordRevision = BigInt(record.revision);\n if (recordRevision > currentRevision) {\n revisionStore.put({ id: 1, revision: recordRevision.toString() });\n }\n resolve();\n };\n getRevisionRequest.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to update sync revision: ${event.target.error.message}`\n )\n );\n };\n };\n\n deleteRequest.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to complete outgoing sync: ${event.target.error.message}`\n )\n );\n };\n });\n }\n\n async syncGetPendingOutgoingChanges(limit) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n [\"sync_outgoing\", \"sync_state\"],\n \"readonly\"\n );\n const outgoingStore = transaction.objectStore(\"sync_outgoing\");\n const stateStore = transaction.objectStore(\"sync_state\");\n\n // Get pending outgoing changes (all records in this store are pending)\n // Use revision index to order by revision ascending\n const revisionIndex = outgoingStore.index(\"revision\");\n const request = revisionIndex.openCursor(null, \"next\");\n const changes = [];\n let count = 0;\n\n request.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor && count < limit) {\n const storeRecord = cursor.value;\n const change = {\n ...storeRecord.record,\n localRevision:\n storeRecord.record.localRevision ?? storeRecord.record.revision,\n };\n\n // Look up parent record if it exists\n const stateRequest = stateStore.get([\n storeRecord.type,\n storeRecord.dataId,\n ]);\n stateRequest.onsuccess = () => {\n const stateRecord = stateRequest.result;\n const parent = stateRecord ? stateRecord.record : null;\n\n changes.push({\n change: change,\n parent: parent,\n });\n\n count++;\n cursor.continue();\n };\n\n stateRequest.onerror = () => {\n changes.push({\n change: change,\n parent: null,\n });\n\n count++;\n cursor.continue();\n };\n } else {\n resolve(changes);\n }\n };\n\n request.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to get pending outgoing changes: ${event.target.error.message}`\n )\n );\n };\n });\n }\n\n async syncGetLastRevision() {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"sync_revision\", \"readonly\");\n const store = transaction.objectStore(\"sync_revision\");\n const request = store.get(1);\n\n request.onsuccess = () => {\n const result = request.result || { id: 1, revision: \"0\" };\n resolve(BigInt(result.revision));\n };\n\n request.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to get last revision: ${event.target.error.message}`\n )\n );\n };\n });\n }\n\n async syncInsertIncomingRecords(records) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction([\"sync_incoming\"], \"readwrite\");\n const store = transaction.objectStore(\"sync_incoming\");\n\n // Add each record to the incoming store\n let recordsProcessed = 0;\n\n for (const record of records) {\n const storeRecord = {\n type: record.id.type,\n dataId: record.id.dataId,\n revision: Number(record.revision),\n record: record,\n };\n\n const request = store.put(storeRecord);\n\n request.onsuccess = () => {\n recordsProcessed++;\n if (recordsProcessed === records.length) {\n resolve();\n }\n };\n\n request.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to insert incoming record: ${event.target.error.message}`\n )\n );\n };\n }\n\n // If no records were provided\n if (records.length === 0) {\n resolve();\n }\n });\n }\n\n async syncDeleteIncomingRecord(record) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction([\"sync_incoming\"], \"readwrite\");\n const store = transaction.objectStore(\"sync_incoming\");\n\n const key = [record.id.type, record.id.dataId, Number(record.revision)];\n const request = store.delete(key);\n\n request.onsuccess = () => {\n resolve();\n };\n\n request.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to delete incoming record: ${event.target.error.message}`\n )\n );\n };\n });\n }\n\n async syncGetIncomingRecords(limit) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n [\"sync_incoming\", \"sync_state\"],\n \"readonly\"\n );\n const incomingStore = transaction.objectStore(\"sync_incoming\");\n const stateStore = transaction.objectStore(\"sync_state\");\n\n // Get records up to the limit, ordered by revision\n const revisionIndex = incomingStore.index(\"revision\");\n const request = revisionIndex.openCursor(null, \"next\");\n const records = [];\n let count = 0;\n\n request.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor && count < limit) {\n const storeRecord = cursor.value;\n const newState = storeRecord.record;\n\n // Look for parent record\n const stateRequest = stateStore.get([\n storeRecord.type,\n storeRecord.dataId,\n ]);\n\n stateRequest.onsuccess = () => {\n const stateRecord = stateRequest.result;\n const oldState = stateRecord ? stateRecord.record : null;\n\n records.push({\n newState: newState,\n oldState: oldState,\n });\n\n count++;\n cursor.continue();\n };\n\n stateRequest.onerror = () => {\n records.push({\n newState: newState,\n oldState: null,\n });\n\n count++;\n cursor.continue();\n };\n } else {\n resolve(records);\n }\n };\n\n request.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to get incoming records: ${event.target.error.message}`\n )\n );\n };\n });\n }\n\n async syncGetLatestOutgoingChange() {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n [\"sync_outgoing\", \"sync_state\"],\n \"readonly\"\n );\n const outgoingStore = transaction.objectStore(\"sync_outgoing\");\n const stateStore = transaction.objectStore(\"sync_state\");\n\n // Get the highest revision record\n const index = outgoingStore.index(\"revision\");\n const request = index.openCursor(null, \"prev\");\n\n request.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor) {\n const storeRecord = cursor.value;\n const change = {\n ...storeRecord.record,\n localRevision:\n storeRecord.record.localRevision ?? storeRecord.record.revision,\n };\n\n // Get the parent record\n const stateRequest = stateStore.get([\n storeRecord.type,\n storeRecord.dataId,\n ]);\n\n stateRequest.onsuccess = () => {\n const stateRecord = stateRequest.result;\n const parent = stateRecord ? stateRecord.record : null;\n\n resolve({\n change: change,\n parent: parent,\n });\n };\n\n stateRequest.onerror = () => {\n resolve({\n change: change,\n parent: null,\n });\n };\n } else {\n // No records found\n resolve(null);\n }\n };\n\n request.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to get latest outgoing change: ${event.target.error.message}`\n )\n );\n };\n });\n }\n\n async syncUpdateRecordFromIncoming(record) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction([\"sync_state\", \"sync_revision\"], \"readwrite\");\n const stateStore = transaction.objectStore(\"sync_state\");\n const revisionStore = transaction.objectStore(\"sync_revision\");\n\n const storeRecord = {\n type: record.id.type,\n dataId: record.id.dataId,\n record: record,\n };\n\n const request = stateStore.put(storeRecord);\n\n request.onsuccess = () => {\n // Update sync_revision to track the highest known revision\n const getRevisionRequest = revisionStore.get(1);\n getRevisionRequest.onsuccess = () => {\n const current = getRevisionRequest.result || { id: 1, revision: \"0\" };\n const currentRevision = BigInt(current.revision);\n const incomingRevision = BigInt(record.revision);\n if (incomingRevision > currentRevision) {\n revisionStore.put({ id: 1, revision: incomingRevision.toString() });\n }\n resolve();\n };\n getRevisionRequest.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to update sync revision: ${event.target.error.message}`\n )\n );\n };\n };\n\n request.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to update record from incoming: ${event.target.error.message}`\n )\n );\n };\n });\n }\n\n // ===== Contact Operations =====\n\n async listContacts(request) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n const actualOffset = request.offset !== null && request.offset !== undefined ? request.offset : 0;\n const actualLimit = request.limit !== null && request.limit !== undefined ? request.limit : 4294967295;\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"contacts\", \"readonly\");\n const store = transaction.objectStore(\"contacts\");\n const nameIndex = store.index(\"name\");\n\n const contacts = [];\n let count = 0;\n let skipped = 0;\n\n const cursorRequest = nameIndex.openCursor();\n\n cursorRequest.onsuccess = (event) => {\n const cursor = event.target.result;\n\n if (!cursor || count >= actualLimit) {\n resolve(contacts);\n return;\n }\n\n if (skipped < actualOffset) {\n skipped++;\n cursor.continue();\n return;\n }\n\n contacts.push(cursor.value);\n count++;\n cursor.continue();\n };\n\n cursorRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to list contacts: ${cursorRequest.error?.message || \"Unknown error\"}`,\n cursorRequest.error\n )\n );\n };\n });\n }\n\n async getContact(id) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"contacts\", \"readonly\");\n const store = transaction.objectStore(\"contacts\");\n const request = store.get(id);\n\n request.onsuccess = () => {\n resolve(request.result || null);\n };\n\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to get contact '${id}': ${request.error?.message || \"Unknown error\"}`,\n request.error\n )\n );\n };\n });\n }\n\n async insertContact(contact) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"contacts\", \"readwrite\");\n const store = transaction.objectStore(\"contacts\");\n\n // Preserve created_at from existing record on update\n const getRequest = store.get(contact.id);\n getRequest.onsuccess = () => {\n const existingById = getRequest.result;\n const toStore = existingById\n ? { ...contact, createdAt: existingById.createdAt }\n : contact;\n\n const putRequest = store.put(toStore);\n putRequest.onsuccess = () => resolve();\n putRequest.onerror = () => {\n reject(\n new StorageError(\n `Inserting contact failed: ${putRequest.error?.name || \"Unknown error\"} - ${putRequest.error?.message || \"\"}`,\n putRequest.error\n )\n );\n };\n };\n getRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to check existing contact: ${getRequest.error?.message || \"Unknown error\"}`,\n getRequest.error\n )\n );\n };\n });\n }\n\n async deleteContact(id) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"contacts\", \"readwrite\");\n const store = transaction.objectStore(\"contacts\");\n const request = store.delete(id);\n\n request.onsuccess = () => resolve();\n\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to delete contact '${id}': ${request.error?.message || \"Unknown error\"}`,\n request.error\n )\n );\n };\n });\n }\n\n // ===== Cross-Chain Swap Operations =====\n\n async setCrossChainSwap(swap) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"cross_chain_swaps\", \"readwrite\");\n const store = transaction.objectStore(\"cross_chain_swaps\");\n // IndexedDB stores nested objects natively, so `data` is kept as-is.\n const request = store.put(swap);\n request.onsuccess = () => resolve();\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to set cross-chain swap '${swap.provider}:${swap.id}': ${request.error?.message || \"Unknown error\"}`,\n request.error\n )\n );\n };\n });\n }\n\n async getCrossChainSwap(provider, id) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"cross_chain_swaps\", \"readonly\");\n const store = transaction.objectStore(\"cross_chain_swaps\");\n const request = store.get([provider, id]);\n request.onsuccess = () => resolve(request.result || null);\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to get cross-chain swap '${provider}:${id}': ${request.error?.message || \"Unknown error\"}`,\n request.error\n )\n );\n };\n });\n }\n\n async listActiveCrossChainSwaps(provider) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"cross_chain_swaps\", \"readonly\");\n const store = transaction.objectStore(\"cross_chain_swaps\");\n const request = store.getAll();\n request.onsuccess = () => {\n const all = request.result || [];\n resolve(\n all.filter((swap) => swap.provider === provider && !swap.isTerminal)\n );\n };\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to list active cross-chain swaps for '${provider}': ${request.error?.message || \"Unknown error\"}`,\n request.error\n )\n );\n };\n });\n }\n\n // ===== Private Helper Methods =====\n\n _paymentToStore(payment) {\n // Ensure details and method are serialized properly\n return {\n ...payment,\n details: payment.details ? JSON.stringify(payment.details) : null,\n method: payment.method ? JSON.stringify(payment.method) : null,\n };\n }\n\n _normalizePaymentStatus(status) {\n return typeof status === \"string\" ? status.toLowerCase() : status;\n }\n\n _isFinalPaymentStatus(status) {\n const normalized = this._normalizePaymentStatus(status);\n return normalized === \"completed\" || normalized === \"failed\";\n }\n\n\n _matchesFilters(payment, request) {\n // Filter by payment type\n if (request.typeFilter && request.typeFilter.length > 0) {\n if (!request.typeFilter.includes(payment.paymentType)) {\n return false;\n }\n }\n\n // Filter by status\n if (request.statusFilter && request.statusFilter.length > 0) {\n if (!request.statusFilter.includes(payment.status)) {\n return false;\n }\n }\n\n // Filter by timestamp range\n if (request.fromTimestamp !== null && request.fromTimestamp !== undefined) {\n if (payment.timestamp < request.fromTimestamp) {\n return false;\n }\n }\n\n if (request.toTimestamp !== null && request.toTimestamp !== undefined) {\n if (payment.timestamp >= request.toTimestamp) {\n return false;\n }\n }\n\n // Filter by payment details\n if (\n request.paymentDetailsFilter &&\n request.paymentDetailsFilter.length > 0\n ) {\n let details = null;\n\n // Parse details if it's a string (stored in IndexedDB)\n if (payment.details && typeof payment.details === \"string\") {\n try {\n details = JSON.parse(payment.details);\n } catch (e) {\n // If parsing fails, treat as no details\n details = null;\n }\n } else {\n details = payment.details;\n }\n\n if (!details) {\n return false;\n }\n\n // Filter by payment details. If any filter matches, we include the payment\n let paymentDetailsFilterMatches = false;\n for (const paymentDetailsFilter of request.paymentDetailsFilter) {\n // Base type check: the payment's details type must match the filter type\n if (details.type !== paymentDetailsFilter.type) {\n continue;\n }\n // Filter by HTLC status (Spark or Lightning)\n if (\n (paymentDetailsFilter.type === \"spark\" ||\n paymentDetailsFilter.type === \"lightning\") &&\n paymentDetailsFilter.htlcStatus != null &&\n paymentDetailsFilter.htlcStatus.length > 0\n ) {\n if (\n details.type !== paymentDetailsFilter.type ||\n !details.htlcDetails ||\n !paymentDetailsFilter.htlcStatus.includes(\n details.htlcDetails.status\n )\n ) {\n continue;\n }\n }\n // Filter by conversion type + status\n if (\n (paymentDetailsFilter.type === \"spark\" ||\n paymentDetailsFilter.type === \"token\" ||\n paymentDetailsFilter.type === \"lightning\") &&\n paymentDetailsFilter.conversionFilter != null\n ) {\n if (\n details.type !== paymentDetailsFilter.type ||\n !details.conversionInfo\n ) {\n continue;\n }\n\n const ci = details.conversionInfo;\n if (paymentDetailsFilter.conversionFilter === \"ammRefundNeeded\") {\n if (ci.type !== \"amm\" || ci.status !== \"refundNeeded\") {\n continue;\n }\n } else if (paymentDetailsFilter.conversionFilter === \"orchestraPending\") {\n if (ci.type !== \"orchestra\" || [\"completed\", \"failed\", \"refunded\"].includes(ci.status)) {\n continue;\n }\n } else if (paymentDetailsFilter.conversionFilter === \"boltzPending\") {\n // Boltz conversion lives on the Lightning leg.\n if (ci.type !== \"boltz\" || [\"completed\", \"failed\", \"refunded\"].includes(ci.status)) {\n continue;\n }\n }\n }\n // Filter by token transaction hash\n if (\n paymentDetailsFilter.type === \"token\" &&\n paymentDetailsFilter.txHash != null\n ) {\n if (\n details.type !== \"token\" ||\n details.txHash !== paymentDetailsFilter.txHash\n ) {\n continue;\n }\n }\n // Filter by token transaction type\n if (\n paymentDetailsFilter.type === \"token\" &&\n paymentDetailsFilter.txType != null\n ) {\n if (\n details.type !== \"token\" ||\n details.txType !== paymentDetailsFilter.txType\n ) {\n continue;\n }\n }\n\n\n paymentDetailsFilterMatches = true;\n break;\n }\n\n if (!paymentDetailsFilterMatches) {\n return false;\n }\n }\n\n // Filter by payment details/method\n if (request.assetFilter) {\n const assetFilter = request.assetFilter;\n let details = null;\n\n // Parse details if it's a string (stored in IndexedDB)\n if (payment.details && typeof payment.details === \"string\") {\n try {\n details = JSON.parse(payment.details);\n } catch (e) {\n // If parsing fails, treat as no details\n details = null;\n }\n } else {\n details = payment.details;\n }\n\n if (!details) {\n return false;\n }\n\n if (assetFilter.type === \"bitcoin\" && details.type === \"token\") {\n return false;\n }\n\n if (assetFilter.type === \"token\") {\n if (details.type !== \"token\") {\n return false;\n }\n\n // Check token identifier if specified\n if (assetFilter.tokenIdentifier) {\n if (\n !details.metadata ||\n details.metadata.identifier !== assetFilter.tokenIdentifier\n ) {\n return false;\n }\n }\n }\n }\n\n return true;\n }\n\n _mergePaymentMetadata(payment, metadata) {\n let details = null;\n if (payment.details) {\n try {\n details = JSON.parse(payment.details);\n } catch (e) {\n throw new StorageError(\n `Failed to parse payment details JSON for payment ${payment.id}: ${e.message}`,\n e\n );\n }\n }\n\n let method = null;\n if (payment.method) {\n try {\n method = JSON.parse(payment.method);\n } catch (e) {\n throw new StorageError(\n `Failed to parse payment method JSON for payment ${payment.id}: ${e.message}`,\n e\n );\n }\n }\n\n if (details && details.type === \"lightning\" && !details.htlcDetails) {\n throw new StorageError(\n `htlc_details is required for Lightning payment ${payment.id}`\n );\n }\n\n if (metadata && details) {\n if (details.type == \"lightning\") {\n if (metadata.lnurlDescription && !details.description) {\n details.description = metadata.lnurlDescription;\n }\n // If lnurlPayInfo exists, parse and add to details\n if (metadata.lnurlPayInfo) {\n try {\n details.lnurlPayInfo = JSON.parse(metadata.lnurlPayInfo);\n } catch (e) {\n throw new StorageError(\n `Failed to parse lnurlPayInfo JSON for payment ${payment.id}: ${e.message}`,\n e\n );\n }\n }\n // If lnurlWithdrawInfo exists, parse and add to details\n if (metadata.lnurlWithdrawInfo) {\n try {\n details.lnurlWithdrawInfo = JSON.parse(metadata.lnurlWithdrawInfo);\n } catch (e) {\n throw new StorageError(\n `Failed to parse lnurlWithdrawInfo JSON for payment ${payment.id}: ${e.message}`,\n e\n );\n }\n }\n }\n\n // conversionInfo is surfaced on Lightning (Boltz hold-invoice pay),\n // Spark, and Token details — every variant that can carry a conversion.\n if (\n (details.type == \"lightning\" ||\n details.type == \"spark\" ||\n details.type == \"token\") &&\n metadata.conversionInfo\n ) {\n try {\n details.conversionInfo = JSON.parse(metadata.conversionInfo);\n } catch (e) {\n throw new StorageError(\n `Failed to parse conversionInfo JSON for payment ${payment.id}: ${e.message}`,\n e\n );\n }\n }\n }\n\n return {\n id: payment.id,\n paymentType: payment.paymentType,\n status: payment.status,\n amount: payment.amount,\n fees: payment.fees,\n timestamp: payment.timestamp,\n method,\n details,\n conversionDetails: metadata?.conversionStatus\n ? { status: metadata.conversionStatus, from: null, to: null }\n : null,\n };\n }\n\n _fetchLnurlReceiveMetadata(payment, lnurlReceiveMetadataStore) {\n // Only fetch for lightning payments with a payment hash\n if (\n !payment.details ||\n payment.details.type !== \"lightning\" ||\n !payment.details.htlcDetails?.paymentHash\n ) {\n return Promise.resolve(payment);\n }\n\n if (!lnurlReceiveMetadataStore) {\n return Promise.resolve(payment);\n }\n\n return new Promise((resolve, reject) => {\n const lnurlReceiveRequest = lnurlReceiveMetadataStore.get(\n payment.details.htlcDetails.paymentHash\n );\n\n lnurlReceiveRequest.onsuccess = () => {\n const lnurlReceiveMetadata = lnurlReceiveRequest.result;\n if (lnurlReceiveMetadata) {\n payment.details.lnurlReceiveMetadata = {\n nostrZapRequest: lnurlReceiveMetadata.nostrZapRequest || null,\n nostrZapReceipt: lnurlReceiveMetadata.nostrZapReceipt || null,\n senderComment: lnurlReceiveMetadata.senderComment || null,\n };\n }\n resolve(payment);\n };\n\n lnurlReceiveRequest.onerror = () => {\n // Continue without lnurlReceiveMetadata if fetch fails\n reject(new Error(\"Failed to fetch lnurl receive metadata\"));\n };\n });\n }\n}\n\nexport async function createDefaultStorage(\n dbName = \"BreezSdkSpark\",\n logger = null\n) {\n const storage = new IndexedDBStorage(dbName, logger);\n await storage.initialize();\n return storage;\n}\n\nexport { IndexedDBStorage, MigrationManager, StorageError };\n"],"x_google_ignoreList":[0],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"storage-Bya5b2Xt.js","names":[],"sources":["../../../../node_modules/@breeztech/breez-sdk-spark/web/storage/index.js"],"sourcesContent":["/**\n * ES6 module for Web IndexedDB Storage Implementation\n * This provides an ES6 interface to IndexedDB storage for web browsers\n */\n\nclass MigrationManager {\n constructor(db, StorageError, logger = null) {\n this.db = db;\n this.StorageError = StorageError;\n this.logger = logger;\n this.migrations = this._getMigrations();\n }\n\n /**\n * Handle IndexedDB upgrade event - called during database opening\n */\n handleUpgrade(event, oldVersion, newVersion) {\n const db = event.target.result;\n const transaction = event.target.transaction;\n\n this._log(\n \"info\",\n `Upgrading IndexedDB from version ${oldVersion} to ${newVersion}`\n );\n\n try {\n for (let i = oldVersion; i < newVersion; i++) {\n const migration = this.migrations[i];\n if (migration) {\n this._log(\"debug\", `Running migration ${i + 1}: ${migration.name}`);\n migration.upgrade(db, transaction);\n }\n }\n this._log(\"info\", `Database migration completed successfully`);\n } catch (error) {\n this._log(\n \"error\",\n `Migration failed at version ${oldVersion}: ${error.message}`\n );\n throw new this.StorageError(\n `Migration failed at version ${oldVersion}: ${error.message}`,\n error\n );\n }\n }\n\n _log(level, message) {\n if (this.logger && typeof this.logger.log === \"function\") {\n this.logger.log({\n line: message,\n level: level,\n });\n } else if (level === \"error\") {\n console.error(`[MigrationManager] ${message}`);\n }\n }\n\n /**\n * Define all database migrations for IndexedDB\n *\n * Each migration is an object with:\n * - name: Description of the migration\n * - upgrade: Function that takes (db, transaction) and creates/modifies object stores\n */\n _getMigrations() {\n return [\n {\n name: \"Create initial object stores\",\n upgrade: (db) => {\n // Settings store (key-value cache)\n if (!db.objectStoreNames.contains(\"settings\")) {\n db.createObjectStore(\"settings\", { keyPath: \"key\" });\n }\n\n // Payments store\n if (!db.objectStoreNames.contains(\"payments\")) {\n const paymentStore = db.createObjectStore(\"payments\", {\n keyPath: \"id\",\n });\n paymentStore.createIndex(\"timestamp\", \"timestamp\", {\n unique: false,\n });\n paymentStore.createIndex(\"paymentType\", \"paymentType\", {\n unique: false,\n });\n paymentStore.createIndex(\"status\", \"status\", { unique: false });\n }\n\n // Payment metadata store\n if (!db.objectStoreNames.contains(\"payment_metadata\")) {\n db.createObjectStore(\"payment_metadata\", { keyPath: \"paymentId\" });\n }\n\n // Unclaimed deposits store\n if (!db.objectStoreNames.contains(\"unclaimed_deposits\")) {\n const depositStore = db.createObjectStore(\"unclaimed_deposits\", {\n keyPath: [\"txid\", \"vout\"],\n });\n depositStore.createIndex(\"txid\", \"txid\", { unique: false });\n }\n },\n },\n {\n name: \"Create invoice index\",\n upgrade: (db, transaction) => {\n const paymentStore = transaction.objectStore(\"payments\");\n if (!paymentStore.indexNames.contains(\"invoice\")) {\n paymentStore.createIndex(\"invoice\", \"details.invoice\", {\n unique: false,\n });\n }\n },\n },\n {\n name: \"Convert amount and fees from Number to BigInt for u128 support\",\n upgrade: (db, transaction) => {\n const store = transaction.objectStore(\"payments\");\n const getAllRequest = store.getAll();\n\n getAllRequest.onsuccess = () => {\n const payments = getAllRequest.result;\n let updated = 0;\n\n payments.forEach((payment) => {\n // Convert amount and fees from Number to BigInt if they're numbers\n let needsUpdate = false;\n\n if (typeof payment.amount === \"number\") {\n payment.amount = BigInt(Math.round(payment.amount));\n needsUpdate = true;\n }\n\n if (typeof payment.fees === \"number\") {\n payment.fees = BigInt(Math.round(payment.fees));\n needsUpdate = true;\n }\n\n if (needsUpdate) {\n store.put(payment);\n updated++;\n }\n });\n\n console.log(`Migrated ${updated} payment records to BigInt format`);\n };\n },\n },\n {\n name: \"Add sync tables\",\n upgrade: (db, transaction) => {\n // sync_revision: tracks the last committed revision (from server-acknowledged\n // or server-received records). Does NOT include pending outgoing revisions.\n if (!db.objectStoreNames.contains(\"sync_revision\")) {\n const syncRevisionStore = db.createObjectStore(\"sync_revision\", {\n keyPath: \"id\",\n });\n transaction\n .objectStore(\"sync_revision\")\n .add({ id: 1, revision: \"0\" });\n }\n\n if (!db.objectStoreNames.contains(\"sync_outgoing\")) {\n db.createObjectStore(\"sync_outgoing\", {\n keyPath: [\"type\", \"dataId\", \"revision\"],\n });\n transaction\n .objectStore(\"sync_outgoing\")\n .createIndex(\"revision\", \"revision\");\n }\n\n if (!db.objectStoreNames.contains(\"sync_incoming\")) {\n db.createObjectStore(\"sync_incoming\", {\n keyPath: [\"type\", \"dataId\", \"revision\"],\n });\n transaction\n .objectStore(\"sync_incoming\")\n .createIndex(\"revision\", \"revision\");\n }\n\n if (!db.objectStoreNames.contains(\"sync_state\")) {\n db.createObjectStore(\"sync_state\", { keyPath: [\"type\", \"dataId\"] });\n }\n },\n },\n {\n name: \"Create lnurl_receive_metadata store\",\n upgrade: (db) => {\n if (!db.objectStoreNames.contains(\"lnurl_receive_metadata\")) {\n db.createObjectStore(\"lnurl_receive_metadata\", {\n keyPath: \"paymentHash\",\n });\n }\n },\n },\n {\n // Delete all unclaimed deposits to clear old claim_error JSON format.\n // Deposits will be recovered on next sync.\n name: \"Clear unclaimed deposits for claim_error format change\",\n upgrade: (db, transaction) => {\n if (db.objectStoreNames.contains(\"unclaimed_deposits\")) {\n const store = transaction.objectStore(\"unclaimed_deposits\");\n store.clear();\n }\n },\n },\n {\n name: \"Clear sync tables for BreezSigner backward compatibility\",\n upgrade: (db, transaction) => {\n // Clear all sync tables due to BreezSigner signature change.\n // This forces users to sync from scratch to the sync server.\n // Also delete the sync_initial_complete flag to force re-populating\n // all payment metadata for outgoing sync using the new key.\n\n // Clear sync tables (only if they exist)\n if (db.objectStoreNames.contains(\"sync_outgoing\")) {\n const syncOutgoing = transaction.objectStore(\"sync_outgoing\");\n syncOutgoing.clear();\n }\n\n if (db.objectStoreNames.contains(\"sync_incoming\")) {\n const syncIncoming = transaction.objectStore(\"sync_incoming\");\n syncIncoming.clear();\n }\n\n if (db.objectStoreNames.contains(\"sync_state\")) {\n const syncState = transaction.objectStore(\"sync_state\");\n syncState.clear();\n }\n\n // Reset revision to 0 (only if store exists)\n if (db.objectStoreNames.contains(\"sync_revision\")) {\n const syncRevision = transaction.objectStore(\"sync_revision\");\n syncRevision.clear();\n syncRevision.put({ id: 1, revision: \"0\" });\n }\n\n // Delete sync_initial_complete setting (only if store exists)\n if (db.objectStoreNames.contains(\"settings\")) {\n const settings = transaction.objectStore(\"settings\");\n settings.delete(\"sync_initial_complete\");\n }\n }\n },\n {\n name: \"Create parentPaymentId index for related payments lookup\",\n upgrade: (db, transaction) => {\n if (db.objectStoreNames.contains(\"payment_metadata\")) {\n const metadataStore = transaction.objectStore(\"payment_metadata\");\n if (!metadataStore.indexNames.contains(\"parentPaymentId\")) {\n metadataStore.createIndex(\"parentPaymentId\", \"parentPaymentId\", { unique: false });\n }\n }\n }\n },\n {\n name: \"Add tx_type to token payments and trigger token re-sync\",\n upgrade: (db, transaction) => {\n // Update all existing token payments to have a default txType\n if (db.objectStoreNames.contains(\"payments\")) {\n const paymentStore = transaction.objectStore(\"payments\");\n const getAllRequest = paymentStore.getAll();\n\n getAllRequest.onsuccess = () => {\n const payments = getAllRequest.result;\n\n payments.forEach((payment) => {\n // Parse details if it's a string\n let details = null;\n if (payment.details && typeof payment.details === \"string\") {\n try {\n details = JSON.parse(payment.details);\n } catch (e) {\n return; // Skip this payment if parsing fails\n }\n } else {\n details = payment.details;\n }\n\n // Add default txType to token payments\n if (details && details.type === \"token\" && !details.txType) {\n details.txType = \"transfer\";\n payment.details = JSON.stringify(details);\n paymentStore.put(payment);\n }\n });\n };\n }\n\n // Reset sync cache to trigger token re-sync\n if (db.objectStoreNames.contains(\"settings\")) {\n const settingsStore = transaction.objectStore(\"settings\");\n const getRequest = settingsStore.get(\"sync_offset\");\n\n getRequest.onsuccess = () => {\n const syncCache = getRequest.result;\n if (syncCache && syncCache.value) {\n try {\n const syncInfo = JSON.parse(syncCache.value);\n // Reset only the token sync position, keep the bitcoin offset\n syncInfo.last_synced_final_token_payment_id = null;\n settingsStore.put({\n key: \"sync_offset\",\n value: JSON.stringify(syncInfo),\n });\n } catch (e) {\n // If parsing fails, just continue\n }\n }\n };\n }\n },\n },\n {\n name: \"Clear sync tables to force re-sync\",\n upgrade: (db, transaction) => {\n if (db.objectStoreNames.contains(\"sync_outgoing\")) {\n transaction.objectStore(\"sync_outgoing\").clear();\n }\n if (db.objectStoreNames.contains(\"sync_incoming\")) {\n transaction.objectStore(\"sync_incoming\").clear();\n }\n if (db.objectStoreNames.contains(\"sync_state\")) {\n transaction.objectStore(\"sync_state\").clear();\n }\n if (db.objectStoreNames.contains(\"sync_revision\")) {\n const syncRevision = transaction.objectStore(\"sync_revision\");\n syncRevision.clear();\n syncRevision.put({ id: 1, revision: \"0\" });\n }\n if (db.objectStoreNames.contains(\"settings\")) {\n transaction.objectStore(\"settings\").delete(\"sync_initial_complete\");\n }\n },\n },\n {\n name: \"Add preimage to lnurl_receive_metadata for LUD-21 and NIP-57\",\n upgrade: (db, transaction) => {\n // IndexedDB doesn't need schema changes for new fields on existing stores.\n // Just clear the lnurl_metadata_updated_after setting to force re-sync.\n if (db.objectStoreNames.contains(\"settings\")) {\n const settings = transaction.objectStore(\"settings\");\n settings.delete(\"lnurl_metadata_updated_after\");\n }\n }\n },\n {\n name: \"Backfill htlc_details for existing Lightning payments\",\n upgrade: (db, transaction) => {\n if (db.objectStoreNames.contains(\"payments\")) {\n const paymentStore = transaction.objectStore(\"payments\");\n const getAllRequest = paymentStore.getAll();\n\n getAllRequest.onsuccess = () => {\n const payments = getAllRequest.result;\n payments.forEach((payment) => {\n let details;\n if (typeof payment.details === \"string\") {\n try {\n details = JSON.parse(payment.details);\n } catch (e) {\n return;\n }\n } else {\n details = payment.details;\n }\n\n if (details && details.type === \"lightning\" && !details.htlcDetails) {\n let htlcStatus;\n if (payment.status === \"completed\") {\n htlcStatus = \"preimageShared\";\n } else if (payment.status === \"pending\") {\n htlcStatus = \"waitingForPreimage\";\n } else {\n htlcStatus = \"returned\";\n }\n details.htlcDetails = {\n paymentHash: details.paymentHash,\n preimage: details.preimage || null,\n expiryTime: 0,\n status: htlcStatus,\n };\n payment.details = JSON.stringify(details);\n paymentStore.put(payment);\n }\n });\n };\n }\n\n // Reset sync offset to trigger resync\n if (db.objectStoreNames.contains(\"settings\")) {\n const settingsStore = transaction.objectStore(\"settings\");\n const getRequest = settingsStore.get(\"sync_offset\");\n\n getRequest.onsuccess = () => {\n const syncCache = getRequest.result;\n if (syncCache && syncCache.value) {\n try {\n const syncInfo = JSON.parse(syncCache.value);\n syncInfo.offset = 0;\n settingsStore.put({\n key: \"sync_offset\",\n value: JSON.stringify(syncInfo),\n });\n } catch (e) {\n // If parsing fails, just continue\n }\n }\n };\n }\n },\n },\n {\n name: \"Create contacts store\",\n upgrade: (db) => {\n if (!db.objectStoreNames.contains(\"contacts\")) {\n const contactsStore = db.createObjectStore(\"contacts\", { keyPath: \"id\" });\n contactsStore.createIndex(\"name_identifier\", [\"name\", \"paymentIdentifier\"], { unique: false });\n contactsStore.createIndex(\"name\", \"name\", { unique: false });\n }\n }\n },\n {\n name: \"Clear cached lightning address for LnurlInfo schema change\",\n upgrade: (db, transaction) => {\n if (db.objectStoreNames.contains(\"settings\")) {\n const settings = transaction.objectStore(\"settings\");\n settings.delete(\"lightning_address\");\n }\n }\n },\n {\n name: \"Drop preimage from lnurl_receive_metadata records\",\n upgrade: (db, transaction) => {\n if (db.objectStoreNames.contains(\"lnurl_receive_metadata\")) {\n const store = transaction.objectStore(\"lnurl_receive_metadata\");\n const request = store.openCursor();\n request.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor) {\n const record = cursor.value;\n if (\"preimage\" in record) {\n delete record.preimage;\n cursor.update(record);\n }\n cursor.continue();\n }\n };\n }\n }\n },\n {\n name: \"Clear cached lightning address for CachedLightningAddress format change\",\n upgrade: (db, transaction) => {\n if (db.objectStoreNames.contains(\"settings\")) {\n const settings = transaction.objectStore(\"settings\");\n settings.delete(\"lightning_address\");\n }\n }\n },\n {\n // Recovery migration for the missing \"contacts\" object store.\n //\n // The original \"Create contacts store\" migration above was INSERTED into\n // the middle of this array (at index 12) instead of being appended, in\n // SDK 0.11.0. That index was already occupied by the \"Clear cached\n // lightning address for LnurlInfo schema change\" migration, which had\n // shipped one release earlier in SDK 0.10.0 (dbVersion 13).\n //\n // Migration array indices map 1:1 to DB version transitions, so any\n // database that ran 0.10.0 reached version 13 and, on upgrading to\n // 0.11.0+ (dbVersion 14), ran only migrations[13] — permanently skipping\n // the newly-inserted migrations[12]. Those databases never got a\n // \"contacts\" object store, so every contact operation fails with\n // NotFoundError.\n //\n // This migration is correctly appended and idempotently (re)creates the\n // store, so affected databases recover on their next upgrade while\n // unaffected databases treat it as a no-op. Keep the original migration\n // in place; do not delete or reorder it.\n name: \"Create contacts store (recovery for skipped migration)\",\n upgrade: (db) => {\n if (!db.objectStoreNames.contains(\"contacts\")) {\n const contactsStore = db.createObjectStore(\"contacts\", { keyPath: \"id\" });\n contactsStore.createIndex(\"name_identifier\", [\"name\", \"paymentIdentifier\"], { unique: false });\n contactsStore.createIndex(\"name\", \"name\", { unique: false });\n }\n }\n },\n {\n // Add deposit_vout to distinguish deposits sharing a funding tx. The\n // new field is carried inside the JSON `details` blob. We can't safely\n // backfill vout on the existing blobs: we never stored the original SSP\n // output_index, and vout=0 is a valid output index, so defaulting would\n // silently mislabel. Instead we clear `details` on legacy deposit blobs\n // so the read path returns `details: None` (matches what the SQL\n // backends do by leaving the payments row but having no matching\n // payment_details_deposit row). Reset the bitcoin sync offset so the\n // resync re-fetches the SSP user_request and the upsert rewrites the\n // blob with the proper vout.\n name: \"Clear legacy deposit details and reset sync offset for vout\",\n upgrade: (db, transaction) => {\n if (db.objectStoreNames.contains(\"payments\")) {\n const paymentStore = transaction.objectStore(\"payments\");\n const cursorRequest = paymentStore.openCursor();\n cursorRequest.onsuccess = (event) => {\n const cursor = event.target.result;\n if (!cursor) return;\n const payment = cursor.value;\n let details = null;\n if (payment.details && typeof payment.details === \"string\") {\n try {\n details = JSON.parse(payment.details);\n } catch (e) {\n details = null;\n }\n } else {\n details = payment.details;\n }\n if (details && details.type === \"deposit\") {\n payment.details = null;\n cursor.update(payment);\n }\n cursor.continue();\n };\n }\n if (db.objectStoreNames.contains(\"settings\")) {\n const settingsStore = transaction.objectStore(\"settings\");\n const getRequest = settingsStore.get(\"sync_offset\");\n\n getRequest.onsuccess = () => {\n const syncCache = getRequest.result;\n if (syncCache && syncCache.value) {\n try {\n const syncInfo = JSON.parse(syncCache.value);\n syncInfo.offset = 0;\n settingsStore.put({\n key: \"sync_offset\",\n value: JSON.stringify(syncInfo),\n });\n } catch (e) {\n // If parsing fails, just continue\n }\n }\n };\n }\n },\n },\n {\n name: \"Backfill conversion_info type discriminator for serde tagged enum\",\n upgrade: (db, transaction) => {\n if (db.objectStoreNames.contains(\"payment_metadata\")) {\n const store = transaction.objectStore(\"payment_metadata\");\n const request = store.openCursor();\n request.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor) {\n const record = cursor.value;\n if (record.conversionInfo) {\n try {\n const ci = typeof record.conversionInfo === \"string\"\n ? JSON.parse(record.conversionInfo)\n : record.conversionInfo;\n if (!ci.type) {\n ci.type = \"amm\";\n record.conversionInfo = JSON.stringify(ci);\n cursor.update(record);\n }\n } catch (e) {\n // Skip unparseable records\n }\n }\n cursor.continue();\n }\n };\n }\n },\n },\n {\n // listActiveCrossChainSwaps scans and filters.\n name: \"Create cross_chain_swaps store\",\n upgrade: (db) => {\n if (!db.objectStoreNames.contains(\"cross_chain_swaps\")) {\n db.createObjectStore(\"cross_chain_swaps\", {\n keyPath: [\"provider\", \"id\"],\n });\n }\n },\n },\n {\n // Only the Declined shape changed, and clearing it costs at most one extra\n // quote. Submitted entries are left alone: their shape is unchanged and\n // they are the only guard against re-claiming a UTXO whose earlier claim\n // is still settling.\n name: \"Clear declined instant claim status after its shape changed\",\n upgrade: (db, transaction) => {\n if (!db.objectStoreNames.contains(\"unclaimed_deposits\")) return;\n const store = transaction.objectStore(\"unclaimed_deposits\");\n const cursorRequest = store.openCursor();\n cursorRequest.onsuccess = (event) => {\n const cursor = event.target.result;\n if (!cursor) return;\n const deposit = cursor.value;\n if (\n deposit.instantClaimStatus &&\n String(deposit.instantClaimStatus).toLowerCase().includes(\"declined\")\n ) {\n deposit.instantClaimStatus = null;\n cursor.update(deposit);\n }\n cursor.continue();\n };\n },\n },\n {\n // Deposit addresses polled on-chain for deposits still in the mempool.\n // Entries are removed once watching them can no longer lead to an early\n // claim, so the store holds only the live watch set.\n name: \"Create watched_deposit_addresses store\",\n upgrade: (db) => {\n if (!db.objectStoreNames.contains(\"watched_deposit_addresses\")) {\n db.createObjectStore(\"watched_deposit_addresses\", {\n keyPath: \"address\",\n });\n }\n },\n },\n ];\n }\n}\n\nclass StorageError extends Error {\n constructor(message, cause = null) {\n super(message);\n this.name = \"StorageError\";\n this.cause = cause;\n\n // Maintain proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, StorageError);\n }\n }\n}\n\nclass IndexedDBStorage {\n constructor(dbName = \"BreezSDK\", logger = null) {\n this.dbName = dbName;\n this.db = null;\n this.migrationManager = null;\n this.logger = logger;\n // IMPORTANT: the migrations array in MigrationManager is append-only. The\n // migration at array index N is the upgrade step from DB version N to N+1,\n // so existing databases depend on indices never shifting. Never insert,\n // reorder, or delete a migration — only append. dbVersion MUST equal the\n // number of migrations (enforced by the guard in initialize()).\n this.dbVersion = 22; // Current schema version (= migration count)\n }\n\n /**\n * Initialize the storage - must be called before using other methods\n */\n async initialize() {\n if (this.db) {\n return this;\n }\n\n if (typeof window === \"undefined\" || !window.indexedDB) {\n throw new StorageError(\"IndexedDB is not available in this environment\");\n }\n\n // Guard: dbVersion must equal the migration count. If they drift apart, the\n // upgrade loop either skips the trailing migration(s) or requests a version\n // no migration fills in. Fail fast — this is a programming error.\n const migrationCount = new MigrationManager(null, StorageError).migrations.length;\n if (this.dbVersion !== migrationCount) {\n throw new StorageError(\n `dbVersion (${this.dbVersion}) must equal the migration count (${migrationCount}). ` +\n `Migrations are append-only: append a new migration and bump dbVersion to match.`\n );\n }\n\n return new Promise((resolve, reject) => {\n const request = indexedDB.open(this.dbName, this.dbVersion);\n\n request.onerror = () => {\n const error = new StorageError(\n `Failed to open IndexedDB: ${request.error?.message || \"Unknown error\"\n }`,\n request.error\n );\n reject(error);\n };\n\n request.onsuccess = () => {\n this.db = request.result;\n this.migrationManager = new MigrationManager(\n this.db,\n StorageError,\n this.logger\n );\n\n // Handle unexpected version changes\n this.db.onversionchange = () => {\n this.db.close();\n this.db = null;\n };\n\n resolve(this);\n };\n\n request.onupgradeneeded = (event) => {\n this.db = event.target.result;\n this.migrationManager = new MigrationManager(\n this.db,\n StorageError,\n this.logger\n );\n\n try {\n this.migrationManager.handleUpgrade(\n event,\n event.oldVersion,\n event.newVersion\n );\n } catch (error) {\n reject(error);\n }\n };\n });\n }\n\n /**\n * Close the database connection\n */\n close() {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n }\n\n // ===== Cache Operations =====\n\n async getCachedItem(key) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"settings\", \"readonly\");\n const store = transaction.objectStore(\"settings\");\n const request = store.get(key);\n\n request.onsuccess = () => {\n const result = request.result;\n resolve(result ? result.value : null);\n };\n\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to get cached item '${key}': ${request.error?.message || \"Unknown error\"\n }`,\n request.error\n )\n );\n };\n });\n }\n\n async setCachedItem(key, value) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"settings\", \"readwrite\");\n const store = transaction.objectStore(\"settings\");\n const request = store.put({ key, value });\n\n request.onsuccess = () => resolve();\n\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to set cached item '${key}': ${request.error?.message || \"Unknown error\"\n }`,\n request.error\n )\n );\n };\n });\n }\n\n async deleteCachedItem(key) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"settings\", \"readwrite\");\n const store = transaction.objectStore(\"settings\");\n const request = store.delete(key);\n\n request.onsuccess = () => resolve();\n\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to delete cached item '${key}': ${request.error?.message || \"Unknown error\"\n }`,\n request.error\n )\n );\n };\n });\n }\n\n // ===== Payment Operations =====\n\n /**\n * Gets the set of payment IDs that are related payments (have a parentPaymentId).\n * Uses the parentPaymentId index for efficient lookup.\n * @param {IDBObjectStore} metadataStore - The payment_metadata object store\n * @returns {Promise<Set<string>>} Set of payment IDs that are related payments\n */\n _getRelatedPaymentIds(metadataStore) {\n return new Promise((resolve) => {\n const relatedPaymentIds = new Set();\n\n // Check if the parentPaymentId index exists (added in migration)\n if (!metadataStore.indexNames.contains(\"parentPaymentId\")) {\n // Index doesn't exist yet, fall back to scanning all metadata\n const cursorRequest = metadataStore.openCursor();\n cursorRequest.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor) {\n if (cursor.value.parentPaymentId) {\n relatedPaymentIds.add(cursor.value.paymentId);\n }\n cursor.continue();\n } else {\n resolve(relatedPaymentIds);\n }\n };\n cursorRequest.onerror = () => resolve(new Set());\n return;\n }\n\n // Use the parentPaymentId index to find all metadata entries with a parent\n const index = metadataStore.index(\"parentPaymentId\");\n const cursorRequest = index.openCursor();\n\n cursorRequest.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor) {\n // Only add if parentPaymentId is truthy (not null/undefined)\n if (cursor.value.parentPaymentId) {\n relatedPaymentIds.add(cursor.value.paymentId);\n }\n cursor.continue();\n } else {\n resolve(relatedPaymentIds);\n }\n };\n\n cursorRequest.onerror = () => {\n // If index lookup fails, return empty set and fall back to per-payment lookup\n resolve(new Set());\n };\n });\n }\n\n async listPayments(request) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n // Handle null values by using default values\n const actualOffset = request.offset !== null ? request.offset : 0;\n const actualLimit = request.limit !== null ? request.limit : 4294967295; // u32::MAX\n\n const transaction = this.db.transaction(\n [\"payments\", \"payment_metadata\", \"lnurl_receive_metadata\"],\n \"readonly\"\n );\n const paymentStore = transaction.objectStore(\"payments\");\n const metadataStore = transaction.objectStore(\"payment_metadata\");\n const lnurlReceiveMetadataStore = transaction.objectStore(\"lnurl_receive_metadata\");\n\n // Build set of related payment IDs upfront for O(1) filtering\n const relatedPaymentIds = await this._getRelatedPaymentIds(metadataStore);\n\n return new Promise((resolve, reject) => {\n const payments = [];\n let count = 0;\n let skipped = 0;\n\n // Determine sort order - \"prev\" for descending (default), \"next\" for ascending\n const cursorDirection = request.sortAscending ? \"next\" : \"prev\";\n\n // Use cursor to iterate through payments ordered by timestamp\n const cursorRequest = paymentStore\n .index(\"timestamp\")\n .openCursor(null, cursorDirection);\n\n cursorRequest.onsuccess = (event) => {\n const cursor = event.target.result;\n\n if (!cursor || count >= actualLimit) {\n resolve(payments);\n return;\n }\n\n const payment = cursor.value;\n\n // Skip related payments (those with a parentPaymentId)\n if (relatedPaymentIds.has(payment.id)) {\n cursor.continue();\n return;\n }\n\n if (skipped < actualOffset) {\n skipped++;\n cursor.continue();\n return;\n }\n\n // Get metadata for this payment (now only for non-related payments)\n const metadataRequest = metadataStore.get(payment.id);\n metadataRequest.onsuccess = () => {\n const metadata = metadataRequest.result;\n\n const paymentWithMetadata = this._mergePaymentMetadata(\n payment,\n metadata\n );\n\n // Fetch lnurl receive metadata before filtering, so Lightning\n // filters can check lnurlReceiveMetadata fields\n this._fetchLnurlReceiveMetadata(\n paymentWithMetadata,\n lnurlReceiveMetadataStore\n )\n .then((mergedPayment) => {\n // Apply filters after lnurl metadata is populated\n if (!this._matchesFilters(mergedPayment, request)) {\n cursor.continue();\n return;\n }\n payments.push(mergedPayment);\n count++;\n cursor.continue();\n })\n .catch(() => {\n // Apply filters even if lnurl metadata fetch fails\n if (!this._matchesFilters(paymentWithMetadata, request)) {\n cursor.continue();\n return;\n }\n payments.push(paymentWithMetadata);\n count++;\n cursor.continue();\n });\n };\n metadataRequest.onerror = () => {\n // Continue without metadata if it fails\n if (this._matchesFilters(payment, request)) {\n payments.push(payment);\n count++;\n }\n\n cursor.continue();\n };\n };\n\n cursorRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to list payments (request: ${JSON.stringify(request)}: ${cursorRequest.error?.message || \"Unknown error\"\n }`,\n cursorRequest.error\n )\n );\n };\n });\n }\n\n async applyPaymentUpdate(payment) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n let shouldEmit = false;\n let settled = false;\n const transaction = this.db.transaction(\"payments\", \"readwrite\");\n const store = transaction.objectStore(\"payments\");\n\n const rejectOnce = (message, error) => {\n if (settled) {\n return;\n }\n settled = true;\n reject(new StorageError(message, error));\n };\n\n transaction.oncomplete = () => {\n if (settled) {\n return;\n }\n settled = true;\n resolve(shouldEmit);\n };\n\n transaction.onerror = () => {\n rejectOnce(\n `Failed to apply payment update '${payment.id}': ${transaction.error?.message || \"Unknown error\"\n }`,\n transaction.error\n );\n };\n\n transaction.onabort = () => {\n rejectOnce(\n `Payment update transaction aborted for '${payment.id}': ${transaction.error?.message || \"Unknown error\"\n }`,\n transaction.error\n );\n };\n\n const getRequest = store.get(payment.id);\n\n getRequest.onsuccess = () => {\n const storedPayment = getRequest.result;\n const stored = storedPayment\n ? this._normalizePaymentStatus(storedPayment.status)\n : null;\n const next = this._normalizePaymentStatus(payment.status);\n\n let shouldPersist;\n if (stored == null) {\n shouldPersist = true;\n shouldEmit = true;\n } else if (stored === next) {\n console.debug(\n `Skipping redundant payment event: id=${payment.id} status=${next}`\n );\n shouldPersist = true;\n shouldEmit = false;\n } else if (this._isFinalPaymentStatus(stored)) {\n console.warn(\n `Skipping payment update (would replace terminal status): id=${payment.id} stored=${stored} new=${next}`\n );\n shouldPersist = false;\n shouldEmit = false;\n } else {\n shouldPersist = true;\n shouldEmit = true;\n }\n\n if (!shouldPersist) {\n return;\n }\n\n const putRequest = store.put(this._paymentToStore(payment));\n putRequest.onerror = () => {\n rejectOnce(\n `Failed to persist payment update '${payment.id}': ${putRequest.error?.message || \"Unknown error\"\n }`,\n putRequest.error\n );\n };\n };\n\n getRequest.onerror = () => {\n rejectOnce(\n `Failed to read payment '${payment.id}' before update: ${getRequest.error?.message || \"Unknown error\"\n }`,\n getRequest.error\n );\n };\n });\n }\n\n async getPaymentById(id) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n [\"payments\", \"payment_metadata\", \"lnurl_receive_metadata\"],\n \"readonly\"\n );\n const paymentStore = transaction.objectStore(\"payments\");\n const metadataStore = transaction.objectStore(\"payment_metadata\");\n const lnurlReceiveMetadataStore = transaction.objectStore(\n \"lnurl_receive_metadata\"\n );\n\n const paymentRequest = paymentStore.get(id);\n\n paymentRequest.onsuccess = () => {\n const payment = paymentRequest.result;\n if (!payment) {\n reject(new StorageError(`Payment with id '${id}' not found`));\n return;\n }\n\n // Get metadata for this payment\n const metadataRequest = metadataStore.get(id);\n metadataRequest.onsuccess = () => {\n const metadata = metadataRequest.result;\n const paymentWithMetadata = this._mergePaymentMetadata(\n payment,\n metadata\n );\n\n // Fetch lnurl receive metadata if it's a lightning payment\n this._fetchLnurlReceiveMetadata(\n paymentWithMetadata,\n lnurlReceiveMetadataStore\n )\n .then(resolve)\n .catch(() => {\n // Continue without lnurl receive metadata if fetch fails\n resolve(paymentWithMetadata);\n });\n };\n metadataRequest.onerror = () => {\n // Return payment without metadata if metadata fetch fails\n resolve(payment);\n };\n };\n\n paymentRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to get payment by id '${id}': ${paymentRequest.error?.message || \"Unknown error\"\n }`,\n paymentRequest.error\n )\n );\n };\n });\n }\n\n async getPaymentByInvoice(invoice) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n [\"payments\", \"payment_metadata\", \"lnurl_receive_metadata\"],\n \"readonly\"\n );\n const paymentStore = transaction.objectStore(\"payments\");\n const invoiceIndex = paymentStore.index(\"invoice\");\n const metadataStore = transaction.objectStore(\"payment_metadata\");\n const lnurlReceiveMetadataStore = transaction.objectStore(\n \"lnurl_receive_metadata\"\n );\n\n const paymentRequest = invoiceIndex.get(invoice);\n\n paymentRequest.onsuccess = () => {\n const payment = paymentRequest.result;\n if (!payment) {\n resolve(null);\n return;\n }\n\n // Get metadata for this payment\n const metadataRequest = metadataStore.get(payment.id);\n metadataRequest.onsuccess = () => {\n const metadata = metadataRequest.result;\n const paymentWithMetadata = this._mergePaymentMetadata(\n payment,\n metadata\n );\n\n // Fetch lnurl receive metadata if it's a lightning payment\n this._fetchLnurlReceiveMetadata(\n paymentWithMetadata,\n lnurlReceiveMetadataStore\n )\n .then(resolve)\n .catch(() => {\n // Continue without lnurl receive metadata if fetch fails\n resolve(paymentWithMetadata);\n });\n };\n metadataRequest.onerror = () => {\n // Return payment without metadata if metadata fetch fails\n resolve(payment);\n };\n };\n\n paymentRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to get payment by invoice '${invoice}': ${paymentRequest.error?.message || \"Unknown error\"\n }`,\n paymentRequest.error\n )\n );\n };\n });\n }\n\n /**\n * Checks if any related payments exist (payments with a parentPaymentId).\n * Uses the parentPaymentId index for efficient lookup.\n * @param {IDBObjectStore} metadataStore - The payment_metadata object store\n * @returns {Promise<boolean>} True if any related payments exist\n */\n _hasRelatedPayments(metadataStore) {\n return new Promise((resolve) => {\n // Check if the parentPaymentId index exists (added in migration)\n if (!metadataStore.indexNames.contains(\"parentPaymentId\")) {\n // Index doesn't exist yet, fall back to scanning all metadata\n const cursorRequest = metadataStore.openCursor();\n cursorRequest.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor) {\n if (cursor.value.parentPaymentId) {\n resolve(true);\n return;\n }\n cursor.continue();\n } else {\n resolve(false);\n }\n };\n cursorRequest.onerror = () => resolve(true); // Assume there might be related payments on error\n return;\n }\n\n const index = metadataStore.index(\"parentPaymentId\");\n const cursorRequest = index.openCursor();\n\n cursorRequest.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor && cursor.value.parentPaymentId) {\n // Found at least one related payment\n resolve(true);\n } else if (cursor) {\n // Entry with null parentPaymentId, continue searching\n cursor.continue();\n } else {\n // No more entries\n resolve(false);\n }\n };\n\n cursorRequest.onerror = () => {\n // If index lookup fails, assume there might be related payments\n resolve(true);\n };\n });\n }\n\n /**\n * Gets payments that have any of the specified parent payment IDs.\n * @param {string[]} parentPaymentIds - Array of parent payment IDs\n * @returns {Promise<Object>} Map of parentPaymentId -> array of RelatedPayment objects\n */\n async getPaymentsByParentIds(parentPaymentIds) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n if (!parentPaymentIds || parentPaymentIds.length === 0) {\n return {};\n }\n\n const transaction = this.db.transaction(\n [\"payments\", \"payment_metadata\", \"lnurl_receive_metadata\"],\n \"readonly\"\n );\n const metadataStore = transaction.objectStore(\"payment_metadata\");\n\n // Early exit if no related payments exist\n const hasRelated = await this._hasRelatedPayments(metadataStore);\n if (!hasRelated) {\n return {};\n }\n\n const parentIdSet = new Set(parentPaymentIds);\n const paymentStore = transaction.objectStore(\"payments\");\n const lnurlReceiveMetadataStore = transaction.objectStore(\"lnurl_receive_metadata\");\n\n return new Promise((resolve, reject) => {\n const result = {};\n const fetchedMetadata = [];\n\n // Query all metadata records and filter by parentPaymentId\n const cursorRequest = metadataStore.openCursor();\n\n cursorRequest.onsuccess = (event) => {\n const cursor = event.target.result;\n if (!cursor) {\n // All metadata processed, now fetch payment details\n if (fetchedMetadata.length === 0) {\n resolve(result);\n return;\n }\n\n let processed = 0;\n for (const metadata of fetchedMetadata) {\n const parentId = metadata.parentPaymentId;\n const paymentRequest = paymentStore.get(metadata.paymentId);\n paymentRequest.onsuccess = () => {\n const payment = paymentRequest.result;\n if (payment) {\n const paymentWithMetadata = this._mergePaymentMetadata(payment, metadata);\n\n if (!result[parentId]) {\n result[parentId] = [];\n }\n\n // Fetch lnurl receive metadata if applicable\n this._fetchLnurlReceiveMetadata(paymentWithMetadata, lnurlReceiveMetadataStore)\n .then((mergedPayment) => {\n result[parentId].push(mergedPayment);\n })\n .catch(() => {\n result[parentId].push(paymentWithMetadata);\n })\n .finally(() => {\n processed++;\n if (processed === fetchedMetadata.length) {\n // Sort each parent's children by timestamp\n for (const parentId of Object.keys(result)) {\n result[parentId].sort((a, b) => a.timestamp - b.timestamp);\n }\n resolve(result);\n }\n });\n } else {\n processed++;\n if (processed === fetchedMetadata.length) {\n resolve(result);\n }\n }\n };\n paymentRequest.onerror = () => {\n processed++;\n if (processed === fetchedMetadata.length) {\n resolve(result);\n }\n };\n }\n return;\n }\n\n const metadata = cursor.value;\n if (metadata.parentPaymentId && parentIdSet.has(metadata.parentPaymentId)) {\n fetchedMetadata.push(metadata);\n }\n cursor.continue();\n };\n\n cursorRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to get payments by parent ids: ${cursorRequest.error?.message || \"Unknown error\"\n }`,\n cursorRequest.error\n )\n );\n };\n });\n }\n\n async insertPaymentMetadata(paymentId, metadata) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"payment_metadata\", \"readwrite\");\n const store = transaction.objectStore(\"payment_metadata\");\n\n // First get existing record to merge with\n const getRequest = store.get(paymentId);\n getRequest.onsuccess = () => {\n const existing = getRequest.result || {};\n\n // Use COALESCE-like behavior: new value if non-null, otherwise keep existing\n const metadataToStore = {\n paymentId,\n parentPaymentId: metadata.parentPaymentId ?? existing.parentPaymentId ?? null,\n lnurlPayInfo: metadata.lnurlPayInfo\n ? JSON.stringify(metadata.lnurlPayInfo)\n : existing.lnurlPayInfo ?? null,\n lnurlWithdrawInfo: metadata.lnurlWithdrawInfo\n ? JSON.stringify(metadata.lnurlWithdrawInfo)\n : existing.lnurlWithdrawInfo ?? null,\n lnurlDescription: metadata.lnurlDescription ?? existing.lnurlDescription ?? null,\n conversionInfo: metadata.conversionInfo\n ? JSON.stringify(metadata.conversionInfo)\n : existing.conversionInfo ?? null,\n conversionStatus: metadata.conversionStatus ?? existing.conversionStatus ?? null,\n };\n\n const putRequest = store.put(metadataToStore);\n putRequest.onsuccess = () => resolve();\n putRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to set payment metadata for '${paymentId}': ${putRequest.error?.message || \"Unknown error\"\n }`,\n putRequest.error\n )\n );\n };\n };\n getRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to get existing payment metadata for '${paymentId}': ${getRequest.error?.message || \"Unknown error\"\n }`,\n getRequest.error\n )\n );\n };\n });\n }\n\n // ===== Deposit Operations =====\n\n async addDeposit(txid, vout, amountSats, isMature) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n \"unclaimed_deposits\",\n \"readwrite\"\n );\n const store = transaction.objectStore(\"unclaimed_deposits\");\n\n // Get existing deposit first to preserve fields on upsert\n const getRequest = store.get([txid, vout]);\n\n getRequest.onsuccess = () => {\n const existing = getRequest.result;\n const depositToStore = {\n txid,\n vout,\n amountSats,\n isMature: isMature ?? true,\n claimError: existing?.claimError ?? null,\n refundTx: existing?.refundTx ?? null,\n refundTxId: existing?.refundTxId ?? null,\n instantClaimStatus: existing?.instantClaimStatus ?? null,\n refundState: existing?.refundState ?? null,\n maxClaimFee: existing?.maxClaimFee ?? null,\n };\n\n const putRequest = store.put(depositToStore);\n putRequest.onsuccess = () => resolve();\n putRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to add deposit '${txid}:${vout}': ${putRequest.error?.message || \"Unknown error\"\n }`,\n putRequest.error\n )\n );\n };\n };\n\n getRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to add deposit '${txid}:${vout}': ${getRequest.error?.message || \"Unknown error\"\n }`,\n getRequest.error\n )\n );\n };\n });\n }\n\n async deleteDeposit(txid, vout) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n \"unclaimed_deposits\",\n \"readwrite\"\n );\n const store = transaction.objectStore(\"unclaimed_deposits\");\n const request = store.delete([txid, vout]);\n\n request.onsuccess = () => resolve();\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to delete deposit '${txid}:${vout}': ${request.error?.message || \"Unknown error\"\n }`,\n request.error\n )\n );\n };\n });\n }\n\n async listDeposits() {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"unclaimed_deposits\", \"readonly\");\n const store = transaction.objectStore(\"unclaimed_deposits\");\n const request = store.getAll();\n\n request.onsuccess = () => {\n const deposits = request.result.map((row) => ({\n txid: row.txid,\n vout: row.vout,\n amountSats: row.amountSats,\n isMature: row.isMature ?? true,\n claimError: row.claimError ? JSON.parse(row.claimError) : null,\n refundTx: row.refundTx,\n refundTxId: row.refundTxId,\n instantClaimStatus: row.instantClaimStatus\n ? JSON.parse(row.instantClaimStatus)\n : null,\n refundState: row.refundState ? JSON.parse(row.refundState) : null,\n maxClaimFee: row.maxClaimFee ? JSON.parse(row.maxClaimFee) : null,\n }));\n resolve(deposits);\n };\n\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to list deposits: ${request.error?.message || \"Unknown error\"\n }`,\n request.error\n )\n );\n };\n });\n }\n\n async updateDeposit(txid, vout, payload) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n \"unclaimed_deposits\",\n \"readwrite\"\n );\n const store = transaction.objectStore(\"unclaimed_deposits\");\n\n // First get the existing deposit\n const getRequest = store.get([txid, vout]);\n\n getRequest.onsuccess = () => {\n const existingDeposit = getRequest.result;\n if (!existingDeposit) {\n // Deposit doesn't exist, just resolve (matches SQLite behavior)\n resolve();\n return;\n }\n\n let updatedDeposit = { ...existingDeposit };\n\n if (payload.type === \"claimError\") {\n updatedDeposit.claimError = JSON.stringify(payload.error);\n } else if (payload.type === \"refund\") {\n updatedDeposit.refundTx = payload.refundTx;\n updatedDeposit.refundTxId = payload.refundTxid;\n updatedDeposit.refundState = JSON.stringify(payload.state);\n updatedDeposit.claimError = null;\n } else if (payload.type === \"instantClaim\") {\n updatedDeposit.instantClaimStatus = JSON.stringify(payload.status);\n } else if (payload.type === \"refundBroadcastState\") {\n // Only while this is still the stored refund.\n if (existingDeposit.refundTxId === payload.refundTxid) {\n updatedDeposit.refundState = JSON.stringify(payload.state);\n }\n } else if (payload.type === \"maxClaimFee\") {\n updatedDeposit.maxClaimFee = payload.maxFee\n ? JSON.stringify(payload.maxFee)\n : null;\n } else {\n reject(new StorageError(`Unknown payload type: ${payload.type}`));\n return;\n }\n\n const putRequest = store.put(updatedDeposit);\n putRequest.onsuccess = () => resolve();\n putRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to update deposit '${txid}:${vout}': ${putRequest.error?.message || \"Unknown error\"\n }`,\n putRequest.error\n )\n );\n };\n };\n\n getRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to get deposit '${txid}:${vout}' for update: ${getRequest.error?.message || \"Unknown error\"\n }`,\n getRequest.error\n )\n );\n };\n });\n }\n\n async listWatchedDepositAddresses() {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n \"watched_deposit_addresses\",\n \"readonly\"\n );\n const store = transaction.objectStore(\"watched_deposit_addresses\");\n const request = store.getAll();\n\n request.onsuccess = () => {\n const watched = (request.result || []).map((entry) => ({\n address: entry.address,\n issuedAt: entry.issuedAt,\n seen: Boolean(entry.seen),\n }));\n // The store is keyed by address, so ordering is applied here rather\n // than by an index.\n watched.sort((a, b) => Number(b.issuedAt) - Number(a.issuedAt));\n resolve(watched);\n };\n request.onerror = () =>\n reject(\n new StorageError(\n `Failed to list watched deposit addresses: ${request.error}`\n )\n );\n });\n }\n\n async updateWatchedDepositAddress(address, payload) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n \"watched_deposit_addresses\",\n \"readwrite\"\n );\n const store = transaction.objectStore(\"watched_deposit_addresses\");\n\n if (payload.type === \"watch\") {\n const request = store.put({\n address,\n issuedAt: payload.issuedAt,\n seen: false,\n });\n request.onsuccess = () => resolve();\n request.onerror = () =>\n reject(\n new StorageError(\n `Failed to watch deposit address '${address}': ${request.error}`\n )\n );\n return;\n }\n\n if (payload.type === \"unwatch\") {\n // Conditional on issuedAt, so an address handed out again since the\n // caller read it is not retired by a decision taken before that. The\n // get and the delete share one readwrite transaction, so nothing can\n // interleave between them.\n const getRequest = store.get(address);\n getRequest.onsuccess = () => {\n const existing = getRequest.result;\n const stale =\n !existing || String(existing.issuedAt) !== String(payload.issuedAt);\n if (stale) {\n resolve();\n return;\n }\n const request = store.delete(address);\n request.onsuccess = () => resolve();\n request.onerror = () =>\n reject(\n new StorageError(\n `Failed to unwatch deposit address '${address}': ${request.error}`\n )\n );\n };\n getRequest.onerror = () =>\n reject(\n new StorageError(\n `Failed to read watched deposit address '${address}': ${getRequest.error}`\n )\n );\n return;\n }\n\n if (payload.type === \"seen\") {\n const getRequest = store.get(address);\n getRequest.onsuccess = () => {\n const existing = getRequest.result;\n if (!existing) {\n // Not watched, so there is nothing to mark (matches the SQL stores,\n // whose UPDATE affects no rows).\n resolve();\n return;\n }\n const request = store.put({ ...existing, seen: true });\n request.onsuccess = () => resolve();\n request.onerror = () =>\n reject(\n new StorageError(\n `Failed to mark deposit address '${address}' seen: ${request.error}`\n )\n );\n };\n getRequest.onerror = () =>\n reject(\n new StorageError(\n `Failed to read watched deposit address '${address}': ${getRequest.error}`\n )\n );\n return;\n }\n\n reject(new StorageError(`Unknown payload type: ${payload.type}`));\n });\n }\n\n async setLnurlMetadata(metadata) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n \"lnurl_receive_metadata\",\n \"readwrite\"\n );\n const store = transaction.objectStore(\"lnurl_receive_metadata\");\n\n let completed = 0;\n const total = metadata.length;\n\n if (total === 0) {\n resolve();\n return;\n }\n\n for (const item of metadata) {\n const request = store.put({\n paymentHash: item.paymentHash,\n nostrZapRequest: item.nostrZapRequest || null,\n nostrZapReceipt: item.nostrZapReceipt || null,\n senderComment: item.senderComment || null,\n });\n\n request.onsuccess = () => {\n completed++;\n if (completed === total) {\n resolve();\n }\n };\n\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to add lnurl metadata for payment hash '${item.paymentHash\n }': ${request.error?.message || \"Unknown error\"}`,\n request.error\n )\n );\n };\n }\n });\n }\n\n async syncAddOutgoingChange(record) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction([\"sync_outgoing\"], \"readwrite\");\n\n // This revision is a local queue id for pending rows, not a server revision.\n const outgoingStore = transaction.objectStore(\"sync_outgoing\");\n const getAllOutgoingRequest = outgoingStore.getAll();\n\n getAllOutgoingRequest.onsuccess = () => {\n const records = getAllOutgoingRequest.result;\n let maxOutgoingRevision = BigInt(0);\n for (const storeRecord of records) {\n const rev = BigInt(\n storeRecord.record.localRevision ?? storeRecord.record.revision\n );\n if (rev > maxOutgoingRevision) {\n maxOutgoingRevision = rev;\n }\n }\n const nextRevision = maxOutgoingRevision + BigInt(1);\n\n const storeRecord = {\n type: record.id.type,\n dataId: record.id.dataId,\n revision: Number(nextRevision),\n record: {\n ...record,\n localRevision: nextRevision,\n },\n };\n\n const addRequest = outgoingStore.add(storeRecord);\n\n addRequest.onsuccess = () => {\n transaction.oncomplete = () => {\n resolve(nextRevision);\n };\n };\n\n addRequest.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to add outgoing change: ${event.target.error.message}`\n )\n );\n };\n };\n\n getAllOutgoingRequest.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to get outgoing records: ${event.target.error.message}`\n )\n );\n };\n\n transaction.onerror = (event) => {\n reject(\n new StorageError(`Transaction failed: ${event.target.error.message}`)\n );\n };\n });\n }\n\n async syncCompleteOutgoingSync(record, localRevision) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n [\"sync_outgoing\", \"sync_state\", \"sync_revision\"],\n \"readwrite\"\n );\n const outgoingStore = transaction.objectStore(\"sync_outgoing\");\n const stateStore = transaction.objectStore(\"sync_state\");\n const revisionStore = transaction.objectStore(\"sync_revision\");\n\n const deleteRequest = outgoingStore.delete([\n record.id.type,\n record.id.dataId,\n Number(localRevision),\n ]);\n\n deleteRequest.onsuccess = () => {\n const stateRecord = {\n type: record.id.type,\n dataId: record.id.dataId,\n record: record,\n };\n stateStore.put(stateRecord);\n\n // Update sync_revision to track the highest known revision\n const getRevisionRequest = revisionStore.get(1);\n getRevisionRequest.onsuccess = () => {\n const current = getRevisionRequest.result || { id: 1, revision: \"0\" };\n const currentRevision = BigInt(current.revision);\n const recordRevision = BigInt(record.revision);\n if (recordRevision > currentRevision) {\n revisionStore.put({ id: 1, revision: recordRevision.toString() });\n }\n resolve();\n };\n getRevisionRequest.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to update sync revision: ${event.target.error.message}`\n )\n );\n };\n };\n\n deleteRequest.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to complete outgoing sync: ${event.target.error.message}`\n )\n );\n };\n });\n }\n\n async syncGetPendingOutgoingChanges(limit) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n [\"sync_outgoing\", \"sync_state\"],\n \"readonly\"\n );\n const outgoingStore = transaction.objectStore(\"sync_outgoing\");\n const stateStore = transaction.objectStore(\"sync_state\");\n\n // Get pending outgoing changes (all records in this store are pending)\n // Use revision index to order by revision ascending\n const revisionIndex = outgoingStore.index(\"revision\");\n const request = revisionIndex.openCursor(null, \"next\");\n const changes = [];\n let count = 0;\n\n request.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor && count < limit) {\n const storeRecord = cursor.value;\n const change = {\n ...storeRecord.record,\n localRevision:\n storeRecord.record.localRevision ?? storeRecord.record.revision,\n };\n\n // Look up parent record if it exists\n const stateRequest = stateStore.get([\n storeRecord.type,\n storeRecord.dataId,\n ]);\n stateRequest.onsuccess = () => {\n const stateRecord = stateRequest.result;\n const parent = stateRecord ? stateRecord.record : null;\n\n changes.push({\n change: change,\n parent: parent,\n });\n\n count++;\n cursor.continue();\n };\n\n stateRequest.onerror = () => {\n changes.push({\n change: change,\n parent: null,\n });\n\n count++;\n cursor.continue();\n };\n } else {\n resolve(changes);\n }\n };\n\n request.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to get pending outgoing changes: ${event.target.error.message}`\n )\n );\n };\n });\n }\n\n async syncGetLastRevision() {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"sync_revision\", \"readonly\");\n const store = transaction.objectStore(\"sync_revision\");\n const request = store.get(1);\n\n request.onsuccess = () => {\n const result = request.result || { id: 1, revision: \"0\" };\n resolve(BigInt(result.revision));\n };\n\n request.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to get last revision: ${event.target.error.message}`\n )\n );\n };\n });\n }\n\n async syncInsertIncomingRecords(records) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction([\"sync_incoming\"], \"readwrite\");\n const store = transaction.objectStore(\"sync_incoming\");\n\n // Add each record to the incoming store\n let recordsProcessed = 0;\n\n for (const record of records) {\n const storeRecord = {\n type: record.id.type,\n dataId: record.id.dataId,\n revision: Number(record.revision),\n record: record,\n };\n\n const request = store.put(storeRecord);\n\n request.onsuccess = () => {\n recordsProcessed++;\n if (recordsProcessed === records.length) {\n resolve();\n }\n };\n\n request.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to insert incoming record: ${event.target.error.message}`\n )\n );\n };\n }\n\n // If no records were provided\n if (records.length === 0) {\n resolve();\n }\n });\n }\n\n async syncDeleteIncomingRecord(record) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction([\"sync_incoming\"], \"readwrite\");\n const store = transaction.objectStore(\"sync_incoming\");\n\n const key = [record.id.type, record.id.dataId, Number(record.revision)];\n const request = store.delete(key);\n\n request.onsuccess = () => {\n resolve();\n };\n\n request.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to delete incoming record: ${event.target.error.message}`\n )\n );\n };\n });\n }\n\n async syncGetIncomingRecords(limit) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n [\"sync_incoming\", \"sync_state\"],\n \"readonly\"\n );\n const incomingStore = transaction.objectStore(\"sync_incoming\");\n const stateStore = transaction.objectStore(\"sync_state\");\n\n // Get records up to the limit, ordered by revision\n const revisionIndex = incomingStore.index(\"revision\");\n const request = revisionIndex.openCursor(null, \"next\");\n const records = [];\n let count = 0;\n\n request.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor && count < limit) {\n const storeRecord = cursor.value;\n const newState = storeRecord.record;\n\n // Look for parent record\n const stateRequest = stateStore.get([\n storeRecord.type,\n storeRecord.dataId,\n ]);\n\n stateRequest.onsuccess = () => {\n const stateRecord = stateRequest.result;\n const oldState = stateRecord ? stateRecord.record : null;\n\n records.push({\n newState: newState,\n oldState: oldState,\n });\n\n count++;\n cursor.continue();\n };\n\n stateRequest.onerror = () => {\n records.push({\n newState: newState,\n oldState: null,\n });\n\n count++;\n cursor.continue();\n };\n } else {\n resolve(records);\n }\n };\n\n request.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to get incoming records: ${event.target.error.message}`\n )\n );\n };\n });\n }\n\n async syncGetLatestOutgoingChange() {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\n [\"sync_outgoing\", \"sync_state\"],\n \"readonly\"\n );\n const outgoingStore = transaction.objectStore(\"sync_outgoing\");\n const stateStore = transaction.objectStore(\"sync_state\");\n\n // Get the highest revision record\n const index = outgoingStore.index(\"revision\");\n const request = index.openCursor(null, \"prev\");\n\n request.onsuccess = (event) => {\n const cursor = event.target.result;\n if (cursor) {\n const storeRecord = cursor.value;\n const change = {\n ...storeRecord.record,\n localRevision:\n storeRecord.record.localRevision ?? storeRecord.record.revision,\n };\n\n // Get the parent record\n const stateRequest = stateStore.get([\n storeRecord.type,\n storeRecord.dataId,\n ]);\n\n stateRequest.onsuccess = () => {\n const stateRecord = stateRequest.result;\n const parent = stateRecord ? stateRecord.record : null;\n\n resolve({\n change: change,\n parent: parent,\n });\n };\n\n stateRequest.onerror = () => {\n resolve({\n change: change,\n parent: null,\n });\n };\n } else {\n // No records found\n resolve(null);\n }\n };\n\n request.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to get latest outgoing change: ${event.target.error.message}`\n )\n );\n };\n });\n }\n\n async syncUpdateRecordFromIncoming(record) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction([\"sync_state\", \"sync_revision\"], \"readwrite\");\n const stateStore = transaction.objectStore(\"sync_state\");\n const revisionStore = transaction.objectStore(\"sync_revision\");\n\n const storeRecord = {\n type: record.id.type,\n dataId: record.id.dataId,\n record: record,\n };\n\n const request = stateStore.put(storeRecord);\n\n request.onsuccess = () => {\n // Update sync_revision to track the highest known revision\n const getRevisionRequest = revisionStore.get(1);\n getRevisionRequest.onsuccess = () => {\n const current = getRevisionRequest.result || { id: 1, revision: \"0\" };\n const currentRevision = BigInt(current.revision);\n const incomingRevision = BigInt(record.revision);\n if (incomingRevision > currentRevision) {\n revisionStore.put({ id: 1, revision: incomingRevision.toString() });\n }\n resolve();\n };\n getRevisionRequest.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to update sync revision: ${event.target.error.message}`\n )\n );\n };\n };\n\n request.onerror = (event) => {\n reject(\n new StorageError(\n `Failed to update record from incoming: ${event.target.error.message}`\n )\n );\n };\n });\n }\n\n // ===== Contact Operations =====\n\n async listContacts(request) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n const actualOffset = request.offset !== null && request.offset !== undefined ? request.offset : 0;\n const actualLimit = request.limit !== null && request.limit !== undefined ? request.limit : 4294967295;\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"contacts\", \"readonly\");\n const store = transaction.objectStore(\"contacts\");\n const nameIndex = store.index(\"name\");\n\n const contacts = [];\n let count = 0;\n let skipped = 0;\n\n const cursorRequest = nameIndex.openCursor();\n\n cursorRequest.onsuccess = (event) => {\n const cursor = event.target.result;\n\n if (!cursor || count >= actualLimit) {\n resolve(contacts);\n return;\n }\n\n if (skipped < actualOffset) {\n skipped++;\n cursor.continue();\n return;\n }\n\n contacts.push(cursor.value);\n count++;\n cursor.continue();\n };\n\n cursorRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to list contacts: ${cursorRequest.error?.message || \"Unknown error\"}`,\n cursorRequest.error\n )\n );\n };\n });\n }\n\n async getContact(id) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"contacts\", \"readonly\");\n const store = transaction.objectStore(\"contacts\");\n const request = store.get(id);\n\n request.onsuccess = () => {\n resolve(request.result || null);\n };\n\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to get contact '${id}': ${request.error?.message || \"Unknown error\"}`,\n request.error\n )\n );\n };\n });\n }\n\n async insertContact(contact) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"contacts\", \"readwrite\");\n const store = transaction.objectStore(\"contacts\");\n\n // Preserve created_at from existing record on update\n const getRequest = store.get(contact.id);\n getRequest.onsuccess = () => {\n const existingById = getRequest.result;\n const toStore = existingById\n ? { ...contact, createdAt: existingById.createdAt }\n : contact;\n\n const putRequest = store.put(toStore);\n putRequest.onsuccess = () => resolve();\n putRequest.onerror = () => {\n reject(\n new StorageError(\n `Inserting contact failed: ${putRequest.error?.name || \"Unknown error\"} - ${putRequest.error?.message || \"\"}`,\n putRequest.error\n )\n );\n };\n };\n getRequest.onerror = () => {\n reject(\n new StorageError(\n `Failed to check existing contact: ${getRequest.error?.message || \"Unknown error\"}`,\n getRequest.error\n )\n );\n };\n });\n }\n\n async deleteContact(id) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"contacts\", \"readwrite\");\n const store = transaction.objectStore(\"contacts\");\n const request = store.delete(id);\n\n request.onsuccess = () => resolve();\n\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to delete contact '${id}': ${request.error?.message || \"Unknown error\"}`,\n request.error\n )\n );\n };\n });\n }\n\n // ===== Cross-Chain Swap Operations =====\n\n async setCrossChainSwap(swap) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"cross_chain_swaps\", \"readwrite\");\n const store = transaction.objectStore(\"cross_chain_swaps\");\n // IndexedDB stores nested objects natively, so `data` is kept as-is.\n const request = store.put(swap);\n request.onsuccess = () => resolve();\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to set cross-chain swap '${swap.provider}:${swap.id}': ${request.error?.message || \"Unknown error\"}`,\n request.error\n )\n );\n };\n });\n }\n\n async getCrossChainSwap(provider, id) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"cross_chain_swaps\", \"readonly\");\n const store = transaction.objectStore(\"cross_chain_swaps\");\n const request = store.get([provider, id]);\n request.onsuccess = () => resolve(request.result || null);\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to get cross-chain swap '${provider}:${id}': ${request.error?.message || \"Unknown error\"}`,\n request.error\n )\n );\n };\n });\n }\n\n async listActiveCrossChainSwaps(provider) {\n if (!this.db) {\n throw new StorageError(\"Database not initialized\");\n }\n\n return new Promise((resolve, reject) => {\n const transaction = this.db.transaction(\"cross_chain_swaps\", \"readonly\");\n const store = transaction.objectStore(\"cross_chain_swaps\");\n const request = store.getAll();\n request.onsuccess = () => {\n const all = request.result || [];\n resolve(\n all.filter((swap) => swap.provider === provider && !swap.isTerminal)\n );\n };\n request.onerror = () => {\n reject(\n new StorageError(\n `Failed to list active cross-chain swaps for '${provider}': ${request.error?.message || \"Unknown error\"}`,\n request.error\n )\n );\n };\n });\n }\n\n // ===== Private Helper Methods =====\n\n _paymentToStore(payment) {\n // Ensure details and method are serialized properly\n return {\n ...payment,\n details: payment.details ? JSON.stringify(payment.details) : null,\n method: payment.method ? JSON.stringify(payment.method) : null,\n };\n }\n\n _normalizePaymentStatus(status) {\n return typeof status === \"string\" ? status.toLowerCase() : status;\n }\n\n _isFinalPaymentStatus(status) {\n const normalized = this._normalizePaymentStatus(status);\n return normalized === \"completed\" || normalized === \"failed\";\n }\n\n\n _matchesFilters(payment, request) {\n // Filter by payment type\n if (request.typeFilter && request.typeFilter.length > 0) {\n if (!request.typeFilter.includes(payment.paymentType)) {\n return false;\n }\n }\n\n // Filter by status\n if (request.statusFilter && request.statusFilter.length > 0) {\n if (!request.statusFilter.includes(payment.status)) {\n return false;\n }\n }\n\n // Filter by timestamp range\n if (request.fromTimestamp !== null && request.fromTimestamp !== undefined) {\n if (payment.timestamp < request.fromTimestamp) {\n return false;\n }\n }\n\n if (request.toTimestamp !== null && request.toTimestamp !== undefined) {\n if (payment.timestamp >= request.toTimestamp) {\n return false;\n }\n }\n\n // Filter by payment details\n if (\n request.paymentDetailsFilter &&\n request.paymentDetailsFilter.length > 0\n ) {\n let details = null;\n\n // Parse details if it's a string (stored in IndexedDB)\n if (payment.details && typeof payment.details === \"string\") {\n try {\n details = JSON.parse(payment.details);\n } catch (e) {\n // If parsing fails, treat as no details\n details = null;\n }\n } else {\n details = payment.details;\n }\n\n if (!details) {\n return false;\n }\n\n // Filter by payment details. If any filter matches, we include the payment\n let paymentDetailsFilterMatches = false;\n for (const paymentDetailsFilter of request.paymentDetailsFilter) {\n // Base type check: the payment's details type must match the filter type\n if (details.type !== paymentDetailsFilter.type) {\n continue;\n }\n // Filter by HTLC status (Spark or Lightning)\n if (\n (paymentDetailsFilter.type === \"spark\" ||\n paymentDetailsFilter.type === \"lightning\") &&\n paymentDetailsFilter.htlcStatus != null &&\n paymentDetailsFilter.htlcStatus.length > 0\n ) {\n if (\n details.type !== paymentDetailsFilter.type ||\n !details.htlcDetails ||\n !paymentDetailsFilter.htlcStatus.includes(\n details.htlcDetails.status\n )\n ) {\n continue;\n }\n }\n // Filter by conversion type + status\n if (\n (paymentDetailsFilter.type === \"spark\" ||\n paymentDetailsFilter.type === \"token\" ||\n paymentDetailsFilter.type === \"lightning\") &&\n paymentDetailsFilter.conversionFilter != null\n ) {\n if (\n details.type !== paymentDetailsFilter.type ||\n !details.conversionInfo\n ) {\n continue;\n }\n\n const ci = details.conversionInfo;\n if (paymentDetailsFilter.conversionFilter === \"ammRefundNeeded\") {\n if (ci.type !== \"amm\" || ci.status !== \"refundNeeded\") {\n continue;\n }\n } else if (paymentDetailsFilter.conversionFilter === \"orchestraPending\") {\n if (ci.type !== \"orchestra\" || [\"completed\", \"failed\", \"refunded\"].includes(ci.status)) {\n continue;\n }\n } else if (paymentDetailsFilter.conversionFilter === \"boltzPending\") {\n // Boltz conversion lives on the Lightning leg.\n if (ci.type !== \"boltz\" || [\"completed\", \"failed\", \"refunded\"].includes(ci.status)) {\n continue;\n }\n }\n }\n // Filter by token transaction hash\n if (\n paymentDetailsFilter.type === \"token\" &&\n paymentDetailsFilter.txHash != null\n ) {\n if (\n details.type !== \"token\" ||\n details.txHash !== paymentDetailsFilter.txHash\n ) {\n continue;\n }\n }\n // Filter by token transaction type\n if (\n paymentDetailsFilter.type === \"token\" &&\n paymentDetailsFilter.txType != null\n ) {\n if (\n details.type !== \"token\" ||\n details.txType !== paymentDetailsFilter.txType\n ) {\n continue;\n }\n }\n\n\n paymentDetailsFilterMatches = true;\n break;\n }\n\n if (!paymentDetailsFilterMatches) {\n return false;\n }\n }\n\n // Filter by payment details/method\n if (request.assetFilter) {\n const assetFilter = request.assetFilter;\n let details = null;\n\n // Parse details if it's a string (stored in IndexedDB)\n if (payment.details && typeof payment.details === \"string\") {\n try {\n details = JSON.parse(payment.details);\n } catch (e) {\n // If parsing fails, treat as no details\n details = null;\n }\n } else {\n details = payment.details;\n }\n\n if (!details) {\n return false;\n }\n\n if (assetFilter.type === \"bitcoin\" && details.type === \"token\") {\n return false;\n }\n\n if (assetFilter.type === \"token\") {\n if (details.type !== \"token\") {\n return false;\n }\n\n // Check token identifier if specified\n if (assetFilter.tokenIdentifier) {\n if (\n !details.metadata ||\n details.metadata.identifier !== assetFilter.tokenIdentifier\n ) {\n return false;\n }\n }\n }\n }\n\n return true;\n }\n\n _mergePaymentMetadata(payment, metadata) {\n let details = null;\n if (payment.details) {\n try {\n details = JSON.parse(payment.details);\n } catch (e) {\n throw new StorageError(\n `Failed to parse payment details JSON for payment ${payment.id}: ${e.message}`,\n e\n );\n }\n }\n\n let method = null;\n if (payment.method) {\n try {\n method = JSON.parse(payment.method);\n } catch (e) {\n throw new StorageError(\n `Failed to parse payment method JSON for payment ${payment.id}: ${e.message}`,\n e\n );\n }\n }\n\n if (details && details.type === \"lightning\" && !details.htlcDetails) {\n throw new StorageError(\n `htlc_details is required for Lightning payment ${payment.id}`\n );\n }\n\n if (metadata && details) {\n if (details.type == \"lightning\") {\n if (metadata.lnurlDescription && !details.description) {\n details.description = metadata.lnurlDescription;\n }\n // If lnurlPayInfo exists, parse and add to details\n if (metadata.lnurlPayInfo) {\n try {\n details.lnurlPayInfo = JSON.parse(metadata.lnurlPayInfo);\n } catch (e) {\n throw new StorageError(\n `Failed to parse lnurlPayInfo JSON for payment ${payment.id}: ${e.message}`,\n e\n );\n }\n }\n // If lnurlWithdrawInfo exists, parse and add to details\n if (metadata.lnurlWithdrawInfo) {\n try {\n details.lnurlWithdrawInfo = JSON.parse(metadata.lnurlWithdrawInfo);\n } catch (e) {\n throw new StorageError(\n `Failed to parse lnurlWithdrawInfo JSON for payment ${payment.id}: ${e.message}`,\n e\n );\n }\n }\n }\n\n // conversionInfo is surfaced on Lightning (Boltz hold-invoice pay),\n // Spark, and Token details — every variant that can carry a conversion.\n if (\n (details.type == \"lightning\" ||\n details.type == \"spark\" ||\n details.type == \"token\") &&\n metadata.conversionInfo\n ) {\n try {\n details.conversionInfo = JSON.parse(metadata.conversionInfo);\n } catch (e) {\n throw new StorageError(\n `Failed to parse conversionInfo JSON for payment ${payment.id}: ${e.message}`,\n e\n );\n }\n }\n }\n\n return {\n id: payment.id,\n paymentType: payment.paymentType,\n status: payment.status,\n amount: payment.amount,\n fees: payment.fees,\n timestamp: payment.timestamp,\n method,\n details,\n conversionDetails: metadata?.conversionStatus\n ? { status: metadata.conversionStatus, from: null, to: null }\n : null,\n };\n }\n\n _fetchLnurlReceiveMetadata(payment, lnurlReceiveMetadataStore) {\n // Only fetch for lightning payments with a payment hash\n if (\n !payment.details ||\n payment.details.type !== \"lightning\" ||\n !payment.details.htlcDetails?.paymentHash\n ) {\n return Promise.resolve(payment);\n }\n\n if (!lnurlReceiveMetadataStore) {\n return Promise.resolve(payment);\n }\n\n return new Promise((resolve, reject) => {\n const lnurlReceiveRequest = lnurlReceiveMetadataStore.get(\n payment.details.htlcDetails.paymentHash\n );\n\n lnurlReceiveRequest.onsuccess = () => {\n const lnurlReceiveMetadata = lnurlReceiveRequest.result;\n if (lnurlReceiveMetadata) {\n payment.details.lnurlReceiveMetadata = {\n nostrZapRequest: lnurlReceiveMetadata.nostrZapRequest || null,\n nostrZapReceipt: lnurlReceiveMetadata.nostrZapReceipt || null,\n senderComment: lnurlReceiveMetadata.senderComment || null,\n };\n }\n resolve(payment);\n };\n\n lnurlReceiveRequest.onerror = () => {\n // Continue without lnurlReceiveMetadata if fetch fails\n reject(new Error(\"Failed to fetch lnurl receive metadata\"));\n };\n });\n }\n}\n\nexport async function createDefaultStorage(\n dbName = \"BreezSdkSpark\",\n logger = null\n) {\n const storage = new IndexedDBStorage(dbName, logger);\n await storage.initialize();\n return storage;\n}\n\nexport { IndexedDBStorage, MigrationManager, StorageError };\n"],"ignoreList":[0],"mappings":"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"}
|