@breeztech/breez-sdk-spark 0.8.0-dev1 → 0.8.3-dev1

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.
@@ -213,27 +213,6 @@ function debugString(val) {
213
213
  // TODO we could test for more things here, like `Set`s and `Map`s.
214
214
  return className;
215
215
  }
216
- /**
217
- * @param {Config} config
218
- * @param {ExternalSigner} signer
219
- * @param {string} storage_dir
220
- * @returns {Promise<BreezSdk>}
221
- */
222
- export function connectWithSigner(config, signer, storage_dir) {
223
- const ptr0 = passStringToWasm0(storage_dir, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
224
- const len0 = WASM_VECTOR_LEN;
225
- const ret = wasm.connectWithSigner(config, signer, ptr0, len0);
226
- return ret;
227
- }
228
-
229
- /**
230
- * @param {ConnectRequest} request
231
- * @returns {Promise<BreezSdk>}
232
- */
233
- export function connect(request) {
234
- const ret = wasm.connect(request);
235
- return ret;
236
- }
237
216
 
238
217
  function takeFromExternrefTable0(idx) {
239
218
  const value = wasm.__wbindgen_export_5.get(idx);
@@ -259,6 +238,15 @@ export function defaultExternalSigner(mnemonic, passphrase, network, key_set_con
259
238
  return DefaultSigner.__wrap(ret[0]);
260
239
  }
261
240
 
241
+ /**
242
+ * @param {ConnectRequest} request
243
+ * @returns {Promise<BreezSdk>}
244
+ */
245
+ export function connect(request) {
246
+ const ret = wasm.connect(request);
247
+ return ret;
248
+ }
249
+
262
250
  /**
263
251
  * @param {Logger} logger
264
252
  * @param {string | null} [filter]
@@ -272,13 +260,15 @@ export function initLogging(logger, filter) {
272
260
  }
273
261
 
274
262
  /**
275
- * Creates a default external signer from a mnemonic phrase.
276
- *
277
- * This creates a signer that can be used with `connectWithSigner` or `SdkBuilder.newWithSigner`.
278
- * @returns {Promise<SparkStatus>}
263
+ * @param {Config} config
264
+ * @param {ExternalSigner} signer
265
+ * @param {string} storage_dir
266
+ * @returns {Promise<BreezSdk>}
279
267
  */
280
- export function getSparkStatus() {
281
- const ret = wasm.getSparkStatus();
268
+ export function connectWithSigner(config, signer, storage_dir) {
269
+ const ptr0 = passStringToWasm0(storage_dir, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
270
+ const len0 = WASM_VECTOR_LEN;
271
+ const ret = wasm.connectWithSigner(config, signer, ptr0, len0);
282
272
  return ret;
283
273
  }
284
274
 
@@ -291,6 +281,17 @@ export function defaultConfig(network) {
291
281
  return ret;
292
282
  }
293
283
 
284
+ /**
285
+ * Creates a default external signer from a mnemonic phrase.
286
+ *
287
+ * This creates a signer that can be used with `connectWithSigner` or `SdkBuilder.newWithSigner`.
288
+ * @returns {Promise<SparkStatus>}
289
+ */
290
+ export function getSparkStatus() {
291
+ const ret = wasm.getSparkStatus();
292
+ return ret;
293
+ }
294
+
294
295
  function passArray8ToWasm0(arg, malloc) {
295
296
  const ptr = malloc(arg.length * 1, 1) >>> 0;
296
297
  getUint8ArrayMemory0().set(arg, ptr / 1);
@@ -309,15 +310,15 @@ export function task_worker_entry_point(ptr) {
309
310
  }
310
311
 
311
312
  function __wbg_adapter_64(arg0, arg1) {
312
- wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hf2ef52c8a8b47594(arg0, arg1);
313
+ wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h127c718764a2a72f(arg0, arg1);
313
314
  }
314
315
 
315
316
  function __wbg_adapter_67(arg0, arg1, arg2) {
316
- wasm.closure1078_externref_shim(arg0, arg1, arg2);
317
+ wasm.closure1090_externref_shim(arg0, arg1, arg2);
317
318
  }
318
319
 
319
- function __wbg_adapter_287(arg0, arg1, arg2, arg3) {
320
- wasm.closure671_externref_shim(arg0, arg1, arg2, arg3);
320
+ function __wbg_adapter_285(arg0, arg1, arg2, arg3) {
321
+ wasm.closure670_externref_shim(arg0, arg1, arg2, arg3);
321
322
  }
322
323
 
323
324
  const __wbindgen_enum_ReadableStreamType = ["bytes"];
@@ -1809,7 +1810,7 @@ function __wbg_get_imports() {
1809
1810
  const a = state0.a;
1810
1811
  state0.a = 0;
1811
1812
  try {
1812
- return __wbg_adapter_287(a, state0.b, arg0, arg1);
1813
+ return __wbg_adapter_285(a, state0.b, arg0, arg1);
1813
1814
  } finally {
1814
1815
  state0.a = a;
1815
1816
  }
@@ -2147,10 +2148,6 @@ function __wbg_get_imports() {
2147
2148
  const ret = arg0.syncInsertIncomingRecords(v0);
2148
2149
  return ret;
2149
2150
  }, arguments) };
2150
- imports.wbg.__wbg_syncRebasePendingOutgoingRecords_b3441ced5dee0c8e = function() { return handleError(function (arg0, arg1) {
2151
- const ret = arg0.syncRebasePendingOutgoingRecords(BigInt.asUintN(64, arg1));
2152
- return ret;
2153
- }, arguments) };
2154
2151
  imports.wbg.__wbg_syncUpdateRecordFromIncoming_a76ad82592bfdcb3 = function() { return handleError(function (arg0, arg1) {
2155
2152
  const ret = arg0.syncUpdateRecordFromIncoming(arg1);
2156
2153
  return ret;
@@ -2245,12 +2242,12 @@ function __wbg_get_imports() {
2245
2242
  const ret = false;
2246
2243
  return ret;
2247
2244
  };
2248
- imports.wbg.__wbindgen_closure_wrapper11759 = function(arg0, arg1, arg2) {
2249
- const ret = makeMutClosure(arg0, arg1, 848, __wbg_adapter_64);
2245
+ imports.wbg.__wbindgen_closure_wrapper11879 = function(arg0, arg1, arg2) {
2246
+ const ret = makeMutClosure(arg0, arg1, 851, __wbg_adapter_64);
2250
2247
  return ret;
2251
2248
  };
2252
- imports.wbg.__wbindgen_closure_wrapper13708 = function(arg0, arg1, arg2) {
2253
- const ret = makeMutClosure(arg0, arg1, 1079, __wbg_adapter_67);
2249
+ imports.wbg.__wbindgen_closure_wrapper13824 = function(arg0, arg1, arg2) {
2250
+ const ret = makeMutClosure(arg0, arg1, 1091, __wbg_adapter_67);
2254
2251
  return ret;
2255
2252
  };
2256
2253
  imports.wbg.__wbindgen_debug_string = function(arg0, arg1) {
Binary file
@@ -113,7 +113,7 @@ export const __wbindgen_export_5: WebAssembly.Table;
113
113
  export const __externref_drop_slice: (a: number, b: number) => void;
114
114
  export const __wbindgen_export_7: WebAssembly.Table;
115
115
  export const __externref_table_dealloc: (a: number) => void;
116
- export const _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hf2ef52c8a8b47594: (a: number, b: number) => void;
117
- export const closure1078_externref_shim: (a: number, b: number, c: any) => void;
118
- export const closure671_externref_shim: (a: number, b: number, c: any, d: any) => void;
116
+ export const _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h127c718764a2a72f: (a: number, b: number) => void;
117
+ export const closure1090_externref_shim: (a: number, b: number, c: any) => void;
118
+ export const closure670_externref_shim: (a: number, b: number, c: any, d: any) => void;
119
119
  export const __wbindgen_start: () => void;
@@ -331,6 +331,72 @@ class MigrationManager {
331
331
  transaction.objectStore("settings").delete("sync_initial_complete");
332
332
  }
333
333
  }
334
+ },
335
+ {
336
+ name: "Backfill htlc_details for existing Lightning payments",
337
+ upgrade: (db, transaction) => {
338
+ if (db.objectStoreNames.contains("payments")) {
339
+ const paymentStore = transaction.objectStore("payments");
340
+ const getAllRequest = paymentStore.getAll();
341
+
342
+ getAllRequest.onsuccess = () => {
343
+ const payments = getAllRequest.result;
344
+ payments.forEach((payment) => {
345
+ let details;
346
+ if (typeof payment.details === "string") {
347
+ try {
348
+ details = JSON.parse(payment.details);
349
+ } catch (e) {
350
+ return;
351
+ }
352
+ } else {
353
+ details = payment.details;
354
+ }
355
+
356
+ if (details && details.type === "lightning" && !details.htlcDetails) {
357
+ let htlcStatus;
358
+ if (payment.status === "completed") {
359
+ htlcStatus = "preimageShared";
360
+ } else if (payment.status === "pending") {
361
+ htlcStatus = "waitingForPreimage";
362
+ } else {
363
+ htlcStatus = "returned";
364
+ }
365
+ details.htlcDetails = {
366
+ paymentHash: details.paymentHash,
367
+ preimage: details.preimage || null,
368
+ expiryTime: 0,
369
+ status: htlcStatus,
370
+ };
371
+ payment.details = JSON.stringify(details);
372
+ paymentStore.put(payment);
373
+ }
374
+ });
375
+ };
376
+ }
377
+
378
+ // Reset sync offset to trigger resync
379
+ if (db.objectStoreNames.contains("settings")) {
380
+ const settingsStore = transaction.objectStore("settings");
381
+ const getRequest = settingsStore.get("sync_offset");
382
+
383
+ getRequest.onsuccess = () => {
384
+ const syncCache = getRequest.result;
385
+ if (syncCache && syncCache.value) {
386
+ try {
387
+ const syncInfo = JSON.parse(syncCache.value);
388
+ syncInfo.offset = 0;
389
+ settingsStore.put({
390
+ key: "sync_offset",
391
+ value: JSON.stringify(syncInfo),
392
+ });
393
+ } catch (e) {
394
+ // If parsing fails, just continue
395
+ }
396
+ }
397
+ };
398
+ }
399
+ },
334
400
  }
335
401
  ];
336
402
  }
@@ -355,7 +421,7 @@ class IndexedDBStorage {
355
421
  this.db = null;
356
422
  this.migrationManager = null;
357
423
  this.logger = logger;
358
- this.dbVersion = 10; // Current schema version
424
+ this.dbVersion = 11; // Current schema version
359
425
  }
360
426
 
361
427
  /**
@@ -1280,30 +1346,24 @@ class IndexedDBStorage {
1280
1346
  }
1281
1347
 
1282
1348
  return new Promise((resolve, reject) => {
1283
- const transaction = this.db.transaction(
1284
- ["sync_outgoing", "sync_revision"],
1285
- "readwrite"
1286
- );
1349
+ const transaction = this.db.transaction(["sync_outgoing"], "readwrite");
1287
1350
 
1288
- // Compute next revision as max(committed, max outgoing) + 1, without updating sync_revision
1289
- const revisionStore = transaction.objectStore("sync_revision");
1351
+ // This revision is a local queue id for pending rows, not a server revision.
1290
1352
  const outgoingStore = transaction.objectStore("sync_outgoing");
1291
-
1292
- const getRevisionRequest = revisionStore.get(1);
1293
1353
  const getAllOutgoingRequest = outgoingStore.getAll();
1294
1354
 
1295
- let committedRevision = null;
1296
- let maxOutgoingRevision = null;
1297
- let resultsReady = 0;
1298
-
1299
- const onBothReady = () => {
1300
- resultsReady++;
1301
- if (resultsReady < 2) return;
1302
-
1303
- const base = committedRevision > maxOutgoingRevision
1304
- ? committedRevision
1305
- : maxOutgoingRevision;
1306
- const nextRevision = base + BigInt(1);
1355
+ getAllOutgoingRequest.onsuccess = () => {
1356
+ const records = getAllOutgoingRequest.result;
1357
+ let maxOutgoingRevision = BigInt(0);
1358
+ for (const storeRecord of records) {
1359
+ const rev = BigInt(
1360
+ storeRecord.record.localRevision ?? storeRecord.record.revision
1361
+ );
1362
+ if (rev > maxOutgoingRevision) {
1363
+ maxOutgoingRevision = rev;
1364
+ }
1365
+ }
1366
+ const nextRevision = maxOutgoingRevision + BigInt(1);
1307
1367
 
1308
1368
  const storeRecord = {
1309
1369
  type: record.id.type,
@@ -1311,7 +1371,7 @@ class IndexedDBStorage {
1311
1371
  revision: Number(nextRevision),
1312
1372
  record: {
1313
1373
  ...record,
1314
- revision: nextRevision,
1374
+ localRevision: nextRevision,
1315
1375
  },
1316
1376
  };
1317
1377
 
@@ -1332,35 +1392,6 @@ class IndexedDBStorage {
1332
1392
  };
1333
1393
  };
1334
1394
 
1335
- getRevisionRequest.onsuccess = () => {
1336
- const revisionData = getRevisionRequest.result || {
1337
- id: 1,
1338
- revision: "0",
1339
- };
1340
- committedRevision = BigInt(revisionData.revision);
1341
- onBothReady();
1342
- };
1343
-
1344
- getAllOutgoingRequest.onsuccess = () => {
1345
- const records = getAllOutgoingRequest.result;
1346
- maxOutgoingRevision = BigInt(0);
1347
- for (const storeRecord of records) {
1348
- const rev = BigInt(storeRecord.record.revision);
1349
- if (rev > maxOutgoingRevision) {
1350
- maxOutgoingRevision = rev;
1351
- }
1352
- }
1353
- onBothReady();
1354
- };
1355
-
1356
- getRevisionRequest.onerror = (event) => {
1357
- reject(
1358
- new StorageError(
1359
- `Failed to get revision: ${event.target.error.message}`
1360
- )
1361
- );
1362
- };
1363
-
1364
1395
  getAllOutgoingRequest.onerror = (event) => {
1365
1396
  reject(
1366
1397
  new StorageError(
@@ -1459,7 +1490,11 @@ class IndexedDBStorage {
1459
1490
  const cursor = event.target.result;
1460
1491
  if (cursor && count < limit) {
1461
1492
  const storeRecord = cursor.value;
1462
- const change = storeRecord.record;
1493
+ const change = {
1494
+ ...storeRecord.record,
1495
+ localRevision:
1496
+ storeRecord.record.localRevision ?? storeRecord.record.revision,
1497
+ };
1463
1498
 
1464
1499
  // Look up parent record if it exists
1465
1500
  const stateRequest = stateStore.get([
@@ -1599,120 +1634,6 @@ class IndexedDBStorage {
1599
1634
  });
1600
1635
  }
1601
1636
 
1602
- async syncRebasePendingOutgoingRecords(revision) {
1603
- if (!this.db) {
1604
- throw new StorageError("Database not initialized");
1605
- }
1606
-
1607
- return new Promise((resolve, reject) => {
1608
- const transaction = this.db.transaction(
1609
- ["sync_outgoing", "sync_revision"],
1610
- "readwrite"
1611
- );
1612
- const outgoingStore = transaction.objectStore("sync_outgoing");
1613
- const revisionStore = transaction.objectStore("sync_revision");
1614
-
1615
- // Get the last committed revision from sync_revision
1616
- const getRevisionRequest = revisionStore.get(1);
1617
-
1618
- getRevisionRequest.onsuccess = () => {
1619
- const revisionData = getRevisionRequest.result || {
1620
- id: 1,
1621
- revision: "0",
1622
- };
1623
- const lastRevision = BigInt(revisionData.revision);
1624
-
1625
- // Calculate the difference
1626
- const diff = revision > lastRevision ? revision - lastRevision : BigInt(0);
1627
-
1628
- // Helper to update sync_revision within the same transaction so retries are idempotent
1629
- const updateSyncRevision = () => {
1630
- if (revision > lastRevision) {
1631
- revisionStore.put({ id: 1, revision: revision.toString() });
1632
- }
1633
- };
1634
-
1635
- if (diff <= BigInt(0)) {
1636
- updateSyncRevision();
1637
- resolve();
1638
- return;
1639
- }
1640
-
1641
- // Get all records from sync_outgoing and update their revisions
1642
- const getAllRequest = outgoingStore.getAll();
1643
-
1644
- getAllRequest.onsuccess = () => {
1645
- const records = getAllRequest.result;
1646
-
1647
- if (records.length === 0) {
1648
- updateSyncRevision();
1649
- resolve();
1650
- return;
1651
- }
1652
-
1653
- let updatesCompleted = 0;
1654
-
1655
- for (const storeRecord of records) {
1656
- // Delete the old record
1657
- const oldKey = [
1658
- storeRecord.type,
1659
- storeRecord.dataId,
1660
- storeRecord.revision,
1661
- ];
1662
- outgoingStore.delete(oldKey);
1663
-
1664
- // Update revision in both the key and the nested record
1665
- const newRevision = storeRecord.record.revision + diff;
1666
- const updatedRecord = {
1667
- type: storeRecord.type,
1668
- dataId: storeRecord.dataId,
1669
- revision: Number(newRevision),
1670
- record: {
1671
- ...storeRecord.record,
1672
- revision: newRevision,
1673
- },
1674
- };
1675
-
1676
- // Add the updated record
1677
- const putRequest = outgoingStore.put(updatedRecord);
1678
-
1679
- putRequest.onsuccess = () => {
1680
- updatesCompleted++;
1681
- if (updatesCompleted === records.length) {
1682
- updateSyncRevision();
1683
- resolve();
1684
- }
1685
- };
1686
-
1687
- putRequest.onerror = (event) => {
1688
- reject(
1689
- new StorageError(
1690
- `Failed to rebase outgoing record: ${event.target.error.message}`
1691
- )
1692
- );
1693
- };
1694
- }
1695
- };
1696
-
1697
- getAllRequest.onerror = (event) => {
1698
- reject(
1699
- new StorageError(
1700
- `Failed to get outgoing records for rebase: ${event.target.error.message}`
1701
- )
1702
- );
1703
- };
1704
- };
1705
-
1706
- getRevisionRequest.onerror = (event) => {
1707
- reject(
1708
- new StorageError(
1709
- `Failed to get last revision: ${event.target.error.message}`
1710
- )
1711
- );
1712
- };
1713
- });
1714
- }
1715
-
1716
1637
  async syncGetIncomingRecords(limit) {
1717
1638
  if (!this.db) {
1718
1639
  throw new StorageError("Database not initialized");
@@ -1802,7 +1723,11 @@ class IndexedDBStorage {
1802
1723
  const cursor = event.target.result;
1803
1724
  if (cursor) {
1804
1725
  const storeRecord = cursor.value;
1805
- const change = storeRecord.record;
1726
+ const change = {
1727
+ ...storeRecord.record,
1728
+ localRevision:
1729
+ storeRecord.record.localRevision ?? storeRecord.record.revision,
1730
+ };
1806
1731
 
1807
1732
  // Get the parent record
1808
1733
  const stateRequest = stateStore.get([
@@ -1947,14 +1872,15 @@ class IndexedDBStorage {
1947
1872
  // Filter by payment details. If any filter matches, we include the payment
1948
1873
  let paymentDetailsFilterMatches = false;
1949
1874
  for (const paymentDetailsFilter of request.paymentDetailsFilter) {
1950
- // Filter by Spark HTLC status
1875
+ // Filter by HTLC status (Spark or Lightning)
1951
1876
  if (
1952
- paymentDetailsFilter.type === "spark" &&
1877
+ (paymentDetailsFilter.type === "spark" ||
1878
+ paymentDetailsFilter.type === "lightning") &&
1953
1879
  paymentDetailsFilter.htlcStatus != null &&
1954
1880
  paymentDetailsFilter.htlcStatus.length > 0
1955
1881
  ) {
1956
1882
  if (
1957
- details.type !== "spark" ||
1883
+ details.type !== paymentDetailsFilter.type ||
1958
1884
  !details.htlcDetails ||
1959
1885
  !paymentDetailsFilter.htlcStatus.includes(
1960
1886
  details.htlcDetails.status
@@ -2008,6 +1934,7 @@ class IndexedDBStorage {
2008
1934
  }
2009
1935
  }
2010
1936
 
1937
+
2011
1938
  paymentDetailsFilterMatches = true;
2012
1939
  break;
2013
1940
  }
@@ -2087,6 +2014,12 @@ class IndexedDBStorage {
2087
2014
  }
2088
2015
  }
2089
2016
 
2017
+ if (details && details.type === "lightning" && !details.htlcDetails) {
2018
+ throw new StorageError(
2019
+ `htlc_details is required for Lightning payment ${payment.id}`
2020
+ );
2021
+ }
2022
+
2090
2023
  if (metadata && details) {
2091
2024
  if (details.type == "lightning") {
2092
2025
  if (metadata.lnurlDescription && !details.description) {
@@ -2146,7 +2079,7 @@ class IndexedDBStorage {
2146
2079
  if (
2147
2080
  !payment.details ||
2148
2081
  payment.details.type !== "lightning" ||
2149
- !payment.details.paymentHash
2082
+ !payment.details.htlcDetails?.paymentHash
2150
2083
  ) {
2151
2084
  return Promise.resolve(payment);
2152
2085
  }
@@ -2157,7 +2090,7 @@ class IndexedDBStorage {
2157
2090
 
2158
2091
  return new Promise((resolve, reject) => {
2159
2092
  const lnurlReceiveRequest = lnurlReceiveMetadataStore.get(
2160
- payment.details.paymentHash
2093
+ payment.details.htlcDetails.paymentHash
2161
2094
  );
2162
2095
 
2163
2096
  lnurlReceiveRequest.onsuccess = () => {
@@ -2193,4 +2126,4 @@ export async function createDefaultStorage(
2193
2126
  return storage;
2194
2127
  }
2195
2128
 
2196
- export { IndexedDBStorage, StorageError };
2129
+ export { IndexedDBStorage, MigrationManager, StorageError };