@breeztech/breez-sdk-spark 0.15.1 → 0.17.0
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/breez-sdk-spark.tgz +0 -0
- package/bundler/breez_sdk_spark_wasm.d.ts +604 -237
- package/bundler/breez_sdk_spark_wasm.js +1 -1
- package/bundler/breez_sdk_spark_wasm_bg.js +729 -434
- package/bundler/breez_sdk_spark_wasm_bg.wasm +0 -0
- package/bundler/breez_sdk_spark_wasm_bg.wasm.d.ts +63 -49
- package/bundler/storage/index.js +356 -34
- package/deno/breez_sdk_spark_wasm.d.ts +604 -237
- package/deno/breez_sdk_spark_wasm.js +729 -434
- package/deno/breez_sdk_spark_wasm_bg.wasm +0 -0
- package/deno/breez_sdk_spark_wasm_bg.wasm.d.ts +63 -49
- package/nodejs/breez_sdk_spark_wasm.d.ts +604 -237
- package/nodejs/breez_sdk_spark_wasm.js +741 -441
- package/nodejs/breez_sdk_spark_wasm_bg.wasm +0 -0
- package/nodejs/breez_sdk_spark_wasm_bg.wasm.d.ts +63 -49
- package/nodejs/index.js +10 -10
- package/nodejs/index.mjs +13 -8
- package/nodejs/mysql-session-store/errors.cjs +13 -0
- package/nodejs/{mysql-session-manager → mysql-session-store}/index.cjs +24 -21
- package/nodejs/{mysql-session-manager → mysql-session-store}/migrations.cjs +17 -11
- package/nodejs/mysql-session-store/package.json +9 -0
- package/nodejs/mysql-storage/index.cjs +358 -125
- package/nodejs/mysql-storage/migrations.cjs +67 -2
- package/nodejs/mysql-token-store/index.cjs +99 -79
- package/nodejs/mysql-token-store/migrations.cjs +59 -2
- package/nodejs/mysql-tree-store/index.cjs +15 -9
- package/nodejs/mysql-tree-store/migrations.cjs +16 -2
- package/nodejs/package.json +2 -2
- package/nodejs/postgres-session-store/errors.cjs +13 -0
- package/nodejs/{postgres-session-manager → postgres-session-store}/index.cjs +23 -23
- package/nodejs/{postgres-session-manager → postgres-session-store}/migrations.cjs +14 -14
- package/nodejs/postgres-session-store/package.json +9 -0
- package/nodejs/postgres-storage/index.cjs +296 -119
- package/nodejs/postgres-storage/migrations.cjs +51 -0
- package/nodejs/postgres-token-store/index.cjs +89 -64
- package/nodejs/postgres-token-store/migrations.cjs +44 -0
- package/nodejs/storage/index.cjs +285 -125
- package/nodejs/storage/migrations.cjs +47 -0
- package/package.json +6 -1
- package/ssr/index.js +57 -28
- package/web/breez_sdk_spark_wasm.d.ts +667 -286
- package/web/breez_sdk_spark_wasm.js +729 -434
- package/web/breez_sdk_spark_wasm_bg.wasm +0 -0
- package/web/breez_sdk_spark_wasm_bg.wasm.d.ts +63 -49
- package/web/passkey-prf-provider/index.d.ts +203 -0
- package/web/passkey-prf-provider/index.js +733 -0
- package/web/storage/index.js +356 -34
- package/nodejs/mysql-session-manager/errors.cjs +0 -13
- package/nodejs/mysql-session-manager/package.json +0 -9
- package/nodejs/postgres-session-manager/errors.cjs +0 -13
- package/nodejs/postgres-session-manager/package.json +0 -9
package/nodejs/storage/index.cjs
CHANGED
|
@@ -41,7 +41,8 @@ const SELECT_PAYMENT_SQL = `
|
|
|
41
41
|
p.timestamp,
|
|
42
42
|
p.method,
|
|
43
43
|
p.withdraw_tx_id,
|
|
44
|
-
|
|
44
|
+
pd.tx_id AS deposit_tx_id,
|
|
45
|
+
pd.vout AS deposit_vout,
|
|
45
46
|
p.spark,
|
|
46
47
|
l.invoice AS lightning_invoice,
|
|
47
48
|
l.payment_hash AS lightning_payment_hash,
|
|
@@ -69,6 +70,7 @@ const SELECT_PAYMENT_SQL = `
|
|
|
69
70
|
LEFT JOIN payment_details_lightning l ON p.id = l.payment_id
|
|
70
71
|
LEFT JOIN payment_details_token t ON p.id = t.payment_id
|
|
71
72
|
LEFT JOIN payment_details_spark s ON p.id = s.payment_id
|
|
73
|
+
LEFT JOIN payment_details_deposit pd ON p.id = pd.payment_id
|
|
72
74
|
LEFT JOIN payment_metadata pm ON p.id = pm.payment_id
|
|
73
75
|
LEFT JOIN lnurl_receive_metadata lrm ON l.payment_hash = lrm.payment_hash`;
|
|
74
76
|
|
|
@@ -204,6 +206,14 @@ class SqliteStorage {
|
|
|
204
206
|
const allPaymentDetailsClauses = [];
|
|
205
207
|
for (const paymentDetailsFilter of request.paymentDetailsFilter) {
|
|
206
208
|
const paymentDetailsClauses = [];
|
|
209
|
+
// Base type check: ensure payment type matches the filter type
|
|
210
|
+
if (paymentDetailsFilter.type === "spark") {
|
|
211
|
+
paymentDetailsClauses.push("p.spark = 1");
|
|
212
|
+
} else if (paymentDetailsFilter.type === "token") {
|
|
213
|
+
paymentDetailsClauses.push("p.spark IS NULL AND t.tx_hash IS NOT NULL");
|
|
214
|
+
} else if (paymentDetailsFilter.type === "lightning") {
|
|
215
|
+
paymentDetailsClauses.push("l.htlc_status IS NOT NULL");
|
|
216
|
+
}
|
|
207
217
|
// Filter by HTLC status (Spark or Lightning)
|
|
208
218
|
const htlcAlias =
|
|
209
219
|
paymentDetailsFilter.type === "spark" ? "s"
|
|
@@ -230,20 +240,35 @@ class SqliteStorage {
|
|
|
230
240
|
}
|
|
231
241
|
params.push(...paymentDetailsFilter.htlcStatus);
|
|
232
242
|
}
|
|
233
|
-
// Filter by
|
|
243
|
+
// Filter by conversion type + status
|
|
234
244
|
if (
|
|
235
|
-
(paymentDetailsFilter.type === "spark" ||
|
|
236
|
-
paymentDetailsFilter.
|
|
245
|
+
(paymentDetailsFilter.type === "spark" ||
|
|
246
|
+
paymentDetailsFilter.type === "token" ||
|
|
247
|
+
paymentDetailsFilter.type === "lightning") &&
|
|
248
|
+
paymentDetailsFilter.conversionFilter !== undefined
|
|
237
249
|
) {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
250
|
+
// Lightning carries the Boltz conversion; its `conversion_info.type`
|
|
251
|
+
// is the authoritative discriminator, so no payment-type column check.
|
|
252
|
+
const typeCheck =
|
|
253
|
+
paymentDetailsFilter.type === "spark"
|
|
254
|
+
? "p.spark = 1"
|
|
255
|
+
: paymentDetailsFilter.type === "token"
|
|
256
|
+
? "p.spark IS NULL"
|
|
257
|
+
: null;
|
|
258
|
+
let statusClause;
|
|
259
|
+
if (paymentDetailsFilter.conversionFilter === "ammRefundNeeded") {
|
|
260
|
+
statusClause = "json_extract(pm.conversion_info, '$.type') = 'amm' AND json_extract(pm.conversion_info, '$.status') = 'refundNeeded'";
|
|
261
|
+
} else if (paymentDetailsFilter.conversionFilter === "orchestraPending") {
|
|
262
|
+
statusClause = "json_extract(pm.conversion_info, '$.type') = 'orchestra' AND json_extract(pm.conversion_info, '$.status') NOT IN ('completed', 'failed', 'refunded')";
|
|
263
|
+
} else if (paymentDetailsFilter.conversionFilter === "boltzPending") {
|
|
264
|
+
statusClause = "json_extract(pm.conversion_info, '$.type') = 'boltz' AND json_extract(pm.conversion_info, '$.status') NOT IN ('completed', 'failed', 'refunded')";
|
|
265
|
+
}
|
|
266
|
+
if (statusClause) {
|
|
267
|
+
const prefix = typeCheck ? `${typeCheck} AND ` : "";
|
|
268
|
+
paymentDetailsClauses.push(
|
|
269
|
+
`${prefix}pm.conversion_info IS NOT NULL AND ${statusClause}`
|
|
270
|
+
);
|
|
271
|
+
}
|
|
247
272
|
}
|
|
248
273
|
// Filter by token transaction hash
|
|
249
274
|
if (
|
|
@@ -313,129 +338,180 @@ class SqliteStorage {
|
|
|
313
338
|
}
|
|
314
339
|
}
|
|
315
340
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
new StorageError("Payment cannot be null or undefined")
|
|
321
|
-
);
|
|
322
|
-
}
|
|
341
|
+
async applyPaymentUpdate(payment) {
|
|
342
|
+
if (!payment) {
|
|
343
|
+
throw new StorageError("Payment cannot be null or undefined");
|
|
344
|
+
}
|
|
323
345
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
ON CONFLICT(id) DO UPDATE SET
|
|
328
|
-
payment_type=excluded.payment_type,
|
|
329
|
-
status=excluded.status,
|
|
330
|
-
amount=excluded.amount,
|
|
331
|
-
fees=excluded.fees,
|
|
332
|
-
timestamp=excluded.timestamp,
|
|
333
|
-
method=excluded.method,
|
|
334
|
-
withdraw_tx_id=excluded.withdraw_tx_id,
|
|
335
|
-
deposit_tx_id=excluded.deposit_tx_id,
|
|
336
|
-
spark=excluded.spark`
|
|
337
|
-
);
|
|
338
|
-
const lightningInsert = this.db.prepare(
|
|
339
|
-
`INSERT INTO payment_details_lightning
|
|
340
|
-
(payment_id, invoice, payment_hash, destination_pubkey, description, preimage, htlc_status, htlc_expiry_time)
|
|
341
|
-
VALUES (@id, @invoice, @paymentHash, @destinationPubkey, @description, @preimage, @htlcStatus, @htlcExpiryTime)
|
|
342
|
-
ON CONFLICT(payment_id) DO UPDATE SET
|
|
343
|
-
invoice=excluded.invoice,
|
|
344
|
-
payment_hash=excluded.payment_hash,
|
|
345
|
-
destination_pubkey=excluded.destination_pubkey,
|
|
346
|
-
description=excluded.description,
|
|
347
|
-
preimage=COALESCE(excluded.preimage, payment_details_lightning.preimage),
|
|
348
|
-
htlc_status=COALESCE(excluded.htlc_status, payment_details_lightning.htlc_status),
|
|
349
|
-
htlc_expiry_time=COALESCE(excluded.htlc_expiry_time, payment_details_lightning.htlc_expiry_time)`
|
|
350
|
-
);
|
|
351
|
-
const tokenInsert = this.db.prepare(
|
|
352
|
-
`INSERT INTO payment_details_token
|
|
353
|
-
(payment_id, metadata, tx_hash, tx_type, invoice_details)
|
|
354
|
-
VALUES (@id, @metadata, @txHash, @txType, @invoiceDetails)
|
|
355
|
-
ON CONFLICT(payment_id) DO UPDATE SET
|
|
356
|
-
metadata=excluded.metadata,
|
|
357
|
-
tx_hash=excluded.tx_hash,
|
|
358
|
-
tx_type=excluded.tx_type,
|
|
359
|
-
invoice_details=COALESCE(excluded.invoice_details, payment_details_token.invoice_details)`
|
|
360
|
-
);
|
|
361
|
-
const sparkInsert = this.db.prepare(
|
|
362
|
-
`INSERT INTO payment_details_spark
|
|
363
|
-
(payment_id, invoice_details, htlc_details)
|
|
364
|
-
VALUES (@id, @invoiceDetails, @htlcDetails)
|
|
365
|
-
ON CONFLICT(payment_id) DO UPDATE SET
|
|
366
|
-
invoice_details=COALESCE(excluded.invoice_details, payment_details_spark.invoice_details),
|
|
367
|
-
htlc_details=COALESCE(excluded.htlc_details, payment_details_spark.htlc_details)`
|
|
346
|
+
try {
|
|
347
|
+
const selectStatus = this.db.prepare(
|
|
348
|
+
"SELECT status FROM payments WHERE id = ?"
|
|
368
349
|
);
|
|
350
|
+
let shouldEmit = false;
|
|
369
351
|
const transaction = this.db.transaction(() => {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
if (
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
? JSON.stringify(payment.details.invoiceDetails)
|
|
394
|
-
: null,
|
|
395
|
-
htlcDetails: payment.details.htlcDetails
|
|
396
|
-
? JSON.stringify(payment.details.htlcDetails)
|
|
397
|
-
: null,
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
if (payment.details?.type === "lightning") {
|
|
402
|
-
lightningInsert.run({
|
|
403
|
-
id: payment.id,
|
|
404
|
-
invoice: payment.details.invoice,
|
|
405
|
-
paymentHash: payment.details.htlcDetails.paymentHash,
|
|
406
|
-
destinationPubkey: payment.details.destinationPubkey,
|
|
407
|
-
description: payment.details.description,
|
|
408
|
-
preimage: payment.details.htlcDetails?.preimage,
|
|
409
|
-
htlcStatus: payment.details.htlcDetails?.status ?? null,
|
|
410
|
-
htlcExpiryTime: payment.details.htlcDetails?.expiryTime ?? 0,
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
if (payment.details?.type === "token") {
|
|
415
|
-
tokenInsert.run({
|
|
416
|
-
id: payment.id,
|
|
417
|
-
metadata: JSON.stringify(payment.details.metadata),
|
|
418
|
-
txHash: payment.details.txHash,
|
|
419
|
-
txType: payment.details.txType,
|
|
420
|
-
invoiceDetails: payment.details.invoiceDetails
|
|
421
|
-
? JSON.stringify(payment.details.invoiceDetails)
|
|
422
|
-
: null,
|
|
423
|
-
});
|
|
352
|
+
const row = selectStatus.get(payment.id);
|
|
353
|
+
const stored = row
|
|
354
|
+
? this._normalizePaymentStatus(row.status)
|
|
355
|
+
: null;
|
|
356
|
+
const next = this._normalizePaymentStatus(payment.status);
|
|
357
|
+
|
|
358
|
+
if (stored == null) {
|
|
359
|
+
this._runPaymentUpsert(payment);
|
|
360
|
+
shouldEmit = true;
|
|
361
|
+
} else if (stored === next) {
|
|
362
|
+
console.debug(
|
|
363
|
+
`Skipping redundant payment event: id=${payment.id} status=${next}`
|
|
364
|
+
);
|
|
365
|
+
this._runPaymentUpsert(payment);
|
|
366
|
+
shouldEmit = false;
|
|
367
|
+
} else if (this._isFinalPaymentStatus(stored)) {
|
|
368
|
+
console.warn(
|
|
369
|
+
`Skipping payment update (would replace terminal status): id=${payment.id} stored=${stored} new=${next}`
|
|
370
|
+
);
|
|
371
|
+
shouldEmit = false;
|
|
372
|
+
} else {
|
|
373
|
+
this._runPaymentUpsert(payment);
|
|
374
|
+
shouldEmit = true;
|
|
424
375
|
}
|
|
425
376
|
});
|
|
426
377
|
|
|
427
|
-
transaction();
|
|
428
|
-
return
|
|
378
|
+
transaction.immediate();
|
|
379
|
+
return shouldEmit;
|
|
429
380
|
} catch (error) {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
error
|
|
434
|
-
)
|
|
381
|
+
throw new StorageError(
|
|
382
|
+
`Failed to apply payment update '${payment.id}': ${error.message}`,
|
|
383
|
+
error
|
|
435
384
|
);
|
|
436
385
|
}
|
|
437
386
|
}
|
|
438
387
|
|
|
388
|
+
_runPaymentUpsert(payment) {
|
|
389
|
+
const paymentInsert = this.db.prepare(
|
|
390
|
+
`INSERT INTO payments (id, payment_type, status, amount, fees, timestamp, method, withdraw_tx_id, spark)
|
|
391
|
+
VALUES (@id, @paymentType, @status, @amount, @fees, @timestamp, @method, @withdrawTxId, @spark)
|
|
392
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
393
|
+
payment_type=excluded.payment_type,
|
|
394
|
+
status=excluded.status,
|
|
395
|
+
amount=excluded.amount,
|
|
396
|
+
fees=excluded.fees,
|
|
397
|
+
timestamp=excluded.timestamp,
|
|
398
|
+
method=excluded.method,
|
|
399
|
+
withdraw_tx_id=excluded.withdraw_tx_id,
|
|
400
|
+
spark=excluded.spark`
|
|
401
|
+
);
|
|
402
|
+
const depositInsert = this.db.prepare(
|
|
403
|
+
`INSERT INTO payment_details_deposit
|
|
404
|
+
(payment_id, tx_id, vout)
|
|
405
|
+
VALUES (@id, @txId, @vout)
|
|
406
|
+
ON CONFLICT(payment_id) DO UPDATE SET
|
|
407
|
+
tx_id=excluded.tx_id,
|
|
408
|
+
vout=excluded.vout`
|
|
409
|
+
);
|
|
410
|
+
const lightningInsert = this.db.prepare(
|
|
411
|
+
`INSERT INTO payment_details_lightning
|
|
412
|
+
(payment_id, invoice, payment_hash, destination_pubkey, description, preimage, htlc_status, htlc_expiry_time)
|
|
413
|
+
VALUES (@id, @invoice, @paymentHash, @destinationPubkey, @description, @preimage, @htlcStatus, @htlcExpiryTime)
|
|
414
|
+
ON CONFLICT(payment_id) DO UPDATE SET
|
|
415
|
+
invoice=excluded.invoice,
|
|
416
|
+
payment_hash=excluded.payment_hash,
|
|
417
|
+
destination_pubkey=excluded.destination_pubkey,
|
|
418
|
+
description=excluded.description,
|
|
419
|
+
preimage=COALESCE(excluded.preimage, payment_details_lightning.preimage),
|
|
420
|
+
htlc_status=COALESCE(excluded.htlc_status, payment_details_lightning.htlc_status),
|
|
421
|
+
htlc_expiry_time=COALESCE(excluded.htlc_expiry_time, payment_details_lightning.htlc_expiry_time)`
|
|
422
|
+
);
|
|
423
|
+
const tokenInsert = this.db.prepare(
|
|
424
|
+
`INSERT INTO payment_details_token
|
|
425
|
+
(payment_id, metadata, tx_hash, tx_type, invoice_details)
|
|
426
|
+
VALUES (@id, @metadata, @txHash, @txType, @invoiceDetails)
|
|
427
|
+
ON CONFLICT(payment_id) DO UPDATE SET
|
|
428
|
+
metadata=excluded.metadata,
|
|
429
|
+
tx_hash=excluded.tx_hash,
|
|
430
|
+
tx_type=excluded.tx_type,
|
|
431
|
+
invoice_details=COALESCE(excluded.invoice_details, payment_details_token.invoice_details)`
|
|
432
|
+
);
|
|
433
|
+
const sparkInsert = this.db.prepare(
|
|
434
|
+
`INSERT INTO payment_details_spark
|
|
435
|
+
(payment_id, invoice_details, htlc_details)
|
|
436
|
+
VALUES (@id, @invoiceDetails, @htlcDetails)
|
|
437
|
+
ON CONFLICT(payment_id) DO UPDATE SET
|
|
438
|
+
invoice_details=COALESCE(excluded.invoice_details, payment_details_spark.invoice_details),
|
|
439
|
+
htlc_details=COALESCE(excluded.htlc_details, payment_details_spark.htlc_details)`
|
|
440
|
+
);
|
|
441
|
+
|
|
442
|
+
paymentInsert.run({
|
|
443
|
+
id: payment.id,
|
|
444
|
+
paymentType: payment.paymentType,
|
|
445
|
+
status: payment.status,
|
|
446
|
+
amount: payment.amount.toString(),
|
|
447
|
+
fees: payment.fees.toString(),
|
|
448
|
+
timestamp: payment.timestamp,
|
|
449
|
+
method: payment.method ? JSON.stringify(payment.method) : null,
|
|
450
|
+
withdrawTxId:
|
|
451
|
+
payment.details?.type === "withdraw" ? payment.details.txId : null,
|
|
452
|
+
spark: payment.details?.type === "spark" ? 1 : null,
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
if (payment.details?.type === "deposit") {
|
|
456
|
+
depositInsert.run({
|
|
457
|
+
id: payment.id,
|
|
458
|
+
txId: payment.details.txId,
|
|
459
|
+
vout: payment.details.vout,
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (
|
|
464
|
+
payment.details?.type === "spark" &&
|
|
465
|
+
(payment.details.invoiceDetails != null ||
|
|
466
|
+
payment.details.htlcDetails != null)
|
|
467
|
+
) {
|
|
468
|
+
sparkInsert.run({
|
|
469
|
+
id: payment.id,
|
|
470
|
+
invoiceDetails: payment.details.invoiceDetails
|
|
471
|
+
? JSON.stringify(payment.details.invoiceDetails)
|
|
472
|
+
: null,
|
|
473
|
+
htlcDetails: payment.details.htlcDetails
|
|
474
|
+
? JSON.stringify(payment.details.htlcDetails)
|
|
475
|
+
: null,
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
if (payment.details?.type === "lightning") {
|
|
480
|
+
lightningInsert.run({
|
|
481
|
+
id: payment.id,
|
|
482
|
+
invoice: payment.details.invoice,
|
|
483
|
+
paymentHash: payment.details.htlcDetails.paymentHash,
|
|
484
|
+
destinationPubkey: payment.details.destinationPubkey,
|
|
485
|
+
description: payment.details.description,
|
|
486
|
+
preimage: payment.details.htlcDetails?.preimage,
|
|
487
|
+
htlcStatus: payment.details.htlcDetails?.status ?? null,
|
|
488
|
+
htlcExpiryTime: payment.details.htlcDetails?.expiryTime ?? 0,
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
if (payment.details?.type === "token") {
|
|
493
|
+
tokenInsert.run({
|
|
494
|
+
id: payment.id,
|
|
495
|
+
metadata: JSON.stringify(payment.details.metadata),
|
|
496
|
+
txHash: payment.details.txHash,
|
|
497
|
+
txType: payment.details.txType,
|
|
498
|
+
invoiceDetails: payment.details.invoiceDetails
|
|
499
|
+
? JSON.stringify(payment.details.invoiceDetails)
|
|
500
|
+
: null,
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
_normalizePaymentStatus(status) {
|
|
506
|
+
return typeof status === "string" ? status.toLowerCase() : status;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
_isFinalPaymentStatus(status) {
|
|
510
|
+
const normalized = this._normalizePaymentStatus(status);
|
|
511
|
+
return normalized === "completed" || normalized === "failed";
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
|
|
439
515
|
getPaymentById(id) {
|
|
440
516
|
try {
|
|
441
517
|
if (!id) {
|
|
@@ -760,6 +836,17 @@ class SqliteStorage {
|
|
|
760
836
|
senderComment: row.lnurl_sender_comment || null,
|
|
761
837
|
};
|
|
762
838
|
}
|
|
839
|
+
|
|
840
|
+
if (row.conversion_info) {
|
|
841
|
+
try {
|
|
842
|
+
details.conversionInfo = JSON.parse(row.conversion_info);
|
|
843
|
+
} catch (e) {
|
|
844
|
+
throw new StorageError(
|
|
845
|
+
`Failed to parse conversion_info JSON for payment ${row.id}: ${e.message}`,
|
|
846
|
+
e
|
|
847
|
+
);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
763
850
|
} else if (row.withdraw_tx_id) {
|
|
764
851
|
details = {
|
|
765
852
|
type: "withdraw",
|
|
@@ -769,6 +856,7 @@ class SqliteStorage {
|
|
|
769
856
|
details = {
|
|
770
857
|
type: "deposit",
|
|
771
858
|
txId: row.deposit_tx_id,
|
|
859
|
+
vout: row.deposit_vout,
|
|
772
860
|
};
|
|
773
861
|
} else if (row.spark) {
|
|
774
862
|
details = {
|
|
@@ -1324,6 +1412,78 @@ class SqliteStorage {
|
|
|
1324
1412
|
);
|
|
1325
1413
|
}
|
|
1326
1414
|
}
|
|
1415
|
+
|
|
1416
|
+
// ===== Cross-Chain Swap Operations =====
|
|
1417
|
+
|
|
1418
|
+
setCrossChainSwap(swap) {
|
|
1419
|
+
try {
|
|
1420
|
+
const stmt = this.db.prepare(`
|
|
1421
|
+
INSERT INTO cross_chain_swaps (provider, id, is_terminal, updated_at, data, secrets)
|
|
1422
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
1423
|
+
ON CONFLICT(provider, id) DO UPDATE SET
|
|
1424
|
+
is_terminal = excluded.is_terminal,
|
|
1425
|
+
updated_at = excluded.updated_at,
|
|
1426
|
+
data = excluded.data,
|
|
1427
|
+
secrets = excluded.secrets
|
|
1428
|
+
`);
|
|
1429
|
+
stmt.run(
|
|
1430
|
+
swap.provider,
|
|
1431
|
+
swap.id,
|
|
1432
|
+
swap.isTerminal ? 1 : 0,
|
|
1433
|
+
swap.updatedAt,
|
|
1434
|
+
swap.data,
|
|
1435
|
+
swap.secrets
|
|
1436
|
+
);
|
|
1437
|
+
return Promise.resolve();
|
|
1438
|
+
} catch (error) {
|
|
1439
|
+
return Promise.reject(
|
|
1440
|
+
new StorageError(`Failed to set cross-chain swap: ${error.message}`, error)
|
|
1441
|
+
);
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
getCrossChainSwap(provider, id) {
|
|
1446
|
+
try {
|
|
1447
|
+
const stmt = this.db.prepare(
|
|
1448
|
+
`SELECT provider, id, is_terminal, updated_at, data, secrets
|
|
1449
|
+
FROM cross_chain_swaps WHERE provider = ? AND id = ?`
|
|
1450
|
+
);
|
|
1451
|
+
const row = stmt.get(provider, id);
|
|
1452
|
+
return Promise.resolve(row ? crossChainSwapFromRow(row) : null);
|
|
1453
|
+
} catch (error) {
|
|
1454
|
+
return Promise.reject(
|
|
1455
|
+
new StorageError(`Failed to get cross-chain swap: ${error.message}`, error)
|
|
1456
|
+
);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
listActiveCrossChainSwaps(provider) {
|
|
1461
|
+
try {
|
|
1462
|
+
const stmt = this.db.prepare(
|
|
1463
|
+
`SELECT provider, id, is_terminal, updated_at, data, secrets
|
|
1464
|
+
FROM cross_chain_swaps WHERE provider = ? AND is_terminal = 0`
|
|
1465
|
+
);
|
|
1466
|
+
const rows = stmt.all(provider);
|
|
1467
|
+
return Promise.resolve(rows.map(crossChainSwapFromRow));
|
|
1468
|
+
} catch (error) {
|
|
1469
|
+
return Promise.reject(
|
|
1470
|
+
new StorageError(`Failed to list active cross-chain swaps: ${error.message}`, error)
|
|
1471
|
+
);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
/// Maps a `cross_chain_swaps` row to a StoredCrossChainSwap, parsing `data` and
|
|
1477
|
+
/// the is_terminal flag back into the camelCase shape the SDK expects.
|
|
1478
|
+
function crossChainSwapFromRow(row) {
|
|
1479
|
+
return {
|
|
1480
|
+
provider: row.provider,
|
|
1481
|
+
id: row.id,
|
|
1482
|
+
isTerminal: row.is_terminal !== 0,
|
|
1483
|
+
updatedAt: Number(row.updated_at),
|
|
1484
|
+
data: row.data,
|
|
1485
|
+
secrets: row.secrets,
|
|
1486
|
+
};
|
|
1327
1487
|
}
|
|
1328
1488
|
|
|
1329
1489
|
async function createDefaultStorage(dataDir, logger = null) {
|
|
@@ -433,6 +433,53 @@ class MigrationManager {
|
|
|
433
433
|
`CREATE INDEX idx_payment_metadata_payment_id ON payment_metadata(payment_id)`,
|
|
434
434
|
],
|
|
435
435
|
},
|
|
436
|
+
{
|
|
437
|
+
// Move deposit details into their own table so vout can be NOT NULL and
|
|
438
|
+
// the schema matches payment_details_lightning / _token / _spark. We can't
|
|
439
|
+
// safely backfill the new table from the dropped deposit_tx_id column: we
|
|
440
|
+
// never stored the original SSP output_index, and vout=0 is a valid output
|
|
441
|
+
// index, so defaulting would silently mislabel. Drop the column and leave
|
|
442
|
+
// the payments row in place. The read path sees an unjoined deposit row
|
|
443
|
+
// as `details: None` until the resync re-fetches the SSP user_request and
|
|
444
|
+
// the upsert inserts the new details row.
|
|
445
|
+
name: "Move deposit details into payment_details_deposit table",
|
|
446
|
+
sql: [
|
|
447
|
+
`CREATE TABLE payment_details_deposit (
|
|
448
|
+
payment_id TEXT PRIMARY KEY,
|
|
449
|
+
tx_id TEXT NOT NULL,
|
|
450
|
+
vout INTEGER NOT NULL,
|
|
451
|
+
FOREIGN KEY (payment_id) REFERENCES payments(id) ON DELETE CASCADE
|
|
452
|
+
)`,
|
|
453
|
+
`ALTER TABLE payments DROP COLUMN deposit_tx_id`,
|
|
454
|
+
`UPDATE settings
|
|
455
|
+
SET value = json_set(value, '$.offset', 0)
|
|
456
|
+
WHERE key = 'sync_offset' AND json_valid(value)`,
|
|
457
|
+
],
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
name: "Backfill conversion_info type discriminator",
|
|
461
|
+
sql: `UPDATE payment_metadata SET conversion_info = json_set(conversion_info, '$.type', 'amm') WHERE conversion_info IS NOT NULL AND json_extract(conversion_info, '$.type') IS NULL`,
|
|
462
|
+
},
|
|
463
|
+
{
|
|
464
|
+
// Cross-chain swap rows, synced for cross-instance recovery. Shared
|
|
465
|
+
// across providers, discriminated by `provider`. `data` is
|
|
466
|
+
// provider-opaque JSON; `secrets` is provider-opaque ciphertext (empty
|
|
467
|
+
// when the provider has none).
|
|
468
|
+
name: "Create cross_chain_swaps table",
|
|
469
|
+
sql: [
|
|
470
|
+
`CREATE TABLE cross_chain_swaps (
|
|
471
|
+
provider TEXT NOT NULL,
|
|
472
|
+
id TEXT NOT NULL,
|
|
473
|
+
is_terminal INTEGER NOT NULL,
|
|
474
|
+
updated_at INTEGER NOT NULL,
|
|
475
|
+
data TEXT NOT NULL,
|
|
476
|
+
secrets TEXT NOT NULL,
|
|
477
|
+
PRIMARY KEY (provider, id)
|
|
478
|
+
)`,
|
|
479
|
+
`CREATE INDEX idx_cross_chain_swaps_provider_is_terminal
|
|
480
|
+
ON cross_chain_swaps(provider, is_terminal)`,
|
|
481
|
+
],
|
|
482
|
+
},
|
|
436
483
|
];
|
|
437
484
|
}
|
|
438
485
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@breeztech/breez-sdk-spark",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Breez Spark SDK",
|
|
5
5
|
"repository": "https://github.com/breez/spark-sdk",
|
|
6
6
|
"author": "Breez <contact@breez.technology> (https://github.com/breez)",
|
|
@@ -23,6 +23,11 @@
|
|
|
23
23
|
"./nodejs": "./nodejs/index.js",
|
|
24
24
|
"./web": "./web/index.js",
|
|
25
25
|
"./ssr": "./ssr/index.js",
|
|
26
|
+
"./passkey-prf-provider": {
|
|
27
|
+
"types": "./web/passkey-prf-provider/index.d.ts",
|
|
28
|
+
"import": "./web/passkey-prf-provider/index.js",
|
|
29
|
+
"default": "./web/passkey-prf-provider/index.js"
|
|
30
|
+
},
|
|
26
31
|
".": {
|
|
27
32
|
"node": {
|
|
28
33
|
"import": "./nodejs/index.mjs",
|