@bsv/wallet-toolbox 1.3.3 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (320) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/docs/client.md +97 -28
  3. package/docs/services.md +2 -1
  4. package/docs/setup.md +404 -14
  5. package/docs/storage.md +720 -42
  6. package/docs/wallet.md +97 -28
  7. package/out/src/Setup.d.ts +2 -69
  8. package/out/src/Setup.d.ts.map +1 -1
  9. package/out/src/Setup.js.map +1 -1
  10. package/out/src/SetupClient.d.ts +126 -0
  11. package/out/src/SetupClient.d.ts.map +1 -0
  12. package/out/src/SetupClient.js +220 -0
  13. package/out/src/SetupClient.js.map +1 -0
  14. package/out/src/SetupWallet.d.ts +100 -0
  15. package/out/src/SetupWallet.d.ts.map +1 -0
  16. package/out/src/{storage/schema/tables/Certificate.js → SetupWallet.js} +1 -1
  17. package/out/src/SetupWallet.js.map +1 -0
  18. package/out/src/index.all.d.ts +2 -0
  19. package/out/src/index.all.d.ts.map +1 -1
  20. package/out/src/index.all.js +2 -0
  21. package/out/src/index.all.js.map +1 -1
  22. package/out/src/index.client.d.ts +1 -0
  23. package/out/src/index.client.d.ts.map +1 -1
  24. package/out/src/index.client.js +1 -0
  25. package/out/src/index.client.js.map +1 -1
  26. package/out/src/monitor/Monitor.d.ts.map +1 -1
  27. package/out/src/monitor/Monitor.js +4 -0
  28. package/out/src/monitor/Monitor.js.map +1 -1
  29. package/out/src/monitor/MonitorDaemon.d.ts.map +1 -1
  30. package/out/src/monitor/MonitorDaemon.js +0 -3
  31. package/out/src/monitor/MonitorDaemon.js.map +1 -1
  32. package/out/src/monitor/tasks/TaskUnFail.d.ts.map +1 -1
  33. package/out/src/monitor/tasks/TaskUnFail.js +1 -2
  34. package/out/src/monitor/tasks/TaskUnFail.js.map +1 -1
  35. package/out/src/sdk/WalletServices.interfaces.d.ts +1 -1
  36. package/out/src/sdk/WalletServices.interfaces.d.ts.map +1 -1
  37. package/out/src/services/__tests/postBeef.test.js +1 -1
  38. package/out/src/services/__tests/postBeef.test.js.map +1 -1
  39. package/out/src/storage/StorageIdb.d.ts +203 -0
  40. package/out/src/storage/StorageIdb.d.ts.map +1 -0
  41. package/out/src/storage/StorageIdb.js +2289 -0
  42. package/out/src/storage/StorageIdb.js.map +1 -0
  43. package/out/src/storage/StorageKnex.d.ts +6 -6
  44. package/out/src/storage/StorageKnex.d.ts.map +1 -1
  45. package/out/src/storage/StorageKnex.js +9 -29
  46. package/out/src/storage/StorageKnex.js.map +1 -1
  47. package/out/src/storage/StorageProvider.d.ts +3 -1
  48. package/out/src/storage/StorageProvider.d.ts.map +1 -1
  49. package/out/src/storage/StorageProvider.js +22 -0
  50. package/out/src/storage/StorageProvider.js.map +1 -1
  51. package/out/src/storage/StorageReader.d.ts +1 -1
  52. package/out/src/storage/StorageReader.d.ts.map +1 -1
  53. package/out/src/storage/StorageReader.js +5 -0
  54. package/out/src/storage/StorageReader.js.map +1 -1
  55. package/out/src/storage/__test/StorageIdb.test.d.ts +2 -0
  56. package/out/src/storage/__test/StorageIdb.test.d.ts.map +1 -0
  57. package/out/src/storage/__test/StorageIdb.test.js +16 -0
  58. package/out/src/storage/__test/StorageIdb.test.js.map +1 -0
  59. package/out/src/storage/methods/ListActionsSpecOp.d.ts +16 -0
  60. package/out/src/storage/methods/ListActionsSpecOp.d.ts.map +1 -0
  61. package/out/src/storage/methods/ListActionsSpecOp.js +40 -0
  62. package/out/src/storage/methods/ListActionsSpecOp.js.map +1 -0
  63. package/out/src/storage/methods/ListOutputsSpecOp.d.ts +26 -0
  64. package/out/src/storage/methods/ListOutputsSpecOp.d.ts.map +1 -0
  65. package/out/src/storage/methods/ListOutputsSpecOp.js +71 -0
  66. package/out/src/storage/methods/ListOutputsSpecOp.js.map +1 -0
  67. package/out/src/storage/methods/listActionsIdb.d.ts +5 -0
  68. package/out/src/storage/methods/listActionsIdb.d.ts.map +1 -0
  69. package/out/src/storage/methods/listActionsIdb.js +155 -0
  70. package/out/src/storage/methods/listActionsIdb.js.map +1 -0
  71. package/out/src/storage/methods/{listActions.d.ts → listActionsKnex.d.ts} +1 -1
  72. package/out/src/storage/methods/listActionsKnex.d.ts.map +1 -0
  73. package/out/src/storage/methods/{listActions.js → listActionsKnex.js} +3 -34
  74. package/out/src/storage/methods/listActionsKnex.js.map +1 -0
  75. package/out/src/storage/methods/listOutputsIdb.d.ts +5 -0
  76. package/out/src/storage/methods/listOutputsIdb.d.ts.map +1 -0
  77. package/out/src/storage/methods/listOutputsIdb.js +181 -0
  78. package/out/src/storage/methods/listOutputsIdb.js.map +1 -0
  79. package/out/src/storage/methods/{listOutputs.d.ts → listOutputsKnex.d.ts} +1 -1
  80. package/out/src/storage/methods/listOutputsKnex.d.ts.map +1 -0
  81. package/out/src/storage/methods/{listOutputs.js → listOutputsKnex.js} +7 -76
  82. package/out/src/storage/methods/listOutputsKnex.js.map +1 -0
  83. package/out/src/storage/methods/purgeDataIdb.d.ts +4 -0
  84. package/out/src/storage/methods/purgeDataIdb.d.ts.map +1 -0
  85. package/out/src/storage/methods/purgeDataIdb.js +9 -0
  86. package/out/src/storage/methods/purgeDataIdb.js.map +1 -0
  87. package/out/src/storage/methods/reviewStatus.d.ts +11 -0
  88. package/out/src/storage/methods/reviewStatus.d.ts.map +1 -1
  89. package/out/src/storage/methods/reviewStatus.js +11 -0
  90. package/out/src/storage/methods/reviewStatus.js.map +1 -1
  91. package/out/src/storage/methods/reviewStatusIdb.d.ts +20 -0
  92. package/out/src/storage/methods/reviewStatusIdb.d.ts.map +1 -0
  93. package/out/src/storage/methods/reviewStatusIdb.js +35 -0
  94. package/out/src/storage/methods/reviewStatusIdb.js.map +1 -0
  95. package/out/src/storage/schema/StorageIdbSchema.d.ts +133 -0
  96. package/out/src/storage/schema/StorageIdbSchema.d.ts.map +1 -0
  97. package/out/src/storage/schema/{tables/CertificateField.js → StorageIdbSchema.js} +1 -1
  98. package/out/src/storage/schema/StorageIdbSchema.js.map +1 -0
  99. package/out/src/storage/schema/entities/__tests/ProvenTxTests.test.js +1 -1
  100. package/out/src/storage/schema/entities/__tests/ProvenTxTests.test.js.map +1 -1
  101. package/out/src/storage/schema/tables/{Certificate.d.ts → TableCertificate.d.ts} +1 -1
  102. package/out/src/storage/schema/tables/TableCertificate.d.ts.map +1 -0
  103. package/out/src/storage/schema/tables/TableCertificate.js +3 -0
  104. package/out/src/storage/schema/tables/TableCertificate.js.map +1 -0
  105. package/out/src/storage/schema/tables/{CertificateField.d.ts → TableCertificateField.d.ts} +1 -1
  106. package/out/src/storage/schema/tables/TableCertificateField.d.ts.map +1 -0
  107. package/out/src/storage/schema/tables/TableCertificateField.js +3 -0
  108. package/out/src/storage/schema/tables/TableCertificateField.js.map +1 -0
  109. package/out/src/storage/schema/tables/{Commission.d.ts → TableCommission.d.ts} +1 -1
  110. package/out/src/storage/schema/tables/TableCommission.d.ts.map +1 -0
  111. package/out/src/storage/schema/tables/TableCommission.js +3 -0
  112. package/out/src/storage/schema/tables/TableCommission.js.map +1 -0
  113. package/out/src/storage/schema/tables/{MonitorEvent.d.ts → TableMonitorEvent.d.ts} +1 -1
  114. package/out/src/storage/schema/tables/TableMonitorEvent.d.ts.map +1 -0
  115. package/out/src/storage/schema/tables/TableMonitorEvent.js +3 -0
  116. package/out/src/storage/schema/tables/TableMonitorEvent.js.map +1 -0
  117. package/out/src/storage/schema/tables/{Output.d.ts → TableOutput.d.ts} +1 -1
  118. package/out/src/storage/schema/tables/TableOutput.d.ts.map +1 -0
  119. package/out/src/storage/schema/tables/{Output.js → TableOutput.js} +1 -1
  120. package/out/src/storage/schema/tables/TableOutput.js.map +1 -0
  121. package/out/src/storage/schema/tables/{OutputBasket.d.ts → TableOutputBasket.d.ts} +1 -1
  122. package/out/src/storage/schema/tables/TableOutputBasket.d.ts.map +1 -0
  123. package/out/src/storage/schema/tables/TableOutputBasket.js +3 -0
  124. package/out/src/storage/schema/tables/TableOutputBasket.js.map +1 -0
  125. package/out/src/storage/schema/tables/{OutputTag.d.ts → TableOutputTag.d.ts} +1 -1
  126. package/out/src/storage/schema/tables/TableOutputTag.d.ts.map +1 -0
  127. package/out/src/storage/schema/tables/{MonitorEvent.js → TableOutputTag.js} +1 -1
  128. package/out/src/storage/schema/tables/TableOutputTag.js.map +1 -0
  129. package/out/src/storage/schema/tables/{OutputTagMap.d.ts → TableOutputTagMap.d.ts} +1 -1
  130. package/out/src/storage/schema/tables/TableOutputTagMap.d.ts.map +1 -0
  131. package/out/src/storage/schema/tables/TableOutputTagMap.js +3 -0
  132. package/out/src/storage/schema/tables/TableOutputTagMap.js.map +1 -0
  133. package/out/src/storage/schema/tables/{ProvenTx.d.ts → TableProvenTx.d.ts} +1 -1
  134. package/out/src/storage/schema/tables/TableProvenTx.d.ts.map +1 -0
  135. package/out/src/storage/schema/tables/{Commission.js → TableProvenTx.js} +1 -1
  136. package/out/src/storage/schema/tables/TableProvenTx.js.map +1 -0
  137. package/out/src/storage/schema/tables/{ProvenTxReq.d.ts → TableProvenTxReq.d.ts} +1 -1
  138. package/out/src/storage/schema/tables/TableProvenTxReq.d.ts.map +1 -0
  139. package/out/src/storage/schema/tables/TableProvenTxReq.js +3 -0
  140. package/out/src/storage/schema/tables/TableProvenTxReq.js.map +1 -0
  141. package/out/src/storage/schema/tables/TableSettings.d.ts +1 -1
  142. package/out/src/storage/schema/tables/TableSettings.d.ts.map +1 -1
  143. package/out/src/storage/schema/tables/{SyncState.d.ts → TableSyncState.d.ts} +1 -1
  144. package/out/src/storage/schema/tables/TableSyncState.d.ts.map +1 -0
  145. package/out/src/storage/schema/tables/TableSyncState.js +3 -0
  146. package/out/src/storage/schema/tables/TableSyncState.js.map +1 -0
  147. package/out/src/storage/schema/tables/{Transaction.d.ts → TableTransaction.d.ts} +1 -1
  148. package/out/src/storage/schema/tables/TableTransaction.d.ts.map +1 -0
  149. package/out/src/storage/schema/tables/{Transaction.js → TableTransaction.js} +1 -1
  150. package/out/src/storage/schema/tables/TableTransaction.js.map +1 -0
  151. package/out/src/storage/schema/tables/{TxLabel.d.ts → TableTxLabel.d.ts} +1 -1
  152. package/out/src/storage/schema/tables/TableTxLabel.d.ts.map +1 -0
  153. package/out/src/storage/schema/tables/{OutputBasket.js → TableTxLabel.js} +1 -1
  154. package/out/src/storage/schema/tables/TableTxLabel.js.map +1 -0
  155. package/out/src/storage/schema/tables/{TxLabelMap.d.ts → TableTxLabelMap.d.ts} +1 -1
  156. package/out/src/storage/schema/tables/TableTxLabelMap.d.ts.map +1 -0
  157. package/out/src/storage/schema/tables/TableTxLabelMap.js +3 -0
  158. package/out/src/storage/schema/tables/TableTxLabelMap.js.map +1 -0
  159. package/out/src/storage/schema/tables/{User.d.ts → TableUser.d.ts} +1 -1
  160. package/out/src/storage/schema/tables/TableUser.d.ts.map +1 -0
  161. package/out/src/storage/schema/tables/{SyncState.js → TableUser.js} +1 -1
  162. package/out/src/storage/schema/tables/TableUser.js.map +1 -0
  163. package/out/src/storage/schema/tables/index.d.ts +15 -15
  164. package/out/src/storage/schema/tables/index.d.ts.map +1 -1
  165. package/out/src/storage/schema/tables/index.js +15 -15
  166. package/out/src/storage/schema/tables/index.js.map +1 -1
  167. package/out/test/Wallet/local/localWallet2.man.test.js +4 -0
  168. package/out/test/Wallet/local/localWallet2.man.test.js.map +1 -1
  169. package/out/test/Wallet/support/operations.man.test.d.ts +2 -0
  170. package/out/test/Wallet/support/operations.man.test.d.ts.map +1 -0
  171. package/out/test/Wallet/support/{opers1.man.test.js → operations.man.test.js} +39 -4
  172. package/out/test/Wallet/support/operations.man.test.js.map +1 -0
  173. package/out/test/storage/find.test.js +1 -1
  174. package/out/test/storage/find.test.js.map +1 -1
  175. package/out/test/storage/idb/allocateChange.test.d.ts +2 -0
  176. package/out/test/storage/idb/allocateChange.test.d.ts.map +1 -0
  177. package/out/test/storage/idb/allocateChange.test.js +110 -0
  178. package/out/test/storage/idb/allocateChange.test.js.map +1 -0
  179. package/out/test/storage/idb/count.test.d.ts +2 -0
  180. package/out/test/storage/idb/count.test.d.ts.map +1 -0
  181. package/out/test/storage/idb/count.test.js +129 -0
  182. package/out/test/storage/idb/count.test.js.map +1 -0
  183. package/out/test/storage/idb/find.test.d.ts +2 -0
  184. package/out/test/storage/idb/find.test.d.ts.map +1 -0
  185. package/out/test/storage/idb/find.test.js +131 -0
  186. package/out/test/storage/idb/find.test.js.map +1 -0
  187. package/out/test/storage/idb/idbSpeed.test.d.ts +2 -0
  188. package/out/test/storage/idb/idbSpeed.test.d.ts.map +1 -0
  189. package/out/test/storage/idb/idbSpeed.test.js +29 -0
  190. package/out/test/storage/idb/idbSpeed.test.js.map +1 -0
  191. package/out/test/storage/idb/insert.test.d.ts +2 -0
  192. package/out/test/storage/idb/insert.test.d.ts.map +1 -0
  193. package/out/test/storage/idb/insert.test.js +242 -0
  194. package/out/test/storage/idb/insert.test.js.map +1 -0
  195. package/out/test/storage/idb/transactionAbort.test.d.ts +2 -0
  196. package/out/test/storage/idb/transactionAbort.test.d.ts.map +1 -0
  197. package/out/test/storage/idb/transactionAbort.test.js +97 -0
  198. package/out/test/storage/idb/transactionAbort.test.js.map +1 -0
  199. package/out/test/storage/idb/update.test.d.ts +2 -0
  200. package/out/test/storage/idb/update.test.d.ts.map +1 -0
  201. package/out/test/storage/idb/update.test.js +902 -0
  202. package/out/test/storage/idb/update.test.js.map +1 -0
  203. package/out/test/storage/update.test.js +2 -2
  204. package/out/test/storage/update.test.js.map +1 -1
  205. package/out/test/utils/TestUtilsWalletStorage.d.ts +24 -1
  206. package/out/test/utils/TestUtilsWalletStorage.d.ts.map +1 -1
  207. package/out/test/utils/TestUtilsWalletStorage.js +147 -3
  208. package/out/test/utils/TestUtilsWalletStorage.js.map +1 -1
  209. package/out/test/wallet/list/listActions.test.d.ts +1 -1
  210. package/out/test/wallet/list/listActions.test.d.ts.map +1 -1
  211. package/out/test/wallet/list/listActions.test.js +9 -3
  212. package/out/test/wallet/list/listActions.test.js.map +1 -1
  213. package/out/test/wallet/list/listOutputs.test.d.ts +1 -1
  214. package/out/test/wallet/list/listOutputs.test.d.ts.map +1 -1
  215. package/out/test/wallet/list/listOutputs.test.js +34 -219
  216. package/out/test/wallet/list/listOutputs.test.js.map +1 -1
  217. package/out/tsconfig.all.tsbuildinfo +1 -1
  218. package/package.json +3 -1
  219. package/src/Setup.ts +1 -71
  220. package/src/SetupClient.ts +312 -0
  221. package/src/SetupWallet.ts +105 -0
  222. package/src/index.all.ts +2 -0
  223. package/src/index.client.ts +1 -0
  224. package/src/monitor/Monitor.ts +4 -0
  225. package/src/monitor/MonitorDaemon.ts +0 -1
  226. package/src/monitor/tasks/TaskUnFail.ts +3 -4
  227. package/src/sdk/WalletServices.interfaces.ts +1 -2
  228. package/src/services/__tests/postBeef.test.ts +1 -1
  229. package/src/storage/StorageIdb.ts +2298 -0
  230. package/src/storage/StorageKnex.ts +7 -32
  231. package/src/storage/StorageProvider.ts +28 -0
  232. package/src/storage/StorageReader.ts +5 -1
  233. package/src/storage/__test/StorageIdb.test.ts +15 -0
  234. package/src/storage/methods/ListActionsSpecOp.ts +68 -0
  235. package/src/storage/methods/ListOutputsSpecOp.ts +125 -0
  236. package/src/storage/methods/listActionsIdb.ts +181 -0
  237. package/src/storage/methods/{listActions.ts → listActionsKnex.ts} +2 -64
  238. package/src/storage/methods/listOutputsIdb.ts +199 -0
  239. package/src/storage/methods/{listOutputs.ts → listOutputsKnex.ts} +9 -133
  240. package/src/storage/methods/purgeDataIdb.ts +15 -0
  241. package/src/storage/methods/reviewStatus.ts +11 -0
  242. package/src/storage/methods/reviewStatusIdb.ts +43 -0
  243. package/src/storage/schema/StorageIdbSchema.ts +150 -0
  244. package/src/storage/schema/entities/__tests/ProvenTxTests.test.ts +1 -1
  245. package/src/storage/schema/tables/TableSettings.ts +1 -1
  246. package/src/storage/schema/tables/index.ts +15 -15
  247. package/test/Wallet/local/localWallet2.man.test.ts +5 -0
  248. package/test/Wallet/support/{opers1.man.test.ts → operations.man.test.ts} +41 -12
  249. package/test/storage/find.test.ts +1 -1
  250. package/test/storage/idb/allocateChange.test.ts +251 -0
  251. package/test/storage/idb/count.test.ts +158 -0
  252. package/test/storage/idb/find.test.ts +177 -0
  253. package/test/storage/idb/idbSpeed.test.ts +34 -0
  254. package/test/storage/idb/insert.test.ts +268 -0
  255. package/test/storage/idb/transactionAbort.test.ts +108 -0
  256. package/test/storage/idb/update.test.ts +1000 -0
  257. package/test/storage/update.test.ts +2 -2
  258. package/test/utils/TestUtilsWalletStorage.ts +188 -4
  259. package/test/wallet/list/listActions.test.ts +15 -5
  260. package/test/wallet/list/listOutputs.test.ts +29 -214
  261. package/out/src/storage/methods/listActions.d.ts.map +0 -1
  262. package/out/src/storage/methods/listActions.js.map +0 -1
  263. package/out/src/storage/methods/listOutputs.d.ts.map +0 -1
  264. package/out/src/storage/methods/listOutputs.js.map +0 -1
  265. package/out/src/storage/schema/tables/Certificate.d.ts.map +0 -1
  266. package/out/src/storage/schema/tables/Certificate.js.map +0 -1
  267. package/out/src/storage/schema/tables/CertificateField.d.ts.map +0 -1
  268. package/out/src/storage/schema/tables/CertificateField.js.map +0 -1
  269. package/out/src/storage/schema/tables/Commission.d.ts.map +0 -1
  270. package/out/src/storage/schema/tables/Commission.js.map +0 -1
  271. package/out/src/storage/schema/tables/MonitorEvent.d.ts.map +0 -1
  272. package/out/src/storage/schema/tables/MonitorEvent.js.map +0 -1
  273. package/out/src/storage/schema/tables/Output.d.ts.map +0 -1
  274. package/out/src/storage/schema/tables/Output.js.map +0 -1
  275. package/out/src/storage/schema/tables/OutputBasket.d.ts.map +0 -1
  276. package/out/src/storage/schema/tables/OutputBasket.js.map +0 -1
  277. package/out/src/storage/schema/tables/OutputTag.d.ts.map +0 -1
  278. package/out/src/storage/schema/tables/OutputTag.js +0 -3
  279. package/out/src/storage/schema/tables/OutputTag.js.map +0 -1
  280. package/out/src/storage/schema/tables/OutputTagMap.d.ts.map +0 -1
  281. package/out/src/storage/schema/tables/OutputTagMap.js +0 -3
  282. package/out/src/storage/schema/tables/OutputTagMap.js.map +0 -1
  283. package/out/src/storage/schema/tables/ProvenTx.d.ts.map +0 -1
  284. package/out/src/storage/schema/tables/ProvenTx.js +0 -3
  285. package/out/src/storage/schema/tables/ProvenTx.js.map +0 -1
  286. package/out/src/storage/schema/tables/ProvenTxReq.d.ts.map +0 -1
  287. package/out/src/storage/schema/tables/ProvenTxReq.js +0 -3
  288. package/out/src/storage/schema/tables/ProvenTxReq.js.map +0 -1
  289. package/out/src/storage/schema/tables/SyncState.d.ts.map +0 -1
  290. package/out/src/storage/schema/tables/SyncState.js.map +0 -1
  291. package/out/src/storage/schema/tables/Transaction.d.ts.map +0 -1
  292. package/out/src/storage/schema/tables/Transaction.js.map +0 -1
  293. package/out/src/storage/schema/tables/TxLabel.d.ts.map +0 -1
  294. package/out/src/storage/schema/tables/TxLabel.js +0 -3
  295. package/out/src/storage/schema/tables/TxLabel.js.map +0 -1
  296. package/out/src/storage/schema/tables/TxLabelMap.d.ts.map +0 -1
  297. package/out/src/storage/schema/tables/TxLabelMap.js +0 -3
  298. package/out/src/storage/schema/tables/TxLabelMap.js.map +0 -1
  299. package/out/src/storage/schema/tables/User.d.ts.map +0 -1
  300. package/out/src/storage/schema/tables/User.js +0 -3
  301. package/out/src/storage/schema/tables/User.js.map +0 -1
  302. package/out/test/Wallet/support/opers1.man.test.d.ts +0 -2
  303. package/out/test/Wallet/support/opers1.man.test.d.ts.map +0 -1
  304. package/out/test/Wallet/support/opers1.man.test.js.map +0 -1
  305. package/unlock-migrations.sh +0 -41
  306. /package/src/storage/schema/tables/{Certificate.ts → TableCertificate.ts} +0 -0
  307. /package/src/storage/schema/tables/{CertificateField.ts → TableCertificateField.ts} +0 -0
  308. /package/src/storage/schema/tables/{Commission.ts → TableCommission.ts} +0 -0
  309. /package/src/storage/schema/tables/{MonitorEvent.ts → TableMonitorEvent.ts} +0 -0
  310. /package/src/storage/schema/tables/{Output.ts → TableOutput.ts} +0 -0
  311. /package/src/storage/schema/tables/{OutputBasket.ts → TableOutputBasket.ts} +0 -0
  312. /package/src/storage/schema/tables/{OutputTag.ts → TableOutputTag.ts} +0 -0
  313. /package/src/storage/schema/tables/{OutputTagMap.ts → TableOutputTagMap.ts} +0 -0
  314. /package/src/storage/schema/tables/{ProvenTx.ts → TableProvenTx.ts} +0 -0
  315. /package/src/storage/schema/tables/{ProvenTxReq.ts → TableProvenTxReq.ts} +0 -0
  316. /package/src/storage/schema/tables/{SyncState.ts → TableSyncState.ts} +0 -0
  317. /package/src/storage/schema/tables/{Transaction.ts → TableTransaction.ts} +0 -0
  318. /package/src/storage/schema/tables/{TxLabel.ts → TableTxLabel.ts} +0 -0
  319. /package/src/storage/schema/tables/{TxLabelMap.ts → TableTxLabelMap.ts} +0 -0
  320. /package/src/storage/schema/tables/{User.ts → TableUser.ts} +0 -0
@@ -0,0 +1,2298 @@
1
+ import { deleteDB, IDBPCursorWithValue, IDBPDatabase, IDBPTransaction, openDB } from 'idb'
2
+ import { ListActionsResult, ListOutputsResult } from '@bsv/sdk'
3
+ import {
4
+ sdk,
5
+ TableCertificate,
6
+ TableCertificateField,
7
+ TableCertificateX,
8
+ TableCommission,
9
+ TableMonitorEvent,
10
+ TableOutput,
11
+ TableOutputBasket,
12
+ TableOutputTag,
13
+ TableOutputTagMap,
14
+ TableProvenTx,
15
+ TableProvenTxReq,
16
+ TableSettings,
17
+ TableSyncState,
18
+ TableTransaction,
19
+ TableTxLabel,
20
+ TableTxLabelMap,
21
+ TableUser,
22
+ verifyOne,
23
+ verifyOneOrNone
24
+ } from '../index.client'
25
+ import { StorageProvider, StorageProviderOptions } from './StorageProvider'
26
+ import { StorageIdbSchema } from './schema/StorageIdbSchema'
27
+ import { DBType } from './StorageReader'
28
+ import { TransactionStatus } from '../sdk'
29
+ import { listActionsIdb } from './methods/listActionsIdb'
30
+ import { listOutputsIdb } from './methods/listOutputsIdb'
31
+ import { reviewStatusIdb } from './methods/reviewStatusIdb'
32
+ import { purgeDataIdb } from './methods/purgeDataIdb'
33
+
34
+ export interface StorageIdbOptions extends StorageProviderOptions {}
35
+
36
+ export class StorageIdb extends StorageProvider implements sdk.WalletStorageProvider {
37
+ dbName: string
38
+ db?: IDBPDatabase<StorageIdbSchema>
39
+
40
+ constructor(options: StorageIdbOptions) {
41
+ super(options)
42
+ this.dbName = `wallet-toolbox-${this.chain}net`
43
+ }
44
+
45
+ /**
46
+ * This method must be called at least once before any other method accesses the database,
47
+ * and each time the schema may have updated.
48
+ *
49
+ * If the database has already been created in this context, `storageName` and `storageIdentityKey`
50
+ * are ignored.
51
+ *
52
+ * @param storageName
53
+ * @param storageIdentityKey
54
+ * @returns
55
+ */
56
+ async migrate(storageName: string, storageIdentityKey: string): Promise<string> {
57
+ const db = await this.verifyDB(storageName, storageIdentityKey)
58
+ return db.version.toString()
59
+ }
60
+
61
+ /**
62
+ * Following initial database initialization, this method verfies that db is ready for use.
63
+ *
64
+ * @throws `WERR_INVALID_OPERATION` if the database has not been initialized by a call to `migrate`.
65
+ *
66
+ * @param storageName
67
+ * @param storageIdentityKey
68
+ *
69
+ * @returns
70
+ */
71
+ async verifyDB(storageName?: string, storageIdentityKey?: string): Promise<IDBPDatabase<StorageIdbSchema>> {
72
+ if (this.db) return this.db
73
+ this.db = await this.initDB(storageName, storageIdentityKey)
74
+ this._settings = (await this.db.getAll('settings'))[0]
75
+ this.whenLastAccess = new Date()
76
+ return this.db
77
+ }
78
+
79
+ /**
80
+ * Convert the standard optional `TrxToken` parameter into either a direct knex database instance,
81
+ * or a Knex.Transaction as appropriate.
82
+ */
83
+ toDbTrx(
84
+ stores: string[],
85
+ mode: 'readonly' | 'readwrite',
86
+ trx?: sdk.TrxToken
87
+ ): IDBPTransaction<StorageIdbSchema, string[], 'readwrite' | 'readonly'> {
88
+ if (trx) {
89
+ const t = trx as IDBPTransaction<StorageIdbSchema, string[], 'readwrite' | 'readonly'>
90
+ return t
91
+ } else {
92
+ if (!this.db) throw new Error('not initialized')
93
+ const db = this.db
94
+ const trx = db.transaction(stores || this.allStores, mode || 'readwrite')
95
+ this.whenLastAccess = new Date()
96
+ return trx
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Called by `makeAvailable` to return storage `TableSettings`.
102
+ * Since this is the first async method that must be called by all clients,
103
+ * it is where async initialization occurs.
104
+ *
105
+ * After initialization, cached settings are returned.
106
+ *
107
+ * @param trx
108
+ */
109
+ async readSettings(trx?: sdk.TrxToken): Promise<TableSettings> {
110
+ await this.verifyDB()
111
+ return this._settings!
112
+ }
113
+
114
+ async initDB(storageName?: string, storageIdentityKey?: string): Promise<IDBPDatabase<StorageIdbSchema>> {
115
+ const chain = this.chain
116
+ const maxOutputScript = 1024
117
+ const db = await openDB<StorageIdbSchema>(this.dbName, 1, {
118
+ upgrade(db, oldVersion, newVersion, transaction) {
119
+ if (!db.objectStoreNames.contains('proven_txs')) {
120
+ // proven_txs object store
121
+ const provenTxsStore = db.createObjectStore('proven_txs', {
122
+ keyPath: 'provenTxId',
123
+ autoIncrement: true
124
+ })
125
+ provenTxsStore.createIndex('txid', 'txid', { unique: true })
126
+ }
127
+
128
+ if (!db.objectStoreNames.contains('proven_tx_reqs')) {
129
+ // proven_tx_reqs object store
130
+ const provenTxReqsStore = db.createObjectStore('proven_tx_reqs', {
131
+ keyPath: 'provenTxReqId',
132
+ autoIncrement: true
133
+ })
134
+ provenTxReqsStore.createIndex('provenTxId', 'provenTxId')
135
+ provenTxReqsStore.createIndex('txid', 'txid', { unique: true })
136
+ provenTxReqsStore.createIndex('status', 'status')
137
+ provenTxReqsStore.createIndex('batch', 'batch')
138
+ }
139
+ if (!db.objectStoreNames.contains('users')) {
140
+ const users = db.createObjectStore('users', {
141
+ keyPath: 'userId',
142
+ autoIncrement: true
143
+ })
144
+ users.createIndex('identityKey', 'identityKey', { unique: true })
145
+ }
146
+ if (!db.objectStoreNames.contains('certificates')) {
147
+ // certificates object store
148
+ const certificatesStore = db.createObjectStore('certificates', {
149
+ keyPath: 'certificateId',
150
+ autoIncrement: true
151
+ })
152
+ certificatesStore.createIndex('userId', 'userId')
153
+ certificatesStore.createIndex(
154
+ 'userId_type_certifier_serialNumber',
155
+ ['userId', 'type', 'certifier', 'serialNumber'],
156
+ { unique: true }
157
+ )
158
+ }
159
+
160
+ if (!db.objectStoreNames.contains('certificate_fields')) {
161
+ // certificate_fields object store
162
+ const certificateFieldsStore = db.createObjectStore('certificate_fields', {
163
+ keyPath: ['certificateId', 'fieldName'] // Composite key
164
+ })
165
+ certificateFieldsStore.createIndex('userId', 'userId')
166
+ certificateFieldsStore.createIndex('certificateId', 'certificateId')
167
+ }
168
+
169
+ if (!db.objectStoreNames.contains('output_baskets')) {
170
+ // output_baskets object store
171
+ const outputBasketsStore = db.createObjectStore('output_baskets', {
172
+ keyPath: 'basketId',
173
+ autoIncrement: true
174
+ })
175
+ outputBasketsStore.createIndex('userId', 'userId')
176
+ outputBasketsStore.createIndex('name_userId', ['name', 'userId'], { unique: true })
177
+ }
178
+
179
+ if (!db.objectStoreNames.contains('transactions')) {
180
+ // transactions object store
181
+ const transactionsStore = db.createObjectStore('transactions', {
182
+ keyPath: 'transactionId',
183
+ autoIncrement: true
184
+ })
185
+ transactionsStore.createIndex('userId', 'userId')
186
+ transactionsStore.createIndex('status', 'status'),
187
+ transactionsStore.createIndex('status_userId', ['status', 'userId'])
188
+ transactionsStore.createIndex('provenTxId', 'provenTxId')
189
+ transactionsStore.createIndex('reference', 'reference', { unique: true })
190
+ }
191
+
192
+ if (!db.objectStoreNames.contains('commissions')) {
193
+ // commissions object store
194
+ const commissionsStore = db.createObjectStore('commissions', {
195
+ keyPath: 'commissionId',
196
+ autoIncrement: true
197
+ })
198
+ commissionsStore.createIndex('userId', 'userId')
199
+ commissionsStore.createIndex('transactionId', 'transactionId', { unique: true })
200
+ }
201
+
202
+ if (!db.objectStoreNames.contains('outputs')) {
203
+ // outputs object store
204
+ const outputsStore = db.createObjectStore('outputs', {
205
+ keyPath: 'outputId',
206
+ autoIncrement: true
207
+ })
208
+ outputsStore.createIndex('userId', 'userId')
209
+ outputsStore.createIndex('transactionId', 'transactionId')
210
+ outputsStore.createIndex('basketId', 'basketId')
211
+ outputsStore.createIndex('spentBy', 'spentBy')
212
+ outputsStore.createIndex('transactionId_vout_userId', ['transactionId', 'vout', 'userId'], { unique: true })
213
+ }
214
+
215
+ if (!db.objectStoreNames.contains('output_tags')) {
216
+ // output_tags object store
217
+ const outputTagsStore = db.createObjectStore('output_tags', {
218
+ keyPath: 'outputTagId',
219
+ autoIncrement: true
220
+ })
221
+ outputTagsStore.createIndex('userId', 'userId')
222
+ outputTagsStore.createIndex('tag_userId', ['tag', 'userId'], { unique: true })
223
+ }
224
+
225
+ if (!db.objectStoreNames.contains('output_tags_map')) {
226
+ // output_tags_map object store
227
+ const outputTagsMapStore = db.createObjectStore('output_tags_map', {
228
+ keyPath: ['outputTagId', 'outputId']
229
+ })
230
+ outputTagsMapStore.createIndex('outputTagId', 'outputTagId')
231
+ outputTagsMapStore.createIndex('outputId', 'outputId')
232
+ }
233
+
234
+ if (!db.objectStoreNames.contains('tx_labels')) {
235
+ // tx_labels object store
236
+ const txLabelsStore = db.createObjectStore('tx_labels', {
237
+ keyPath: 'txLabelId',
238
+ autoIncrement: true
239
+ })
240
+ txLabelsStore.createIndex('userId', 'userId')
241
+ txLabelsStore.createIndex('label_userId', ['label', 'userId'], { unique: true })
242
+ }
243
+
244
+ if (!db.objectStoreNames.contains('tx_labels_map')) {
245
+ // tx_labels_map object store
246
+ const txLabelsMapStore = db.createObjectStore('tx_labels_map', {
247
+ keyPath: ['txLabelId', 'transactionId']
248
+ })
249
+ txLabelsMapStore.createIndex('txLabelId', 'txLabelId')
250
+ txLabelsMapStore.createIndex('transactionId', 'transactionId')
251
+ }
252
+
253
+ if (!db.objectStoreNames.contains('monitor_events')) {
254
+ // monitor_events object store
255
+ const monitorEventsStore = db.createObjectStore('monitor_events', {
256
+ keyPath: 'id',
257
+ autoIncrement: true
258
+ })
259
+ }
260
+
261
+ if (!db.objectStoreNames.contains('sync_states')) {
262
+ // sync_states object store
263
+ const syncStatesStore = db.createObjectStore('sync_states', {
264
+ keyPath: 'syncStateId',
265
+ autoIncrement: true
266
+ })
267
+ syncStatesStore.createIndex('userId', 'userId')
268
+ syncStatesStore.createIndex('refNum', 'refNum', { unique: true })
269
+ syncStatesStore.createIndex('status', 'status')
270
+ }
271
+
272
+ if (!db.objectStoreNames.contains('settings')) {
273
+ if (!storageName || !storageIdentityKey) {
274
+ throw new sdk.WERR_INVALID_OPERATION('migrate must be called before first access')
275
+ }
276
+ const settings = db.createObjectStore('settings', {
277
+ keyPath: 'storageIdentityKey'
278
+ })
279
+ const s: TableSettings = {
280
+ created_at: new Date(),
281
+ updated_at: new Date(),
282
+ storageIdentityKey,
283
+ storageName,
284
+ chain,
285
+ dbtype: 'IndexedDB',
286
+ maxOutputScript
287
+ }
288
+ settings.put(s)
289
+ }
290
+ }
291
+ })
292
+ return db
293
+ }
294
+
295
+ //
296
+ // StorageProvider abstract methods
297
+ //
298
+
299
+ async reviewStatus(args: { agedLimit: Date; trx?: sdk.TrxToken }): Promise<{ log: string }> {
300
+ return await reviewStatusIdb(this, args)
301
+ }
302
+
303
+ async purgeData(params: sdk.PurgeParams, trx?: sdk.TrxToken): Promise<sdk.PurgeResults> {
304
+ return await purgeDataIdb(this, params, trx)
305
+ }
306
+
307
+ /**
308
+ * Proceeds in three stages:
309
+ * 1. Find an output that exactly funds the transaction (if exactSatoshis is not undefined).
310
+ * 2. Find an output that overfunds by the least amount (targetSatoshis).
311
+ * 3. Find an output that comes as close to funding as possible (targetSatoshis).
312
+ * 4. Return undefined if no output is found.
313
+ *
314
+ * Outputs must belong to userId and basketId and have spendable true.
315
+ * Their corresponding transaction must have status of 'completed', 'unproven', or 'sending' (if excludeSending is false).
316
+ *
317
+ * @param userId
318
+ * @param basketId
319
+ * @param targetSatoshis
320
+ * @param exactSatoshis
321
+ * @param excludeSending
322
+ * @param transactionId
323
+ * @returns next funding output to add to transaction or undefined if there are none.
324
+ */
325
+ async allocateChangeInput(
326
+ userId: number,
327
+ basketId: number,
328
+ targetSatoshis: number,
329
+ exactSatoshis: number | undefined,
330
+ excludeSending: boolean,
331
+ transactionId: number
332
+ ): Promise<TableOutput | undefined> {
333
+ const dbTrx = this.toDbTrx(['outputs', 'transactions'], 'readwrite')
334
+ try {
335
+ const txStatus: TransactionStatus[] = ['completed', 'unproven']
336
+ if (!excludeSending) txStatus.push('sending')
337
+ const args: sdk.FindOutputsArgs = {
338
+ partial: { userId, basketId, spendable: true },
339
+ txStatus,
340
+ trx: dbTrx
341
+ }
342
+ const outputs = await this.findOutputs(args)
343
+ let output: TableOutput | undefined
344
+ let scores: { output: TableOutput; score: number }[] = []
345
+ for (const o of outputs) {
346
+ if (exactSatoshis && o.satoshis === exactSatoshis) {
347
+ output = o
348
+ break
349
+ }
350
+ const score = o.satoshis - targetSatoshis
351
+ scores.push({ output: o, score })
352
+ }
353
+ if (!output) {
354
+ // sort scores increasing by score property
355
+ scores = scores.sort((a, b) => a.score - b.score)
356
+ // find the first score that is greater than or equal to 0
357
+ const o = scores.find(s => s.score >= 0)
358
+ if (o) {
359
+ // stage 2 satisfied (minimally funded)
360
+ output = o.output
361
+ } else if (scores.length > 0) {
362
+ // stage 3 satisfied (minimally under-funded)
363
+ output = scores.slice(-1)[0].output
364
+ } else {
365
+ // no available funding outputs
366
+ output = undefined
367
+ }
368
+ }
369
+ if (output) {
370
+ // mark output as spent by transactionId
371
+ await this.updateOutput(output.outputId, { spendable: false, spentBy: transactionId }, dbTrx)
372
+ }
373
+ return output
374
+ } finally {
375
+ await dbTrx.done
376
+ }
377
+ }
378
+
379
+ async getProvenOrRawTx(txid: string, trx?: sdk.TrxToken): Promise<sdk.ProvenOrRawTx> {
380
+ const r: sdk.ProvenOrRawTx = {
381
+ proven: undefined,
382
+ rawTx: undefined,
383
+ inputBEEF: undefined
384
+ }
385
+
386
+ r.proven = verifyOneOrNone(await this.findProvenTxs({ partial: { txid: txid }, trx }))
387
+ if (!r.proven) {
388
+ const req = verifyOneOrNone(await this.findProvenTxReqs({ partial: { txid: txid }, trx }))
389
+ if (req && ['unsent', 'unmined', 'unconfirmed', 'sending', 'nosend', 'completed'].includes(req.status)) {
390
+ r.rawTx = req.rawTx
391
+ r.inputBEEF = req.inputBEEF
392
+ }
393
+ }
394
+
395
+ return r
396
+ }
397
+
398
+ async getRawTxOfKnownValidTransaction(
399
+ txid?: string,
400
+ offset?: number,
401
+ length?: number,
402
+ trx?: sdk.TrxToken
403
+ ): Promise<number[] | undefined> {
404
+ if (!txid) return undefined
405
+ if (!this.isAvailable()) await this.makeAvailable()
406
+
407
+ let rawTx: number[] | undefined = undefined
408
+ const r = await this.getProvenOrRawTx(txid, trx)
409
+ if (r.proven) rawTx = r.proven.rawTx
410
+ else rawTx = r.rawTx
411
+ if (rawTx && offset !== undefined && length !== undefined && Number.isInteger(offset) && Number.isInteger(length)) {
412
+ rawTx = rawTx.slice(offset, offset + length)
413
+ }
414
+ return rawTx
415
+ }
416
+
417
+ async getLabelsForTransactionId(transactionId?: number, trx?: sdk.TrxToken): Promise<TableTxLabel[]> {
418
+ const maps = await this.findTxLabelMaps({ partial: { transactionId, isDeleted: false }, trx })
419
+ const labelIds = maps.map(m => m.txLabelId)
420
+ const labels: TableTxLabel[] = []
421
+ for (const txLabelId of labelIds) {
422
+ const label = verifyOne(await this.findTxLabels({ partial: { txLabelId, isDeleted: false }, trx }))
423
+ labels.push(label)
424
+ }
425
+ return labels
426
+ }
427
+
428
+ async getTagsForOutputId(outputId: number, trx?: sdk.TrxToken): Promise<TableOutputTag[]> {
429
+ const maps = await this.findOutputTagMaps({ partial: { outputId, isDeleted: false }, trx })
430
+ const tagIds = maps.map(m => m.outputTagId)
431
+ const tags: TableOutputTag[] = []
432
+ for (const outputTagId of tagIds) {
433
+ const tag = verifyOne(await this.findOutputTags({ partial: { outputTagId, isDeleted: false }, trx }))
434
+ tags.push(tag)
435
+ }
436
+ return tags
437
+ }
438
+
439
+ async listActions(auth: sdk.AuthId, vargs: sdk.ValidListActionsArgs): Promise<ListActionsResult> {
440
+ if (!auth.userId) throw new sdk.WERR_UNAUTHORIZED()
441
+ return await listActionsIdb(this, auth, vargs)
442
+ }
443
+
444
+ async listOutputs(auth: sdk.AuthId, vargs: sdk.ValidListOutputsArgs): Promise<ListOutputsResult> {
445
+ if (!auth.userId) throw new sdk.WERR_UNAUTHORIZED()
446
+ return await listOutputsIdb(this, auth, vargs)
447
+ }
448
+
449
+ async countChangeInputs(userId: number, basketId: number, excludeSending: boolean): Promise<number> {
450
+ const txStatus: sdk.TransactionStatus[] = ['completed', 'unproven']
451
+ if (!excludeSending) txStatus.push('sending')
452
+ const args: sdk.FindOutputsArgs = { partial: { userId, basketId }, txStatus }
453
+ let count = 0
454
+ await this.filterOutputs(args, r => {
455
+ count++
456
+ })
457
+ return count
458
+ }
459
+
460
+ async findCertificatesAuth(auth: sdk.AuthId, args: sdk.FindCertificatesArgs): Promise<TableCertificateX[]> {
461
+ if (!auth.userId || (args.partial.userId && args.partial.userId !== auth.userId)) throw new sdk.WERR_UNAUTHORIZED()
462
+ args.partial.userId = auth.userId
463
+ return await this.findCertificates(args)
464
+ }
465
+ async findOutputBasketsAuth(auth: sdk.AuthId, args: sdk.FindOutputBasketsArgs): Promise<TableOutputBasket[]> {
466
+ if (!auth.userId || (args.partial.userId && args.partial.userId !== auth.userId)) throw new sdk.WERR_UNAUTHORIZED()
467
+ args.partial.userId = auth.userId
468
+ return await this.findOutputBaskets(args)
469
+ }
470
+ async findOutputsAuth(auth: sdk.AuthId, args: sdk.FindOutputsArgs): Promise<TableOutput[]> {
471
+ if (!auth.userId || (args.partial.userId && args.partial.userId !== auth.userId)) throw new sdk.WERR_UNAUTHORIZED()
472
+ args.partial.userId = auth.userId
473
+ return await this.findOutputs(args)
474
+ }
475
+
476
+ async insertCertificateAuth(auth: sdk.AuthId, certificate: TableCertificateX): Promise<number> {
477
+ if (!auth.userId || (certificate.userId && certificate.userId !== auth.userId)) throw new sdk.WERR_UNAUTHORIZED()
478
+ certificate.userId = auth.userId
479
+ return await this.insertCertificate(certificate)
480
+ }
481
+
482
+ //
483
+ // StorageReaderWriter abstract methods
484
+ //
485
+
486
+ async dropAllData(): Promise<void> {
487
+ await deleteDB(this.dbName)
488
+ }
489
+
490
+ async filterOutputTagMaps(
491
+ args: sdk.FindOutputTagMapsArgs,
492
+ filtered: (v: TableOutputTagMap) => void,
493
+ userId?: number
494
+ ): Promise<void> {
495
+ const offset = args.paged?.offset || 0
496
+ let skipped = 0
497
+ let count = 0
498
+ const dbTrx = this.toDbTrx(['output_tags_map'], 'readonly', args.trx)
499
+ let cursor:
500
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'output_tags_map', unknown, 'readwrite' | 'readonly'>
501
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'output_tags_map', 'outputTagId', 'readwrite' | 'readonly'>
502
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'output_tags_map', 'outputId', 'readwrite' | 'readonly'>
503
+ | null
504
+ if (args.partial?.outputTagId !== undefined) {
505
+ cursor = await dbTrx.objectStore('output_tags_map').index('outputTagId').openCursor(args.partial.outputTagId)
506
+ } else if (args.partial?.outputId !== undefined) {
507
+ cursor = await dbTrx.objectStore('output_tags_map').index('outputId').openCursor(args.partial.outputId)
508
+ } else {
509
+ cursor = await dbTrx.objectStore('output_tags_map').openCursor()
510
+ }
511
+ let firstTime = true
512
+ while (cursor) {
513
+ if (!firstTime) cursor = await cursor.continue()
514
+ if (!cursor) break
515
+ firstTime = false
516
+ const r = cursor.value
517
+ if (args.since && args.since > r.updated_at) continue
518
+ if (args.tagIds && !args.tagIds.includes(r.outputTagId)) continue
519
+ if (args.partial) {
520
+ if (args.partial.outputTagId && r.outputTagId !== args.partial.outputTagId) continue
521
+ if (args.partial.outputId && r.outputId !== args.partial.outputId) continue
522
+ if (args.partial.created_at && r.created_at.getTime() !== args.partial.created_at.getTime()) continue
523
+ if (args.partial.updated_at && r.updated_at.getTime() !== args.partial.updated_at.getTime()) continue
524
+ if (args.partial.isDeleted !== undefined && r.isDeleted !== args.partial.isDeleted) continue
525
+ }
526
+ if (userId !== undefined && r.txid) {
527
+ const count = await this.countOutputTags({ partial: { userId, outputTagId: r.outputTagId }, trx: args.trx })
528
+ if (count === 0) continue
529
+ }
530
+ if (skipped < offset) {
531
+ skipped++
532
+ continue
533
+ }
534
+ filtered(r)
535
+ count++
536
+ if (args.paged?.limit && count >= args.paged.limit) break
537
+ }
538
+ if (!args.trx) await dbTrx.done
539
+ }
540
+
541
+ async findOutputTagMaps(args: sdk.FindOutputTagMapsArgs): Promise<TableOutputTagMap[]> {
542
+ const results: TableOutputTagMap[] = []
543
+ await this.filterOutputTagMaps(args, r => {
544
+ results.push(this.validateEntity(r))
545
+ })
546
+ return results
547
+ }
548
+
549
+ async filterProvenTxReqs(
550
+ args: sdk.FindProvenTxReqsArgs,
551
+ filtered: (v: TableProvenTxReq) => void,
552
+ userId?: number
553
+ ): Promise<void> {
554
+ if (args.partial.rawTx)
555
+ throw new sdk.WERR_INVALID_PARAMETER(
556
+ 'args.partial.rawTx',
557
+ `undefined. ProvenTxReqs may not be found by rawTx value.`
558
+ )
559
+ if (args.partial.inputBEEF)
560
+ throw new sdk.WERR_INVALID_PARAMETER(
561
+ 'args.partial.inputBEEF',
562
+ `undefined. ProvenTxReqs may not be found by inputBEEF value.`
563
+ )
564
+ const offset = args.paged?.offset || 0
565
+ let skipped = 0
566
+ let count = 0
567
+ const dbTrx = this.toDbTrx(['proven_tx_reqs'], 'readonly', args.trx)
568
+ let cursor:
569
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'proven_tx_reqs', unknown, 'readwrite' | 'readonly'>
570
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'proven_tx_reqs', 'provenTxId', 'readwrite' | 'readonly'>
571
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'proven_tx_reqs', 'txid', 'readwrite' | 'readonly'>
572
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'proven_tx_reqs', 'status', 'readwrite' | 'readonly'>
573
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'proven_tx_reqs', 'batch', 'readwrite' | 'readonly'>
574
+ | null
575
+ if (args.partial?.provenTxReqId) {
576
+ cursor = await dbTrx.objectStore('proven_tx_reqs').openCursor(args.partial.provenTxReqId)
577
+ } else if (args.partial?.provenTxId !== undefined) {
578
+ cursor = await dbTrx.objectStore('proven_tx_reqs').index('provenTxId').openCursor(args.partial.provenTxId)
579
+ } else if (args.partial?.txid !== undefined) {
580
+ cursor = await dbTrx.objectStore('proven_tx_reqs').index('txid').openCursor(args.partial.txid)
581
+ } else if (args.partial?.status !== undefined) {
582
+ cursor = await dbTrx.objectStore('proven_tx_reqs').index('status').openCursor(args.partial.status)
583
+ } else if (args.partial?.batch !== undefined) {
584
+ cursor = await dbTrx.objectStore('proven_tx_reqs').index('batch').openCursor(args.partial.batch)
585
+ } else {
586
+ cursor = await dbTrx.objectStore('proven_tx_reqs').openCursor()
587
+ }
588
+ let firstTime = true
589
+ while (cursor) {
590
+ if (!firstTime) cursor = await cursor.continue()
591
+ if (!cursor) break
592
+ firstTime = false
593
+ const r = cursor.value
594
+ if (args.since && args.since > r.updated_at) continue
595
+ if (args.partial) {
596
+ if (args.partial.provenTxReqId && r.provenTxReqId !== args.partial.provenTxReqId) continue
597
+ if (args.partial.provenTxId && r.provenTxId !== args.partial.provenTxId) continue
598
+ if (args.partial.created_at && r.created_at.getTime() !== args.partial.created_at.getTime()) continue
599
+ if (args.partial.updated_at && r.updated_at.getTime() !== args.partial.updated_at.getTime()) continue
600
+ if (args.partial.status && r.status !== args.partial.status) continue
601
+ if (args.partial.attempts !== undefined && r.attempts !== args.partial.attempts) continue
602
+ if (args.partial.notified !== undefined && r.notified !== args.partial.notified) continue
603
+ if (args.partial.txid && r.txid !== args.partial.txid) continue
604
+ if (args.partial.batch && r.batch !== args.partial.batch) continue
605
+ if (args.partial.history && r.history !== args.partial.history) continue
606
+ if (args.partial.notify && r.notify !== args.partial.notify) continue
607
+ }
608
+ if (userId !== undefined && r.txid) {
609
+ const count = await this.countTransactions({ partial: { userId, txid: r.txid }, trx: args.trx })
610
+ if (count === 0) continue
611
+ }
612
+ if (skipped < offset) {
613
+ skipped++
614
+ continue
615
+ }
616
+ filtered(r)
617
+ count++
618
+ if (args.paged?.limit && count >= args.paged.limit) break
619
+ }
620
+ if (!args.trx) await dbTrx.done
621
+ }
622
+
623
+ async findProvenTxReqs(args: sdk.FindProvenTxReqsArgs): Promise<TableProvenTxReq[]> {
624
+ const results: TableProvenTxReq[] = []
625
+ await this.filterProvenTxReqs(args, r => {
626
+ results.push(this.validateEntity(r))
627
+ })
628
+ return results
629
+ }
630
+
631
+ async filterProvenTxs(
632
+ args: sdk.FindProvenTxsArgs,
633
+ filtered: (v: TableProvenTx) => void,
634
+ userId?: number
635
+ ): Promise<void> {
636
+ if (args.partial.rawTx)
637
+ throw new sdk.WERR_INVALID_PARAMETER(
638
+ 'args.partial.rawTx',
639
+ `undefined. ProvenTxs may not be found by rawTx value.`
640
+ )
641
+ if (args.partial.merklePath)
642
+ throw new sdk.WERR_INVALID_PARAMETER(
643
+ 'args.partial.merklePath',
644
+ `undefined. ProvenTxs may not be found by merklePath value.`
645
+ )
646
+ const offset = args.paged?.offset || 0
647
+ let skipped = 0
648
+ let count = 0
649
+ const dbTrx = this.toDbTrx(['proven_txs'], 'readonly', args.trx)
650
+ let cursor:
651
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'proven_txs', unknown, 'readwrite' | 'readonly'>
652
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'proven_txs', 'txid', 'readwrite' | 'readonly'>
653
+ | null
654
+ if (args.partial?.provenTxId) {
655
+ cursor = await dbTrx.objectStore('proven_txs').openCursor(args.partial.provenTxId)
656
+ } else if (args.partial?.txid !== undefined) {
657
+ cursor = await dbTrx.objectStore('proven_txs').index('txid').openCursor(args.partial.txid)
658
+ } else {
659
+ cursor = await dbTrx.objectStore('proven_txs').openCursor()
660
+ }
661
+ let firstTime = true
662
+ while (cursor) {
663
+ if (!firstTime) cursor = await cursor.continue()
664
+ if (!cursor) break
665
+ firstTime = false
666
+ const r = cursor.value
667
+ if (args.since && args.since > r.updated_at) continue
668
+ if (args.partial) {
669
+ if (args.partial.provenTxId && r.provenTxId !== args.partial.provenTxId) continue
670
+ if (args.partial.created_at && r.created_at.getTime() !== args.partial.created_at.getTime()) continue
671
+ if (args.partial.updated_at && r.updated_at.getTime() !== args.partial.updated_at.getTime()) continue
672
+ if (args.partial.txid && r.txid !== args.partial.txid) continue
673
+ if (args.partial.height !== undefined && r.height !== args.partial.height) continue
674
+ if (args.partial.index !== undefined && r.index !== args.partial.index) continue
675
+ if (args.partial.blockHash && r.blockHash !== args.partial.blockHash) continue
676
+ if (args.partial.merkleRoot && r.merkleRoot !== args.partial.merkleRoot) continue
677
+ }
678
+ if (userId !== undefined) {
679
+ const count = await this.countTransactions({ partial: { userId, provenTxId: r.provenTxId }, trx: args.trx })
680
+ if (count === 0) continue
681
+ }
682
+ if (skipped < offset) {
683
+ skipped++
684
+ continue
685
+ }
686
+ filtered(r)
687
+ count++
688
+ if (args.paged?.limit && count >= args.paged.limit) break
689
+ }
690
+ if (!args.trx) await dbTrx.done
691
+ }
692
+
693
+ async findProvenTxs(args: sdk.FindProvenTxsArgs): Promise<TableProvenTx[]> {
694
+ const results: TableProvenTx[] = []
695
+ await this.filterProvenTxs(args, r => {
696
+ results.push(this.validateEntity(r))
697
+ })
698
+ return results
699
+ }
700
+
701
+ async filterTxLabelMaps(
702
+ args: sdk.FindTxLabelMapsArgs,
703
+ filtered: (v: TableTxLabelMap) => void,
704
+ userId?: number
705
+ ): Promise<void> {
706
+ const offset = args.paged?.offset || 0
707
+ let skipped = 0
708
+ let count = 0
709
+ const dbTrx = this.toDbTrx(['tx_labels_map'], 'readonly', args.trx)
710
+ let cursor:
711
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'tx_labels_map', unknown, 'readwrite' | 'readonly'>
712
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'tx_labels_map', 'transactionId', 'readwrite' | 'readonly'>
713
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'tx_labels_map', 'txLabelId', 'readwrite' | 'readonly'>
714
+ | null
715
+ if (args.partial?.transactionId !== undefined) {
716
+ cursor = await dbTrx.objectStore('tx_labels_map').index('transactionId').openCursor(args.partial.transactionId)
717
+ } else if (args.partial?.txLabelId !== undefined) {
718
+ cursor = await dbTrx.objectStore('tx_labels_map').index('txLabelId').openCursor(args.partial.txLabelId)
719
+ } else {
720
+ cursor = await dbTrx.objectStore('tx_labels_map').openCursor()
721
+ }
722
+ let firstTime = true
723
+ while (cursor) {
724
+ if (!firstTime) cursor = await cursor.continue()
725
+ if (!cursor) break
726
+ firstTime = false
727
+ const r = cursor.value
728
+ if (args.since && args.since > r.updated_at) continue
729
+ if (args.partial) {
730
+ if (args.partial.txLabelId && r.txLabelId !== args.partial.txLabelId) continue
731
+ if (args.partial.transactionId && r.transactionId !== args.partial.transactionId) continue
732
+ if (args.partial.created_at && r.created_at.getTime() !== args.partial.created_at.getTime()) continue
733
+ if (args.partial.updated_at && r.updated_at.getTime() !== args.partial.updated_at.getTime()) continue
734
+ if (args.partial.isDeleted !== undefined && r.isDeleted !== args.partial.isDeleted) continue
735
+ }
736
+ if (userId !== undefined) {
737
+ const count = await this.countTxLabels({ partial: { userId, txLabelId: r.txLabelId }, trx: args.trx })
738
+ if (count === 0) continue
739
+ }
740
+ if (skipped < offset) {
741
+ skipped++
742
+ continue
743
+ }
744
+ filtered(r)
745
+ count++
746
+ if (args.paged?.limit && count >= args.paged.limit) break
747
+ }
748
+ if (!args.trx) await dbTrx.done
749
+ }
750
+
751
+ async findTxLabelMaps(args: sdk.FindTxLabelMapsArgs): Promise<TableTxLabelMap[]> {
752
+ const results: TableTxLabelMap[] = []
753
+ await this.filterTxLabelMaps(args, r => {
754
+ results.push(this.validateEntity(r))
755
+ })
756
+ return results
757
+ }
758
+
759
+ async countOutputTagMaps(args: sdk.FindOutputTagMapsArgs): Promise<number> {
760
+ let count = 0
761
+ await this.filterOutputTagMaps(args, () => {
762
+ count++
763
+ })
764
+ return count
765
+ }
766
+ async countProvenTxReqs(args: sdk.FindProvenTxReqsArgs): Promise<number> {
767
+ let count = 0
768
+ await this.filterProvenTxReqs(args, () => {
769
+ count++
770
+ })
771
+ return count
772
+ }
773
+ async countProvenTxs(args: sdk.FindProvenTxsArgs): Promise<number> {
774
+ let count = 0
775
+ await this.filterProvenTxs(args, () => {
776
+ count++
777
+ })
778
+ return count
779
+ }
780
+ async countTxLabelMaps(args: sdk.FindTxLabelMapsArgs): Promise<number> {
781
+ let count = 0
782
+ await this.filterTxLabelMaps(args, () => {
783
+ count++
784
+ })
785
+ return count
786
+ }
787
+
788
+ async insertCertificate(certificate: TableCertificateX, trx?: sdk.TrxToken): Promise<number> {
789
+ const e = await this.validateEntityForInsert(certificate, trx, undefined, ['isDeleted'])
790
+ const fields = e.fields
791
+ if (e.fields) delete e.fields
792
+ if (e.certificateId === 0) delete e.certificateId
793
+
794
+ const dbTrx = this.toDbTrx(['certificates', 'certificate_fields'], 'readwrite', trx)
795
+ const store = dbTrx.objectStore('certificates')
796
+ try {
797
+ const id = Number(await store.add!(e))
798
+ certificate.certificateId = id
799
+
800
+ if (fields) {
801
+ for (const field of fields) {
802
+ field.certificateId = certificate.certificateId
803
+ field.userId = certificate.userId
804
+ await this.insertCertificateField(field, dbTrx)
805
+ }
806
+ }
807
+ } finally {
808
+ if (!trx) await dbTrx.done
809
+ }
810
+ return certificate.certificateId
811
+ }
812
+
813
+ async insertCertificateField(certificateField: TableCertificateField, trx?: sdk.TrxToken): Promise<void> {
814
+ const e = await this.validateEntityForInsert(certificateField, trx)
815
+ const dbTrx = this.toDbTrx(['certificate_fields'], 'readwrite', trx)
816
+ const store = dbTrx.objectStore('certificate_fields')
817
+ try {
818
+ await store.add!(e)
819
+ } finally {
820
+ if (!trx) await dbTrx.done
821
+ }
822
+ }
823
+
824
+ async insertCommission(commission: TableCommission, trx?: sdk.TrxToken): Promise<number> {
825
+ const e = await this.validateEntityForInsert(commission, trx)
826
+ if (e.commissionId === 0) delete e.commissionId
827
+ const dbTrx = this.toDbTrx(['commissions'], 'readwrite', trx)
828
+ const store = dbTrx.objectStore('commissions')
829
+ try {
830
+ const id = Number(await store.add!(e))
831
+ commission.commissionId = id
832
+ } finally {
833
+ if (!trx) await dbTrx.done
834
+ }
835
+ return commission.commissionId
836
+ }
837
+ async insertMonitorEvent(event: TableMonitorEvent, trx?: sdk.TrxToken): Promise<number> {
838
+ const e = await this.validateEntityForInsert(event, trx)
839
+ if (e.id === 0) delete e.id
840
+ const dbTrx = this.toDbTrx(['monitor_events'], 'readwrite', trx)
841
+ const store = dbTrx.objectStore('monitor_events')
842
+ try {
843
+ const id = Number(await store.add!(e))
844
+ event.id = id
845
+ } finally {
846
+ if (!trx) await dbTrx.done
847
+ }
848
+ return event.id
849
+ }
850
+ async insertOutput(output: TableOutput, trx?: sdk.TrxToken): Promise<number> {
851
+ const e = await this.validateEntityForInsert(output, trx)
852
+ if (e.outputId === 0) delete e.outputId
853
+ const dbTrx = this.toDbTrx(['outputs'], 'readwrite', trx)
854
+ const store = dbTrx.objectStore('outputs')
855
+ try {
856
+ const id = Number(await store.add!(e))
857
+ output.outputId = id
858
+ } finally {
859
+ if (!trx) await dbTrx.done
860
+ }
861
+ return output.outputId
862
+ }
863
+ async insertOutputBasket(basket: TableOutputBasket, trx?: sdk.TrxToken): Promise<number> {
864
+ const e = await this.validateEntityForInsert(basket, trx, undefined, ['isDeleted'])
865
+ if (e.basketId === 0) delete e.basketId
866
+ const dbTrx = this.toDbTrx(['output_baskets'], 'readwrite', trx)
867
+ const store = dbTrx.objectStore('output_baskets')
868
+ try {
869
+ const id = Number(await store.add!(e))
870
+ basket.basketId = id
871
+ } finally {
872
+ if (!trx) await dbTrx.done
873
+ }
874
+ return basket.basketId
875
+ }
876
+ async insertOutputTag(tag: TableOutputTag, trx?: sdk.TrxToken): Promise<number> {
877
+ const e = await this.validateEntityForInsert(tag, trx, undefined, ['isDeleted'])
878
+ if (e.outputTagId === 0) delete e.outputTagId
879
+ const dbTrx = this.toDbTrx(['output_tags'], 'readwrite', trx)
880
+ const store = dbTrx.objectStore('output_tags')
881
+ try {
882
+ const id = Number(await store.add!(e))
883
+ tag.outputTagId = id
884
+ } finally {
885
+ if (!trx) await dbTrx.done
886
+ }
887
+ return tag.outputTagId
888
+ }
889
+ async insertOutputTagMap(tagMap: TableOutputTagMap, trx?: sdk.TrxToken): Promise<void> {
890
+ const e = await this.validateEntityForInsert(tagMap, trx, undefined, ['isDeleted'])
891
+ const dbTrx = this.toDbTrx(['output_tags_map'], 'readwrite', trx)
892
+ const store = dbTrx.objectStore('output_tags_map')
893
+ try {
894
+ await store.add!(e)
895
+ } finally {
896
+ if (!trx) await dbTrx.done
897
+ }
898
+ }
899
+ async insertProvenTx(tx: TableProvenTx, trx?: sdk.TrxToken): Promise<number> {
900
+ const e = await this.validateEntityForInsert(tx, trx)
901
+ if (e.provenTxId === 0) delete e.provenTxId
902
+ const dbTrx = this.toDbTrx(['proven_txs'], 'readwrite', trx)
903
+ const store = dbTrx.objectStore('proven_txs')
904
+ try {
905
+ const id = Number(await store.add!(e))
906
+ tx.provenTxId = id
907
+ } finally {
908
+ if (!trx) await dbTrx.done
909
+ }
910
+ return tx.provenTxId
911
+ }
912
+ async insertProvenTxReq(tx: TableProvenTxReq, trx?: sdk.TrxToken): Promise<number> {
913
+ const e = await this.validateEntityForInsert(tx, trx)
914
+ if (e.provenTxReqId === 0) delete e.provenTxReqId
915
+ const dbTrx = this.toDbTrx(['proven_tx_reqs'], 'readwrite', trx)
916
+ const store = dbTrx.objectStore('proven_tx_reqs')
917
+ try {
918
+ const id = Number(await store.add!(e))
919
+ tx.provenTxReqId = id
920
+ } finally {
921
+ if (!trx) await dbTrx.done
922
+ }
923
+ return tx.provenTxReqId
924
+ }
925
+ async insertSyncState(syncState: TableSyncState, trx?: sdk.TrxToken): Promise<number> {
926
+ const e = await this.validateEntityForInsert(syncState, trx, ['when'], ['init'])
927
+ if (e.syncStateId === 0) delete e.syncStateId
928
+ const dbTrx = this.toDbTrx(['sync_states'], 'readwrite', trx)
929
+ const store = dbTrx.objectStore('sync_states')
930
+ try {
931
+ const id = Number(await store.add!(e))
932
+ syncState.syncStateId = id
933
+ } finally {
934
+ if (!trx) await dbTrx.done
935
+ }
936
+ return syncState.syncStateId
937
+ }
938
+ async insertTransaction(tx: TableTransaction, trx?: sdk.TrxToken): Promise<number> {
939
+ const e = await this.validateEntityForInsert(tx, trx)
940
+ if (e.transactionId === 0) delete e.transactionId
941
+ const dbTrx = this.toDbTrx(['transactions'], 'readwrite', trx)
942
+ const store = dbTrx.objectStore('transactions')
943
+ try {
944
+ const id = Number(await store.add!(e))
945
+ tx.transactionId = id
946
+ } finally {
947
+ if (!trx) await dbTrx.done
948
+ }
949
+ return tx.transactionId
950
+ }
951
+ async insertTxLabel(label: TableTxLabel, trx?: sdk.TrxToken): Promise<number> {
952
+ const e = await this.validateEntityForInsert(label, trx, undefined, ['isDeleted'])
953
+ if (e.txLabelId === 0) delete e.txLabelId
954
+ const dbTrx = this.toDbTrx(['tx_labels'], 'readwrite', trx)
955
+ const store = dbTrx.objectStore('tx_labels')
956
+ try {
957
+ const id = Number(await store.add!(e))
958
+ label.txLabelId = id
959
+ } finally {
960
+ if (!trx) await dbTrx.done
961
+ }
962
+ return label.txLabelId
963
+ }
964
+ async insertTxLabelMap(labelMap: TableTxLabelMap, trx?: sdk.TrxToken): Promise<void> {
965
+ const e = await this.validateEntityForInsert(labelMap, trx, undefined, ['isDeleted'])
966
+ const dbTrx = this.toDbTrx(['tx_labels_map'], 'readwrite', trx)
967
+ const store = dbTrx.objectStore('tx_labels_map')
968
+ try {
969
+ await store.add!(e)
970
+ } finally {
971
+ if (!trx) await dbTrx.done
972
+ }
973
+ }
974
+ async insertUser(user: TableUser, trx?: sdk.TrxToken): Promise<number> {
975
+ const e = await this.validateEntityForInsert(user, trx)
976
+ if (e.userId === 0) delete e.userId
977
+ const dbTrx = this.toDbTrx(['users'], 'readwrite', trx)
978
+ const store = dbTrx.objectStore('users')
979
+ try {
980
+ const id = Number(await store.add!(e))
981
+ user.userId = id
982
+ } finally {
983
+ if (!trx) await dbTrx.done
984
+ }
985
+ return user.userId
986
+ }
987
+
988
+ async updateIdb<T>(
989
+ id: number | number[],
990
+ update: Partial<T>,
991
+ keyProp: string,
992
+ storeName: string,
993
+ trx?: sdk.TrxToken
994
+ ): Promise<number> {
995
+ if (update[keyProp] !== undefined && (Array.isArray(id) || update[keyProp] !== id)) {
996
+ throw new sdk.WERR_INVALID_PARAMETER(`update.${keyProp}`, `undefined`)
997
+ }
998
+ const u = this.validatePartialForUpdate(update)
999
+ const dbTrx = this.toDbTrx([storeName], 'readwrite', trx)
1000
+ const store = dbTrx.objectStore(storeName)
1001
+ const ids = Array.isArray(id) ? id : [id]
1002
+ try {
1003
+ for (const i of ids) {
1004
+ const e = await store.get(i)
1005
+ if (!e) throw new sdk.WERR_INVALID_PARAMETER('id', `an existing record to update ${keyProp} ${i} not found`)
1006
+ const v: T = {
1007
+ ...e,
1008
+ ...u
1009
+ }
1010
+ const uid = await store.put!(v)
1011
+ if (uid !== i) throw new sdk.WERR_INTERNAL(`updated id ${uid} does not match original ${id}`)
1012
+ }
1013
+ } finally {
1014
+ if (!trx) await dbTrx.done
1015
+ }
1016
+ return 1
1017
+ }
1018
+
1019
+ async updateIdbKey<T>(
1020
+ key: (number | string)[],
1021
+ update: Partial<T>,
1022
+ keyProps: string[],
1023
+ storeName: string,
1024
+ trx?: sdk.TrxToken
1025
+ ): Promise<number> {
1026
+ if (key.length !== keyProps.length)
1027
+ throw new sdk.WERR_INTERNAL(`key.length ${key.length} !== keyProps.length ${keyProps.length}`)
1028
+ for (let i = 0; i < key.length; i++) {
1029
+ if (update[keyProps[i]] !== undefined && update[keyProps[i]] !== key[i]) {
1030
+ throw new sdk.WERR_INVALID_PARAMETER(`update.${keyProps[i]}`, `undefined`)
1031
+ }
1032
+ }
1033
+ const u = this.validatePartialForUpdate(update)
1034
+ const dbTrx = this.toDbTrx([storeName], 'readwrite', trx)
1035
+ const store = dbTrx.objectStore(storeName)
1036
+ try {
1037
+ const e = await store.get(key)
1038
+ if (!e)
1039
+ throw new sdk.WERR_INVALID_PARAMETER(
1040
+ 'key',
1041
+ `an existing record to update ${keyProps.join(',')} ${key.join(',')} not found`
1042
+ )
1043
+ const v: T = {
1044
+ ...e,
1045
+ ...u
1046
+ }
1047
+ const uid = await store.put!(v)
1048
+ for (let i = 0; i < key.length; i++) {
1049
+ if (uid[i] !== key[i]) throw new sdk.WERR_INTERNAL(`updated key ${uid[i]} does not match original ${key[i]}`)
1050
+ }
1051
+ } finally {
1052
+ if (!trx) await dbTrx.done
1053
+ }
1054
+
1055
+ return 1
1056
+ }
1057
+
1058
+ async updateCertificate(id: number, update: Partial<TableCertificate>, trx?: sdk.TrxToken): Promise<number> {
1059
+ return this.updateIdb(id, update, 'certificateId', 'certificates', trx)
1060
+ }
1061
+
1062
+ async updateCertificateField(
1063
+ certificateId: number,
1064
+ fieldName: string,
1065
+ update: Partial<TableCertificateField>,
1066
+ trx?: sdk.TrxToken
1067
+ ): Promise<number> {
1068
+ return this.updateIdbKey(
1069
+ [certificateId, fieldName],
1070
+ update,
1071
+ ['certificateId', 'fieldName'],
1072
+ 'certificate_fields',
1073
+ trx
1074
+ )
1075
+ }
1076
+
1077
+ async updateCommission(id: number, update: Partial<TableCommission>, trx?: sdk.TrxToken): Promise<number> {
1078
+ return this.updateIdb(id, update, 'commissionId', 'commissions', trx)
1079
+ }
1080
+ async updateMonitorEvent(id: number, update: Partial<TableMonitorEvent>, trx?: sdk.TrxToken): Promise<number> {
1081
+ return this.updateIdb(id, update, 'id', 'monitor_events', trx)
1082
+ }
1083
+ async updateOutput(id: number, update: Partial<TableOutput>, trx?: sdk.TrxToken): Promise<number> {
1084
+ return this.updateIdb(id, update, 'outputId', 'outputs', trx)
1085
+ }
1086
+ async updateOutputBasket(id: number, update: Partial<TableOutputBasket>, trx?: sdk.TrxToken): Promise<number> {
1087
+ return this.updateIdb(id, update, 'basketId', 'output_baskets', trx)
1088
+ }
1089
+ async updateOutputTag(id: number, update: Partial<TableOutputTag>, trx?: sdk.TrxToken): Promise<number> {
1090
+ return this.updateIdb(id, update, 'outputTagId', 'output_tags', trx)
1091
+ }
1092
+ async updateProvenTx(id: number, update: Partial<TableProvenTx>, trx?: sdk.TrxToken): Promise<number> {
1093
+ return this.updateIdb(id, update, 'provenTxId', 'proven_txs', trx)
1094
+ }
1095
+ async updateProvenTxReq(
1096
+ id: number | number[],
1097
+ update: Partial<TableProvenTxReq>,
1098
+ trx?: sdk.TrxToken
1099
+ ): Promise<number> {
1100
+ return this.updateIdb(id, update, 'provenTxReqId', 'proven_tx_reqs', trx)
1101
+ }
1102
+ async updateSyncState(id: number, update: Partial<TableSyncState>, trx?: sdk.TrxToken): Promise<number> {
1103
+ return this.updateIdb(id, update, 'syncStateId', 'sync_states', trx)
1104
+ }
1105
+ async updateTransaction(
1106
+ id: number | number[],
1107
+ update: Partial<TableTransaction>,
1108
+ trx?: sdk.TrxToken
1109
+ ): Promise<number> {
1110
+ return this.updateIdb(id, update, 'transactionId', 'transactions', trx)
1111
+ }
1112
+ async updateTxLabel(id: number, update: Partial<TableTxLabel>, trx?: sdk.TrxToken): Promise<number> {
1113
+ return this.updateIdb(id, update, 'txLabelId', 'tx_labels', trx)
1114
+ }
1115
+ async updateUser(id: number, update: Partial<TableUser>, trx?: sdk.TrxToken): Promise<number> {
1116
+ return this.updateIdb(id, update, 'userId', 'users', trx)
1117
+ }
1118
+ async updateOutputTagMap(
1119
+ outputId: number,
1120
+ tagId: number,
1121
+ update: Partial<TableOutputTagMap>,
1122
+ trx?: sdk.TrxToken
1123
+ ): Promise<number> {
1124
+ return this.updateIdbKey([tagId, outputId], update, ['outputTagId', 'outputId'], 'output_tags_map', trx)
1125
+ }
1126
+ async updateTxLabelMap(
1127
+ transactionId: number,
1128
+ txLabelId: number,
1129
+ update: Partial<TableTxLabelMap>,
1130
+ trx?: sdk.TrxToken
1131
+ ): Promise<number> {
1132
+ return this.updateIdbKey([txLabelId, transactionId], update, ['txLabelId', 'transactionId'], 'tx_labels_map', trx)
1133
+ }
1134
+
1135
+ //
1136
+ // StorageReader abstract methods
1137
+ //
1138
+
1139
+ async destroy(): Promise<void> {
1140
+ if (this.db) {
1141
+ this.db.close()
1142
+ }
1143
+ this.db = undefined
1144
+ this._settings = undefined
1145
+ }
1146
+
1147
+ allStores: string[] = [
1148
+ 'certificates',
1149
+ 'certificate_fields',
1150
+ 'commissions',
1151
+ 'monitor_events',
1152
+ 'outputs',
1153
+ 'output_baskets',
1154
+ 'output_tags',
1155
+ 'output_tags_map',
1156
+ 'proven_txs',
1157
+ 'proven_tx_reqs',
1158
+ 'sync_states',
1159
+ 'transactions',
1160
+ 'tx_labels',
1161
+ 'tx_labels_map',
1162
+ 'users'
1163
+ ]
1164
+
1165
+ /**
1166
+ * @param scope
1167
+ * @param trx
1168
+ * @returns
1169
+ */
1170
+ async transaction<T>(scope: (trx: sdk.TrxToken) => Promise<T>, trx?: sdk.TrxToken): Promise<T> {
1171
+ if (trx) return await scope(trx)
1172
+
1173
+ const stores = this.allStores
1174
+
1175
+ const db = await this.verifyDB()
1176
+ const tx = db.transaction(stores, 'readwrite')
1177
+
1178
+ try {
1179
+ const r = await scope(tx as sdk.TrxToken)
1180
+ await tx.done
1181
+ return r
1182
+ } catch (err) {
1183
+ tx.abort()
1184
+ await tx.done
1185
+ throw err
1186
+ }
1187
+ }
1188
+
1189
+ async filterCertificateFields(
1190
+ args: sdk.FindCertificateFieldsArgs,
1191
+ filtered: (v: TableCertificateField) => void
1192
+ ): Promise<void> {
1193
+ const offset = args.paged?.offset || 0
1194
+ let skipped = 0
1195
+ let count = 0
1196
+ const dbTrx = this.toDbTrx(['certificate_fields'], 'readonly', args.trx)
1197
+ let cursor:
1198
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'certificate_fields', unknown, 'readwrite' | 'readonly'>
1199
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'certificate_fields', 'userId', 'readwrite' | 'readonly'>
1200
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'certificate_fields', 'certificateId', 'readwrite' | 'readonly'>
1201
+ | null
1202
+ if (args.partial?.certificateId !== undefined) {
1203
+ cursor = await dbTrx
1204
+ .objectStore('certificate_fields')
1205
+ .index('certificateId')
1206
+ .openCursor(args.partial.certificateId)
1207
+ } else if (args.partial?.userId !== undefined) {
1208
+ cursor = await dbTrx.objectStore('certificate_fields').index('userId').openCursor(args.partial.userId)
1209
+ } else {
1210
+ cursor = await dbTrx.objectStore('certificate_fields').openCursor()
1211
+ }
1212
+ let firstTime = true
1213
+ while (cursor) {
1214
+ if (!firstTime) cursor = await cursor.continue()
1215
+ if (!cursor) break
1216
+ firstTime = false
1217
+ const r = cursor.value
1218
+ if (args.since && args.since > r.updated_at) continue
1219
+ if (args.partial) {
1220
+ if (args.partial.userId && r.userId !== args.partial.userId) continue
1221
+ if (args.partial.certificateId && r.certificateId !== args.partial.certificateId) continue
1222
+ if (args.partial.created_at && r.created_at.getTime() !== args.partial.created_at.getTime()) continue
1223
+ if (args.partial.updated_at && r.updated_at.getTime() !== args.partial.updated_at.getTime()) continue
1224
+ if (args.partial.fieldName && r.fieldName !== args.partial.fieldName) continue
1225
+ if (args.partial.fieldValue && r.fieldValue !== args.partial.fieldValue) continue
1226
+ if (args.partial.masterKey && r.masterKey !== args.partial.masterKey) continue
1227
+ }
1228
+ if (skipped < offset) {
1229
+ skipped++
1230
+ continue
1231
+ }
1232
+ filtered(r)
1233
+ count++
1234
+ if (args.paged?.limit && count >= args.paged.limit) break
1235
+ }
1236
+ if (!args.trx) await dbTrx.done
1237
+ }
1238
+
1239
+ async findCertificateFields(args: sdk.FindCertificateFieldsArgs): Promise<TableCertificateField[]> {
1240
+ const result: TableCertificateField[] = []
1241
+ await this.filterCertificateFields(args, r => {
1242
+ result.push(this.validateEntity(r))
1243
+ })
1244
+ return result
1245
+ }
1246
+
1247
+ async filterCertificates(args: sdk.FindCertificatesArgs, filtered: (v: TableCertificateX) => void): Promise<void> {
1248
+ const offset = args.paged?.offset || 0
1249
+ let skipped = 0
1250
+ let count = 0
1251
+ const dbTrx = this.toDbTrx(['certificates'], 'readonly', args.trx)
1252
+ let cursor:
1253
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'certificates', unknown, 'readwrite' | 'readonly'>
1254
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'certificates', 'userId', 'readwrite' | 'readonly'>
1255
+ | IDBPCursorWithValue<
1256
+ StorageIdbSchema,
1257
+ string[],
1258
+ 'certificates',
1259
+ 'userId_type_certifier_serialNumber',
1260
+ 'readwrite' | 'readonly'
1261
+ >
1262
+ | null
1263
+ if (args.partial?.certificateId) {
1264
+ cursor = await dbTrx.objectStore('certificates').openCursor(args.partial.certificateId)
1265
+ } else if (args.partial?.userId !== undefined) {
1266
+ if (args.partial?.type && args.partial?.certifier && args.partial?.serialNumber) {
1267
+ cursor = await dbTrx
1268
+ .objectStore('certificates')
1269
+ .index('userId_type_certifier_serialNumber')
1270
+ .openCursor([args.partial.userId, args.partial.type, args.partial.certifier, args.partial.serialNumber])
1271
+ } else {
1272
+ cursor = await dbTrx.objectStore('certificates').index('userId').openCursor(args.partial.userId)
1273
+ }
1274
+ } else {
1275
+ cursor = await dbTrx.objectStore('certificates').openCursor()
1276
+ }
1277
+ let firstTime = true
1278
+ while (cursor) {
1279
+ if (!firstTime) cursor = await cursor.continue()
1280
+ if (!cursor) break
1281
+ firstTime = false
1282
+ const r = cursor.value
1283
+ if (args.since && args.since > r.updated_at) continue
1284
+ if (args.certifiers && !args.certifiers.includes(r.certifier)) continue
1285
+ if (args.types && !args.types.includes(r.type)) continue
1286
+ if (args.partial) {
1287
+ if (args.partial.userId && r.userId !== args.partial.userId) continue
1288
+ if (args.partial.certificateId && r.certificateId !== args.partial.certificateId) continue
1289
+ if (args.partial.created_at && r.created_at.getTime() !== args.partial.created_at.getTime()) continue
1290
+ if (args.partial.updated_at && r.updated_at.getTime() !== args.partial.updated_at.getTime()) continue
1291
+ if (args.partial.type && r.type !== args.partial.type) continue
1292
+ if (args.partial.serialNumber && r.serialNumber !== args.partial.serialNumber) continue
1293
+ if (args.partial.certifier && r.certifier !== args.partial.certifier) continue
1294
+ if (args.partial.subject && r.subject !== args.partial.subject) continue
1295
+ if (args.partial.verifier && r.verifier !== args.partial.verifier) continue
1296
+ if (args.partial.revocationOutpoint && r.revocationOutpoint !== args.partial.revocationOutpoint) continue
1297
+ if (args.partial.signature && r.signature !== args.partial.signature) continue
1298
+ if (args.partial.isDeleted && r.isDeleted !== args.partial.isDeleted) continue
1299
+ }
1300
+ if (skipped < offset) {
1301
+ skipped++
1302
+ continue
1303
+ }
1304
+ filtered(r)
1305
+ count++
1306
+ if (args.paged?.limit && count >= args.paged.limit) break
1307
+ }
1308
+ if (!args.trx) await dbTrx.done
1309
+ }
1310
+
1311
+ async findCertificates(args: sdk.FindCertificatesArgs): Promise<TableCertificateX[]> {
1312
+ const result: TableCertificateX[] = []
1313
+ await this.filterCertificates(args, r => {
1314
+ result.push(this.validateEntity(r))
1315
+ })
1316
+ if (args.includeFields) {
1317
+ for (const c of result) {
1318
+ const fields = await this.findCertificateFields({ partial: { certificateId: c.certificateId }, trx: args.trx })
1319
+ c.fields = fields
1320
+ }
1321
+ }
1322
+ return result
1323
+ }
1324
+
1325
+ async filterCommissions(args: sdk.FindCommissionsArgs, filtered: (v: TableCommission) => void): Promise<void> {
1326
+ if (args.partial.lockingScript)
1327
+ throw new sdk.WERR_INVALID_PARAMETER(
1328
+ 'partial.lockingScript',
1329
+ `undefined. Commissions may not be found by lockingScript value.`
1330
+ )
1331
+ const offset = args.paged?.offset || 0
1332
+ let skipped = 0
1333
+ let count = 0
1334
+ const dbTrx = this.toDbTrx(['commissions'], 'readonly', args.trx)
1335
+ let cursor:
1336
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'commissions', unknown, 'readwrite' | 'readonly'>
1337
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'commissions', 'userId', 'readwrite' | 'readonly'>
1338
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'commissions', 'transactionId', 'readwrite' | 'readonly'>
1339
+ | null
1340
+ if (args.partial?.commissionId) {
1341
+ cursor = await dbTrx.objectStore('commissions').openCursor(args.partial.commissionId)
1342
+ } else if (args.partial?.userId !== undefined) {
1343
+ cursor = await dbTrx.objectStore('commissions').index('userId').openCursor(args.partial.userId)
1344
+ } else if (args.partial?.transactionId !== undefined) {
1345
+ cursor = await dbTrx.objectStore('commissions').index('transactionId').openCursor(args.partial.transactionId)
1346
+ } else {
1347
+ cursor = await dbTrx.objectStore('commissions').openCursor()
1348
+ }
1349
+ let firstTime = true
1350
+ while (cursor) {
1351
+ if (!firstTime) cursor = await cursor.continue()
1352
+ if (!cursor) break
1353
+ firstTime = false
1354
+ const r = cursor.value
1355
+ if (args.since && args.since > r.updated_at) continue
1356
+ if (args.partial) {
1357
+ if (args.partial.commissionId && r.commissionId !== args.partial.commissionId) continue
1358
+ if (args.partial.transactionId && r.transactionId !== args.partial.transactionId) continue
1359
+ if (args.partial.userId && r.userId !== args.partial.userId) continue
1360
+ if (args.partial.created_at && r.created_at.getTime() !== args.partial.created_at.getTime()) continue
1361
+ if (args.partial.updated_at && r.updated_at.getTime() !== args.partial.updated_at.getTime()) continue
1362
+ if (args.partial.satoshis !== undefined && r.satoshis !== args.partial.satoshis) continue
1363
+ if (args.partial.keyOffset && r.keyOffset !== args.partial.keyOffset) continue
1364
+ if (args.partial.isRedeemed !== undefined && r.isRedeemed !== args.partial.isRedeemed) continue
1365
+ }
1366
+ if (skipped < offset) {
1367
+ skipped++
1368
+ continue
1369
+ }
1370
+ filtered(r)
1371
+ count++
1372
+ if (args.paged?.limit && count >= args.paged.limit) break
1373
+ }
1374
+ if (!args.trx) await dbTrx.done
1375
+ }
1376
+
1377
+ async findCommissions(args: sdk.FindCommissionsArgs): Promise<TableCommission[]> {
1378
+ const result: TableCommission[] = []
1379
+ await this.filterCommissions(args, r => {
1380
+ result.push(this.validateEntity(r))
1381
+ })
1382
+ return result
1383
+ }
1384
+
1385
+ async filterMonitorEvents(args: sdk.FindMonitorEventsArgs, filtered: (v: TableMonitorEvent) => void): Promise<void> {
1386
+ const offset = args.paged?.offset || 0
1387
+ let skipped = 0
1388
+ let count = 0
1389
+ const dbTrx = this.toDbTrx(['monitor_events'], 'readonly', args.trx)
1390
+ let cursor: IDBPCursorWithValue<
1391
+ StorageIdbSchema,
1392
+ string[],
1393
+ 'monitor_events',
1394
+ unknown,
1395
+ 'readwrite' | 'readonly'
1396
+ > | null
1397
+ if (args.partial?.id) {
1398
+ cursor = await dbTrx.objectStore('monitor_events').openCursor(args.partial.id)
1399
+ } else {
1400
+ cursor = await dbTrx.objectStore('monitor_events').openCursor()
1401
+ }
1402
+ let firstTime = true
1403
+ while (cursor) {
1404
+ if (!firstTime) cursor = await cursor.continue()
1405
+ if (!cursor) break
1406
+ firstTime = false
1407
+ const r = cursor.value
1408
+ if (args.since && args.since > r.updated_at) continue
1409
+ if (args.partial) {
1410
+ if (args.partial.id && r.id !== args.partial.id) continue
1411
+ if (args.partial.created_at && r.created_at.getTime() !== args.partial.created_at.getTime()) continue
1412
+ if (args.partial.updated_at && r.updated_at.getTime() !== args.partial.updated_at.getTime()) continue
1413
+ if (args.partial.event && r.event !== args.partial.event) continue
1414
+ if (args.partial.details && r.details !== args.partial.details) continue
1415
+ }
1416
+ if (skipped < offset) {
1417
+ skipped++
1418
+ continue
1419
+ }
1420
+ filtered(r)
1421
+ count++
1422
+ if (args.paged?.limit && count >= args.paged.limit) break
1423
+ }
1424
+ if (!args.trx) await dbTrx.done
1425
+ }
1426
+
1427
+ async findMonitorEvents(args: sdk.FindMonitorEventsArgs): Promise<TableMonitorEvent[]> {
1428
+ const result: TableMonitorEvent[] = []
1429
+ await this.filterMonitorEvents(args, r => {
1430
+ result.push(this.validateEntity(r))
1431
+ })
1432
+ return result
1433
+ }
1434
+
1435
+ async filterOutputBaskets(args: sdk.FindOutputBasketsArgs, filtered: (v: TableOutputBasket) => void): Promise<void> {
1436
+ const offset = args.paged?.offset || 0
1437
+ let skipped = 0
1438
+ let count = 0
1439
+ const dbTrx = this.toDbTrx(['output_baskets'], 'readonly', args.trx)
1440
+ let cursor:
1441
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'output_baskets', unknown, 'readwrite' | 'readonly'>
1442
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'output_baskets', 'userId', 'readwrite' | 'readonly'>
1443
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'output_baskets', 'name_userId', 'readwrite' | 'readonly'>
1444
+ | null
1445
+ if (args.partial?.basketId) {
1446
+ cursor = await dbTrx.objectStore('output_baskets').openCursor(args.partial.basketId)
1447
+ } else if (args.partial?.userId !== undefined) {
1448
+ if (args.partial?.name !== undefined) {
1449
+ cursor = await dbTrx
1450
+ .objectStore('output_baskets')
1451
+ .index('name_userId')
1452
+ .openCursor([args.partial.name, args.partial.userId])
1453
+ } else {
1454
+ cursor = await dbTrx.objectStore('output_baskets').index('userId').openCursor(args.partial.userId)
1455
+ }
1456
+ } else {
1457
+ cursor = await dbTrx.objectStore('output_baskets').openCursor()
1458
+ }
1459
+ let firstTime = true
1460
+ while (cursor) {
1461
+ if (!firstTime) cursor = await cursor.continue()
1462
+ if (!cursor) break
1463
+ firstTime = false
1464
+ const r = cursor.value
1465
+ if (args.since && args.since > r.updated_at) continue
1466
+ if (args.partial) {
1467
+ if (args.partial.basketId && r.basketId !== args.partial.basketId) continue
1468
+ if (args.partial.userId && r.userId !== args.partial.userId) continue
1469
+ if (args.partial.created_at && r.created_at.getTime() !== args.partial.created_at.getTime()) continue
1470
+ if (args.partial.updated_at && r.updated_at.getTime() !== args.partial.updated_at.getTime()) continue
1471
+ if (args.partial.name && r.name !== args.partial.name) continue
1472
+ if (
1473
+ args.partial.numberOfDesiredUTXOs !== undefined &&
1474
+ r.numberOfDesiredUTXOs !== args.partial.numberOfDesiredUTXOs
1475
+ )
1476
+ continue
1477
+ if (
1478
+ args.partial.minimumDesiredUTXOValue !== undefined &&
1479
+ r.numberOfDesiredSatoshis !== args.partial.minimumDesiredUTXOValue
1480
+ )
1481
+ continue
1482
+ if (args.partial.isDeleted !== undefined && r.isDeleted !== args.partial.isDeleted) continue
1483
+ }
1484
+ if (skipped < offset) {
1485
+ skipped++
1486
+ continue
1487
+ }
1488
+ filtered(r)
1489
+ count++
1490
+ if (args.paged?.limit && count >= args.paged.limit) break
1491
+ }
1492
+ if (!args.trx) await dbTrx.done
1493
+ }
1494
+
1495
+ async findOutputBaskets(args: sdk.FindOutputBasketsArgs): Promise<TableOutputBasket[]> {
1496
+ const result: TableOutputBasket[] = []
1497
+ await this.filterOutputBaskets(args, r => {
1498
+ result.push(this.validateEntity(r))
1499
+ })
1500
+ return result
1501
+ }
1502
+
1503
+ async filterOutputs(
1504
+ args: sdk.FindOutputsArgs,
1505
+ filtered: (v: TableOutput) => void,
1506
+ tagIds?: number[],
1507
+ isQueryModeAll?: boolean
1508
+ ): Promise<void> {
1509
+ // args.txStatus
1510
+ // args.noScript
1511
+ if (args.partial.lockingScript)
1512
+ throw new sdk.WERR_INVALID_PARAMETER(
1513
+ 'args.partial.lockingScript',
1514
+ `undefined. Outputs may not be found by lockingScript value.`
1515
+ )
1516
+ const offset = args.paged?.offset || 0
1517
+ let skipped = 0
1518
+ let count = 0
1519
+ const stores = ['outputs']
1520
+ if (tagIds && tagIds.length > 0) {
1521
+ stores.push('output_tags_map')
1522
+ }
1523
+ if (args.txStatus) {
1524
+ stores.push('transactions')
1525
+ }
1526
+ const dbTrx = this.toDbTrx(stores, 'readonly', args.trx)
1527
+ let cursor:
1528
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'outputs', unknown, 'readwrite' | 'readonly'>
1529
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'outputs', 'userId', 'readwrite' | 'readonly'>
1530
+ | IDBPCursorWithValue<
1531
+ StorageIdbSchema,
1532
+ string[],
1533
+ 'outputs',
1534
+ 'transactionId_vout_userId',
1535
+ 'readwrite' | 'readonly'
1536
+ >
1537
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'outputs', 'transactionId', 'readwrite' | 'readonly'>
1538
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'outputs', 'basketId', 'readwrite' | 'readonly'>
1539
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'outputs', 'spentBy', 'readwrite' | 'readonly'>
1540
+ | null
1541
+ if (args.partial?.outputId) {
1542
+ cursor = await dbTrx.objectStore('outputs').openCursor(args.partial.outputId)
1543
+ } else if (args.partial?.userId !== undefined) {
1544
+ if (args.partial?.transactionId && args.partial?.vout !== undefined) {
1545
+ cursor = await dbTrx
1546
+ .objectStore('outputs')
1547
+ .index('transactionId_vout_userId')
1548
+ .openCursor([args.partial.transactionId, args.partial.vout, args.partial.userId])
1549
+ } else {
1550
+ cursor = await dbTrx.objectStore('outputs').index('userId').openCursor(args.partial.userId)
1551
+ }
1552
+ } else if (args.partial?.transactionId !== undefined) {
1553
+ cursor = await dbTrx.objectStore('outputs').index('transactionId').openCursor(args.partial.transactionId)
1554
+ } else if (args.partial?.basketId !== undefined) {
1555
+ cursor = await dbTrx.objectStore('outputs').index('basketId').openCursor(args.partial.basketId)
1556
+ } else if (args.partial?.spentBy !== undefined) {
1557
+ cursor = await dbTrx.objectStore('outputs').index('spentBy').openCursor(args.partial.spentBy)
1558
+ } else {
1559
+ cursor = await dbTrx.objectStore('outputs').openCursor()
1560
+ }
1561
+ let firstTime = true
1562
+ while (cursor) {
1563
+ if (!firstTime) cursor = await cursor.continue()
1564
+ if (!cursor) break
1565
+ firstTime = false
1566
+ const r = cursor.value
1567
+ if (args.since && args.since > r.updated_at) continue
1568
+ if (args.partial) {
1569
+ if (args.partial.outputId && r.outputId !== args.partial.outputId) continue
1570
+ if (args.partial.userId && r.userId !== args.partial.userId) continue
1571
+ if (args.partial.transactionId && r.transactionId !== args.partial.transactionId) continue
1572
+ if (args.partial.basketId && r.basketId !== args.partial.basketId) continue
1573
+ if (args.partial.created_at && r.created_at.getTime() !== args.partial.created_at.getTime()) continue
1574
+ if (args.partial.updated_at && r.updated_at.getTime() !== args.partial.updated_at.getTime()) continue
1575
+ if (args.partial.spendable !== undefined && r.spendable !== args.partial.spendable) continue
1576
+ if (args.partial.change !== undefined && r.change !== args.partial.change) continue
1577
+ if (args.partial.outputDescription && r.outputDescription !== args.partial.outputDescription) continue
1578
+ if (args.partial.vout !== undefined && r.vout !== args.partial.vout) continue
1579
+ if (args.partial.satoshis !== undefined && r.satoshis !== args.partial.satoshis) continue
1580
+ if (args.partial.providedBy && r.providedBy !== args.partial.providedBy) continue
1581
+ if (args.partial.purpose && r.purpose !== args.partial.purpose) continue
1582
+ if (args.partial.type && r.type !== args.partial.type) continue
1583
+ if (args.partial.txid && r.txid !== args.partial.txid) continue
1584
+ if (args.partial.senderIdentityKey && r.senderIdentityKey !== args.partial.senderIdentityKey) continue
1585
+ if (args.partial.derivationPrefix && r.derivationPrefix !== args.partial.derivationPrefix) continue
1586
+ if (args.partial.derivationSuffix && r.derivationSuffix !== args.partial.derivationSuffix) continue
1587
+ if (args.partial.customInstructions && r.customInstructions !== args.partial.customInstructions) continue
1588
+ if (args.partial.spentBy && r.spentBy !== args.partial.spentBy) continue
1589
+ if (args.partial.sequenceNumber !== undefined && r.sequenceNumber !== args.partial.sequenceNumber) continue
1590
+ if (args.partial.scriptLength !== undefined && r.scriptLength !== args.partial.scriptLength) continue
1591
+ if (args.partial.scriptOffset !== undefined && r.scriptOffset !== args.partial.scriptOffset) continue
1592
+ }
1593
+ if (args.txStatus !== undefined) {
1594
+ const count = await this.countTransactions({
1595
+ partial: { transactionId: r.transactionId },
1596
+ status: args.txStatus,
1597
+ trx: dbTrx
1598
+ })
1599
+ if (count === 0) continue
1600
+ }
1601
+ if (tagIds && tagIds.length > 0) {
1602
+ let ids = [...tagIds]
1603
+ await this.filterOutputTagMaps({ partial: { outputId: r.outputId }, trx: dbTrx }, tm => {
1604
+ if (ids.length > 0) {
1605
+ const i = ids.indexOf(tm.outputTagId)
1606
+ if (i >= 0) {
1607
+ if (isQueryModeAll) {
1608
+ ids.splice(i, 1)
1609
+ } else {
1610
+ ids = []
1611
+ }
1612
+ }
1613
+ }
1614
+ })
1615
+ if (ids.length > 0) continue
1616
+ }
1617
+ if (skipped < offset) {
1618
+ skipped++
1619
+ continue
1620
+ }
1621
+ if (args.noScript === true) {
1622
+ r.script = undefined
1623
+ }
1624
+ filtered(r)
1625
+ count++
1626
+ if (args.paged?.limit && count >= args.paged.limit) break
1627
+ }
1628
+ if (!args.trx) await dbTrx.done
1629
+ }
1630
+
1631
+ async findOutputs(args: sdk.FindOutputsArgs, tagIds?: number[], isQueryModeAll?: boolean): Promise<TableOutput[]> {
1632
+ const results: TableOutput[] = []
1633
+ await this.filterOutputs(
1634
+ args,
1635
+ r => {
1636
+ results.push(this.validateEntity(r))
1637
+ },
1638
+ tagIds,
1639
+ isQueryModeAll
1640
+ )
1641
+ for (const o of results) {
1642
+ if (!args.noScript) {
1643
+ await this.validateOutputScript(o)
1644
+ } else {
1645
+ o.lockingScript = undefined
1646
+ }
1647
+ }
1648
+ return results
1649
+ }
1650
+
1651
+ async filterOutputTags(args: sdk.FindOutputTagsArgs, filtered: (v: TableOutputTag) => void): Promise<void> {
1652
+ const offset = args.paged?.offset || 0
1653
+ let skipped = 0
1654
+ let count = 0
1655
+ const dbTrx = this.toDbTrx(['output_tags'], 'readonly', args.trx)
1656
+ let cursor:
1657
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'output_tags', unknown, 'readwrite' | 'readonly'>
1658
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'output_tags', 'userId', 'readwrite' | 'readonly'>
1659
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'output_tags', 'tag_userId', 'readwrite' | 'readonly'>
1660
+ | null
1661
+ if (args.partial?.outputTagId) {
1662
+ cursor = await dbTrx.objectStore('output_tags').openCursor(args.partial.outputTagId)
1663
+ } else if (args.partial?.userId !== undefined) {
1664
+ if (args.partial?.tag !== undefined) {
1665
+ cursor = await dbTrx
1666
+ .objectStore('output_tags')
1667
+ .index('tag_userId')
1668
+ .openCursor([args.partial.tag, args.partial.userId])
1669
+ } else {
1670
+ cursor = await dbTrx.objectStore('output_tags').index('userId').openCursor(args.partial.userId)
1671
+ }
1672
+ } else {
1673
+ cursor = await dbTrx.objectStore('output_tags').openCursor()
1674
+ }
1675
+ let firstTime = true
1676
+ while (cursor) {
1677
+ if (!firstTime) cursor = await cursor.continue()
1678
+ if (!cursor) break
1679
+ firstTime = false
1680
+ const r = cursor.value
1681
+ if (args.since && args.since > r.updated_at) continue
1682
+ if (args.partial) {
1683
+ if (args.partial.outputTagId && r.outputTagId !== args.partial.outputTagId) continue
1684
+ if (args.partial.userId && r.userId !== args.partial.userId) continue
1685
+ if (args.partial.created_at && r.created_at.getTime() !== args.partial.created_at.getTime()) continue
1686
+ if (args.partial.updated_at && r.updated_at.getTime() !== args.partial.updated_at.getTime()) continue
1687
+ if (args.partial.tag && r.tag !== args.partial.tag) continue
1688
+ if (args.partial.isDeleted !== undefined && r.isDeleted !== args.partial.isDeleted) continue
1689
+ }
1690
+ if (skipped < offset) {
1691
+ skipped++
1692
+ continue
1693
+ }
1694
+ filtered(r)
1695
+ count++
1696
+ if (args.paged?.limit && count >= args.paged.limit) break
1697
+ }
1698
+ if (!args.trx) await dbTrx.done
1699
+ }
1700
+
1701
+ async findOutputTags(args: sdk.FindOutputTagsArgs): Promise<TableOutputTag[]> {
1702
+ const result: TableOutputTag[] = []
1703
+ await this.filterOutputTags(args, r => {
1704
+ result.push(this.validateEntity(r))
1705
+ })
1706
+ return result
1707
+ }
1708
+
1709
+ async filterSyncStates(args: sdk.FindSyncStatesArgs, filtered: (v: TableSyncState) => void): Promise<void> {
1710
+ if (args.partial.syncMap)
1711
+ throw new sdk.WERR_INVALID_PARAMETER(
1712
+ 'args.partial.syncMap',
1713
+ `undefined. SyncStates may not be found by syncMap value.`
1714
+ )
1715
+ const offset = args.paged?.offset || 0
1716
+ let skipped = 0
1717
+ let count = 0
1718
+ const dbTrx = this.toDbTrx(['sync_states'], 'readonly', args.trx)
1719
+ let cursor:
1720
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'sync_states', unknown, 'readwrite' | 'readonly'>
1721
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'sync_states', 'userId', 'readwrite' | 'readonly'>
1722
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'sync_states', 'refNum', 'readwrite' | 'readonly'>
1723
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'sync_states', 'status', 'readwrite' | 'readonly'>
1724
+ | null
1725
+ if (args.partial?.syncStateId) {
1726
+ cursor = await dbTrx.objectStore('sync_states').openCursor(args.partial.syncStateId)
1727
+ } else if (args.partial?.userId !== undefined) {
1728
+ cursor = await dbTrx.objectStore('sync_states').index('userId').openCursor(args.partial.userId)
1729
+ } else if (args.partial?.refNum !== undefined) {
1730
+ cursor = await dbTrx.objectStore('sync_states').index('refNum').openCursor(args.partial.refNum)
1731
+ } else if (args.partial?.status !== undefined) {
1732
+ cursor = await dbTrx.objectStore('sync_states').index('status').openCursor(args.partial.status)
1733
+ } else {
1734
+ cursor = await dbTrx.objectStore('sync_states').openCursor()
1735
+ }
1736
+ let firstTime = true
1737
+ while (cursor) {
1738
+ if (!firstTime) cursor = await cursor.continue()
1739
+ if (!cursor) break
1740
+ firstTime = false
1741
+ const r = cursor.value
1742
+ if (args.since && args.since > r.updated_at) continue
1743
+ if (args.partial) {
1744
+ if (args.partial.syncStateId && r.syncStateId !== args.partial.syncStateId) continue
1745
+ if (args.partial.userId && r.userId !== args.partial.userId) continue
1746
+ if (args.partial.created_at && r.created_at.getTime() !== args.partial.created_at.getTime()) continue
1747
+ if (args.partial.updated_at && r.updated_at.getTime() !== args.partial.updated_at.getTime()) continue
1748
+ if (args.partial.storageIdentityKey && r.storageIdentityKey !== args.partial.storageIdentityKey) continue
1749
+ if (args.partial.storageName && r.storageName !== args.partial.storageName) continue
1750
+ if (args.partial.status && r.status !== args.partial.status) continue
1751
+ if (args.partial.init !== undefined && r.init !== args.partial.init) continue
1752
+ if (args.partial.refNum !== undefined && r.refNum !== args.partial.refNum) continue
1753
+ if (args.partial.when && r.when?.getTime() !== args.partial.when.getTime()) continue
1754
+ if (args.partial.satoshis !== undefined && r.satoshis !== args.partial.satoshis) continue
1755
+ if (args.partial.errorLocal && r.errorLocale !== args.partial.errorLocal) continue
1756
+ if (args.partial.errorOther && r.errorOther !== args.partial.errorOther) continue
1757
+ }
1758
+ if (skipped < offset) {
1759
+ skipped++
1760
+ continue
1761
+ }
1762
+ filtered(r)
1763
+ count++
1764
+ if (args.paged?.limit && count >= args.paged.limit) break
1765
+ }
1766
+ if (!args.trx) await dbTrx.done
1767
+ }
1768
+
1769
+ async findSyncStates(args: sdk.FindSyncStatesArgs): Promise<TableSyncState[]> {
1770
+ const result: TableSyncState[] = []
1771
+ await this.filterSyncStates(args, r => {
1772
+ result.push(this.validateEntity(r))
1773
+ })
1774
+ return result
1775
+ }
1776
+
1777
+ async filterTransactions(
1778
+ args: sdk.FindTransactionsArgs,
1779
+ filtered: (v: TableTransaction) => void,
1780
+ labelIds?: number[],
1781
+ isQueryModeAll?: boolean
1782
+ ): Promise<void> {
1783
+ if (args.partial.rawTx)
1784
+ throw new sdk.WERR_INVALID_PARAMETER(
1785
+ 'args.partial.rawTx',
1786
+ `undefined. Transactions may not be found by rawTx value.`
1787
+ )
1788
+ if (args.partial.inputBEEF)
1789
+ throw new sdk.WERR_INVALID_PARAMETER(
1790
+ 'args.partial.inputBEEF',
1791
+ `undefined. Transactions may not be found by inputBEEF value.`
1792
+ )
1793
+ const offset = args.paged?.offset || 0
1794
+ let skipped = 0
1795
+ let count = 0
1796
+ const stores = ['transactions']
1797
+ if (labelIds && labelIds.length > 0) {
1798
+ stores.push('tx_labels_map')
1799
+ }
1800
+ const dbTrx = this.toDbTrx(stores, 'readonly', args.trx)
1801
+ let cursor:
1802
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'transactions', unknown, 'readwrite' | 'readonly'>
1803
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'transactions', 'userId', 'readwrite' | 'readonly'>
1804
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'transactions', 'status', 'readwrite' | 'readonly'>
1805
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'transactions', 'status_userId', 'readwrite' | 'readonly'>
1806
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'transactions', 'provenTxId', 'readwrite' | 'readonly'>
1807
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'transactions', 'reference', 'readwrite' | 'readonly'>
1808
+ | null
1809
+ if (args.partial?.transactionId) {
1810
+ cursor = await dbTrx.objectStore('transactions').openCursor(args.partial.transactionId)
1811
+ } else if (args.partial?.userId !== undefined) {
1812
+ if (args.partial?.status !== undefined) {
1813
+ cursor = await dbTrx
1814
+ .objectStore('transactions')
1815
+ .index('status_userId')
1816
+ .openCursor([args.partial.status, args.partial.userId])
1817
+ } else {
1818
+ cursor = await dbTrx.objectStore('transactions').index('userId').openCursor(args.partial.userId)
1819
+ }
1820
+ } else if (args.partial?.status !== undefined) {
1821
+ cursor = await dbTrx.objectStore('transactions').index('status').openCursor(args.partial.status)
1822
+ } else if (args.partial?.provenTxId !== undefined) {
1823
+ cursor = await dbTrx.objectStore('transactions').index('provenTxId').openCursor(args.partial.provenTxId)
1824
+ } else if (args.partial?.reference !== undefined) {
1825
+ cursor = await dbTrx.objectStore('transactions').index('reference').openCursor(args.partial.reference)
1826
+ } else {
1827
+ cursor = await dbTrx.objectStore('transactions').openCursor()
1828
+ }
1829
+ let firstTime = true
1830
+ while (cursor) {
1831
+ if (!firstTime) cursor = await cursor.continue()
1832
+ if (!cursor) break
1833
+ firstTime = false
1834
+ const r = cursor.value
1835
+ if (args.since && args.since > r.updated_at) continue
1836
+ if (args.status && !args.status.includes(r.status)) continue
1837
+ if (args.partial) {
1838
+ if (args.partial.transactionId && r.transactionId !== args.partial.transactionId) continue
1839
+ if (args.partial.userId && r.userId !== args.partial.userId) continue
1840
+ if (args.partial.created_at && r.created_at.getTime() !== args.partial.created_at.getTime()) continue
1841
+ if (args.partial.updated_at && r.updated_at.getTime() !== args.partial.updated_at.getTime()) continue
1842
+ if (args.partial.provenTxId && r.provenTxId !== args.partial.provenTxId) continue
1843
+ if (args.partial.status && r.status !== args.partial.status) continue
1844
+ if (args.partial.reference && r.reference !== args.partial.reference) continue
1845
+ if (args.partial.isOutgoing !== undefined && r.isOutgoing !== args.partial.isOutgoing) continue
1846
+ if (args.partial.satoshis !== undefined && r.satoshis !== args.partial.satoshis) continue
1847
+ if (args.partial.description && r.description !== args.partial.description) continue
1848
+ if (args.partial.version !== undefined && r.version !== args.partial.version) continue
1849
+ if (args.partial.lockTime !== undefined && r.lockTime !== args.partial.lockTime) continue
1850
+ if (args.partial.txid && r.txid !== args.partial.txid) continue
1851
+ }
1852
+ if (labelIds && labelIds.length > 0) {
1853
+ let ids = [...labelIds]
1854
+ await this.filterTxLabelMaps({ partial: { transactionId: r.transactionId }, trx: dbTrx }, lm => {
1855
+ if (ids.length > 0) {
1856
+ const i = ids.indexOf(lm.txLabelId)
1857
+ if (i >= 0) {
1858
+ if (isQueryModeAll) {
1859
+ ids.splice(i, 1)
1860
+ } else {
1861
+ ids = []
1862
+ }
1863
+ }
1864
+ }
1865
+ })
1866
+ if (ids.length > 0) continue
1867
+ }
1868
+ if (skipped < offset) {
1869
+ skipped++
1870
+ continue
1871
+ }
1872
+ filtered(r)
1873
+ count++
1874
+ if (args.paged?.limit && count >= args.paged.limit) break
1875
+ }
1876
+ if (!args.trx) await dbTrx.done
1877
+ }
1878
+
1879
+ async findTransactions(
1880
+ args: sdk.FindTransactionsArgs,
1881
+ labelIds?: number[],
1882
+ isQueryModeAll?: boolean
1883
+ ): Promise<TableTransaction[]> {
1884
+ const results: TableTransaction[] = []
1885
+ await this.filterTransactions(
1886
+ args,
1887
+ r => {
1888
+ results.push(this.validateEntity(r))
1889
+ },
1890
+ labelIds,
1891
+ isQueryModeAll
1892
+ )
1893
+ for (const t of results) {
1894
+ if (!args.noRawTx) {
1895
+ await this.validateRawTransaction(t, args.trx)
1896
+ } else {
1897
+ t.rawTx = undefined
1898
+ t.inputBEEF = undefined
1899
+ }
1900
+ }
1901
+ return results
1902
+ }
1903
+
1904
+ async filterTxLabels(args: sdk.FindTxLabelsArgs, filtered: (v: TableTxLabel) => void): Promise<void> {
1905
+ const offset = args.paged?.offset || 0
1906
+ let skipped = 0
1907
+ let count = 0
1908
+ const dbTrx = this.toDbTrx(['tx_labels'], 'readonly', args.trx)
1909
+ let cursor:
1910
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'tx_labels', unknown, 'readwrite' | 'readonly'>
1911
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'tx_labels', 'userId', 'readwrite' | 'readonly'>
1912
+ | IDBPCursorWithValue<StorageIdbSchema, string[], 'tx_labels', 'label_userId', 'readwrite' | 'readonly'>
1913
+ | null
1914
+ if (args.partial?.txLabelId) {
1915
+ cursor = await dbTrx.objectStore('tx_labels').openCursor(args.partial.txLabelId)
1916
+ } else if (args.partial?.userId !== undefined) {
1917
+ if (args.partial?.label !== undefined) {
1918
+ cursor = await dbTrx
1919
+ .objectStore('tx_labels')
1920
+ .index('label_userId')
1921
+ .openCursor([args.partial.label, args.partial.userId])
1922
+ } else {
1923
+ cursor = await dbTrx.objectStore('tx_labels').index('userId').openCursor(args.partial.userId)
1924
+ }
1925
+ } else {
1926
+ cursor = await dbTrx.objectStore('tx_labels').openCursor()
1927
+ }
1928
+ let firstTime = true
1929
+ while (cursor) {
1930
+ if (!firstTime) cursor = await cursor.continue()
1931
+ if (!cursor) break
1932
+ firstTime = false
1933
+ const r = cursor.value
1934
+ if (args.since && args.since > r.updated_at) continue
1935
+ if (args.partial) {
1936
+ if (args.partial.txLabelId && r.txLabelId !== args.partial.txLabelId) continue
1937
+ if (args.partial.userId && r.userId !== args.partial.userId) continue
1938
+ if (args.partial.created_at && r.created_at.getTime() !== args.partial.created_at.getTime()) continue
1939
+ if (args.partial.updated_at && r.updated_at.getTime() !== args.partial.updated_at.getTime()) continue
1940
+ if (args.partial.label && r.label !== args.partial.label) continue
1941
+ if (args.partial.isDeleted !== undefined && r.isDeleted !== args.partial.isDeleted) continue
1942
+ }
1943
+ if (skipped < offset) {
1944
+ skipped++
1945
+ continue
1946
+ }
1947
+ filtered(r)
1948
+ count++
1949
+ if (args.paged?.limit && count >= args.paged.limit) break
1950
+ }
1951
+ if (!args.trx) await dbTrx.done
1952
+ }
1953
+
1954
+ async findTxLabels(args: sdk.FindTxLabelsArgs): Promise<TableTxLabel[]> {
1955
+ const result: TableTxLabel[] = []
1956
+ await this.filterTxLabels(args, r => {
1957
+ result.push(this.validateEntity(r))
1958
+ })
1959
+ return result
1960
+ }
1961
+
1962
+ async filterUsers(args: sdk.FindUsersArgs, filtered: (v: TableUser) => void): Promise<void> {
1963
+ const offset = args.paged?.offset || 0
1964
+ let skipped = 0
1965
+ let count = 0
1966
+ const dbTrx = this.toDbTrx(['users'], 'readonly', args.trx)
1967
+ let cursor = await dbTrx.objectStore('users').openCursor()
1968
+ let firstTime = true
1969
+ while (cursor) {
1970
+ if (!firstTime) cursor = await cursor.continue()
1971
+ if (!cursor) break
1972
+ firstTime = false
1973
+ const r = cursor.value
1974
+ if (args.since && args.since > r.updated_at) continue
1975
+ if (args.partial) {
1976
+ if (args.partial.userId && r.userId !== args.partial.userId) continue
1977
+ if (args.partial.created_at && r.created_at.getTime() !== args.partial.created_at.getTime()) continue
1978
+ if (args.partial.updated_at && r.updated_at.getTime() !== args.partial.updated_at.getTime()) continue
1979
+ if (args.partial.identityKey && r.identityKey !== args.partial.identityKey) continue
1980
+ if (args.partial.activeStorage && r.activeStorage !== args.partial.activeStorage) continue
1981
+ }
1982
+ if (skipped < offset) {
1983
+ skipped++
1984
+ continue
1985
+ }
1986
+ filtered(r)
1987
+ count++
1988
+ if (args.paged?.limit && count >= args.paged.limit) break
1989
+ }
1990
+ if (!args.trx) await dbTrx.done
1991
+ }
1992
+
1993
+ async findUsers(args: sdk.FindUsersArgs): Promise<TableUser[]> {
1994
+ const result: TableUser[] = []
1995
+ await this.filterUsers(args, r => {
1996
+ result.push(this.validateEntity(r))
1997
+ })
1998
+ return result
1999
+ }
2000
+
2001
+ async countCertificateFields(args: sdk.FindCertificateFieldsArgs): Promise<number> {
2002
+ let count = 0
2003
+ await this.filterCertificateFields(args, () => {
2004
+ count++
2005
+ })
2006
+ return count
2007
+ }
2008
+ async countCertificates(args: sdk.FindCertificatesArgs): Promise<number> {
2009
+ let count = 0
2010
+ await this.filterCertificates(args, () => {
2011
+ count++
2012
+ })
2013
+ return count
2014
+ }
2015
+ async countCommissions(args: sdk.FindCommissionsArgs): Promise<number> {
2016
+ let count = 0
2017
+ await this.filterCommissions(args, () => {
2018
+ count++
2019
+ })
2020
+ return count
2021
+ }
2022
+ async countMonitorEvents(args: sdk.FindMonitorEventsArgs): Promise<number> {
2023
+ let count = 0
2024
+ await this.filterMonitorEvents(args, () => {
2025
+ count++
2026
+ })
2027
+ return count
2028
+ }
2029
+ async countOutputBaskets(args: sdk.FindOutputBasketsArgs): Promise<number> {
2030
+ let count = 0
2031
+ await this.filterOutputBaskets(args, () => {
2032
+ count++
2033
+ })
2034
+ return count
2035
+ }
2036
+ async countOutputs(args: sdk.FindOutputsArgs, tagIds?: number[], isQueryModeAll?: boolean): Promise<number> {
2037
+ let count = 0
2038
+ await this.filterOutputs(
2039
+ { ...args, noScript: true },
2040
+ () => {
2041
+ count++
2042
+ },
2043
+ tagIds,
2044
+ isQueryModeAll
2045
+ )
2046
+ return count
2047
+ }
2048
+ async countOutputTags(args: sdk.FindOutputTagsArgs): Promise<number> {
2049
+ let count = 0
2050
+ await this.filterOutputTags(args, () => {
2051
+ count++
2052
+ })
2053
+ return count
2054
+ }
2055
+ async countSyncStates(args: sdk.FindSyncStatesArgs): Promise<number> {
2056
+ let count = 0
2057
+ await this.filterSyncStates(args, () => {
2058
+ count++
2059
+ })
2060
+ return count
2061
+ }
2062
+ async countTransactions(
2063
+ args: sdk.FindTransactionsArgs,
2064
+ labelIds?: number[],
2065
+ isQueryModeAll?: boolean
2066
+ ): Promise<number> {
2067
+ let count = 0
2068
+ await this.filterTransactions(
2069
+ { ...args, noRawTx: true },
2070
+ () => {
2071
+ count++
2072
+ },
2073
+ labelIds,
2074
+ isQueryModeAll
2075
+ )
2076
+ return count
2077
+ }
2078
+ async countTxLabels(args: sdk.FindTxLabelsArgs): Promise<number> {
2079
+ let count = 0
2080
+ await this.filterTxLabels(args, () => {
2081
+ count++
2082
+ })
2083
+ return count
2084
+ }
2085
+ async countUsers(args: sdk.FindUsersArgs): Promise<number> {
2086
+ let count = 0
2087
+ await this.filterUsers(args, () => {
2088
+ count++
2089
+ })
2090
+ return count
2091
+ }
2092
+
2093
+ async getProvenTxsForUser(args: sdk.FindForUserSincePagedArgs): Promise<TableProvenTx[]> {
2094
+ const results: TableProvenTx[] = []
2095
+ const fargs: sdk.FindProvenTxsArgs = {
2096
+ partial: {},
2097
+ since: args.since,
2098
+ paged: args.paged,
2099
+ trx: args.trx
2100
+ }
2101
+ await this.filterProvenTxs(
2102
+ fargs,
2103
+ r => {
2104
+ results.push(this.validateEntity(r))
2105
+ },
2106
+ args.userId
2107
+ )
2108
+ return results
2109
+ }
2110
+
2111
+ async getProvenTxReqsForUser(args: sdk.FindForUserSincePagedArgs): Promise<TableProvenTxReq[]> {
2112
+ const results: TableProvenTxReq[] = []
2113
+ const fargs: sdk.FindProvenTxReqsArgs = {
2114
+ partial: {},
2115
+ since: args.since,
2116
+ paged: args.paged,
2117
+ trx: args.trx
2118
+ }
2119
+ await this.filterProvenTxReqs(
2120
+ fargs,
2121
+ r => {
2122
+ results.push(this.validateEntity(r))
2123
+ },
2124
+ args.userId
2125
+ )
2126
+ return results
2127
+ }
2128
+
2129
+ async getTxLabelMapsForUser(args: sdk.FindForUserSincePagedArgs): Promise<TableTxLabelMap[]> {
2130
+ const results: TableTxLabelMap[] = []
2131
+ const fargs: sdk.FindTxLabelMapsArgs = {
2132
+ partial: {},
2133
+ since: args.since,
2134
+ paged: args.paged,
2135
+ trx: args.trx
2136
+ }
2137
+ await this.filterTxLabelMaps(
2138
+ fargs,
2139
+ r => {
2140
+ results.push(this.validateEntity(r))
2141
+ },
2142
+ args.userId
2143
+ )
2144
+ return results
2145
+ }
2146
+
2147
+ async getOutputTagMapsForUser(args: sdk.FindForUserSincePagedArgs): Promise<TableOutputTagMap[]> {
2148
+ const results: TableOutputTagMap[] = []
2149
+ const fargs: sdk.FindOutputTagMapsArgs = {
2150
+ partial: {},
2151
+ since: args.since,
2152
+ paged: args.paged,
2153
+ trx: args.trx
2154
+ }
2155
+ await this.filterOutputTagMaps(
2156
+ fargs,
2157
+ r => {
2158
+ results.push(this.validateEntity(r))
2159
+ },
2160
+ args.userId
2161
+ )
2162
+ return results
2163
+ }
2164
+
2165
+ async verifyReadyForDatabaseAccess(trx?: sdk.TrxToken): Promise<DBType> {
2166
+ if (!this._settings) {
2167
+ this._settings = await this.readSettings()
2168
+ }
2169
+
2170
+ return this._settings.dbtype
2171
+ }
2172
+
2173
+ /**
2174
+ * Helper to force uniform behavior across database engines.
2175
+ * Use to process all individual records with time stamps or number[] retreived from database.
2176
+ */
2177
+ validateEntity<T extends sdk.EntityTimeStamp>(entity: T, dateFields?: string[], booleanFields?: string[]): T {
2178
+ entity.created_at = this.validateDate(entity.created_at)
2179
+ entity.updated_at = this.validateDate(entity.updated_at)
2180
+ if (dateFields) {
2181
+ for (const df of dateFields) {
2182
+ if (entity[df]) entity[df] = this.validateDate(entity[df])
2183
+ }
2184
+ }
2185
+ if (booleanFields) {
2186
+ for (const df of booleanFields) {
2187
+ if (entity[df] !== undefined) entity[df] = !!entity[df]
2188
+ }
2189
+ }
2190
+ for (const key of Object.keys(entity)) {
2191
+ const val = entity[key]
2192
+ if (val === null) {
2193
+ entity[key] = undefined
2194
+ } else if (Buffer.isBuffer(val) || val instanceof Uint8Array) {
2195
+ entity[key] = Array.from(val)
2196
+ }
2197
+ }
2198
+ return entity
2199
+ }
2200
+
2201
+ /**
2202
+ * Helper to force uniform behavior across database engines.
2203
+ * Use to process all arrays of records with time stamps retreived from database.
2204
+ * @returns input `entities` array with contained values validated.
2205
+ */
2206
+ validateEntities<T extends sdk.EntityTimeStamp>(entities: T[], dateFields?: string[], booleanFields?: string[]): T[] {
2207
+ for (let i = 0; i < entities.length; i++) {
2208
+ entities[i] = this.validateEntity(entities[i], dateFields, booleanFields)
2209
+ }
2210
+ return entities
2211
+ }
2212
+ /**
2213
+ * Helper to force uniform behavior across database engines.
2214
+ * Use to process the update template for entities being updated.
2215
+ */
2216
+ validatePartialForUpdate<T extends sdk.EntityTimeStamp>(
2217
+ update: Partial<T>,
2218
+ dateFields?: string[],
2219
+ booleanFields?: string[]
2220
+ ): Partial<T> {
2221
+ if (!this.dbtype) throw new sdk.WERR_INTERNAL('must call verifyReadyForDatabaseAccess first')
2222
+ const v: any = update
2223
+ if (v.created_at) v.created_at = this.validateEntityDate(v.created_at)
2224
+ if (v.updated_at) v.updated_at = this.validateEntityDate(v.updated_at)
2225
+ if (!v.created_at) delete v.created_at
2226
+ if (!v.updated_at) v.updated_at = this.validateEntityDate(new Date())
2227
+
2228
+ if (dateFields) {
2229
+ for (const df of dateFields) {
2230
+ if (v[df]) v[df] = this.validateOptionalEntityDate(v[df])
2231
+ }
2232
+ }
2233
+ if (booleanFields) {
2234
+ for (const df of booleanFields) {
2235
+ if (update[df] !== undefined) update[df] = !!update[df] ? 1 : 0
2236
+ }
2237
+ }
2238
+ for (const key of Object.keys(v)) {
2239
+ const val = v[key]
2240
+ if (Array.isArray(val) && (val.length === 0 || typeof val[0] === 'number')) {
2241
+ v[key] = Buffer.from(val)
2242
+ } else if (val === undefined) {
2243
+ v[key] = null
2244
+ }
2245
+ }
2246
+ this.isDirty = true
2247
+ return v
2248
+ }
2249
+
2250
+ /**
2251
+ * Helper to force uniform behavior across database engines.
2252
+ * Use to process new entities being inserted into the database.
2253
+ */
2254
+ async validateEntityForInsert<T extends sdk.EntityTimeStamp>(
2255
+ entity: T,
2256
+ trx?: sdk.TrxToken,
2257
+ dateFields?: string[],
2258
+ booleanFields?: string[]
2259
+ ): Promise<any> {
2260
+ await this.verifyReadyForDatabaseAccess(trx)
2261
+ const v: any = { ...entity }
2262
+ v.created_at = this.validateOptionalEntityDate(v.created_at, true)!
2263
+ v.updated_at = this.validateOptionalEntityDate(v.updated_at, true)!
2264
+ if (!v.created_at) delete v.created_at
2265
+ if (!v.updated_at) delete v.updated_at
2266
+ if (dateFields) {
2267
+ for (const df of dateFields) {
2268
+ if (v[df]) v[df] = this.validateOptionalEntityDate(v[df])
2269
+ }
2270
+ }
2271
+ if (booleanFields) {
2272
+ for (const df of booleanFields) {
2273
+ if (entity[df] !== undefined) entity[df] = !!entity[df] ? 1 : 0
2274
+ }
2275
+ }
2276
+ for (const key of Object.keys(v)) {
2277
+ const val = v[key]
2278
+ if (Array.isArray(val) && (val.length === 0 || typeof val[0] === 'number')) {
2279
+ v[key] = Buffer.from(val)
2280
+ } else if (val === undefined) {
2281
+ v[key] = null
2282
+ }
2283
+ }
2284
+ this.isDirty = true
2285
+ return v
2286
+ }
2287
+
2288
+ async validateRawTransaction(t: TableTransaction, trx?: sdk.TrxToken): Promise<void> {
2289
+ // if there is no txid or there is a rawTransaction return what we have.
2290
+ if (t.rawTx || !t.txid) return
2291
+
2292
+ // rawTransaction is missing, see if we moved it ...
2293
+
2294
+ const rawTx = await this.getRawTxOfKnownValidTransaction(t.txid, undefined, undefined, trx)
2295
+ if (!rawTx) return
2296
+ t.rawTx = rawTx
2297
+ }
2298
+ }