@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.
@@ -221,27 +221,6 @@ function debugString(val) {
221
221
  // TODO we could test for more things here, like `Set`s and `Map`s.
222
222
  return className;
223
223
  }
224
- /**
225
- * @param {Config} config
226
- * @param {ExternalSigner} signer
227
- * @param {string} storage_dir
228
- * @returns {Promise<BreezSdk>}
229
- */
230
- export function connectWithSigner(config, signer, storage_dir) {
231
- const ptr0 = passStringToWasm0(storage_dir, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
232
- const len0 = WASM_VECTOR_LEN;
233
- const ret = wasm.connectWithSigner(config, signer, ptr0, len0);
234
- return ret;
235
- }
236
-
237
- /**
238
- * @param {ConnectRequest} request
239
- * @returns {Promise<BreezSdk>}
240
- */
241
- export function connect(request) {
242
- const ret = wasm.connect(request);
243
- return ret;
244
- }
245
224
 
246
225
  function takeFromExternrefTable0(idx) {
247
226
  const value = wasm.__wbindgen_export_5.get(idx);
@@ -267,6 +246,15 @@ export function defaultExternalSigner(mnemonic, passphrase, network, key_set_con
267
246
  return DefaultSigner.__wrap(ret[0]);
268
247
  }
269
248
 
249
+ /**
250
+ * @param {ConnectRequest} request
251
+ * @returns {Promise<BreezSdk>}
252
+ */
253
+ export function connect(request) {
254
+ const ret = wasm.connect(request);
255
+ return ret;
256
+ }
257
+
270
258
  /**
271
259
  * @param {Logger} logger
272
260
  * @param {string | null} [filter]
@@ -280,13 +268,15 @@ export function initLogging(logger, filter) {
280
268
  }
281
269
 
282
270
  /**
283
- * Creates a default external signer from a mnemonic phrase.
284
- *
285
- * This creates a signer that can be used with `connectWithSigner` or `SdkBuilder.newWithSigner`.
286
- * @returns {Promise<SparkStatus>}
271
+ * @param {Config} config
272
+ * @param {ExternalSigner} signer
273
+ * @param {string} storage_dir
274
+ * @returns {Promise<BreezSdk>}
287
275
  */
288
- export function getSparkStatus() {
289
- const ret = wasm.getSparkStatus();
276
+ export function connectWithSigner(config, signer, storage_dir) {
277
+ const ptr0 = passStringToWasm0(storage_dir, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
278
+ const len0 = WASM_VECTOR_LEN;
279
+ const ret = wasm.connectWithSigner(config, signer, ptr0, len0);
290
280
  return ret;
291
281
  }
292
282
 
@@ -299,6 +289,17 @@ export function defaultConfig(network) {
299
289
  return ret;
300
290
  }
301
291
 
292
+ /**
293
+ * Creates a default external signer from a mnemonic phrase.
294
+ *
295
+ * This creates a signer that can be used with `connectWithSigner` or `SdkBuilder.newWithSigner`.
296
+ * @returns {Promise<SparkStatus>}
297
+ */
298
+ export function getSparkStatus() {
299
+ const ret = wasm.getSparkStatus();
300
+ return ret;
301
+ }
302
+
302
303
  function passArray8ToWasm0(arg, malloc) {
303
304
  const ptr = malloc(arg.length * 1, 1) >>> 0;
304
305
  getUint8ArrayMemory0().set(arg, ptr / 1);
@@ -317,15 +318,15 @@ export function task_worker_entry_point(ptr) {
317
318
  }
318
319
 
319
320
  function __wbg_adapter_64(arg0, arg1) {
320
- wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hf2ef52c8a8b47594(arg0, arg1);
321
+ wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h127c718764a2a72f(arg0, arg1);
321
322
  }
322
323
 
323
324
  function __wbg_adapter_67(arg0, arg1, arg2) {
324
- wasm.closure1078_externref_shim(arg0, arg1, arg2);
325
+ wasm.closure1090_externref_shim(arg0, arg1, arg2);
325
326
  }
326
327
 
327
- function __wbg_adapter_287(arg0, arg1, arg2, arg3) {
328
- wasm.closure671_externref_shim(arg0, arg1, arg2, arg3);
328
+ function __wbg_adapter_285(arg0, arg1, arg2, arg3) {
329
+ wasm.closure670_externref_shim(arg0, arg1, arg2, arg3);
329
330
  }
330
331
 
331
332
  const __wbindgen_enum_ReadableStreamType = ["bytes"];
@@ -1876,7 +1877,7 @@ export function __wbg_new_23a2665fac83c611(arg0, arg1) {
1876
1877
  const a = state0.a;
1877
1878
  state0.a = 0;
1878
1879
  try {
1879
- return __wbg_adapter_287(a, state0.b, arg0, arg1);
1880
+ return __wbg_adapter_285(a, state0.b, arg0, arg1);
1880
1881
  } finally {
1881
1882
  state0.a = a;
1882
1883
  }
@@ -2288,11 +2289,6 @@ export function __wbg_syncInsertIncomingRecords_dde4039dbc9cb38f() { return hand
2288
2289
  return ret;
2289
2290
  }, arguments) };
2290
2291
 
2291
- export function __wbg_syncRebasePendingOutgoingRecords_b3441ced5dee0c8e() { return handleError(function (arg0, arg1) {
2292
- const ret = arg0.syncRebasePendingOutgoingRecords(BigInt.asUintN(64, arg1));
2293
- return ret;
2294
- }, arguments) };
2295
-
2296
2292
  export function __wbg_syncUpdateRecordFromIncoming_a76ad82592bfdcb3() { return handleError(function (arg0, arg1) {
2297
2293
  const ret = arg0.syncUpdateRecordFromIncoming(arg1);
2298
2294
  return ret;
@@ -2406,13 +2402,13 @@ export function __wbindgen_cb_drop(arg0) {
2406
2402
  return ret;
2407
2403
  };
2408
2404
 
2409
- export function __wbindgen_closure_wrapper11759(arg0, arg1, arg2) {
2410
- const ret = makeMutClosure(arg0, arg1, 848, __wbg_adapter_64);
2405
+ export function __wbindgen_closure_wrapper11879(arg0, arg1, arg2) {
2406
+ const ret = makeMutClosure(arg0, arg1, 851, __wbg_adapter_64);
2411
2407
  return ret;
2412
2408
  };
2413
2409
 
2414
- export function __wbindgen_closure_wrapper13708(arg0, arg1, arg2) {
2415
- const ret = makeMutClosure(arg0, arg1, 1079, __wbg_adapter_67);
2410
+ export function __wbindgen_closure_wrapper13824(arg0, arg1, arg2) {
2411
+ const ret = makeMutClosure(arg0, arg1, 1091, __wbg_adapter_67);
2416
2412
  return ret;
2417
2413
  };
2418
2414
 
@@ -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 };