@bopen-io/wallet-toolbox-client 1.7.19 → 1.7.20-idb-fix.16

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.
@@ -75,6 +75,16 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
75
75
  toDbTrx(stores, mode, trx) {
76
76
  if (trx) {
77
77
  const t = trx;
78
+ // Check if the transaction is still active by trying to access an object store
79
+ try {
80
+ const storeToCheck = stores[0] || this.allStores[0];
81
+ t.objectStore(storeToCheck);
82
+ }
83
+ catch (e) {
84
+ console.error(`[StorageIdb.toDbTrx] Passed transaction already finished! stores=${stores.join(',')}, mode=${mode}`);
85
+ console.error('[StorageIdb.toDbTrx] Stack trace:', new Error().stack);
86
+ throw e;
87
+ }
78
88
  return t;
79
89
  }
80
90
  else {
@@ -290,7 +300,9 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
290
300
  * @returns next funding output to add to transaction or undefined if there are none.
291
301
  */
292
302
  async allocateChangeInput(userId, basketId, targetSatoshis, exactSatoshis, excludeSending, transactionId) {
293
- const dbTrx = this.toDbTrx(['outputs', 'transactions'], 'readwrite');
303
+ // Include proven_txs and proven_tx_reqs in store list since
304
+ // findOutputs -> validateOutputScript -> getProvenOrRawTx needs both
305
+ const dbTrx = this.toDbTrx(['outputs', 'transactions', 'proven_txs', 'proven_tx_reqs'], 'readwrite');
294
306
  try {
295
307
  const txStatus = ['completed', 'unproven'];
296
308
  if (!excludeSending)
@@ -444,19 +456,33 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
444
456
  }
445
457
  async filterOutputTagMaps(args, filtered, userId) {
446
458
  var _a, _b, _c, _d;
459
+ // Pre-compute outputTagIds for this user BEFORE opening cursor.
460
+ // This avoids nested queries inside the cursor loop which cause IDB transaction timeouts.
461
+ let userOutputTagIds;
462
+ if (userId !== undefined) {
463
+ userOutputTagIds = new Set();
464
+ const userTags = await this.findOutputTags({ partial: { userId } });
465
+ for (const tag of userTags) {
466
+ userOutputTagIds.add(tag.outputTagId);
467
+ }
468
+ }
447
469
  const offset = ((_a = args.paged) === null || _a === void 0 ? void 0 : _a.offset) || 0;
448
470
  let skipped = 0;
449
471
  let count = 0;
450
472
  const dbTrx = this.toDbTrx(['output_tags_map'], 'readonly', args.trx);
473
+ const direction = args.orderDescending ? 'prev' : 'next';
451
474
  let cursor;
452
475
  if (((_b = args.partial) === null || _b === void 0 ? void 0 : _b.outputTagId) !== undefined) {
453
- cursor = await dbTrx.objectStore('output_tags_map').index('outputTagId').openCursor(args.partial.outputTagId);
476
+ cursor = await dbTrx
477
+ .objectStore('output_tags_map')
478
+ .index('outputTagId')
479
+ .openCursor(args.partial.outputTagId, direction);
454
480
  }
455
481
  else if (((_c = args.partial) === null || _c === void 0 ? void 0 : _c.outputId) !== undefined) {
456
- cursor = await dbTrx.objectStore('output_tags_map').index('outputId').openCursor(args.partial.outputId);
482
+ cursor = await dbTrx.objectStore('output_tags_map').index('outputId').openCursor(args.partial.outputId, direction);
457
483
  }
458
484
  else {
459
- cursor = await dbTrx.objectStore('output_tags_map').openCursor();
485
+ cursor = await dbTrx.objectStore('output_tags_map').openCursor(null, direction);
460
486
  }
461
487
  let firstTime = true;
462
488
  while (cursor) {
@@ -482,10 +508,8 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
482
508
  if (args.partial.isDeleted !== undefined && r.isDeleted !== args.partial.isDeleted)
483
509
  continue;
484
510
  }
485
- if (userId !== undefined && r.txid) {
486
- const count = await this.countOutputTags({ partial: { userId, outputTagId: r.outputTagId }, trx: args.trx });
487
- if (count === 0)
488
- continue;
511
+ if (userOutputTagIds !== undefined && !userOutputTagIds.has(r.outputTagId)) {
512
+ continue;
489
513
  }
490
514
  if (skipped < offset) {
491
515
  skipped++;
@@ -512,28 +536,44 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
512
536
  throw new WERR_errors_1.WERR_INVALID_PARAMETER('args.partial.rawTx', `undefined. ProvenTxReqs may not be found by rawTx value.`);
513
537
  if (args.partial.inputBEEF)
514
538
  throw new WERR_errors_1.WERR_INVALID_PARAMETER('args.partial.inputBEEF', `undefined. ProvenTxReqs may not be found by inputBEEF value.`);
539
+ // Pre-compute txids for this user's transactions BEFORE opening cursor.
540
+ // This avoids nested queries inside the cursor loop which cause IDB transaction timeouts.
541
+ let userTxIds;
542
+ if (userId !== undefined) {
543
+ userTxIds = new Set();
544
+ const userTxs = await this.findTransactions({ partial: { userId }, noRawTx: true });
545
+ for (const tx of userTxs) {
546
+ if (tx.txid) {
547
+ userTxIds.add(tx.txid);
548
+ }
549
+ }
550
+ }
515
551
  const offset = ((_a = args.paged) === null || _a === void 0 ? void 0 : _a.offset) || 0;
516
552
  let skipped = 0;
517
553
  let count = 0;
518
554
  const dbTrx = this.toDbTrx(['proven_tx_reqs'], 'readonly', args.trx);
555
+ const direction = args.orderDescending ? 'prev' : 'next';
519
556
  let cursor;
520
557
  if ((_b = args.partial) === null || _b === void 0 ? void 0 : _b.provenTxReqId) {
521
- cursor = await dbTrx.objectStore('proven_tx_reqs').openCursor(args.partial.provenTxReqId);
558
+ cursor = await dbTrx.objectStore('proven_tx_reqs').openCursor(args.partial.provenTxReqId, direction);
522
559
  }
523
560
  else if (((_c = args.partial) === null || _c === void 0 ? void 0 : _c.provenTxId) !== undefined) {
524
- cursor = await dbTrx.objectStore('proven_tx_reqs').index('provenTxId').openCursor(args.partial.provenTxId);
561
+ cursor = await dbTrx
562
+ .objectStore('proven_tx_reqs')
563
+ .index('provenTxId')
564
+ .openCursor(args.partial.provenTxId, direction);
525
565
  }
526
566
  else if (((_d = args.partial) === null || _d === void 0 ? void 0 : _d.txid) !== undefined) {
527
- cursor = await dbTrx.objectStore('proven_tx_reqs').index('txid').openCursor(args.partial.txid);
567
+ cursor = await dbTrx.objectStore('proven_tx_reqs').index('txid').openCursor(args.partial.txid, direction);
528
568
  }
529
569
  else if (((_e = args.partial) === null || _e === void 0 ? void 0 : _e.status) !== undefined) {
530
- cursor = await dbTrx.objectStore('proven_tx_reqs').index('status').openCursor(args.partial.status);
570
+ cursor = await dbTrx.objectStore('proven_tx_reqs').index('status').openCursor(args.partial.status, direction);
531
571
  }
532
572
  else if (((_f = args.partial) === null || _f === void 0 ? void 0 : _f.batch) !== undefined) {
533
- cursor = await dbTrx.objectStore('proven_tx_reqs').index('batch').openCursor(args.partial.batch);
573
+ cursor = await dbTrx.objectStore('proven_tx_reqs').index('batch').openCursor(args.partial.batch, direction);
534
574
  }
535
575
  else {
536
- cursor = await dbTrx.objectStore('proven_tx_reqs').openCursor();
576
+ cursor = await dbTrx.objectStore('proven_tx_reqs').openCursor(null, direction);
537
577
  }
538
578
  let firstTime = true;
539
579
  while (cursor) {
@@ -545,6 +585,10 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
545
585
  const r = cursor.value;
546
586
  if (args.since && args.since > r.updated_at)
547
587
  continue;
588
+ if (args.status && args.status.length > 0 && !args.status.includes(r.status))
589
+ continue;
590
+ if (args.txids && args.txids.length > 0 && !args.txids.includes(r.txid))
591
+ continue;
548
592
  if (args.partial) {
549
593
  if (args.partial.provenTxReqId && r.provenTxReqId !== args.partial.provenTxReqId)
550
594
  continue;
@@ -569,10 +613,8 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
569
613
  if (args.partial.notify && r.notify !== args.partial.notify)
570
614
  continue;
571
615
  }
572
- if (userId !== undefined && r.txid) {
573
- const count = await this.countTransactions({ partial: { userId, txid: r.txid }, trx: args.trx });
574
- if (count === 0)
575
- continue;
616
+ if (userTxIds !== undefined && r.txid && !userTxIds.has(r.txid)) {
617
+ continue;
576
618
  }
577
619
  if (skipped < offset) {
578
620
  skipped++;
@@ -599,19 +641,32 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
599
641
  throw new WERR_errors_1.WERR_INVALID_PARAMETER('args.partial.rawTx', `undefined. ProvenTxs may not be found by rawTx value.`);
600
642
  if (args.partial.merklePath)
601
643
  throw new WERR_errors_1.WERR_INVALID_PARAMETER('args.partial.merklePath', `undefined. ProvenTxs may not be found by merklePath value.`);
644
+ // Pre-compute provenTxIds for this user's transactions BEFORE opening cursor.
645
+ // This avoids nested queries inside the cursor loop which cause IDB transaction timeouts.
646
+ let userProvenTxIds;
647
+ if (userId !== undefined) {
648
+ userProvenTxIds = new Set();
649
+ const userTxs = await this.findTransactions({ partial: { userId }, noRawTx: true });
650
+ for (const tx of userTxs) {
651
+ if (tx.provenTxId !== undefined) {
652
+ userProvenTxIds.add(tx.provenTxId);
653
+ }
654
+ }
655
+ }
602
656
  const offset = ((_a = args.paged) === null || _a === void 0 ? void 0 : _a.offset) || 0;
603
657
  let skipped = 0;
604
658
  let count = 0;
605
659
  const dbTrx = this.toDbTrx(['proven_txs'], 'readonly', args.trx);
660
+ const direction = args.orderDescending ? 'prev' : 'next';
606
661
  let cursor;
607
662
  if ((_b = args.partial) === null || _b === void 0 ? void 0 : _b.provenTxId) {
608
- cursor = await dbTrx.objectStore('proven_txs').openCursor(args.partial.provenTxId);
663
+ cursor = await dbTrx.objectStore('proven_txs').openCursor(args.partial.provenTxId, direction);
609
664
  }
610
665
  else if (((_c = args.partial) === null || _c === void 0 ? void 0 : _c.txid) !== undefined) {
611
- cursor = await dbTrx.objectStore('proven_txs').index('txid').openCursor(args.partial.txid);
666
+ cursor = await dbTrx.objectStore('proven_txs').index('txid').openCursor(args.partial.txid, direction);
612
667
  }
613
668
  else {
614
- cursor = await dbTrx.objectStore('proven_txs').openCursor();
669
+ cursor = await dbTrx.objectStore('proven_txs').openCursor(null, direction);
615
670
  }
616
671
  let firstTime = true;
617
672
  while (cursor) {
@@ -641,10 +696,8 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
641
696
  if (args.partial.merkleRoot && r.merkleRoot !== args.partial.merkleRoot)
642
697
  continue;
643
698
  }
644
- if (userId !== undefined) {
645
- const count = await this.countTransactions({ partial: { userId, provenTxId: r.provenTxId }, trx: args.trx });
646
- if (count === 0)
647
- continue;
699
+ if (userProvenTxIds !== undefined && !userProvenTxIds.has(r.provenTxId)) {
700
+ continue;
648
701
  }
649
702
  if (skipped < offset) {
650
703
  skipped++;
@@ -667,19 +720,33 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
667
720
  }
668
721
  async filterTxLabelMaps(args, filtered, userId) {
669
722
  var _a, _b, _c, _d;
723
+ // Pre-compute txLabelIds for this user BEFORE opening cursor.
724
+ // This avoids nested queries inside the cursor loop which cause IDB transaction timeouts.
725
+ let userTxLabelIds;
726
+ if (userId !== undefined) {
727
+ userTxLabelIds = new Set();
728
+ const userLabels = await this.findTxLabels({ partial: { userId } });
729
+ for (const label of userLabels) {
730
+ userTxLabelIds.add(label.txLabelId);
731
+ }
732
+ }
670
733
  const offset = ((_a = args.paged) === null || _a === void 0 ? void 0 : _a.offset) || 0;
671
734
  let skipped = 0;
672
735
  let count = 0;
673
736
  const dbTrx = this.toDbTrx(['tx_labels_map'], 'readonly', args.trx);
737
+ const direction = args.orderDescending ? 'prev' : 'next';
674
738
  let cursor;
675
739
  if (((_b = args.partial) === null || _b === void 0 ? void 0 : _b.transactionId) !== undefined) {
676
- cursor = await dbTrx.objectStore('tx_labels_map').index('transactionId').openCursor(args.partial.transactionId);
740
+ cursor = await dbTrx
741
+ .objectStore('tx_labels_map')
742
+ .index('transactionId')
743
+ .openCursor(args.partial.transactionId, direction);
677
744
  }
678
745
  else if (((_c = args.partial) === null || _c === void 0 ? void 0 : _c.txLabelId) !== undefined) {
679
- cursor = await dbTrx.objectStore('tx_labels_map').index('txLabelId').openCursor(args.partial.txLabelId);
746
+ cursor = await dbTrx.objectStore('tx_labels_map').index('txLabelId').openCursor(args.partial.txLabelId, direction);
680
747
  }
681
748
  else {
682
- cursor = await dbTrx.objectStore('tx_labels_map').openCursor();
749
+ cursor = await dbTrx.objectStore('tx_labels_map').openCursor(null, direction);
683
750
  }
684
751
  let firstTime = true;
685
752
  while (cursor) {
@@ -691,10 +758,12 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
691
758
  const r = cursor.value;
692
759
  if (args.since && args.since > r.updated_at)
693
760
  continue;
761
+ if (args.labelIds && !args.labelIds.includes(r.txLabelId))
762
+ continue;
694
763
  if (args.partial) {
695
- if (args.partial.txLabelId && r.txLabelId !== args.partial.txLabelId)
764
+ if (args.partial.txLabelId !== undefined && r.txLabelId !== args.partial.txLabelId)
696
765
  continue;
697
- if (args.partial.transactionId && r.transactionId !== args.partial.transactionId)
766
+ if (args.partial.transactionId !== undefined && r.transactionId !== args.partial.transactionId)
698
767
  continue;
699
768
  if (args.partial.created_at && r.created_at.getTime() !== args.partial.created_at.getTime())
700
769
  continue;
@@ -703,10 +772,8 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
703
772
  if (args.partial.isDeleted !== undefined && r.isDeleted !== args.partial.isDeleted)
704
773
  continue;
705
774
  }
706
- if (userId !== undefined) {
707
- const count = await this.countTxLabels({ partial: { userId, txLabelId: r.txLabelId }, trx: args.trx });
708
- if (count === 0)
709
- continue;
775
+ if (userTxLabelIds !== undefined && !userTxLabelIds.has(r.txLabelId)) {
776
+ continue;
710
777
  }
711
778
  if (skipped < offset) {
712
779
  skipped++;
@@ -765,6 +832,16 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
765
832
  const dbTrx = this.toDbTrx(['certificates', 'certificate_fields'], 'readwrite', trx);
766
833
  const store = dbTrx.objectStore('certificates');
767
834
  try {
835
+ const existing = await store.index('userId_type_certifier_serialNumber').get([
836
+ certificate.userId,
837
+ certificate.type,
838
+ certificate.certifier,
839
+ certificate.serialNumber
840
+ ]);
841
+ if (existing) {
842
+ certificate.certificateId = existing.certificateId;
843
+ return certificate.certificateId;
844
+ }
768
845
  const id = Number(await store.add(e));
769
846
  certificate.certificateId = id;
770
847
  if (fields) {
@@ -800,6 +877,11 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
800
877
  const dbTrx = this.toDbTrx(['commissions'], 'readwrite', trx);
801
878
  const store = dbTrx.objectStore('commissions');
802
879
  try {
880
+ const existing = await store.index('transactionId').get(commission.transactionId);
881
+ if (existing) {
882
+ commission.commissionId = existing.commissionId;
883
+ return commission.commissionId;
884
+ }
803
885
  const id = Number(await store.add(e));
804
886
  commission.commissionId = id;
805
887
  }
@@ -832,6 +914,11 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
832
914
  const dbTrx = this.toDbTrx(['outputs'], 'readwrite', trx);
833
915
  const store = dbTrx.objectStore('outputs');
834
916
  try {
917
+ const existing = await store.index('transactionId_vout_userId').get([output.transactionId, output.vout, output.userId]);
918
+ if (existing) {
919
+ output.outputId = existing.outputId;
920
+ return output.outputId;
921
+ }
835
922
  const id = Number(await store.add(e));
836
923
  output.outputId = id;
837
924
  }
@@ -848,6 +935,11 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
848
935
  const dbTrx = this.toDbTrx(['output_baskets'], 'readwrite', trx);
849
936
  const store = dbTrx.objectStore('output_baskets');
850
937
  try {
938
+ const existing = await store.index('name_userId').get([basket.name, basket.userId]);
939
+ if (existing) {
940
+ basket.basketId = existing.basketId;
941
+ return basket.basketId;
942
+ }
851
943
  const id = Number(await store.add(e));
852
944
  basket.basketId = id;
853
945
  }
@@ -864,6 +956,11 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
864
956
  const dbTrx = this.toDbTrx(['output_tags'], 'readwrite', trx);
865
957
  const store = dbTrx.objectStore('output_tags');
866
958
  try {
959
+ const existing = await store.index('tag_userId').get([tag.tag, tag.userId]);
960
+ if (existing) {
961
+ tag.outputTagId = existing.outputTagId;
962
+ return tag.outputTagId;
963
+ }
867
964
  const id = Number(await store.add(e));
868
965
  tag.outputTagId = id;
869
966
  }
@@ -892,6 +989,11 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
892
989
  const dbTrx = this.toDbTrx(['proven_txs'], 'readwrite', trx);
893
990
  const store = dbTrx.objectStore('proven_txs');
894
991
  try {
992
+ const existing = await store.index('txid').get(tx.txid);
993
+ if (existing) {
994
+ tx.provenTxId = existing.provenTxId;
995
+ return tx.provenTxId;
996
+ }
895
997
  const id = Number(await store.add(e));
896
998
  tx.provenTxId = id;
897
999
  }
@@ -908,6 +1010,11 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
908
1010
  const dbTrx = this.toDbTrx(['proven_tx_reqs'], 'readwrite', trx);
909
1011
  const store = dbTrx.objectStore('proven_tx_reqs');
910
1012
  try {
1013
+ const existing = await store.index('txid').get(tx.txid);
1014
+ if (existing) {
1015
+ tx.provenTxReqId = existing.provenTxReqId;
1016
+ return tx.provenTxReqId;
1017
+ }
911
1018
  const id = Number(await store.add(e));
912
1019
  tx.provenTxReqId = id;
913
1020
  }
@@ -940,6 +1047,11 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
940
1047
  const dbTrx = this.toDbTrx(['transactions'], 'readwrite', trx);
941
1048
  const store = dbTrx.objectStore('transactions');
942
1049
  try {
1050
+ const existing = await store.index('reference').get(tx.reference);
1051
+ if (existing) {
1052
+ tx.transactionId = existing.transactionId;
1053
+ return tx.transactionId;
1054
+ }
943
1055
  const id = Number(await store.add(e));
944
1056
  tx.transactionId = id;
945
1057
  }
@@ -956,6 +1068,11 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
956
1068
  const dbTrx = this.toDbTrx(['tx_labels'], 'readwrite', trx);
957
1069
  const store = dbTrx.objectStore('tx_labels');
958
1070
  try {
1071
+ const existing = await store.index('label_userId').get([label.label, label.userId]);
1072
+ if (existing) {
1073
+ label.txLabelId = existing.txLabelId;
1074
+ return label.txLabelId;
1075
+ }
959
1076
  const id = Number(await store.add(e));
960
1077
  label.txLabelId = id;
961
1078
  }
@@ -984,6 +1101,11 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
984
1101
  const dbTrx = this.toDbTrx(['users'], 'readwrite', trx);
985
1102
  const store = dbTrx.objectStore('users');
986
1103
  try {
1104
+ const existing = await store.index('identityKey').get(user.identityKey);
1105
+ if (existing) {
1106
+ user.userId = existing.userId;
1107
+ return user.userId;
1108
+ }
987
1109
  const id = Number(await store.add(e));
988
1110
  user.userId = id;
989
1111
  }
@@ -999,7 +1121,14 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
999
1121
  }
1000
1122
  const u = this.validatePartialForUpdate(update);
1001
1123
  const dbTrx = this.toDbTrx([storeName], 'readwrite', trx);
1002
- const store = dbTrx.objectStore(storeName);
1124
+ let store;
1125
+ try {
1126
+ store = dbTrx.objectStore(storeName);
1127
+ }
1128
+ catch (e) {
1129
+ console.error(`[StorageIdb.updateIdb] objectStore('${storeName}') failed for id=${JSON.stringify(id)}, trx=${!!trx}:`, e);
1130
+ throw e;
1131
+ }
1003
1132
  const ids = Array.isArray(id) ? id : [id];
1004
1133
  try {
1005
1134
  for (const i of ids) {
@@ -1124,7 +1253,14 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
1124
1253
  return r;
1125
1254
  }
1126
1255
  catch (err) {
1127
- tx.abort();
1256
+ // Log more detail about transaction errors to help debug IDB issues
1257
+ console.error('[StorageIdb] Transaction error:', err instanceof Error ? err.message : err);
1258
+ try {
1259
+ tx.abort();
1260
+ }
1261
+ catch (abortErr) {
1262
+ console.error('[StorageIdb] Error aborting transaction:', abortErr);
1263
+ }
1128
1264
  await tx.done;
1129
1265
  throw err;
1130
1266
  }
@@ -1135,18 +1271,19 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
1135
1271
  let skipped = 0;
1136
1272
  let count = 0;
1137
1273
  const dbTrx = this.toDbTrx(['certificate_fields'], 'readonly', args.trx);
1274
+ const direction = args.orderDescending ? 'prev' : 'next';
1138
1275
  let cursor;
1139
1276
  if (((_b = args.partial) === null || _b === void 0 ? void 0 : _b.certificateId) !== undefined) {
1140
1277
  cursor = await dbTrx
1141
1278
  .objectStore('certificate_fields')
1142
1279
  .index('certificateId')
1143
- .openCursor(args.partial.certificateId);
1280
+ .openCursor(args.partial.certificateId, direction);
1144
1281
  }
1145
1282
  else if (((_c = args.partial) === null || _c === void 0 ? void 0 : _c.userId) !== undefined) {
1146
- cursor = await dbTrx.objectStore('certificate_fields').index('userId').openCursor(args.partial.userId);
1283
+ cursor = await dbTrx.objectStore('certificate_fields').index('userId').openCursor(args.partial.userId, direction);
1147
1284
  }
1148
1285
  else {
1149
- cursor = await dbTrx.objectStore('certificate_fields').openCursor();
1286
+ cursor = await dbTrx.objectStore('certificate_fields').openCursor(null, direction);
1150
1287
  }
1151
1288
  let firstTime = true;
1152
1289
  while (cursor) {
@@ -1199,23 +1336,24 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
1199
1336
  let skipped = 0;
1200
1337
  let count = 0;
1201
1338
  const dbTrx = this.toDbTrx(['certificates'], 'readonly', args.trx);
1339
+ const direction = args.orderDescending ? 'prev' : 'next';
1202
1340
  let cursor;
1203
1341
  if ((_b = args.partial) === null || _b === void 0 ? void 0 : _b.certificateId) {
1204
- cursor = await dbTrx.objectStore('certificates').openCursor(args.partial.certificateId);
1342
+ cursor = await dbTrx.objectStore('certificates').openCursor(args.partial.certificateId, direction);
1205
1343
  }
1206
1344
  else if (((_c = args.partial) === null || _c === void 0 ? void 0 : _c.userId) !== undefined) {
1207
1345
  if (((_d = args.partial) === null || _d === void 0 ? void 0 : _d.type) && ((_e = args.partial) === null || _e === void 0 ? void 0 : _e.certifier) && ((_f = args.partial) === null || _f === void 0 ? void 0 : _f.serialNumber)) {
1208
1346
  cursor = await dbTrx
1209
1347
  .objectStore('certificates')
1210
1348
  .index('userId_type_certifier_serialNumber')
1211
- .openCursor([args.partial.userId, args.partial.type, args.partial.certifier, args.partial.serialNumber]);
1349
+ .openCursor([args.partial.userId, args.partial.type, args.partial.certifier, args.partial.serialNumber], direction);
1212
1350
  }
1213
1351
  else {
1214
- cursor = await dbTrx.objectStore('certificates').index('userId').openCursor(args.partial.userId);
1352
+ cursor = await dbTrx.objectStore('certificates').index('userId').openCursor(args.partial.userId, direction);
1215
1353
  }
1216
1354
  }
1217
1355
  else {
1218
- cursor = await dbTrx.objectStore('certificates').openCursor();
1356
+ cursor = await dbTrx.objectStore('certificates').openCursor(null, direction);
1219
1357
  }
1220
1358
  let firstTime = true;
1221
1359
  while (cursor) {
@@ -1290,18 +1428,22 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
1290
1428
  let skipped = 0;
1291
1429
  let count = 0;
1292
1430
  const dbTrx = this.toDbTrx(['commissions'], 'readonly', args.trx);
1431
+ const direction = args.orderDescending ? 'prev' : 'next';
1293
1432
  let cursor;
1294
1433
  if ((_b = args.partial) === null || _b === void 0 ? void 0 : _b.commissionId) {
1295
- cursor = await dbTrx.objectStore('commissions').openCursor(args.partial.commissionId);
1434
+ cursor = await dbTrx.objectStore('commissions').openCursor(args.partial.commissionId, direction);
1296
1435
  }
1297
1436
  else if (((_c = args.partial) === null || _c === void 0 ? void 0 : _c.userId) !== undefined) {
1298
- cursor = await dbTrx.objectStore('commissions').index('userId').openCursor(args.partial.userId);
1437
+ cursor = await dbTrx.objectStore('commissions').index('userId').openCursor(args.partial.userId, direction);
1299
1438
  }
1300
1439
  else if (((_d = args.partial) === null || _d === void 0 ? void 0 : _d.transactionId) !== undefined) {
1301
- cursor = await dbTrx.objectStore('commissions').index('transactionId').openCursor(args.partial.transactionId);
1440
+ cursor = await dbTrx
1441
+ .objectStore('commissions')
1442
+ .index('transactionId')
1443
+ .openCursor(args.partial.transactionId, direction);
1302
1444
  }
1303
1445
  else {
1304
- cursor = await dbTrx.objectStore('commissions').openCursor();
1446
+ cursor = await dbTrx.objectStore('commissions').openCursor(null, direction);
1305
1447
  }
1306
1448
  let firstTime = true;
1307
1449
  while (cursor) {
@@ -1356,12 +1498,13 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
1356
1498
  let skipped = 0;
1357
1499
  let count = 0;
1358
1500
  const dbTrx = this.toDbTrx(['monitor_events'], 'readonly', args.trx);
1501
+ const direction = args.orderDescending ? 'prev' : 'next';
1359
1502
  let cursor;
1360
1503
  if ((_b = args.partial) === null || _b === void 0 ? void 0 : _b.id) {
1361
- cursor = await dbTrx.objectStore('monitor_events').openCursor(args.partial.id);
1504
+ cursor = await dbTrx.objectStore('monitor_events').openCursor(args.partial.id, direction);
1362
1505
  }
1363
1506
  else {
1364
- cursor = await dbTrx.objectStore('monitor_events').openCursor();
1507
+ cursor = await dbTrx.objectStore('monitor_events').openCursor(null, direction);
1365
1508
  }
1366
1509
  let firstTime = true;
1367
1510
  while (cursor) {
@@ -1410,23 +1553,24 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
1410
1553
  let skipped = 0;
1411
1554
  let count = 0;
1412
1555
  const dbTrx = this.toDbTrx(['output_baskets'], 'readonly', args.trx);
1556
+ const direction = args.orderDescending ? 'prev' : 'next';
1413
1557
  let cursor;
1414
1558
  if ((_b = args.partial) === null || _b === void 0 ? void 0 : _b.basketId) {
1415
- cursor = await dbTrx.objectStore('output_baskets').openCursor(args.partial.basketId);
1559
+ cursor = await dbTrx.objectStore('output_baskets').openCursor(args.partial.basketId, direction);
1416
1560
  }
1417
1561
  else if (((_c = args.partial) === null || _c === void 0 ? void 0 : _c.userId) !== undefined) {
1418
1562
  if (((_d = args.partial) === null || _d === void 0 ? void 0 : _d.name) !== undefined) {
1419
1563
  cursor = await dbTrx
1420
1564
  .objectStore('output_baskets')
1421
1565
  .index('name_userId')
1422
- .openCursor([args.partial.name, args.partial.userId]);
1566
+ .openCursor([args.partial.name, args.partial.userId], direction);
1423
1567
  }
1424
1568
  else {
1425
- cursor = await dbTrx.objectStore('output_baskets').index('userId').openCursor(args.partial.userId);
1569
+ cursor = await dbTrx.objectStore('output_baskets').index('userId').openCursor(args.partial.userId, direction);
1426
1570
  }
1427
1571
  }
1428
1572
  else {
1429
- cursor = await dbTrx.objectStore('output_baskets').openCursor();
1573
+ cursor = await dbTrx.objectStore('output_baskets').openCursor(null, direction);
1430
1574
  }
1431
1575
  let firstTime = true;
1432
1576
  while (cursor) {
@@ -1453,7 +1597,7 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
1453
1597
  r.numberOfDesiredUTXOs !== args.partial.numberOfDesiredUTXOs)
1454
1598
  continue;
1455
1599
  if (args.partial.minimumDesiredUTXOValue !== undefined &&
1456
- r.numberOfDesiredSatoshis !== args.partial.minimumDesiredUTXOValue)
1600
+ r.minimumDesiredUTXOValue !== args.partial.minimumDesiredUTXOValue)
1457
1601
  continue;
1458
1602
  if (args.partial.isDeleted !== undefined && r.isDeleted !== args.partial.isDeleted)
1459
1603
  continue;
@@ -1494,32 +1638,36 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
1494
1638
  stores.push('transactions');
1495
1639
  }
1496
1640
  const dbTrx = this.toDbTrx(stores, 'readonly', args.trx);
1641
+ const direction = args.orderDescending ? 'prev' : 'next';
1497
1642
  let cursor;
1498
1643
  if ((_b = args.partial) === null || _b === void 0 ? void 0 : _b.outputId) {
1499
- cursor = await dbTrx.objectStore('outputs').openCursor(args.partial.outputId);
1644
+ cursor = await dbTrx.objectStore('outputs').openCursor(args.partial.outputId, direction);
1500
1645
  }
1501
1646
  else if (((_c = args.partial) === null || _c === void 0 ? void 0 : _c.userId) !== undefined) {
1502
1647
  if (((_d = args.partial) === null || _d === void 0 ? void 0 : _d.transactionId) && ((_e = args.partial) === null || _e === void 0 ? void 0 : _e.vout) !== undefined) {
1503
1648
  cursor = await dbTrx
1504
1649
  .objectStore('outputs')
1505
1650
  .index('transactionId_vout_userId')
1506
- .openCursor([args.partial.transactionId, args.partial.vout, args.partial.userId]);
1651
+ .openCursor([args.partial.transactionId, args.partial.vout, args.partial.userId], direction);
1507
1652
  }
1508
1653
  else {
1509
- cursor = await dbTrx.objectStore('outputs').index('userId').openCursor(args.partial.userId);
1654
+ cursor = await dbTrx.objectStore('outputs').index('userId').openCursor(args.partial.userId, direction);
1510
1655
  }
1511
1656
  }
1512
1657
  else if (((_f = args.partial) === null || _f === void 0 ? void 0 : _f.transactionId) !== undefined) {
1513
- cursor = await dbTrx.objectStore('outputs').index('transactionId').openCursor(args.partial.transactionId);
1658
+ cursor = await dbTrx
1659
+ .objectStore('outputs')
1660
+ .index('transactionId')
1661
+ .openCursor(args.partial.transactionId, direction);
1514
1662
  }
1515
1663
  else if (((_g = args.partial) === null || _g === void 0 ? void 0 : _g.basketId) !== undefined) {
1516
- cursor = await dbTrx.objectStore('outputs').index('basketId').openCursor(args.partial.basketId);
1664
+ cursor = await dbTrx.objectStore('outputs').index('basketId').openCursor(args.partial.basketId, direction);
1517
1665
  }
1518
1666
  else if (((_h = args.partial) === null || _h === void 0 ? void 0 : _h.spentBy) !== undefined) {
1519
- cursor = await dbTrx.objectStore('outputs').index('spentBy').openCursor(args.partial.spentBy);
1667
+ cursor = await dbTrx.objectStore('outputs').index('spentBy').openCursor(args.partial.spentBy, direction);
1520
1668
  }
1521
1669
  else {
1522
- cursor = await dbTrx.objectStore('outputs').openCursor();
1670
+ cursor = await dbTrx.objectStore('outputs').openCursor(null, direction);
1523
1671
  }
1524
1672
  let firstTime = true;
1525
1673
  while (cursor) {
@@ -1628,7 +1776,9 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
1628
1776
  }, tagIds, isQueryModeAll);
1629
1777
  for (const o of results) {
1630
1778
  if (!args.noScript) {
1631
- await this.validateOutputScript(o);
1779
+ // Pass the transaction to avoid creating separate IDB operations
1780
+ // that would cause a passed transaction to auto-commit
1781
+ await this.validateOutputScript(o, args.trx);
1632
1782
  }
1633
1783
  else {
1634
1784
  o.lockingScript = undefined;
@@ -1642,23 +1792,24 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
1642
1792
  let skipped = 0;
1643
1793
  let count = 0;
1644
1794
  const dbTrx = this.toDbTrx(['output_tags'], 'readonly', args.trx);
1795
+ const direction = args.orderDescending ? 'prev' : 'next';
1645
1796
  let cursor;
1646
1797
  if ((_b = args.partial) === null || _b === void 0 ? void 0 : _b.outputTagId) {
1647
- cursor = await dbTrx.objectStore('output_tags').openCursor(args.partial.outputTagId);
1798
+ cursor = await dbTrx.objectStore('output_tags').openCursor(args.partial.outputTagId, direction);
1648
1799
  }
1649
1800
  else if (((_c = args.partial) === null || _c === void 0 ? void 0 : _c.userId) !== undefined) {
1650
1801
  if (((_d = args.partial) === null || _d === void 0 ? void 0 : _d.tag) !== undefined) {
1651
1802
  cursor = await dbTrx
1652
1803
  .objectStore('output_tags')
1653
1804
  .index('tag_userId')
1654
- .openCursor([args.partial.tag, args.partial.userId]);
1805
+ .openCursor([args.partial.tag, args.partial.userId], direction);
1655
1806
  }
1656
1807
  else {
1657
- cursor = await dbTrx.objectStore('output_tags').index('userId').openCursor(args.partial.userId);
1808
+ cursor = await dbTrx.objectStore('output_tags').index('userId').openCursor(args.partial.userId, direction);
1658
1809
  }
1659
1810
  }
1660
1811
  else {
1661
- cursor = await dbTrx.objectStore('output_tags').openCursor();
1812
+ cursor = await dbTrx.objectStore('output_tags').openCursor(null, direction);
1662
1813
  }
1663
1814
  let firstTime = true;
1664
1815
  while (cursor) {
@@ -1711,21 +1862,22 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
1711
1862
  let skipped = 0;
1712
1863
  let count = 0;
1713
1864
  const dbTrx = this.toDbTrx(['sync_states'], 'readonly', args.trx);
1865
+ const direction = args.orderDescending ? 'prev' : 'next';
1714
1866
  let cursor;
1715
1867
  if ((_b = args.partial) === null || _b === void 0 ? void 0 : _b.syncStateId) {
1716
- cursor = await dbTrx.objectStore('sync_states').openCursor(args.partial.syncStateId);
1868
+ cursor = await dbTrx.objectStore('sync_states').openCursor(args.partial.syncStateId, direction);
1717
1869
  }
1718
1870
  else if (((_c = args.partial) === null || _c === void 0 ? void 0 : _c.userId) !== undefined) {
1719
- cursor = await dbTrx.objectStore('sync_states').index('userId').openCursor(args.partial.userId);
1871
+ cursor = await dbTrx.objectStore('sync_states').index('userId').openCursor(args.partial.userId, direction);
1720
1872
  }
1721
1873
  else if (((_d = args.partial) === null || _d === void 0 ? void 0 : _d.refNum) !== undefined) {
1722
- cursor = await dbTrx.objectStore('sync_states').index('refNum').openCursor(args.partial.refNum);
1874
+ cursor = await dbTrx.objectStore('sync_states').index('refNum').openCursor(args.partial.refNum, direction);
1723
1875
  }
1724
1876
  else if (((_e = args.partial) === null || _e === void 0 ? void 0 : _e.status) !== undefined) {
1725
- cursor = await dbTrx.objectStore('sync_states').index('status').openCursor(args.partial.status);
1877
+ cursor = await dbTrx.objectStore('sync_states').index('status').openCursor(args.partial.status, direction);
1726
1878
  }
1727
1879
  else {
1728
- cursor = await dbTrx.objectStore('sync_states').openCursor();
1880
+ cursor = await dbTrx.objectStore('sync_states').openCursor(null, direction);
1729
1881
  }
1730
1882
  let firstTime = true;
1731
1883
  while (cursor) {
@@ -1760,7 +1912,7 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
1760
1912
  continue;
1761
1913
  if (args.partial.satoshis !== undefined && r.satoshis !== args.partial.satoshis)
1762
1914
  continue;
1763
- if (args.partial.errorLocal && r.errorLocale !== args.partial.errorLocal)
1915
+ if (args.partial.errorLocal && r.errorLocal !== args.partial.errorLocal)
1764
1916
  continue;
1765
1917
  if (args.partial.errorOther && r.errorOther !== args.partial.errorOther)
1766
1918
  continue;
@@ -1798,32 +1950,36 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
1798
1950
  stores.push('tx_labels_map');
1799
1951
  }
1800
1952
  const dbTrx = this.toDbTrx(stores, 'readonly', args.trx);
1953
+ const direction = args.orderDescending ? 'prev' : 'next';
1801
1954
  let cursor;
1802
1955
  if ((_b = args.partial) === null || _b === void 0 ? void 0 : _b.transactionId) {
1803
- cursor = await dbTrx.objectStore('transactions').openCursor(args.partial.transactionId);
1956
+ cursor = await dbTrx.objectStore('transactions').openCursor(args.partial.transactionId, direction);
1804
1957
  }
1805
1958
  else if (((_c = args.partial) === null || _c === void 0 ? void 0 : _c.userId) !== undefined) {
1806
1959
  if (((_d = args.partial) === null || _d === void 0 ? void 0 : _d.status) !== undefined) {
1807
1960
  cursor = await dbTrx
1808
1961
  .objectStore('transactions')
1809
1962
  .index('status_userId')
1810
- .openCursor([args.partial.status, args.partial.userId]);
1963
+ .openCursor([args.partial.status, args.partial.userId], direction);
1811
1964
  }
1812
1965
  else {
1813
- cursor = await dbTrx.objectStore('transactions').index('userId').openCursor(args.partial.userId);
1966
+ cursor = await dbTrx.objectStore('transactions').index('userId').openCursor(args.partial.userId, direction);
1814
1967
  }
1815
1968
  }
1816
1969
  else if (((_e = args.partial) === null || _e === void 0 ? void 0 : _e.status) !== undefined) {
1817
- cursor = await dbTrx.objectStore('transactions').index('status').openCursor(args.partial.status);
1970
+ cursor = await dbTrx.objectStore('transactions').index('status').openCursor(args.partial.status, direction);
1818
1971
  }
1819
1972
  else if (((_f = args.partial) === null || _f === void 0 ? void 0 : _f.provenTxId) !== undefined) {
1820
- cursor = await dbTrx.objectStore('transactions').index('provenTxId').openCursor(args.partial.provenTxId);
1973
+ cursor = await dbTrx
1974
+ .objectStore('transactions')
1975
+ .index('provenTxId')
1976
+ .openCursor(args.partial.provenTxId, direction);
1821
1977
  }
1822
1978
  else if (((_g = args.partial) === null || _g === void 0 ? void 0 : _g.reference) !== undefined) {
1823
- cursor = await dbTrx.objectStore('transactions').index('reference').openCursor(args.partial.reference);
1979
+ cursor = await dbTrx.objectStore('transactions').index('reference').openCursor(args.partial.reference, direction);
1824
1980
  }
1825
1981
  else {
1826
- cursor = await dbTrx.objectStore('transactions').openCursor();
1982
+ cursor = await dbTrx.objectStore('transactions').openCursor(null, direction);
1827
1983
  }
1828
1984
  let firstTime = true;
1829
1985
  while (cursor) {
@@ -1917,23 +2073,24 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
1917
2073
  let skipped = 0;
1918
2074
  let count = 0;
1919
2075
  const dbTrx = this.toDbTrx(['tx_labels'], 'readonly', args.trx);
2076
+ const direction = args.orderDescending ? 'prev' : 'next';
1920
2077
  let cursor;
1921
2078
  if ((_b = args.partial) === null || _b === void 0 ? void 0 : _b.txLabelId) {
1922
- cursor = await dbTrx.objectStore('tx_labels').openCursor(args.partial.txLabelId);
2079
+ cursor = await dbTrx.objectStore('tx_labels').openCursor(args.partial.txLabelId, direction);
1923
2080
  }
1924
2081
  else if (((_c = args.partial) === null || _c === void 0 ? void 0 : _c.userId) !== undefined) {
1925
2082
  if (((_d = args.partial) === null || _d === void 0 ? void 0 : _d.label) !== undefined) {
1926
2083
  cursor = await dbTrx
1927
2084
  .objectStore('tx_labels')
1928
2085
  .index('label_userId')
1929
- .openCursor([args.partial.label, args.partial.userId]);
2086
+ .openCursor([args.partial.label, args.partial.userId], direction);
1930
2087
  }
1931
2088
  else {
1932
- cursor = await dbTrx.objectStore('tx_labels').index('userId').openCursor(args.partial.userId);
2089
+ cursor = await dbTrx.objectStore('tx_labels').index('userId').openCursor(args.partial.userId, direction);
1933
2090
  }
1934
2091
  }
1935
2092
  else {
1936
- cursor = await dbTrx.objectStore('tx_labels').openCursor();
2093
+ cursor = await dbTrx.objectStore('tx_labels').openCursor(null, direction);
1937
2094
  }
1938
2095
  let firstTime = true;
1939
2096
  while (cursor) {
@@ -1984,7 +2141,8 @@ class StorageIdb extends StorageProvider_1.StorageProvider {
1984
2141
  let skipped = 0;
1985
2142
  let count = 0;
1986
2143
  const dbTrx = this.toDbTrx(['users'], 'readonly', args.trx);
1987
- let cursor = await dbTrx.objectStore('users').openCursor();
2144
+ const direction = args.orderDescending ? 'prev' : 'next';
2145
+ let cursor = await dbTrx.objectStore('users').openCursor(null, direction);
1988
2146
  let firstTime = true;
1989
2147
  while (cursor) {
1990
2148
  if (!firstTime)