@bopen-io/wallet-toolbox 2.6.2-brc153.5 → 2.14.5

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 (878) hide show
  1. package/CHANGELOG.md +744 -1
  2. package/LICENSES/Open-BSV-License-4-wallet-pre-2026.txt +28 -0
  3. package/README.md +823 -14
  4. package/THIRD_PARTY_NOTICES.md +35 -0
  5. package/docs/README.md +44 -31
  6. package/docs/action-batch-planning.md +80 -37
  7. package/docs/client.md +12996 -4571
  8. package/docs/identity-verification.md +218 -0
  9. package/docs/local-first-chaintracks.md +129 -0
  10. package/docs/managed-change-liquidity.md +258 -0
  11. package/docs/managed-change-policy.md +14 -1
  12. package/docs/monitor.md +505 -190
  13. package/docs/no-send-expiry.md +167 -0
  14. package/docs/prepared-beef.md +197 -0
  15. package/docs/services.md +4013 -1153
  16. package/docs/setup.md +107 -56
  17. package/docs/storage.md +5781 -1599
  18. package/docs/sync-transfer.md +144 -0
  19. package/docs/wab-shamir.md +5 -1
  20. package/docs/wallet.md +10188 -10904
  21. package/out/src/CWIStyleWalletManager.d.ts +39 -31
  22. package/out/src/CWIStyleWalletManager.d.ts.map +1 -1
  23. package/out/src/CWIStyleWalletManager.js +309 -258
  24. package/out/src/CWIStyleWalletManager.js.map +1 -1
  25. package/out/src/Setup.d.ts +14 -0
  26. package/out/src/Setup.d.ts.map +1 -1
  27. package/out/src/Setup.js +6 -2
  28. package/out/src/Setup.js.map +1 -1
  29. package/out/src/SetupClient.d.ts +3 -0
  30. package/out/src/SetupClient.d.ts.map +1 -1
  31. package/out/src/SetupClient.js +1 -0
  32. package/out/src/SetupClient.js.map +1 -1
  33. package/out/src/SetupWallet.d.ts +3 -0
  34. package/out/src/SetupWallet.d.ts.map +1 -1
  35. package/out/src/ShamirWalletManager.d.ts.map +1 -1
  36. package/out/src/ShamirWalletManager.js +34 -19
  37. package/out/src/ShamirWalletManager.js.map +1 -1
  38. package/out/src/SimpleWalletManager.d.ts.map +1 -1
  39. package/out/src/SimpleWalletManager.js +7 -6
  40. package/out/src/SimpleWalletManager.js.map +1 -1
  41. package/out/src/Wallet.d.ts +54 -14
  42. package/out/src/Wallet.d.ts.map +1 -1
  43. package/out/src/Wallet.js +216 -114
  44. package/out/src/Wallet.js.map +1 -1
  45. package/out/src/WalletAuthenticationManager.d.ts +32 -0
  46. package/out/src/WalletAuthenticationManager.d.ts.map +1 -1
  47. package/out/src/WalletAuthenticationManager.js +531 -78
  48. package/out/src/WalletAuthenticationManager.js.map +1 -1
  49. package/out/src/WalletLogger.js +1 -1
  50. package/out/src/WalletLogger.js.map +1 -1
  51. package/out/src/WalletPermissionsManager.d.ts +101 -43
  52. package/out/src/WalletPermissionsManager.d.ts.map +1 -1
  53. package/out/src/WalletPermissionsManager.js +897 -414
  54. package/out/src/WalletPermissionsManager.js.map +1 -1
  55. package/out/src/WalletSettingsManager.d.ts +3 -2
  56. package/out/src/WalletSettingsManager.d.ts.map +1 -1
  57. package/out/src/WalletSettingsManager.js +143 -8
  58. package/out/src/WalletSettingsManager.js.map +1 -1
  59. package/out/src/entropy/EntropyCollector.d.ts.map +1 -1
  60. package/out/src/entropy/EntropyCollector.js +3 -2
  61. package/out/src/entropy/EntropyCollector.js.map +1 -1
  62. package/out/src/fundWalletP2PKH.d.ts.map +1 -1
  63. package/out/src/fundWalletP2PKH.js +143 -44
  64. package/out/src/fundWalletP2PKH.js.map +1 -1
  65. package/out/src/index.client.d.ts +6 -0
  66. package/out/src/index.client.d.ts.map +1 -1
  67. package/out/src/index.client.js +16 -1
  68. package/out/src/index.client.js.map +1 -1
  69. package/out/src/index.mobile.d.ts +7 -0
  70. package/out/src/index.mobile.d.ts.map +1 -1
  71. package/out/src/index.mobile.js +17 -1
  72. package/out/src/index.mobile.js.map +1 -1
  73. package/out/src/mockchain/MockChainTracker.d.ts.map +1 -1
  74. package/out/src/mockchain/MockChainTracker.js +5 -5
  75. package/out/src/mockchain/MockChainTracker.js.map +1 -1
  76. package/out/src/mockchain/MockServices.d.ts +2 -0
  77. package/out/src/mockchain/MockServices.d.ts.map +1 -1
  78. package/out/src/mockchain/MockServices.js +54 -14
  79. package/out/src/mockchain/MockServices.js.map +1 -1
  80. package/out/src/monitor/Monitor.d.ts +51 -0
  81. package/out/src/monitor/Monitor.d.ts.map +1 -1
  82. package/out/src/monitor/Monitor.js +282 -41
  83. package/out/src/monitor/Monitor.js.map +1 -1
  84. package/out/src/monitor/MonitorDaemon.d.ts.map +1 -1
  85. package/out/src/monitor/MonitorDaemon.js +64 -16
  86. package/out/src/monitor/MonitorDaemon.js.map +1 -1
  87. package/out/src/monitor/monitorValidation.d.ts +12 -0
  88. package/out/src/monitor/monitorValidation.d.ts.map +1 -0
  89. package/out/src/monitor/monitorValidation.js +133 -0
  90. package/out/src/monitor/monitorValidation.js.map +1 -0
  91. package/out/src/monitor/tasks/TaskArcSSE.d.ts +6 -1
  92. package/out/src/monitor/tasks/TaskArcSSE.d.ts.map +1 -1
  93. package/out/src/monitor/tasks/TaskArcSSE.js +117 -74
  94. package/out/src/monitor/tasks/TaskArcSSE.js.map +1 -1
  95. package/out/src/monitor/tasks/TaskCheckForProofs.d.ts +5 -0
  96. package/out/src/monitor/tasks/TaskCheckForProofs.d.ts.map +1 -1
  97. package/out/src/monitor/tasks/TaskCheckForProofs.js +29 -24
  98. package/out/src/monitor/tasks/TaskCheckForProofs.js.map +1 -1
  99. package/out/src/monitor/tasks/TaskCheckNoSends.d.ts.map +1 -1
  100. package/out/src/monitor/tasks/TaskCheckNoSends.js +11 -3
  101. package/out/src/monitor/tasks/TaskCheckNoSends.js.map +1 -1
  102. package/out/src/monitor/tasks/TaskFailAbandoned.d.ts.map +1 -1
  103. package/out/src/monitor/tasks/TaskFailAbandoned.js +9 -4
  104. package/out/src/monitor/tasks/TaskFailAbandoned.js.map +1 -1
  105. package/out/src/monitor/tasks/TaskNewHeader.d.ts.map +1 -1
  106. package/out/src/monitor/tasks/TaskNewHeader.js +3 -1
  107. package/out/src/monitor/tasks/TaskNewHeader.js.map +1 -1
  108. package/out/src/monitor/tasks/TaskNoSendExpiry.d.ts +19 -0
  109. package/out/src/monitor/tasks/TaskNoSendExpiry.d.ts.map +1 -0
  110. package/out/src/monitor/tasks/TaskNoSendExpiry.js +47 -0
  111. package/out/src/monitor/tasks/TaskNoSendExpiry.js.map +1 -0
  112. package/out/src/monitor/tasks/TaskReconcilePendingTransactions.d.ts +27 -0
  113. package/out/src/monitor/tasks/TaskReconcilePendingTransactions.d.ts.map +1 -0
  114. package/out/src/monitor/tasks/TaskReconcilePendingTransactions.js +242 -0
  115. package/out/src/monitor/tasks/TaskReconcilePendingTransactions.js.map +1 -0
  116. package/out/src/monitor/tasks/TaskReorg.d.ts.map +1 -1
  117. package/out/src/monitor/tasks/TaskReorg.js +4 -4
  118. package/out/src/monitor/tasks/TaskReorg.js.map +1 -1
  119. package/out/src/monitor/tasks/TaskReviewDoubleSpends.d.ts.map +1 -1
  120. package/out/src/monitor/tasks/TaskReviewDoubleSpends.js +31 -9
  121. package/out/src/monitor/tasks/TaskReviewDoubleSpends.js.map +1 -1
  122. package/out/src/monitor/tasks/TaskReviewProvenTxs.d.ts +18 -1
  123. package/out/src/monitor/tasks/TaskReviewProvenTxs.d.ts.map +1 -1
  124. package/out/src/monitor/tasks/TaskReviewProvenTxs.js +99 -21
  125. package/out/src/monitor/tasks/TaskReviewProvenTxs.js.map +1 -1
  126. package/out/src/monitor/tasks/TaskReviewUtxos.d.ts +33 -6
  127. package/out/src/monitor/tasks/TaskReviewUtxos.d.ts.map +1 -1
  128. package/out/src/monitor/tasks/TaskReviewUtxos.js +189 -13
  129. package/out/src/monitor/tasks/TaskReviewUtxos.js.map +1 -1
  130. package/out/src/monitor/tasks/TaskSendWaiting.d.ts.map +1 -1
  131. package/out/src/monitor/tasks/TaskSendWaiting.js +52 -11
  132. package/out/src/monitor/tasks/TaskSendWaiting.js.map +1 -1
  133. package/out/src/monitor/tasks/TaskUnFail.d.ts +1 -0
  134. package/out/src/monitor/tasks/TaskUnFail.d.ts.map +1 -1
  135. package/out/src/monitor/tasks/TaskUnFail.js +26 -8
  136. package/out/src/monitor/tasks/TaskUnFail.js.map +1 -1
  137. package/out/src/monitor/tasks/index.all.d.ts +2 -0
  138. package/out/src/monitor/tasks/index.all.d.ts.map +1 -1
  139. package/out/src/monitor/tasks/index.all.js +2 -0
  140. package/out/src/monitor/tasks/index.all.js.map +1 -1
  141. package/out/src/sdk/ActionBatch.interfaces.d.ts +23 -0
  142. package/out/src/sdk/ActionBatch.interfaces.d.ts.map +1 -1
  143. package/out/src/sdk/PrivilegedKeyManager.d.ts.map +1 -1
  144. package/out/src/sdk/PrivilegedKeyManager.js +3 -2
  145. package/out/src/sdk/PrivilegedKeyManager.js.map +1 -1
  146. package/out/src/sdk/WERR_errors.d.ts +23 -0
  147. package/out/src/sdk/WERR_errors.d.ts.map +1 -1
  148. package/out/src/sdk/WERR_errors.js +51 -7
  149. package/out/src/sdk/WERR_errors.js.map +1 -1
  150. package/out/src/sdk/WalletError.d.ts.map +1 -1
  151. package/out/src/sdk/WalletError.js +7 -21
  152. package/out/src/sdk/WalletError.js.map +1 -1
  153. package/out/src/sdk/WalletErrorFromJson.d.ts.map +1 -1
  154. package/out/src/sdk/WalletErrorFromJson.js +121 -3
  155. package/out/src/sdk/WalletErrorFromJson.js.map +1 -1
  156. package/out/src/sdk/WalletServices.interfaces.d.ts +45 -2
  157. package/out/src/sdk/WalletServices.interfaces.d.ts.map +1 -1
  158. package/out/src/sdk/WalletStorage.interfaces.d.ts +87 -4
  159. package/out/src/sdk/WalletStorage.interfaces.d.ts.map +1 -1
  160. package/out/src/sdk/types.d.ts +3 -2
  161. package/out/src/sdk/types.d.ts.map +1 -1
  162. package/out/src/sdk/types.js +3 -2
  163. package/out/src/sdk/types.js.map +1 -1
  164. package/out/src/services/ServiceCollection.js +2 -2
  165. package/out/src/services/ServiceCollection.js.map +1 -1
  166. package/out/src/services/Services.d.ts +5 -0
  167. package/out/src/services/Services.d.ts.map +1 -1
  168. package/out/src/services/Services.js +346 -120
  169. package/out/src/services/Services.js.map +1 -1
  170. package/out/src/services/chaintracker/BHServiceClient.d.ts +21 -4
  171. package/out/src/services/chaintracker/BHServiceClient.d.ts.map +1 -1
  172. package/out/src/services/chaintracker/BHServiceClient.js +269 -66
  173. package/out/src/services/chaintracker/BHServiceClient.js.map +1 -1
  174. package/out/src/services/chaintracker/ChaintracksChainTracker.d.ts +25 -3
  175. package/out/src/services/chaintracker/ChaintracksChainTracker.d.ts.map +1 -1
  176. package/out/src/services/chaintracker/ChaintracksChainTracker.js +188 -53
  177. package/out/src/services/chaintracker/ChaintracksChainTracker.js.map +1 -1
  178. package/out/src/services/chaintracker/LocalChainTracker.d.ts +122 -0
  179. package/out/src/services/chaintracker/LocalChainTracker.d.ts.map +1 -0
  180. package/out/src/services/chaintracker/LocalChainTracker.js +465 -0
  181. package/out/src/services/chaintracker/LocalChainTracker.js.map +1 -0
  182. package/out/src/services/chaintracker/chaintracks/Api/BlockHeaderApi.d.ts.map +1 -1
  183. package/out/src/services/chaintracker/chaintracks/Api/BlockHeaderApi.js +59 -7
  184. package/out/src/services/chaintracker/chaintracks/Api/BlockHeaderApi.js.map +1 -1
  185. package/out/src/services/chaintracker/chaintracks/Api/BulkFileDataCacheApi.d.ts +48 -0
  186. package/out/src/services/chaintracker/chaintracks/Api/BulkFileDataCacheApi.d.ts.map +1 -0
  187. package/out/src/services/chaintracker/chaintracks/Api/BulkFileDataCacheApi.js +3 -0
  188. package/out/src/services/chaintracker/chaintracks/Api/BulkFileDataCacheApi.js.map +1 -0
  189. package/out/src/services/chaintracker/chaintracks/Api/BulkFileDataValidatorApi.d.ts +70 -0
  190. package/out/src/services/chaintracker/chaintracks/Api/BulkFileDataValidatorApi.d.ts.map +1 -0
  191. package/out/src/services/chaintracker/chaintracks/Api/BulkFileDataValidatorApi.js +21 -0
  192. package/out/src/services/chaintracker/chaintracks/Api/BulkFileDataValidatorApi.js.map +1 -0
  193. package/out/src/services/chaintracker/chaintracks/Api/ChaintracksApi.d.ts +6 -0
  194. package/out/src/services/chaintracker/chaintracks/Api/ChaintracksApi.d.ts.map +1 -1
  195. package/out/src/services/chaintracker/chaintracks/Api/ChaintracksClientApi.d.ts +53 -0
  196. package/out/src/services/chaintracker/chaintracks/Api/ChaintracksClientApi.d.ts.map +1 -1
  197. package/out/src/services/chaintracker/chaintracks/Api/ChaintracksFetchApi.d.ts +9 -2
  198. package/out/src/services/chaintracker/chaintracks/Api/ChaintracksFetchApi.d.ts.map +1 -1
  199. package/out/src/services/chaintracker/chaintracks/Api/ChaintracksStorageApi.d.ts +9 -0
  200. package/out/src/services/chaintracker/chaintracks/Api/ChaintracksStorageApi.d.ts.map +1 -1
  201. package/out/src/services/chaintracker/chaintracks/Chaintracks.d.ts +28 -3
  202. package/out/src/services/chaintracker/chaintracks/Chaintracks.d.ts.map +1 -1
  203. package/out/src/services/chaintracker/chaintracks/Chaintracks.js +282 -64
  204. package/out/src/services/chaintracker/chaintracks/Chaintracks.js.map +1 -1
  205. package/out/src/services/chaintracker/chaintracks/ChaintracksService.d.ts +16 -0
  206. package/out/src/services/chaintracker/chaintracks/ChaintracksService.d.ts.map +1 -1
  207. package/out/src/services/chaintracker/chaintracks/ChaintracksService.js +150 -26
  208. package/out/src/services/chaintracker/chaintracks/ChaintracksService.js.map +1 -1
  209. package/out/src/services/chaintracker/chaintracks/ChaintracksServiceClient.d.ts +30 -1
  210. package/out/src/services/chaintracker/chaintracks/ChaintracksServiceClient.d.ts.map +1 -1
  211. package/out/src/services/chaintracker/chaintracks/ChaintracksServiceClient.js +348 -30
  212. package/out/src/services/chaintracker/chaintracks/ChaintracksServiceClient.js.map +1 -1
  213. package/out/src/services/chaintracker/chaintracks/GoChaintracksServiceClient.d.ts +32 -1
  214. package/out/src/services/chaintracker/chaintracks/GoChaintracksServiceClient.d.ts.map +1 -1
  215. package/out/src/services/chaintracker/chaintracks/GoChaintracksServiceClient.js +378 -44
  216. package/out/src/services/chaintracker/chaintracks/GoChaintracksServiceClient.js.map +1 -1
  217. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorBase.d.ts.map +1 -1
  218. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorBase.js +28 -3
  219. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorBase.js.map +1 -1
  220. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDN.d.ts.map +1 -1
  221. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDN.js +33 -9
  222. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDN.js.map +1 -1
  223. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDNBabbage.d.ts.map +1 -1
  224. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDNBabbage.js.map +1 -1
  225. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorChaintracks.d.ts.map +1 -1
  226. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorChaintracks.js +4 -2
  227. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorChaintracks.js.map +1 -1
  228. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.d.ts +2 -0
  229. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.d.ts.map +1 -1
  230. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.js +17 -4
  231. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.js.map +1 -1
  232. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainWs.d.ts +2 -0
  233. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainWs.d.ts.map +1 -1
  234. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainWs.js +40 -20
  235. package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainWs.js.map +1 -1
  236. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorBase.d.ts.map +1 -1
  237. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorBase.js +14 -0
  238. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorBase.js.map +1 -1
  239. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorChaintracksSSE.d.ts +6 -0
  240. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorChaintracksSSE.d.ts.map +1 -1
  241. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorChaintracksSSE.js +56 -9
  242. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorChaintracksSSE.js.map +1 -1
  243. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorTeranodeP2P.d.ts.map +1 -1
  244. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorTeranodeP2P.js +6 -3
  245. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorTeranodeP2P.js.map +1 -1
  246. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.d.ts +4 -0
  247. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.d.ts.map +1 -1
  248. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.js +27 -9
  249. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.js.map +1 -1
  250. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainWs.d.ts +8 -0
  251. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainWs.d.ts.map +1 -1
  252. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainWs.js +49 -5
  253. package/out/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainWs.js.map +1 -1
  254. package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.d.ts +1 -1
  255. package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.d.ts.map +1 -1
  256. package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.js +90 -21
  257. package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.js.map +1 -1
  258. package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.d.ts +3 -1
  259. package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.d.ts.map +1 -1
  260. package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.js +185 -38
  261. package/out/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.js.map +1 -1
  262. package/out/src/services/chaintracker/chaintracks/Storage/BulkStorageBase.d.ts.map +1 -1
  263. package/out/src/services/chaintracker/chaintracks/Storage/BulkStorageBase.js +59 -6
  264. package/out/src/services/chaintracker/chaintracks/Storage/BulkStorageBase.js.map +1 -1
  265. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksKnexMigrations.d.ts +2 -0
  266. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksKnexMigrations.d.ts.map +1 -1
  267. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksKnexMigrations.js +89 -39
  268. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksKnexMigrations.js.map +1 -1
  269. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.d.ts +10 -0
  270. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.d.ts.map +1 -1
  271. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.js +230 -28
  272. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.js.map +1 -1
  273. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageIdb.d.ts +2 -1
  274. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageIdb.d.ts.map +1 -1
  275. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageIdb.js +265 -96
  276. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageIdb.js.map +1 -1
  277. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.d.ts +3 -1
  278. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.d.ts.map +1 -1
  279. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.js +240 -87
  280. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.js.map +1 -1
  281. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.d.ts +3 -0
  282. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.d.ts.map +1 -1
  283. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.js +121 -35
  284. package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.js.map +1 -1
  285. package/out/src/services/chaintracker/chaintracks/configureChaintracksIngestors.d.ts +8 -0
  286. package/out/src/services/chaintracker/chaintracks/configureChaintracksIngestors.d.ts.map +1 -1
  287. package/out/src/services/chaintracker/chaintracks/configureChaintracksIngestors.js +6 -3
  288. package/out/src/services/chaintracker/chaintracks/configureChaintracksIngestors.js.map +1 -1
  289. package/out/src/services/chaintracker/chaintracks/createDefaultIdbChaintracksOptions.d.ts.map +1 -1
  290. package/out/src/services/chaintracker/chaintracks/createDefaultIdbChaintracksOptions.js.map +1 -1
  291. package/out/src/services/chaintracker/chaintracks/createDefaultKnexChaintracksOptions.d.ts.map +1 -1
  292. package/out/src/services/chaintracker/chaintracks/createDefaultKnexChaintracksOptions.js.map +1 -1
  293. package/out/src/services/chaintracker/chaintracks/createDefaultNoDbChaintracksOptions.d.ts.map +1 -1
  294. package/out/src/services/chaintracker/chaintracks/createDefaultNoDbChaintracksOptions.js.map +1 -1
  295. package/out/src/services/chaintracker/chaintracks/createIdbChaintracks.d.ts.map +1 -1
  296. package/out/src/services/chaintracker/chaintracks/createIdbChaintracks.js +1 -7
  297. package/out/src/services/chaintracker/chaintracks/createIdbChaintracks.js.map +1 -1
  298. package/out/src/services/chaintracker/chaintracks/createKnexChaintracks.d.ts.map +1 -1
  299. package/out/src/services/chaintracker/chaintracks/createKnexChaintracks.js +1 -7
  300. package/out/src/services/chaintracker/chaintracks/createKnexChaintracks.js.map +1 -1
  301. package/out/src/services/chaintracker/chaintracks/createNoDbChaintracks.d.ts.map +1 -1
  302. package/out/src/services/chaintracker/chaintracks/createNoDbChaintracks.js +1 -7
  303. package/out/src/services/chaintracker/chaintracks/createNoDbChaintracks.js.map +1 -1
  304. package/out/src/services/chaintracker/chaintracks/index.all.d.ts +3 -0
  305. package/out/src/services/chaintracker/chaintracks/index.all.d.ts.map +1 -1
  306. package/out/src/services/chaintracker/chaintracks/index.all.js +3 -0
  307. package/out/src/services/chaintracker/chaintracks/index.all.js.map +1 -1
  308. package/out/src/services/chaintracker/chaintracks/index.mobile.d.ts +5 -0
  309. package/out/src/services/chaintracker/chaintracks/index.mobile.d.ts.map +1 -1
  310. package/out/src/services/chaintracker/chaintracks/index.mobile.js +5 -0
  311. package/out/src/services/chaintracker/chaintracks/index.mobile.js.map +1 -1
  312. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataCacheFs.d.ts +51 -0
  313. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataCacheFs.d.ts.map +1 -0
  314. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataCacheFs.js +394 -0
  315. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataCacheFs.js.map +1 -0
  316. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.d.ts +45 -1
  317. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.d.ts.map +1 -1
  318. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.js +733 -166
  319. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataManager.js.map +1 -1
  320. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataReader.d.ts.map +1 -1
  321. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataReader.js +17 -1
  322. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataReader.js.map +1 -1
  323. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataValidator.worker.d.ts +32 -0
  324. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataValidator.worker.d.ts.map +1 -0
  325. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataValidator.worker.js +40 -0
  326. package/out/src/services/chaintracker/chaintracks/util/BulkFileDataValidator.worker.js.map +1 -0
  327. package/out/src/services/chaintracker/chaintracks/util/BulkFilesReader.d.ts.map +1 -1
  328. package/out/src/services/chaintracker/chaintracks/util/BulkFilesReader.js +99 -30
  329. package/out/src/services/chaintracker/chaintracks/util/BulkFilesReader.js.map +1 -1
  330. package/out/src/services/chaintracker/chaintracks/util/BulkHeaderFile.d.ts +3 -1
  331. package/out/src/services/chaintracker/chaintracks/util/BulkHeaderFile.d.ts.map +1 -1
  332. package/out/src/services/chaintracker/chaintracks/util/BulkHeaderFile.js +23 -15
  333. package/out/src/services/chaintracker/chaintracks/util/BulkHeaderFile.js.map +1 -1
  334. package/out/src/services/chaintracker/chaintracks/util/ChaintracksFetch.d.ts +38 -4
  335. package/out/src/services/chaintracker/chaintracks/util/ChaintracksFetch.d.ts.map +1 -1
  336. package/out/src/services/chaintracker/chaintracks/util/ChaintracksFetch.js +191 -47
  337. package/out/src/services/chaintracker/chaintracks/util/ChaintracksFetch.js.map +1 -1
  338. package/out/src/services/chaintracker/chaintracks/util/ChaintracksFs.d.ts +2 -1
  339. package/out/src/services/chaintracker/chaintracks/util/ChaintracksFs.d.ts.map +1 -1
  340. package/out/src/services/chaintracker/chaintracks/util/ChaintracksFs.js +57 -11
  341. package/out/src/services/chaintracker/chaintracks/util/ChaintracksFs.js.map +1 -1
  342. package/out/src/services/chaintracker/chaintracks/util/DurableFileBulkFileDownloadBudget.d.ts +48 -0
  343. package/out/src/services/chaintracker/chaintracks/util/DurableFileBulkFileDownloadBudget.d.ts.map +1 -0
  344. package/out/src/services/chaintracker/chaintracks/util/DurableFileBulkFileDownloadBudget.js +280 -0
  345. package/out/src/services/chaintracker/chaintracks/util/DurableFileBulkFileDownloadBudget.js.map +1 -0
  346. package/out/src/services/chaintracker/chaintracks/util/FixedWindowBulkFileDownloadBudget.d.ts +30 -0
  347. package/out/src/services/chaintracker/chaintracks/util/FixedWindowBulkFileDownloadBudget.d.ts.map +1 -0
  348. package/out/src/services/chaintracker/chaintracks/util/FixedWindowBulkFileDownloadBudget.js +57 -0
  349. package/out/src/services/chaintracker/chaintracks/util/FixedWindowBulkFileDownloadBudget.js.map +1 -0
  350. package/out/src/services/chaintracker/chaintracks/util/HeightRange.d.ts.map +1 -1
  351. package/out/src/services/chaintracker/chaintracks/util/HeightRange.js.map +1 -1
  352. package/out/src/services/chaintracker/chaintracks/util/InlineBulkFileDataValidator.d.ts +14 -0
  353. package/out/src/services/chaintracker/chaintracks/util/InlineBulkFileDataValidator.d.ts.map +1 -0
  354. package/out/src/services/chaintracker/chaintracks/util/InlineBulkFileDataValidator.js +148 -0
  355. package/out/src/services/chaintracker/chaintracks/util/InlineBulkFileDataValidator.js.map +1 -0
  356. package/out/src/services/chaintracker/chaintracks/util/NodeBulkFileDataValidator.d.ts +41 -0
  357. package/out/src/services/chaintracker/chaintracks/util/NodeBulkFileDataValidator.d.ts.map +1 -0
  358. package/out/src/services/chaintracker/chaintracks/util/NodeBulkFileDataValidator.js +271 -0
  359. package/out/src/services/chaintracker/chaintracks/util/NodeBulkFileDataValidator.js.map +1 -0
  360. package/out/src/services/chaintracker/chaintracks/util/SingleWriterMultiReaderLock.d.ts +3 -0
  361. package/out/src/services/chaintracker/chaintracks/util/SingleWriterMultiReaderLock.d.ts.map +1 -1
  362. package/out/src/services/chaintracker/chaintracks/util/SingleWriterMultiReaderLock.js +15 -0
  363. package/out/src/services/chaintracker/chaintracks/util/SingleWriterMultiReaderLock.js.map +1 -1
  364. package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.d.ts +17 -4
  365. package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.d.ts.map +1 -1
  366. package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.js +362 -105
  367. package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.js.map +1 -1
  368. package/out/src/services/chaintracker/chaintracks/util/safeDiagnostic.d.ts +4 -0
  369. package/out/src/services/chaintracker/chaintracks/util/safeDiagnostic.d.ts.map +1 -0
  370. package/out/src/services/chaintracker/chaintracks/util/safeDiagnostic.js +33 -0
  371. package/out/src/services/chaintracker/chaintracks/util/safeDiagnostic.js.map +1 -0
  372. package/out/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.d.ts.map +1 -1
  373. package/out/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.js.map +1 -1
  374. package/out/src/services/chaintracker/index.all.d.ts +1 -0
  375. package/out/src/services/chaintracker/index.all.d.ts.map +1 -1
  376. package/out/src/services/chaintracker/index.all.js +1 -0
  377. package/out/src/services/chaintracker/index.all.js.map +1 -1
  378. package/out/src/services/chaintracker/index.client.d.ts +1 -0
  379. package/out/src/services/chaintracker/index.client.d.ts.map +1 -1
  380. package/out/src/services/chaintracker/index.client.js +1 -0
  381. package/out/src/services/chaintracker/index.client.js.map +1 -1
  382. package/out/src/services/chaintracker/index.mobile.d.ts +1 -0
  383. package/out/src/services/chaintracker/index.mobile.d.ts.map +1 -1
  384. package/out/src/services/chaintracker/index.mobile.js +1 -0
  385. package/out/src/services/chaintracker/index.mobile.js.map +1 -1
  386. package/out/src/services/classifyOutputUtxo.d.ts +25 -0
  387. package/out/src/services/classifyOutputUtxo.d.ts.map +1 -0
  388. package/out/src/services/classifyOutputUtxo.js +96 -0
  389. package/out/src/services/classifyOutputUtxo.js.map +1 -0
  390. package/out/src/services/createDefaultWalletServicesOptions.d.ts +16 -3
  391. package/out/src/services/createDefaultWalletServicesOptions.d.ts.map +1 -1
  392. package/out/src/services/createDefaultWalletServicesOptions.js +38 -8
  393. package/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
  394. package/out/src/services/fiatRateValidation.d.ts +12 -0
  395. package/out/src/services/fiatRateValidation.d.ts.map +1 -0
  396. package/out/src/services/fiatRateValidation.js +138 -0
  397. package/out/src/services/fiatRateValidation.js.map +1 -0
  398. package/out/src/services/getCanonicalMerklePath.d.ts +15 -0
  399. package/out/src/services/getCanonicalMerklePath.d.ts.map +1 -0
  400. package/out/src/services/getCanonicalMerklePath.js +90 -0
  401. package/out/src/services/getCanonicalMerklePath.js.map +1 -0
  402. package/out/src/services/providers/ARC.d.ts +3 -16
  403. package/out/src/services/providers/ARC.d.ts.map +1 -1
  404. package/out/src/services/providers/ARC.js +36 -37
  405. package/out/src/services/providers/ARC.js.map +1 -1
  406. package/out/src/services/providers/ArcSSEClient.d.ts +38 -23
  407. package/out/src/services/providers/ArcSSEClient.d.ts.map +1 -1
  408. package/out/src/services/providers/ArcSSEClient.js +384 -63
  409. package/out/src/services/providers/ArcSSEClient.js.map +1 -1
  410. package/out/src/services/providers/Arcade.d.ts +11 -1
  411. package/out/src/services/providers/Arcade.d.ts.map +1 -1
  412. package/out/src/services/providers/Arcade.js +111 -33
  413. package/out/src/services/providers/Arcade.js.map +1 -1
  414. package/out/src/services/providers/Bitails.d.ts +3 -0
  415. package/out/src/services/providers/Bitails.d.ts.map +1 -1
  416. package/out/src/services/providers/Bitails.js +79 -12
  417. package/out/src/services/providers/Bitails.js.map +1 -1
  418. package/out/src/services/providers/SdkWhatsOnChain.d.ts +8 -2
  419. package/out/src/services/providers/SdkWhatsOnChain.d.ts.map +1 -1
  420. package/out/src/services/providers/SdkWhatsOnChain.js +83 -10
  421. package/out/src/services/providers/SdkWhatsOnChain.js.map +1 -1
  422. package/out/src/services/providers/WhatsOnChain.d.ts +3 -0
  423. package/out/src/services/providers/WhatsOnChain.d.ts.map +1 -1
  424. package/out/src/services/providers/WhatsOnChain.js +221 -69
  425. package/out/src/services/providers/WhatsOnChain.js.map +1 -1
  426. package/out/src/services/providers/arcProviderConfig.d.ts +27 -0
  427. package/out/src/services/providers/arcProviderConfig.d.ts.map +1 -0
  428. package/out/src/services/providers/arcProviderConfig.js +83 -0
  429. package/out/src/services/providers/arcProviderConfig.js.map +1 -0
  430. package/out/src/services/providers/arcTxDataValidation.d.ts +4 -0
  431. package/out/src/services/providers/arcTxDataValidation.d.ts.map +1 -0
  432. package/out/src/services/providers/arcTxDataValidation.js +92 -0
  433. package/out/src/services/providers/arcTxDataValidation.js.map +1 -0
  434. package/out/src/services/providers/arcadeStatus.d.ts +18 -0
  435. package/out/src/services/providers/arcadeStatus.d.ts.map +1 -0
  436. package/out/src/services/providers/arcadeStatus.js +56 -0
  437. package/out/src/services/providers/arcadeStatus.js.map +1 -0
  438. package/out/src/services/providers/exchangeRates.d.ts +3 -3
  439. package/out/src/services/providers/exchangeRates.d.ts.map +1 -1
  440. package/out/src/services/providers/exchangeRates.js +153 -226
  441. package/out/src/services/providers/exchangeRates.js.map +1 -1
  442. package/out/src/services/providers/getBeefForTxid.d.ts.map +1 -1
  443. package/out/src/services/providers/getBeefForTxid.js.map +1 -1
  444. package/out/src/services/providers/whatsOnChainHelpers.d.ts +2 -2
  445. package/out/src/services/providers/whatsOnChainHelpers.d.ts.map +1 -1
  446. package/out/src/services/providers/whatsOnChainHelpers.js +11 -8
  447. package/out/src/services/providers/whatsOnChainHelpers.js.map +1 -1
  448. package/out/src/services/validateMerklePathResult.d.ts +30 -0
  449. package/out/src/services/validateMerklePathResult.d.ts.map +1 -0
  450. package/out/src/services/validateMerklePathResult.js +272 -0
  451. package/out/src/services/validateMerklePathResult.js.map +1 -0
  452. package/out/src/services/validatePostBeefResult.d.ts +17 -0
  453. package/out/src/services/validatePostBeefResult.d.ts.map +1 -0
  454. package/out/src/services/validatePostBeefResult.js +334 -0
  455. package/out/src/services/validatePostBeefResult.js.map +1 -0
  456. package/out/src/services/validateRawTxResult.d.ts +6 -0
  457. package/out/src/services/validateRawTxResult.d.ts.map +1 -0
  458. package/out/src/services/validateRawTxResult.js +77 -0
  459. package/out/src/services/validateRawTxResult.js.map +1 -0
  460. package/out/src/services/validateScriptHashHistoryResult.d.ts +5 -0
  461. package/out/src/services/validateScriptHashHistoryResult.d.ts.map +1 -0
  462. package/out/src/services/validateScriptHashHistoryResult.js +99 -0
  463. package/out/src/services/validateScriptHashHistoryResult.js.map +1 -0
  464. package/out/src/services/validateStatusForTxidsResult.d.ts +8 -0
  465. package/out/src/services/validateStatusForTxidsResult.d.ts.map +1 -0
  466. package/out/src/services/validateStatusForTxidsResult.js +181 -0
  467. package/out/src/services/validateStatusForTxidsResult.js.map +1 -0
  468. package/out/src/services/validateUtxoStatusResult.d.ts +6 -0
  469. package/out/src/services/validateUtxoStatusResult.d.ts.map +1 -0
  470. package/out/src/services/validateUtxoStatusResult.js +126 -0
  471. package/out/src/services/validateUtxoStatusResult.js.map +1 -0
  472. package/out/src/signer/actionBatch/ActionBatchPlanner.d.ts +3 -2
  473. package/out/src/signer/actionBatch/ActionBatchPlanner.d.ts.map +1 -1
  474. package/out/src/signer/actionBatch/ActionBatchPlanner.js +29 -6
  475. package/out/src/signer/actionBatch/ActionBatchPlanner.js.map +1 -1
  476. package/out/src/signer/actionBatch/ActionBatchWorkspace.d.ts +8 -5
  477. package/out/src/signer/actionBatch/ActionBatchWorkspace.d.ts.map +1 -1
  478. package/out/src/signer/actionBatch/ActionBatchWorkspace.js +186 -73
  479. package/out/src/signer/actionBatch/ActionBatchWorkspace.js.map +1 -1
  480. package/out/src/signer/actionBatch/actionBatchBootstrap.d.ts +2 -2
  481. package/out/src/signer/actionBatch/actionBatchBootstrap.d.ts.map +1 -1
  482. package/out/src/signer/actionBatch/actionBatchBootstrap.js +3 -3
  483. package/out/src/signer/actionBatch/actionBatchBootstrap.js.map +1 -1
  484. package/out/src/signer/methods/acquireDirectCertificate.d.ts +3 -2
  485. package/out/src/signer/methods/acquireDirectCertificate.d.ts.map +1 -1
  486. package/out/src/signer/methods/acquireDirectCertificate.js.map +1 -1
  487. package/out/src/signer/methods/buildSignableTransaction.d.ts +6 -5
  488. package/out/src/signer/methods/buildSignableTransaction.d.ts.map +1 -1
  489. package/out/src/signer/methods/buildSignableTransaction.js +6 -11
  490. package/out/src/signer/methods/buildSignableTransaction.js.map +1 -1
  491. package/out/src/signer/methods/createAction.d.ts +4 -3
  492. package/out/src/signer/methods/createAction.d.ts.map +1 -1
  493. package/out/src/signer/methods/createAction.js +3 -1
  494. package/out/src/signer/methods/createAction.js.map +1 -1
  495. package/out/src/signer/methods/createNoSendExpiryAction.d.ts +7 -0
  496. package/out/src/signer/methods/createNoSendExpiryAction.d.ts.map +1 -0
  497. package/out/src/signer/methods/createNoSendExpiryAction.js +254 -0
  498. package/out/src/signer/methods/createNoSendExpiryAction.js.map +1 -0
  499. package/out/src/signer/methods/internalizeAction.d.ts.map +1 -1
  500. package/out/src/signer/methods/internalizeAction.js +9 -5
  501. package/out/src/signer/methods/internalizeAction.js.map +1 -1
  502. package/out/src/signer/methods/proveCertificate.d.ts +3 -2
  503. package/out/src/signer/methods/proveCertificate.d.ts.map +1 -1
  504. package/out/src/signer/methods/proveCertificate.js.map +1 -1
  505. package/out/src/signer/methods/signAction.d.ts.map +1 -1
  506. package/out/src/signer/methods/signAction.js +12 -2
  507. package/out/src/signer/methods/signAction.js.map +1 -1
  508. package/out/src/signer/methods/verifyUnlockScripts.d.ts.map +1 -1
  509. package/out/src/signer/methods/verifyUnlockScripts.js +12 -17
  510. package/out/src/signer/methods/verifyUnlockScripts.js.map +1 -1
  511. package/out/src/storage/StorageIdb.d.ts +11 -3
  512. package/out/src/storage/StorageIdb.d.ts.map +1 -1
  513. package/out/src/storage/StorageIdb.js +134 -44
  514. package/out/src/storage/StorageIdb.js.map +1 -1
  515. package/out/src/storage/StorageKnex.d.ts +68 -7
  516. package/out/src/storage/StorageKnex.d.ts.map +1 -1
  517. package/out/src/storage/StorageKnex.js +551 -105
  518. package/out/src/storage/StorageKnex.js.map +1 -1
  519. package/out/src/storage/StorageProvider.d.ts +41 -10
  520. package/out/src/storage/StorageProvider.d.ts.map +1 -1
  521. package/out/src/storage/StorageProvider.js +397 -107
  522. package/out/src/storage/StorageProvider.js.map +1 -1
  523. package/out/src/storage/StorageReader.d.ts +9 -3
  524. package/out/src/storage/StorageReader.d.ts.map +1 -1
  525. package/out/src/storage/StorageReader.js +21 -43
  526. package/out/src/storage/StorageReader.js.map +1 -1
  527. package/out/src/storage/StorageReaderWriter.d.ts +4 -0
  528. package/out/src/storage/StorageReaderWriter.d.ts.map +1 -1
  529. package/out/src/storage/StorageReaderWriter.js +68 -38
  530. package/out/src/storage/StorageReaderWriter.js.map +1 -1
  531. package/out/src/storage/StorageSyncReader.d.ts +1 -1
  532. package/out/src/storage/StorageSyncReader.d.ts.map +1 -1
  533. package/out/src/storage/StorageSyncReader.js +3 -36
  534. package/out/src/storage/StorageSyncReader.js.map +1 -1
  535. package/out/src/storage/WalletStorageManager.d.ts +31 -6
  536. package/out/src/storage/WalletStorageManager.d.ts.map +1 -1
  537. package/out/src/storage/WalletStorageManager.js +166 -75
  538. package/out/src/storage/WalletStorageManager.js.map +1 -1
  539. package/out/src/storage/adminServer/adminServer.d.ts +3 -1
  540. package/out/src/storage/adminServer/adminServer.d.ts.map +1 -1
  541. package/out/src/storage/adminServer/adminServer.js +38 -49
  542. package/out/src/storage/adminServer/adminServer.js.map +1 -1
  543. package/out/src/storage/adminServer/adminUi.d.ts.map +1 -1
  544. package/out/src/storage/adminServer/adminUi.js +32 -9
  545. package/out/src/storage/adminServer/adminUi.js.map +1 -1
  546. package/out/src/storage/adminServer/reviewUtxos.d.ts +27 -0
  547. package/out/src/storage/adminServer/reviewUtxos.d.ts.map +1 -0
  548. package/out/src/storage/adminServer/reviewUtxos.js +62 -0
  549. package/out/src/storage/adminServer/reviewUtxos.js.map +1 -0
  550. package/out/src/storage/idbHelpers.d.ts.map +1 -1
  551. package/out/src/storage/idbHelpers.js +14 -2
  552. package/out/src/storage/idbHelpers.js.map +1 -1
  553. package/out/src/storage/index.all.d.ts +3 -0
  554. package/out/src/storage/index.all.d.ts.map +1 -1
  555. package/out/src/storage/index.all.js +3 -0
  556. package/out/src/storage/index.all.js.map +1 -1
  557. package/out/src/storage/index.client.d.ts +1 -0
  558. package/out/src/storage/index.client.d.ts.map +1 -1
  559. package/out/src/storage/index.client.js +1 -0
  560. package/out/src/storage/index.client.js.map +1 -1
  561. package/out/src/storage/index.mobile.d.ts +1 -0
  562. package/out/src/storage/index.mobile.d.ts.map +1 -1
  563. package/out/src/storage/index.mobile.js +1 -0
  564. package/out/src/storage/index.mobile.js.map +1 -1
  565. package/out/src/storage/methods/ListActionsSpecOp.d.ts +2 -2
  566. package/out/src/storage/methods/ListActionsSpecOp.d.ts.map +1 -1
  567. package/out/src/storage/methods/ListActionsSpecOp.js.map +1 -1
  568. package/out/src/storage/methods/ListOutputsSpecOp.d.ts +7 -4
  569. package/out/src/storage/methods/ListOutputsSpecOp.d.ts.map +1 -1
  570. package/out/src/storage/methods/ListOutputsSpecOp.js +5 -44
  571. package/out/src/storage/methods/ListOutputsSpecOp.js.map +1 -1
  572. package/out/src/storage/methods/actionBatch.d.ts +9 -2
  573. package/out/src/storage/methods/actionBatch.d.ts.map +1 -1
  574. package/out/src/storage/methods/actionBatch.js +260 -67
  575. package/out/src/storage/methods/actionBatch.js.map +1 -1
  576. package/out/src/storage/methods/actionBatchBlobs.d.ts +2 -0
  577. package/out/src/storage/methods/actionBatchBlobs.d.ts.map +1 -1
  578. package/out/src/storage/methods/actionBatchBlobs.js +47 -26
  579. package/out/src/storage/methods/actionBatchBlobs.js.map +1 -1
  580. package/out/src/storage/methods/actionBatchValidation.d.ts.map +1 -1
  581. package/out/src/storage/methods/actionBatchValidation.js +22 -30
  582. package/out/src/storage/methods/actionBatchValidation.js.map +1 -1
  583. package/out/src/storage/methods/attemptToPostReqsToNetwork.d.ts +7 -2
  584. package/out/src/storage/methods/attemptToPostReqsToNetwork.d.ts.map +1 -1
  585. package/out/src/storage/methods/attemptToPostReqsToNetwork.js +59 -110
  586. package/out/src/storage/methods/attemptToPostReqsToNetwork.js.map +1 -1
  587. package/out/src/storage/methods/availableManagedChange.d.ts +8 -1
  588. package/out/src/storage/methods/availableManagedChange.d.ts.map +1 -1
  589. package/out/src/storage/methods/availableManagedChange.js.map +1 -1
  590. package/out/src/storage/methods/createAction.d.ts +60 -3
  591. package/out/src/storage/methods/createAction.d.ts.map +1 -1
  592. package/out/src/storage/methods/createAction.js +390 -105
  593. package/out/src/storage/methods/createAction.js.map +1 -1
  594. package/out/src/storage/methods/generateChange.d.ts +15 -5
  595. package/out/src/storage/methods/generateChange.d.ts.map +1 -1
  596. package/out/src/storage/methods/generateChange.js +187 -27
  597. package/out/src/storage/methods/generateChange.js.map +1 -1
  598. package/out/src/storage/methods/getBeefForTransaction.js +5 -7
  599. package/out/src/storage/methods/getBeefForTransaction.js.map +1 -1
  600. package/out/src/storage/methods/getSyncChunk.d.ts.map +1 -1
  601. package/out/src/storage/methods/getSyncChunk.js +42 -11
  602. package/out/src/storage/methods/getSyncChunk.js.map +1 -1
  603. package/out/src/storage/methods/internalizeAction.d.ts +3 -3
  604. package/out/src/storage/methods/internalizeAction.d.ts.map +1 -1
  605. package/out/src/storage/methods/internalizeAction.js +171 -133
  606. package/out/src/storage/methods/internalizeAction.js.map +1 -1
  607. package/out/src/storage/methods/listActionsIdb.d.ts +3 -2
  608. package/out/src/storage/methods/listActionsIdb.d.ts.map +1 -1
  609. package/out/src/storage/methods/listActionsIdb.js +2 -2
  610. package/out/src/storage/methods/listActionsIdb.js.map +1 -1
  611. package/out/src/storage/methods/listActionsKnex.d.ts +3 -2
  612. package/out/src/storage/methods/listActionsKnex.d.ts.map +1 -1
  613. package/out/src/storage/methods/listActionsKnex.js +22 -11
  614. package/out/src/storage/methods/listActionsKnex.js.map +1 -1
  615. package/out/src/storage/methods/listCertificates.d.ts +3 -2
  616. package/out/src/storage/methods/listCertificates.d.ts.map +1 -1
  617. package/out/src/storage/methods/listCertificates.js.map +1 -1
  618. package/out/src/storage/methods/listOutputsIdb.d.ts +3 -2
  619. package/out/src/storage/methods/listOutputsIdb.d.ts.map +1 -1
  620. package/out/src/storage/methods/listOutputsIdb.js +25 -18
  621. package/out/src/storage/methods/listOutputsIdb.js.map +1 -1
  622. package/out/src/storage/methods/listOutputsKnex.d.ts +3 -2
  623. package/out/src/storage/methods/listOutputsKnex.d.ts.map +1 -1
  624. package/out/src/storage/methods/listOutputsKnex.js +32 -30
  625. package/out/src/storage/methods/listOutputsKnex.js.map +1 -1
  626. package/out/src/storage/methods/managedChangePolicy.d.ts +44 -0
  627. package/out/src/storage/methods/managedChangePolicy.d.ts.map +1 -0
  628. package/out/src/storage/methods/managedChangePolicy.js +58 -0
  629. package/out/src/storage/methods/managedChangePolicy.js.map +1 -0
  630. package/out/src/storage/methods/maxPossibleSatoshis.d.ts +13 -0
  631. package/out/src/storage/methods/maxPossibleSatoshis.d.ts.map +1 -0
  632. package/out/src/storage/methods/maxPossibleSatoshis.js +16 -0
  633. package/out/src/storage/methods/maxPossibleSatoshis.js.map +1 -0
  634. package/out/src/storage/methods/noSendExpiry.d.ts +11 -0
  635. package/out/src/storage/methods/noSendExpiry.d.ts.map +1 -0
  636. package/out/src/storage/methods/noSendExpiry.js +359 -0
  637. package/out/src/storage/methods/noSendExpiry.js.map +1 -0
  638. package/out/src/storage/methods/noSendExpiryLifecycle.d.ts +14 -0
  639. package/out/src/storage/methods/noSendExpiryLifecycle.d.ts.map +1 -0
  640. package/out/src/storage/methods/noSendExpiryLifecycle.js +691 -0
  641. package/out/src/storage/methods/noSendExpiryLifecycle.js.map +1 -0
  642. package/out/src/storage/methods/preparedBeef.d.ts +104 -0
  643. package/out/src/storage/methods/preparedBeef.d.ts.map +1 -0
  644. package/out/src/storage/methods/preparedBeef.js +524 -0
  645. package/out/src/storage/methods/preparedBeef.js.map +1 -0
  646. package/out/src/storage/methods/processAction.d.ts.map +1 -1
  647. package/out/src/storage/methods/processAction.js +144 -32
  648. package/out/src/storage/methods/processAction.js.map +1 -1
  649. package/out/src/storage/methods/purgeData.d.ts.map +1 -1
  650. package/out/src/storage/methods/purgeData.js +21 -3
  651. package/out/src/storage/methods/purgeData.js.map +1 -1
  652. package/out/src/storage/methods/reconcileFailedTransactionInputs.d.ts +32 -0
  653. package/out/src/storage/methods/reconcileFailedTransactionInputs.d.ts.map +1 -0
  654. package/out/src/storage/methods/reconcileFailedTransactionInputs.js +142 -0
  655. package/out/src/storage/methods/reconcileFailedTransactionInputs.js.map +1 -0
  656. package/out/src/storage/methods/reviewStatus.d.ts.map +1 -1
  657. package/out/src/storage/methods/reviewStatus.js +7 -4
  658. package/out/src/storage/methods/reviewStatus.js.map +1 -1
  659. package/out/src/storage/methods/reviewStatusIdb.d.ts +1 -1
  660. package/out/src/storage/methods/reviewStatusIdb.d.ts.map +1 -1
  661. package/out/src/storage/methods/reviewStatusIdb.js.map +1 -1
  662. package/out/src/storage/methods/reviewUtxoOutputs.d.ts +38 -0
  663. package/out/src/storage/methods/reviewUtxoOutputs.d.ts.map +1 -0
  664. package/out/src/storage/methods/reviewUtxoOutputs.js +197 -0
  665. package/out/src/storage/methods/reviewUtxoOutputs.js.map +1 -0
  666. package/out/src/storage/methods/validateSyncProof.d.ts +32 -0
  667. package/out/src/storage/methods/validateSyncProof.d.ts.map +1 -0
  668. package/out/src/storage/methods/validateSyncProof.js +139 -0
  669. package/out/src/storage/methods/validateSyncProof.js.map +1 -0
  670. package/out/src/storage/portable/index.d.ts.map +1 -1
  671. package/out/src/storage/portable/index.js +25 -15
  672. package/out/src/storage/portable/index.js.map +1 -1
  673. package/out/src/storage/remoting/BinaryJson.d.ts +11 -0
  674. package/out/src/storage/remoting/BinaryJson.d.ts.map +1 -1
  675. package/out/src/storage/remoting/BinaryJson.js +94 -8
  676. package/out/src/storage/remoting/BinaryJson.js.map +1 -1
  677. package/out/src/storage/remoting/KnexPaymentReplayStore.d.ts.map +1 -1
  678. package/out/src/storage/remoting/KnexPaymentReplayStore.js +1 -0
  679. package/out/src/storage/remoting/KnexPaymentReplayStore.js.map +1 -1
  680. package/out/src/storage/remoting/KnexSessionManager.d.ts +26 -2
  681. package/out/src/storage/remoting/KnexSessionManager.d.ts.map +1 -1
  682. package/out/src/storage/remoting/KnexSessionManager.js +221 -40
  683. package/out/src/storage/remoting/KnexSessionManager.js.map +1 -1
  684. package/out/src/storage/remoting/KnexSyncTransferStore.d.ts +26 -0
  685. package/out/src/storage/remoting/KnexSyncTransferStore.d.ts.map +1 -0
  686. package/out/src/storage/remoting/KnexSyncTransferStore.js +222 -0
  687. package/out/src/storage/remoting/KnexSyncTransferStore.js.map +1 -0
  688. package/out/src/storage/remoting/StorageClient.d.ts +6 -1
  689. package/out/src/storage/remoting/StorageClient.d.ts.map +1 -1
  690. package/out/src/storage/remoting/StorageClient.js +65 -8
  691. package/out/src/storage/remoting/StorageClient.js.map +1 -1
  692. package/out/src/storage/remoting/StorageClientBase.d.ts +57 -10
  693. package/out/src/storage/remoting/StorageClientBase.d.ts.map +1 -1
  694. package/out/src/storage/remoting/StorageClientBase.js +372 -9
  695. package/out/src/storage/remoting/StorageClientBase.js.map +1 -1
  696. package/out/src/storage/remoting/StorageMobile.d.ts +5 -0
  697. package/out/src/storage/remoting/StorageMobile.d.ts.map +1 -1
  698. package/out/src/storage/remoting/StorageMobile.js +13 -11
  699. package/out/src/storage/remoting/StorageMobile.js.map +1 -1
  700. package/out/src/storage/remoting/StorageServer.d.ts +10 -1
  701. package/out/src/storage/remoting/StorageServer.d.ts.map +1 -1
  702. package/out/src/storage/remoting/StorageServer.js +221 -20
  703. package/out/src/storage/remoting/StorageServer.js.map +1 -1
  704. package/out/src/storage/remoting/SyncTransfer.d.ts +29 -0
  705. package/out/src/storage/remoting/SyncTransfer.d.ts.map +1 -0
  706. package/out/src/storage/remoting/SyncTransfer.js +153 -0
  707. package/out/src/storage/remoting/SyncTransfer.js.map +1 -0
  708. package/out/src/storage/remoting/entityValidationHelpers.d.ts.map +1 -1
  709. package/out/src/storage/remoting/entityValidationHelpers.js +35 -0
  710. package/out/src/storage/remoting/entityValidationHelpers.js.map +1 -1
  711. package/out/src/storage/remoting/syncChunkBinary.d.ts +4 -0
  712. package/out/src/storage/remoting/syncChunkBinary.d.ts.map +1 -0
  713. package/out/src/storage/remoting/syncChunkBinary.js +38 -0
  714. package/out/src/storage/remoting/syncChunkBinary.js.map +1 -0
  715. package/out/src/storage/remoting/validateRpcSyncProofs.d.ts +5 -0
  716. package/out/src/storage/remoting/validateRpcSyncProofs.d.ts.map +1 -0
  717. package/out/src/storage/remoting/validateRpcSyncProofs.js +82 -0
  718. package/out/src/storage/remoting/validateRpcSyncProofs.js.map +1 -0
  719. package/out/src/storage/schema/KnexMigrations.d.ts +6 -0
  720. package/out/src/storage/schema/KnexMigrations.d.ts.map +1 -1
  721. package/out/src/storage/schema/KnexMigrations.js +194 -5
  722. package/out/src/storage/schema/KnexMigrations.js.map +1 -1
  723. package/out/src/storage/schema/StorageIdbSchema.d.ts +3 -0
  724. package/out/src/storage/schema/StorageIdbSchema.d.ts.map +1 -1
  725. package/out/src/storage/schema/entities/EntityOutput.d.ts.map +1 -1
  726. package/out/src/storage/schema/entities/EntityOutput.js +24 -4
  727. package/out/src/storage/schema/entities/EntityOutput.js.map +1 -1
  728. package/out/src/storage/schema/entities/EntityOutputBasket.d.ts.map +1 -1
  729. package/out/src/storage/schema/entities/EntityOutputBasket.js +5 -2
  730. package/out/src/storage/schema/entities/EntityOutputBasket.js.map +1 -1
  731. package/out/src/storage/schema/entities/EntityProvenTx.d.ts +4 -1
  732. package/out/src/storage/schema/entities/EntityProvenTx.d.ts.map +1 -1
  733. package/out/src/storage/schema/entities/EntityProvenTx.js +125 -41
  734. package/out/src/storage/schema/entities/EntityProvenTx.js.map +1 -1
  735. package/out/src/storage/schema/entities/EntityProvenTxReq.js +1 -1
  736. package/out/src/storage/schema/entities/EntityProvenTxReq.js.map +1 -1
  737. package/out/src/storage/schema/entities/EntitySyncState.d.ts +4 -2
  738. package/out/src/storage/schema/entities/EntitySyncState.d.ts.map +1 -1
  739. package/out/src/storage/schema/entities/EntitySyncState.js +12 -6
  740. package/out/src/storage/schema/entities/EntitySyncState.js.map +1 -1
  741. package/out/src/storage/schema/entities/EntityTransaction.d.ts +26 -0
  742. package/out/src/storage/schema/entities/EntityTransaction.d.ts.map +1 -1
  743. package/out/src/storage/schema/entities/EntityTransaction.js +221 -21
  744. package/out/src/storage/schema/entities/EntityTransaction.js.map +1 -1
  745. package/out/src/storage/schema/tables/TableCertificate.d.ts +1 -1
  746. package/out/src/storage/schema/tables/TableCertificate.d.ts.map +1 -1
  747. package/out/src/storage/schema/tables/TableCertificateField.d.ts +1 -1
  748. package/out/src/storage/schema/tables/TableCertificateField.d.ts.map +1 -1
  749. package/out/src/storage/schema/tables/TableCommission.d.ts +1 -1
  750. package/out/src/storage/schema/tables/TableCommission.d.ts.map +1 -1
  751. package/out/src/storage/schema/tables/TableMonitorEvent.d.ts +1 -1
  752. package/out/src/storage/schema/tables/TableMonitorEvent.d.ts.map +1 -1
  753. package/out/src/storage/schema/tables/TableOutput.d.ts +1 -1
  754. package/out/src/storage/schema/tables/TableOutput.d.ts.map +1 -1
  755. package/out/src/storage/schema/tables/TableOutputBasket.d.ts +1 -1
  756. package/out/src/storage/schema/tables/TableOutputBasket.d.ts.map +1 -1
  757. package/out/src/storage/schema/tables/TableOutputTag.d.ts +1 -1
  758. package/out/src/storage/schema/tables/TableOutputTag.d.ts.map +1 -1
  759. package/out/src/storage/schema/tables/TableOutputTagMap.d.ts +1 -1
  760. package/out/src/storage/schema/tables/TableOutputTagMap.d.ts.map +1 -1
  761. package/out/src/storage/schema/tables/TablePreparedBeef.interfaces.d.ts +23 -0
  762. package/out/src/storage/schema/tables/TablePreparedBeef.interfaces.d.ts.map +1 -0
  763. package/out/src/storage/schema/tables/TablePreparedBeef.interfaces.js +3 -0
  764. package/out/src/storage/schema/tables/TablePreparedBeef.interfaces.js.map +1 -0
  765. package/out/src/storage/schema/tables/TableProvenTx.d.ts +1 -1
  766. package/out/src/storage/schema/tables/TableProvenTx.d.ts.map +1 -1
  767. package/out/src/storage/schema/tables/TableProvenTxReq.d.ts +1 -1
  768. package/out/src/storage/schema/tables/TableProvenTxReq.d.ts.map +1 -1
  769. package/out/src/storage/schema/tables/TableSettings.d.ts +2 -2
  770. package/out/src/storage/schema/tables/TableSettings.d.ts.map +1 -1
  771. package/out/src/storage/schema/tables/TableSyncState.d.ts +1 -1
  772. package/out/src/storage/schema/tables/TableSyncState.d.ts.map +1 -1
  773. package/out/src/storage/schema/tables/TableTransaction.d.ts +17 -1
  774. package/out/src/storage/schema/tables/TableTransaction.d.ts.map +1 -1
  775. package/out/src/storage/schema/tables/TableTransaction.js +14 -1
  776. package/out/src/storage/schema/tables/TableTransaction.js.map +1 -1
  777. package/out/src/storage/schema/tables/TableTxLabel.d.ts +1 -1
  778. package/out/src/storage/schema/tables/TableTxLabel.d.ts.map +1 -1
  779. package/out/src/storage/schema/tables/TableTxLabelMap.d.ts +1 -1
  780. package/out/src/storage/schema/tables/TableTxLabelMap.d.ts.map +1 -1
  781. package/out/src/storage/schema/tables/TableUser.d.ts +1 -1
  782. package/out/src/storage/schema/tables/TableUser.d.ts.map +1 -1
  783. package/out/src/storage/sync/StorageMySQLDojoReader.d.ts.map +1 -1
  784. package/out/src/storage/sync/StorageMySQLDojoReader.js +8 -7
  785. package/out/src/storage/sync/StorageMySQLDojoReader.js.map +1 -1
  786. package/out/src/storage/sync/SyncPageBudget.d.ts +8 -0
  787. package/out/src/storage/sync/SyncPageBudget.d.ts.map +1 -0
  788. package/out/src/storage/sync/SyncPageBudget.js +24 -0
  789. package/out/src/storage/sync/SyncPageBudget.js.map +1 -0
  790. package/out/src/storage/sync/syncCheckpoint.d.ts +4 -0
  791. package/out/src/storage/sync/syncCheckpoint.d.ts.map +1 -0
  792. package/out/src/storage/sync/syncCheckpoint.js +49 -0
  793. package/out/src/storage/sync/syncCheckpoint.js.map +1 -0
  794. package/out/src/utility/Argon2idBackend.d.ts +36 -0
  795. package/out/src/utility/Argon2idBackend.d.ts.map +1 -0
  796. package/out/src/utility/Argon2idBackend.js +60 -0
  797. package/out/src/utility/Argon2idBackend.js.map +1 -0
  798. package/out/src/utility/actionBatchDigest.d.ts.map +1 -1
  799. package/out/src/utility/actionBatchDigest.js +9 -7
  800. package/out/src/utility/actionBatchDigest.js.map +1 -1
  801. package/out/src/utility/actionBatchPack.d.ts.map +1 -1
  802. package/out/src/utility/actionBatchPack.js +7 -12
  803. package/out/src/utility/actionBatchPack.js.map +1 -1
  804. package/out/src/utility/beefForTxids.d.ts +12 -3
  805. package/out/src/utility/beefForTxids.d.ts.map +1 -1
  806. package/out/src/utility/beefForTxids.js +69 -21
  807. package/out/src/utility/beefForTxids.js.map +1 -1
  808. package/out/src/utility/brc153ReferenceLabels.d.ts +16 -0
  809. package/out/src/utility/brc153ReferenceLabels.d.ts.map +1 -1
  810. package/out/src/utility/brc153ReferenceLabels.js +20 -5
  811. package/out/src/utility/brc153ReferenceLabels.js.map +1 -1
  812. package/out/src/utility/brc177NoSendExpiry.d.ts +34 -0
  813. package/out/src/utility/brc177NoSendExpiry.d.ts.map +1 -0
  814. package/out/src/utility/brc177NoSendExpiry.js +81 -0
  815. package/out/src/utility/brc177NoSendExpiry.js.map +1 -0
  816. package/out/src/utility/canonicalizeAtomicBeef.d.ts +12 -0
  817. package/out/src/utility/canonicalizeAtomicBeef.d.ts.map +1 -0
  818. package/out/src/utility/canonicalizeAtomicBeef.js +23 -0
  819. package/out/src/utility/canonicalizeAtomicBeef.js.map +1 -0
  820. package/out/src/utility/exactActionSpend.d.ts +9 -0
  821. package/out/src/utility/exactActionSpend.d.ts.map +1 -0
  822. package/out/src/utility/exactActionSpend.js +26 -0
  823. package/out/src/utility/exactActionSpend.js.map +1 -0
  824. package/out/src/utility/hashWasm.d.ts +1 -1
  825. package/out/src/utility/hashWasm.d.ts.map +1 -1
  826. package/out/src/utility/hashWasm.js +83 -1
  827. package/out/src/utility/hashWasm.js.map +1 -1
  828. package/out/src/utility/identityUtils.d.ts +44 -4
  829. package/out/src/utility/identityUtils.d.ts.map +1 -1
  830. package/out/src/utility/identityUtils.js +523 -61
  831. package/out/src/utility/identityUtils.js.map +1 -1
  832. package/out/src/utility/index.all.d.ts +2 -0
  833. package/out/src/utility/index.all.d.ts.map +1 -1
  834. package/out/src/utility/index.all.js +2 -0
  835. package/out/src/utility/index.all.js.map +1 -1
  836. package/out/src/utility/index.client.d.ts +2 -0
  837. package/out/src/utility/index.client.d.ts.map +1 -1
  838. package/out/src/utility/index.client.js +2 -0
  839. package/out/src/utility/index.client.js.map +1 -1
  840. package/out/src/utility/parseTxScriptOffsets.d.ts.map +1 -1
  841. package/out/src/utility/parseTxScriptOffsets.js +1 -19
  842. package/out/src/utility/parseTxScriptOffsets.js.map +1 -1
  843. package/out/src/utility/tscProofToMerklePath.d.ts.map +1 -1
  844. package/out/src/utility/tscProofToMerklePath.js +35 -4
  845. package/out/src/utility/tscProofToMerklePath.js.map +1 -1
  846. package/out/src/utility/utilityHelpers.d.ts +1 -1
  847. package/out/src/utility/utilityHelpers.d.ts.map +1 -1
  848. package/out/src/utility/utilityHelpers.js +10 -7
  849. package/out/src/utility/utilityHelpers.js.map +1 -1
  850. package/out/src/utility/utilityHelpers.noBuffer.d.ts.map +1 -1
  851. package/out/src/utility/utilityHelpers.noBuffer.js +6 -6
  852. package/out/src/utility/utilityHelpers.noBuffer.js.map +1 -1
  853. package/out/src/utility/verifyOverlayOutput.d.ts +12 -0
  854. package/out/src/utility/verifyOverlayOutput.d.ts.map +1 -0
  855. package/out/src/utility/verifyOverlayOutput.js +22 -0
  856. package/out/src/utility/verifyOverlayOutput.js.map +1 -0
  857. package/out/src/utility/walletResultGuards.d.ts +14 -0
  858. package/out/src/utility/walletResultGuards.d.ts.map +1 -0
  859. package/out/src/utility/walletResultGuards.js +28 -0
  860. package/out/src/utility/walletResultGuards.js.map +1 -0
  861. package/out/src/wab-client/WABClient.d.ts +4 -17
  862. package/out/src/wab-client/WABClient.d.ts.map +1 -1
  863. package/out/src/wab-client/WABClient.js +35 -12
  864. package/out/src/wab-client/WABClient.js.map +1 -1
  865. package/out/src/wab-client/WABResponseValidation.d.ts +48 -0
  866. package/out/src/wab-client/WABResponseValidation.d.ts.map +1 -0
  867. package/out/src/wab-client/WABResponseValidation.js +321 -0
  868. package/out/src/wab-client/WABResponseValidation.js.map +1 -0
  869. package/out/src/wab-client/WABTransport.d.ts +17 -23
  870. package/out/src/wab-client/WABTransport.d.ts.map +1 -1
  871. package/out/src/wab-client/WABTransport.js +130 -142
  872. package/out/src/wab-client/WABTransport.js.map +1 -1
  873. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.d.ts +8 -0
  874. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.d.ts.map +1 -1
  875. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.js +3 -2
  876. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.js.map +1 -1
  877. package/package.json +36 -32
  878. package/docs/open-rpc/index.html +0 -46
@@ -1,8 +1,94 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WalletPermissionsManager = void 0;
4
+ const validationHelpers_1 = require("@bsv/sdk/wallet/validationHelpers");
4
5
  const sdk_1 = require("@bsv/sdk");
6
+ const utils_1 = require("@bsv/sdk/primitives/utils");
5
7
  const brc114ActionTimeLabels_1 = require("./utility/brc114ActionTimeLabels");
8
+ const brc177NoSendExpiry_1 = require("./utility/brc177NoSendExpiry");
9
+ const exactActionSpend_1 = require("./utility/exactActionSpend");
10
+ const WERR_errors_1 = require("./sdk/WERR_errors");
11
+ // Imported from the leaf module directly (not generateChange.ts, which
12
+ // transitively imports StorageProvider.ts and the full signer/create-action
13
+ // module graph) to avoid an unrelated circular-import edge from this file.
14
+ const maxPossibleSatoshis_1 = require("./storage/methods/maxPossibleSatoshis");
15
+ const MAX_PERMISSION_TOKEN_FIELD_BYTES = 1024 * 1024;
16
+ const MAX_PERMISSION_TOKEN_PAYLOAD_BYTES = 4 * 1024 * 1024;
17
+ const MAX_PERMISSION_TOKEN_LIST_FIELDS = 256;
18
+ const MAX_MONEY_SATOSHIS = 21e14;
19
+ function parseCanonicalPermissionInteger(value, label, maximum = Number.MAX_SAFE_INTEGER) {
20
+ if (!/^(?:0|[1-9]\d*)$/.test(value))
21
+ throw new Error(`${label} is not a canonical non-negative integer.`);
22
+ const parsed = Number(value);
23
+ if (!Number.isSafeInteger(parsed) || parsed > maximum) {
24
+ throw new Error(`${label} is outside the supported range.`);
25
+ }
26
+ return parsed;
27
+ }
28
+ function parsePermissionBoolean(value, label) {
29
+ if (value !== 'true' && value !== 'false')
30
+ throw new Error(`${label} must be true or false.`);
31
+ return value === 'true';
32
+ }
33
+ function parsePermissionCertificateFields(value) {
34
+ const parsed = JSON.parse(value);
35
+ if (!Array.isArray(parsed) || parsed.length > MAX_PERMISSION_TOKEN_LIST_FIELDS) {
36
+ throw new Error('Permission certificate fields must be a bounded array.');
37
+ }
38
+ const fields = [];
39
+ const seen = new Set();
40
+ for (const field of parsed) {
41
+ if (typeof field !== 'string' ||
42
+ field.length === 0 ||
43
+ new TextEncoder().encode(field).length >= 50 ||
44
+ seen.has(field)) {
45
+ throw new Error('Permission certificate fields are invalid.');
46
+ }
47
+ seen.add(field);
48
+ fields.push(field);
49
+ }
50
+ return fields;
51
+ }
52
+ function brc177PreflightSatoshis(args) {
53
+ const outputs = args.outputs ?? [];
54
+ let total = 0;
55
+ for (const output of outputs) {
56
+ if (typeof output.satoshis !== 'number' || !Number.isSafeInteger(output.satoshis) || output.satoshis < 0) {
57
+ throw new Error('BRC-177 outputs must contain valid satoshi amounts');
58
+ }
59
+ // A sendMax output is requested with the `maxPossibleSatoshis` sentinel
60
+ // (see storage/methods/generateChange); its real cost is unknowable until
61
+ // storage funds the transaction, so it cannot contribute a meaningful
62
+ // amount to this pre-funding estimate. The real amount is still gated by
63
+ // the post-funding spend check in createAction (computeNetSpend) once it
64
+ // is known.
65
+ if (output.satoshis === maxPossibleSatoshis_1.maxPossibleSatoshis)
66
+ continue;
67
+ total += output.satoshis;
68
+ if (!Number.isSafeInteger(total))
69
+ throw new Error('BRC-177 output amount exceeds the safely supported range');
70
+ }
71
+ // Even an action funded entirely by caller-supplied inputs incurs a wallet
72
+ // prefunding fee. Require a spending grant before that fee can be broadcast.
73
+ return Math.max(1, total);
74
+ }
75
+ function validateBrc177CreateActionShape(args) {
76
+ const request = args;
77
+ if (!Array.isArray(request.outputs) || request.outputs.length === 0) {
78
+ throw new Error('BRC-177 protected actions require at least one output');
79
+ }
80
+ if (request.options?.noSend !== true)
81
+ throw new Error('BRC-177 protected actions require noSend');
82
+ if ((request.options.sendWith?.length ?? 0) > 0) {
83
+ throw new Error('BRC-177 protected actions cannot use sendWith');
84
+ }
85
+ if ((request.options.noSendChange?.length ?? 0) > 0) {
86
+ throw new Error('BRC-177 protected actions cannot supply noSendChange');
87
+ }
88
+ if (request.options.returnTXIDOnly === true) {
89
+ throw new Error('BRC-177 protected actions cannot use returnTXIDOnly');
90
+ }
91
+ }
6
92
  // Security invariant: only the configured admin originator bypasses permission
7
93
  // prompts. Admin-reserved protocols, baskets, and labels are rejected for all
8
94
  // other originators; counterparty bypasses require an explicit configuration
@@ -61,6 +147,16 @@ const BASKET_MAP = {
61
147
  * - Token revocation or renewal uses standard BRC-100 flows: we build a transaction that consumes
62
148
  * the old token UTXO and outputs a new one (or none, if fully revoked).
63
149
  */
150
+ /**
151
+ * Signing changes the txid, so change outpoints the signable createAction
152
+ * result named (by the unsigned txid) are moved onto the signed transaction.
153
+ * Signing never reorders outputs, so each vout stays the same.
154
+ */
155
+ function noSendChangeOnSignedTransaction(noSendChange, signedTxid) {
156
+ if (noSendChange === undefined || signedTxid === undefined)
157
+ return noSendChange;
158
+ return noSendChange.map(outpoint => `${signedTxid}.${outpoint.slice(outpoint.lastIndexOf('.') + 1)}`);
159
+ }
64
160
  class WalletPermissionsManager {
65
161
  /** A reference to the BRC-100 wallet instance. */
66
162
  underlying;
@@ -92,6 +188,23 @@ class WalletPermissionsManager {
92
188
  /** Cache recently confirmed permissions to avoid repeated lookups. */
93
189
  permissionCache = new Map();
94
190
  recentGrants = new Map();
191
+ /** Originator binding for partial actions issued through this manager. */
192
+ pendingActionOriginators = new Map();
193
+ /** Exact authorized transaction template for each pending action. */
194
+ pendingActionTemplates = new Map();
195
+ /** References that failed authorization and could not be conclusively aborted. */
196
+ blockedActionReferences = new Set();
197
+ /** Pending references whose action was created with `noSend`. */
198
+ pendingNoSendReferences = new Set();
199
+ /**
200
+ * Originator binding for signed no-send actions, keyed by lowercase txid.
201
+ * Signing drops the pending reference, so without this a non-admin caller
202
+ * could not release the action it created.
203
+ */
204
+ noSendActions = new Map();
205
+ /** Reference a caller signed a no-send action under, to that action's txid key. */
206
+ noSendActionReferences = new Map();
207
+ permissionTokenLockingKeyPromise;
95
208
  /**
96
209
  * Token mints currently being written on-chain, keyed by permission cache
97
210
  * key. A granted permission is only cached once its token finishes minting
@@ -100,9 +213,18 @@ class WalletPermissionsManager {
100
213
  * Stored promises never reject.
101
214
  */
102
215
  mintsInFlight = new Map();
216
+ /**
217
+ * Monotonic nonce used to keep spending prompts one-to-one with the wallet
218
+ * operations they authorize. Unlike capability permissions, spending
219
+ * requests must never share a pending approval merely because their amounts
220
+ * happen to match.
221
+ */
222
+ spendingRequestSequence = 0;
103
223
  manifestCache = new Map();
104
224
  manifestFetchInProgress = new Map();
105
225
  static MANIFEST_CACHE_TTL_MS = 5 * 60 * 1000;
226
+ static MANIFEST_MAX_BYTES = 256 * 1024;
227
+ static MANIFEST_TIMEOUT_MS = 10_000;
106
228
  groupedPermissionFlowTail = new Map();
107
229
  pactEstablishedCache = new Map();
108
230
  /**
@@ -118,11 +240,6 @@ class WalletPermissionsManager {
118
240
  static CACHE_TTL_MS = 5 * 60 * 1000;
119
241
  /** Window during which freshly granted permissions are auto-allowed (except spending). */
120
242
  static RECENT_GRANT_COVER_MS = 15 * 1000;
121
- /** Default ports used when normalizing originator values. */
122
- static DEFAULT_PORTS = {
123
- 'http:': '80',
124
- 'https:': '443'
125
- };
126
243
  /**
127
244
  * Configuration that determines whether to skip or apply various checks and encryption.
128
245
  */
@@ -162,7 +279,41 @@ class WalletPermissionsManager {
162
279
  seekGroupedPermission: true,
163
280
  differentiatePrivilegedOperations: true,
164
281
  whitelistedCounterparties: {},
165
- ...config // override with user-specified config
282
+ ...config,
283
+ permissionModules: {
284
+ ...config.permissionModules,
285
+ // BRC-177 is a built-in reserved BRC-111 module in every Toolbox wallet.
286
+ nosend: {
287
+ onRequest: async (req) => {
288
+ const labels = req.args.labels;
289
+ (0, brc177NoSendExpiry_1.parseBrc177NoSendExpiryLabels)(labels);
290
+ if (req.method !== 'createAction' && req.method !== 'listActions') {
291
+ throw new Error('BRC-177 noSend expiry labels are only valid for createAction and listActions');
292
+ }
293
+ if (req.method === 'createAction')
294
+ validateBrc177CreateActionShape(req.args);
295
+ // Prefunding has a real miner fee, so authorize use of this
296
+ // module before the underlying wallet can broadcast it. This is
297
+ // deliberately separate from the later amount-specific spend
298
+ // authorization for the protected transaction.
299
+ await this.ensureLabelAccess({
300
+ originator: req.originator,
301
+ label: 'BRC-177 noSend expiry',
302
+ reason: req.method,
303
+ usageType: req.method === 'createAction' ? 'apply' : 'list'
304
+ });
305
+ if (req.method === 'createAction') {
306
+ await this.ensureSpendingAuthorization({
307
+ originator: req.originator,
308
+ satoshis: brc177PreflightSatoshis(req.args),
309
+ reason: 'BRC-177 protected action prefunding'
310
+ });
311
+ }
312
+ return { args: req.args };
313
+ },
314
+ onResponse: async (res) => res
315
+ }
316
+ }
166
317
  };
167
318
  }
168
319
  /* ---------------------------------------------------------------------
@@ -189,12 +340,19 @@ class WalletPermissionsManager {
189
340
  if (module == null) {
190
341
  throw new Error(`Unsupported P-module scheme: p ${schemeID}`);
191
342
  }
343
+ const request = { method, args, originator };
344
+ if (module.handleRequest != null) {
345
+ let nextCalled = false;
346
+ return (await module.handleRequest(request, async (transformedArgs) => {
347
+ if (nextCalled) {
348
+ throw new Error(`P-module p ${schemeID} called its underlying wallet operation more than once`);
349
+ }
350
+ nextCalled = true;
351
+ return await underlyingCall(transformedArgs, originator);
352
+ }));
353
+ }
192
354
  // Transform request with module
193
- const transformedReq = await module.onRequest({
194
- method,
195
- args,
196
- originator
197
- });
355
+ const transformedReq = await module.onRequest(request);
198
356
  // Call underlying method with transformed request
199
357
  const results = await underlyingCall(transformedReq.args, originator);
200
358
  // Transform response with module
@@ -393,6 +551,43 @@ class WalletPermissionsManager {
393
551
  /* ---------------------------------------------------------------------
394
552
  * 2) PERMISSION (GRANT / DENY) METHODS
395
553
  * --------------------------------------------------------------------- */
554
+ async grantPersistentPermission(request, expiry, amount) {
555
+ const key = this.buildRequestKey(request);
556
+ // Several first-contact prompts for the same permission can stack up
557
+ // before any token exists (e.g. one per usage type). Granting them all
558
+ // should yield ONE token: if an identical non-renewal grant just minted
559
+ // (or is minting), don't mint a duplicate. Spending authorizations are
560
+ // excluded — their tokens carry amounts, so every grant is honored.
561
+ let skipDuplicateMint = !request.renewal &&
562
+ request.type !== 'spending' &&
563
+ (this.isPermissionCached(key) || this.isRecentlyGranted(key) || this.mintsInFlight.has(key));
564
+ if (skipDuplicateMint) {
565
+ const inFlight = this.mintsInFlight.get(key);
566
+ if (inFlight != null) {
567
+ await inFlight;
568
+ // The awaited mint may have failed; only skip if it landed.
569
+ skipDuplicateMint = this.isPermissionCached(key) || this.isRecentlyGranted(key);
570
+ }
571
+ }
572
+ if (!skipDuplicateMint) {
573
+ const mint = request.renewal
574
+ ? this.renewPermissionOnChain(request.previousToken, request, expiry, amount)
575
+ : this.createPermissionOnChain(request, expiry, amount);
576
+ // Publish the in-flight mint so concurrent ensures for the same
577
+ // permission wait for it instead of re-prompting (stored promise
578
+ // never rejects; failures still propagate to this caller below).
579
+ this.mintsInFlight.set(key, mint.then(() => { }, () => { }));
580
+ try {
581
+ await mint;
582
+ }
583
+ finally {
584
+ this.mintsInFlight.delete(key);
585
+ }
586
+ }
587
+ if (request.type !== 'spending')
588
+ this.cachePermission(key, expiry);
589
+ this.markRecentGrant(request);
590
+ }
396
591
  /**
397
592
  * Grants a previously requested permission.
398
593
  * This method:
@@ -413,47 +608,10 @@ class WalletPermissionsManager {
413
608
  x.resolve(true);
414
609
  }
415
610
  this.activeRequests.delete(params.requestID);
416
- // 3) If `ephemeral !== true`, we create or renew an on-chain token
417
- // Only cache non-ephemeral permissions
418
- // Ephemeral permissions should not be cached as they are one-time authorizations
419
- if (!params.ephemeral) {
420
- const request = matching.request;
421
- const expiry = params.expiry || 0; // default: never expires
422
- const key = this.buildRequestKey(request);
423
- // Several first-contact prompts for the same permission can stack up
424
- // before any token exists (e.g. one per usage type). Granting them all
425
- // should yield ONE token: if an identical non-renewal grant just minted
426
- // (or is minting), don't mint a duplicate. Spending authorizations are
427
- // excluded — their tokens carry amounts, so every grant is honored.
428
- let skipDuplicateMint = !request.renewal &&
429
- request.type !== 'spending' &&
430
- (this.isPermissionCached(key) || this.isRecentlyGranted(key) || this.mintsInFlight.has(key));
431
- if (skipDuplicateMint) {
432
- const inFlight = this.mintsInFlight.get(key);
433
- if (inFlight != null) {
434
- await inFlight;
435
- // The awaited mint may have failed; only skip if it landed.
436
- skipDuplicateMint = this.isPermissionCached(key) || this.isRecentlyGranted(key);
437
- }
438
- }
439
- if (!skipDuplicateMint) {
440
- const mint = request.renewal
441
- ? this.renewPermissionOnChain(request.previousToken, request, expiry, params.amount)
442
- : this.createPermissionOnChain(request, expiry, params.amount);
443
- // Publish the in-flight mint so concurrent ensures for the same
444
- // permission wait for it instead of re-prompting (stored promise
445
- // never rejects; failures still propagate to this caller below).
446
- this.mintsInFlight.set(key, mint.then(() => { }, () => { }));
447
- try {
448
- await mint;
449
- }
450
- finally {
451
- this.mintsInFlight.delete(key);
452
- }
453
- }
454
- this.cachePermission(key, expiry);
455
- this.markRecentGrant(request);
456
- }
611
+ // 3) Ephemeral permissions are one-time authorizations and never persist.
612
+ if (params.ephemeral)
613
+ return;
614
+ await this.grantPersistentPermission(matching.request, params.expiry || 0, params.amount);
457
615
  }
458
616
  /**
459
617
  * Denies a previously requested permission.
@@ -552,27 +710,18 @@ class WalletPermissionsManager {
552
710
  expiry
553
711
  });
554
712
  }
555
- const created = await this.createPermissionTokensBestEffort(toCreate);
556
- const renewed = await this.renewPermissionTokensBestEffort(toRenew);
557
- for (const req of [...created, ...renewed]) {
558
- this.markRecentGrant(req);
559
- }
560
- // Success - resolve all pending promises for this request
561
- for (const p of matching.pending) {
562
- p.resolve(true);
563
- }
713
+ // A user-visible grouped grant is atomic from the caller's perspective:
714
+ // never resolve the waiting wallet call if one of the requested tokens
715
+ // failed to persist. The best-effort helpers intentionally suppress
716
+ // singleton failures and are therefore only suitable for maintenance
717
+ // operations where a partial result is explicitly returned.
718
+ await this.persistPermissionGrant(toCreate, toRenew);
719
+ this.settleActiveGrant(params.requestID, matching, 'resolve', true);
564
720
  }
565
721
  catch (error) {
566
- // Failure - reject all pending promises so callers don't hang forever
567
- for (const p of matching.pending) {
568
- p.reject(error);
569
- }
722
+ this.settleActiveGrant(params.requestID, matching, 'reject', error);
570
723
  throw error;
571
724
  }
572
- finally {
573
- // Always clean up the request entry
574
- this.activeRequests.delete(params.requestID);
575
- }
576
725
  }
577
726
  /**
578
727
  * Denies a previously requested grouped permission.
@@ -608,6 +757,17 @@ class WalletPermissionsManager {
608
757
  }
609
758
  this.activeRequests.delete(requestID);
610
759
  }
760
+ settleActiveGrant(requestID, matching, method, value) {
761
+ for (const pending of matching.pending)
762
+ pending[method](value);
763
+ this.activeRequests.delete(requestID);
764
+ }
765
+ async persistPermissionGrant(toCreate, toRenew) {
766
+ const created = await this.createPermissionTokensBestEffort(toCreate, true);
767
+ const renewed = await this.renewPermissionTokensBestEffort(toRenew, true);
768
+ for (const request of [...created, ...renewed])
769
+ this.markRecentGrant(request);
770
+ }
611
771
  async denyGroupedPermission(requestID) {
612
772
  this.denyActiveRequest(requestID);
613
773
  }
@@ -675,15 +835,14 @@ class WalletPermissionsManager {
675
835
  toRenew.push({ oldToken: token, request, expiry });
676
836
  }
677
837
  }
678
- const created = await this.createPermissionTokensBestEffort(toCreate);
679
- const renewed = await this.renewPermissionTokensBestEffort(toRenew);
680
- for (const req of [...created, ...renewed]) {
681
- this.markRecentGrant(req);
838
+ try {
839
+ await this.persistPermissionGrant(toCreate, toRenew);
840
+ this.settleActiveGrant(params.requestID, matching, 'resolve', true);
682
841
  }
683
- for (const p of matching.pending) {
684
- p.resolve(true);
842
+ catch (error) {
843
+ this.settleActiveGrant(params.requestID, matching, 'reject', error);
844
+ throw error;
685
845
  }
686
- this.activeRequests.delete(params.requestID);
687
846
  }
688
847
  async denyCounterpartyPermission(requestID) {
689
848
  this.denyActiveRequest(requestID);
@@ -879,19 +1038,11 @@ class WalletPermissionsManager {
879
1038
  // We skip spending permission entirely
880
1039
  return true;
881
1040
  }
882
- const cacheKey = this.buildRequestKey({ type: 'spending', originator, spending: { satoshis } });
883
- // Spending keys are amount-scoped. The recent-grant window this adds sits
884
- // inside the pre-existing permissionCache window grantPermission already
885
- // wrote for spending, so accounting exposure is unchanged.
886
- if (await this.hasRecentOrPendingGrant(cacheKey)) {
887
- return true;
888
- }
889
1041
  const token = await this.findSpendingToken(originator, lookupValues);
890
1042
  if (token?.authorizedAmount) {
891
1043
  // Check how much has been spent so far
892
1044
  const spentSoFar = await this.querySpentSince(token);
893
1045
  if (spentSoFar + satoshis <= token.authorizedAmount) {
894
- this.cachePermission(cacheKey, token.expiry);
895
1046
  return true;
896
1047
  }
897
1048
  else {
@@ -1046,11 +1197,22 @@ class WalletPermissionsManager {
1046
1197
  return await inProgress;
1047
1198
  }
1048
1199
  const fetchPromise = (async () => {
1200
+ const controller = new AbortController();
1201
+ const timeout = setTimeout(() => controller.abort(), WalletPermissionsManager.MANIFEST_TIMEOUT_MS);
1049
1202
  try {
1050
- const proto = originator.startsWith('localhost:') ? 'http' : 'https';
1051
- const response = await fetch(`${proto}://${originator}/manifest.json`);
1203
+ const localDevelopment = originator === 'localhost' || originator.startsWith('localhost:');
1204
+ const proto = localDevelopment ? 'http' : 'https';
1205
+ const expectedOrigin = `${proto}://${originator}`;
1206
+ // Localhost HTTP is an explicit development compatibility path. Every
1207
+ // public origin uses resolved-address validation and a DNS-pinned
1208
+ // connection so a manifest hostname cannot rebind to a private host.
1209
+ const manifestFetch = localDevelopment ? globalThis.fetch : (0, sdk_1.createPublicHTTPSFetch)(expectedOrigin);
1210
+ const response = await manifestFetch(`${expectedOrigin}/manifest.json`, {
1211
+ redirect: 'error',
1212
+ signal: controller.signal
1213
+ });
1052
1214
  if (response.ok) {
1053
- const manifest = await response.json();
1215
+ const manifest = await this.readBoundedManifest(response);
1054
1216
  const namespace = manifest?.metanet || manifest?.babbage;
1055
1217
  const groupPermissions = namespace?.groupPermissions || null;
1056
1218
  const counterpartyPermissionsDeclared = this.validateCounterpartyPermissions(namespace?.counterpartyPermissions);
@@ -1065,6 +1227,9 @@ class WalletPermissionsManager {
1065
1227
  catch {
1066
1228
  // Manifest fetch or parse failed — fall through to return null/null defaults below
1067
1229
  }
1230
+ finally {
1231
+ clearTimeout(timeout);
1232
+ }
1068
1233
  const result = { groupPermissions: null, counterpartyPermissions: null };
1069
1234
  this.manifestCache.set(originator, { ...result, fetchedAt: Date.now() });
1070
1235
  return result;
@@ -1077,6 +1242,49 @@ class WalletPermissionsManager {
1077
1242
  this.manifestFetchInProgress.delete(originator);
1078
1243
  }
1079
1244
  }
1245
+ async readBoundedManifest(response) {
1246
+ const declaredLength = response.headers?.get('content-length');
1247
+ if (declaredLength != null) {
1248
+ const parsedLength = Number(declaredLength);
1249
+ if (!Number.isSafeInteger(parsedLength) ||
1250
+ parsedLength < 0 ||
1251
+ parsedLength > WalletPermissionsManager.MANIFEST_MAX_BYTES) {
1252
+ throw new Error('Manifest response exceeds the configured size limit.');
1253
+ }
1254
+ }
1255
+ if (response.body == null) {
1256
+ // Test and embedded fetch implementations may expose only json(). Bound
1257
+ // their parsed representation before accepting it.
1258
+ const parsed = await response.json();
1259
+ if (new TextEncoder().encode(JSON.stringify(parsed)).length > WalletPermissionsManager.MANIFEST_MAX_BYTES) {
1260
+ throw new Error('Manifest response exceeds the configured size limit.');
1261
+ }
1262
+ return parsed;
1263
+ }
1264
+ const reader = response.body.getReader();
1265
+ const chunks = [];
1266
+ let total = 0;
1267
+ for (;;) {
1268
+ const { done, value } = await reader.read();
1269
+ if (done)
1270
+ break;
1271
+ if (value == null)
1272
+ continue;
1273
+ total += value.byteLength;
1274
+ if (total > WalletPermissionsManager.MANIFEST_MAX_BYTES) {
1275
+ await reader.cancel();
1276
+ throw new Error('Manifest response exceeds the configured size limit.');
1277
+ }
1278
+ chunks.push(value);
1279
+ }
1280
+ const bytes = new Uint8Array(total);
1281
+ let offset = 0;
1282
+ for (const chunk of chunks) {
1283
+ bytes.set(chunk, offset);
1284
+ offset += chunk.byteLength;
1285
+ }
1286
+ return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes));
1287
+ }
1080
1288
  async fetchManifestGroupPermissions(originator) {
1081
1289
  const { groupPermissions } = await this.fetchManifestPermissions(originator);
1082
1290
  return groupPermissions;
@@ -1669,7 +1877,7 @@ class WalletPermissionsManager {
1669
1877
  ];
1670
1878
  /** We always use `keyID="1"` and `counterparty="self"` for these encryption ops. */
1671
1879
  async encryptPermissionTokenField(plaintext) {
1672
- const data = typeof plaintext === 'string' ? sdk_1.Utils.toArray(plaintext, 'utf8') : plaintext;
1880
+ const data = typeof plaintext === 'string' ? (0, utils_1.toArray)(plaintext, 'utf8') : plaintext;
1673
1881
  const { ciphertext } = await this.underlying.encrypt({
1674
1882
  plaintext: data,
1675
1883
  protocolID: WalletPermissionsManager.PERM_TOKEN_ENCRYPTION_PROTOCOL,
@@ -1691,7 +1899,7 @@ class WalletPermissionsManager {
1691
1899
  let parsed = this.parsedBeefCache.get(beef);
1692
1900
  if (parsed === undefined) {
1693
1901
  try {
1694
- parsed = sdk_1.Beef.fromBinary(beef);
1902
+ parsed = sdk_1.Beef.fromBinaryStrict(beef);
1695
1903
  }
1696
1904
  catch {
1697
1905
  parsed = null;
@@ -1709,6 +1917,60 @@ class WalletPermissionsManager {
1709
1917
  // fast path can't serve.
1710
1918
  return sdk_1.Transaction.fromBEEF(beef ?? [], txid);
1711
1919
  }
1920
+ async permissionTokenLockingKey() {
1921
+ const pending = this.permissionTokenLockingKeyPromise ??
1922
+ this.underlying
1923
+ .getPublicKey({
1924
+ protocolID: WalletPermissionsManager.PERM_TOKEN_ENCRYPTION_PROTOCOL,
1925
+ keyID: '1',
1926
+ counterparty: 'self',
1927
+ forSelf: true
1928
+ }, this.adminOriginator)
1929
+ .then(({ publicKey }) => {
1930
+ if (typeof publicKey !== 'string' || !/^(?:02|03)[0-9a-f]{64}$/i.test(publicKey)) {
1931
+ throw new Error('Wallet returned an invalid permission-token locking key.');
1932
+ }
1933
+ return publicKey.toLowerCase();
1934
+ });
1935
+ this.permissionTokenLockingKeyPromise = pending;
1936
+ try {
1937
+ return await pending;
1938
+ }
1939
+ catch (error) {
1940
+ if (this.permissionTokenLockingKeyPromise === pending)
1941
+ this.permissionTokenLockingKeyPromise = undefined;
1942
+ throw error;
1943
+ }
1944
+ }
1945
+ async authenticatedPermissionTokenSource(result, output, dataFieldCount) {
1946
+ try {
1947
+ const [txid, outputIndex] = this.parseOutpoint(output.outpoint);
1948
+ const tx = this.transactionFromResultBeef(result, txid);
1949
+ if (tx.id('hex').toLowerCase() !== txid)
1950
+ throw new Error('Permission token transaction ID mismatch.');
1951
+ const txOutput = tx.outputs[outputIndex];
1952
+ if (txOutput == null || txOutput.satoshis !== 1 || output.satoshis !== 1) {
1953
+ throw new Error('Permission token source output is invalid.');
1954
+ }
1955
+ const decoded = (0, sdk_1.decodeCanonicalPushDrop)(txOutput.lockingScript, {
1956
+ fieldCount: dataFieldCount + 1,
1957
+ maximumFieldBytes: MAX_PERMISSION_TOKEN_FIELD_BYTES,
1958
+ maximumPayloadBytes: MAX_PERMISSION_TOKEN_PAYLOAD_BYTES
1959
+ });
1960
+ if (decoded.lockingPublicKey.toString().toLowerCase() !== (await this.permissionTokenLockingKey())) {
1961
+ throw new Error('Permission token is not controlled by this wallet.');
1962
+ }
1963
+ const fields = decoded.fields.slice(0, -1);
1964
+ const signature = sdk_1.Signature.fromDER(decoded.fields.at(-1));
1965
+ if (!signature.verify(fields.flat(), decoded.lockingPublicKey)) {
1966
+ throw new Error('Permission token field signature is invalid.');
1967
+ }
1968
+ return { tx, txid, outputIndex, fields };
1969
+ }
1970
+ catch {
1971
+ return undefined;
1972
+ }
1973
+ }
1712
1974
  async decryptPermissionTokenField(ciphertext) {
1713
1975
  // Field decrypts run in tight loops over every token in a basket; yield a
1714
1976
  // macrotask periodically so large scans don't starve the caller's event
@@ -1729,6 +1991,9 @@ class WalletPermissionsManager {
1729
1991
  return ciphertext;
1730
1992
  }
1731
1993
  }
1994
+ async decryptPermissionTokenText(ciphertext) {
1995
+ return (0, utils_1.toUTF8Strict)(await this.decryptPermissionTokenField(ciphertext));
1996
+ }
1732
1997
  /**
1733
1998
  * Encrypts wallet metadata if configured to do so, otherwise returns the original plaintext for storage.
1734
1999
  * @param plaintext The metadata to encrypt if configured to do so
@@ -1739,11 +2004,11 @@ class WalletPermissionsManager {
1739
2004
  return plaintext;
1740
2005
  }
1741
2006
  const { ciphertext } = await this.underlying.encrypt({
1742
- plaintext: sdk_1.Utils.toArray(plaintext, 'utf8'),
2007
+ plaintext: (0, utils_1.toArray)(plaintext, 'utf8'),
1743
2008
  protocolID: WalletPermissionsManager.METADATA_ENCRYPTION_PROTOCOL,
1744
2009
  keyID: '1'
1745
2010
  }, this.adminOriginator);
1746
- return sdk_1.Utils.toBase64(ciphertext);
2011
+ return (0, utils_1.toBase64)(ciphertext);
1747
2012
  }
1748
2013
  /**
1749
2014
  * Attempts to decrypt metadata. if decryption fails, assumes the value is already plaintext and returns it.
@@ -1753,11 +2018,11 @@ class WalletPermissionsManager {
1753
2018
  async maybeDecryptMetadata(ciphertext) {
1754
2019
  try {
1755
2020
  const { plaintext } = await this.underlying.decrypt({
1756
- ciphertext: sdk_1.Utils.toArray(ciphertext, 'base64'),
2021
+ ciphertext: (0, utils_1.toArray)(ciphertext, 'base64'),
1757
2022
  protocolID: WalletPermissionsManager.METADATA_ENCRYPTION_PROTOCOL,
1758
2023
  keyID: '1'
1759
2024
  }, this.adminOriginator);
1760
- return sdk_1.Utils.toUTF8(plaintext);
2025
+ return (0, utils_1.toUTF8)(plaintext);
1761
2026
  }
1762
2027
  catch {
1763
2028
  // Decryption failed (e.g. wrong key, unencrypted legacy value) — return original string unchanged
@@ -1771,32 +2036,33 @@ class WalletPermissionsManager {
1771
2036
  }
1772
2037
  /** Decrypts the standard 6 fields from a protocol (DPACP) PushDrop script. */
1773
2038
  async decryptProtocolTokenFields(fields) {
1774
- const domainDecoded = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(fields[0]));
1775
- const expiryDecoded = Number.parseInt(sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(fields[1])), 10);
1776
- const privDecoded = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(fields[2])) === 'true';
1777
- const secLevelDecoded = Number.parseInt(sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(fields[3])), 10);
1778
- const protoNameDecoded = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(fields[4]));
1779
- const cptyDecoded = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(fields[5]));
2039
+ const domainDecoded = await this.decryptPermissionTokenText(fields[0]);
2040
+ const expiryDecoded = parseCanonicalPermissionInteger(await this.decryptPermissionTokenText(fields[1]), 'Permission expiry');
2041
+ const privDecoded = parsePermissionBoolean(await this.decryptPermissionTokenText(fields[2]), 'Permission privileged flag');
2042
+ const securityLevel = parseCanonicalPermissionInteger(await this.decryptPermissionTokenText(fields[3]), 'Permission security level', 2);
2043
+ const secLevelDecoded = securityLevel;
2044
+ const protoNameDecoded = await this.decryptPermissionTokenText(fields[4]);
2045
+ const cptyDecoded = await this.decryptPermissionTokenText(fields[5]);
1780
2046
  return { domainDecoded, expiryDecoded, privDecoded, secLevelDecoded, protoNameDecoded, cptyDecoded };
1781
2047
  }
1782
2048
  protocolTokenTags(originator, privileged, securityLevel, protocolName, counterparty) {
1783
2049
  const tags = [
1784
- `originator ${originator}`,
1785
2050
  `privileged ${!!privileged}`,
1786
2051
  `protocolName ${protocolName}`,
1787
2052
  `protocolSecurityLevel ${securityLevel}`
1788
2053
  ];
2054
+ if (originator !== undefined)
2055
+ tags.unshift(`originator ${originator}`);
1789
2056
  if (securityLevel === 2)
1790
2057
  tags.push(`counterparty ${counterparty}`);
1791
2058
  return tags;
1792
2059
  }
1793
2060
  async parseProtocolTokenOutput(result, output, expected) {
1794
- const [txid, outputIndex] = this.parseOutpoint(output.outpoint);
1795
- const tx = this.transactionFromResultBeef(result, txid);
1796
- const decoded = sdk_1.PushDrop.decode(tx.outputs[outputIndex].lockingScript);
1797
- if (decoded?.fields == null || decoded.fields.length < 6)
2061
+ const source = await this.authenticatedPermissionTokenSource(result, output, 6);
2062
+ if (source == null)
1798
2063
  return undefined;
1799
- const fields = await this.decryptProtocolTokenFields(decoded.fields);
2064
+ const { tx, txid, outputIndex } = source;
2065
+ const fields = await this.decryptProtocolTokenFields(source.fields);
1800
2066
  if (this.normalizeOriginator(fields.domainDecoded) !== expected.originator)
1801
2067
  return undefined;
1802
2068
  const matches = fields.privDecoded === !!expected.privileged &&
@@ -1821,16 +2087,15 @@ class WalletPermissionsManager {
1821
2087
  };
1822
2088
  }
1823
2089
  async parseBasketTokenOutput(result, output, originator, basket) {
1824
- const [txid, outputIndex] = this.parseOutpoint(output.outpoint);
1825
- const tx = this.transactionFromResultBeef(result, txid);
1826
- const decoded = sdk_1.PushDrop.decode(tx.outputs[outputIndex].lockingScript);
1827
- if (decoded?.fields == null || decoded.fields.length < 3)
2090
+ const source = await this.authenticatedPermissionTokenSource(result, output, 3);
2091
+ if (source == null)
1828
2092
  return undefined;
1829
- const domainDecoded = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(decoded.fields[0]));
2093
+ const { tx, txid, outputIndex, fields } = source;
2094
+ const domainDecoded = await this.decryptPermissionTokenText(fields[0]);
1830
2095
  if (this.normalizeOriginator(domainDecoded) !== originator)
1831
2096
  return undefined;
1832
- const expiryDecoded = Number.parseInt(sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(decoded.fields[1])), 10);
1833
- const basketDecoded = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(decoded.fields[2]));
2097
+ const expiryDecoded = parseCanonicalPermissionInteger(await this.decryptPermissionTokenText(fields[1]), 'Permission expiry');
2098
+ const basketDecoded = await this.decryptPermissionTokenText(fields[2]);
1834
2099
  if (basketDecoded !== basket)
1835
2100
  return undefined;
1836
2101
  return {
@@ -1846,20 +2111,19 @@ class WalletPermissionsManager {
1846
2111
  };
1847
2112
  }
1848
2113
  async parseCertificateTokenOutput(result, output, expected) {
1849
- const [txid, outputIndex] = this.parseOutpoint(output.outpoint);
1850
- const tx = this.transactionFromResultBeef(result, txid);
1851
- const decoded = sdk_1.PushDrop.decode(tx.outputs[outputIndex].lockingScript);
1852
- if (decoded?.fields == null || decoded.fields.length < 6)
2114
+ const source = await this.authenticatedPermissionTokenSource(result, output, 6);
2115
+ if (source == null)
1853
2116
  return undefined;
1854
- const [domainRaw, expiryRaw, privRaw, typeRaw, fieldsRaw, verifierRaw] = decoded.fields;
1855
- const domainDecoded = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(domainRaw));
2117
+ const { tx, txid, outputIndex } = source;
2118
+ const [domainRaw, expiryRaw, privRaw, typeRaw, fieldsRaw, verifierRaw] = source.fields;
2119
+ const domainDecoded = await this.decryptPermissionTokenText(domainRaw);
1856
2120
  if (this.normalizeOriginator(domainDecoded) !== expected.originator)
1857
2121
  return undefined;
1858
- const expiryDecoded = Number.parseInt(sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(expiryRaw)), 10);
1859
- const privileged = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(privRaw)) === 'true';
1860
- const certType = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(typeRaw));
1861
- const verifier = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(verifierRaw));
1862
- const allFields = JSON.parse(sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(fieldsRaw)));
2122
+ const expiryDecoded = parseCanonicalPermissionInteger(await this.decryptPermissionTokenText(expiryRaw), 'Permission expiry');
2123
+ const privileged = parsePermissionBoolean(await this.decryptPermissionTokenText(privRaw), 'Permission privileged flag');
2124
+ const certType = await this.decryptPermissionTokenText(typeRaw);
2125
+ const verifier = await this.decryptPermissionTokenText(verifierRaw);
2126
+ const allFields = parsePermissionCertificateFields(await this.decryptPermissionTokenText(fieldsRaw));
1863
2127
  const metadataMatches = privileged === !!expected.privileged && certType === expected.certType && verifier === expected.verifier;
1864
2128
  if (!metadataMatches)
1865
2129
  return undefined;
@@ -1883,61 +2147,14 @@ class WalletPermissionsManager {
1883
2147
  }
1884
2148
  /** Parses outpoint string "txid.vout" into [txid, outputIndex]. */
1885
2149
  parseOutpoint(outpoint) {
1886
- const [txid, indexStr] = outpoint.split('.');
1887
- return [txid, Number.parseInt(indexStr, 10)];
1888
- }
1889
- /** Normalizes a txid string to lowercase. */
1890
- normalizeTxid(txid) {
1891
- return (txid ?? '').toLowerCase();
1892
- }
1893
- /** Reverses a 32-byte hex txid (for endian normalization). */
1894
- reverseHexTxid(txid) {
1895
- const hex = this.normalizeTxid(txid);
1896
- if (!/^[0-9a-f]{64}$/.test(hex))
1897
- return hex;
1898
- const bytes = hex.match(/../g);
1899
- return bytes != null ? bytes.reverse().join('') : hex;
1900
- }
1901
- /**
1902
- * Returns true when an outpoint string (e.g. "txid.vout" or "txid:vout") refers to `token`.
1903
- */
1904
- tokenMatchesOutpointString(outpoint, token) {
1905
- const dot = outpoint.lastIndexOf('.');
1906
- const colon = outpoint.lastIndexOf(':');
1907
- const sep = Math.max(dot, colon);
1908
- if (sep === -1)
1909
- return false;
1910
- const txidPart = outpoint.slice(0, sep);
1911
- const vout = Number(outpoint.slice(sep + 1));
1912
- if (!Number.isFinite(vout))
1913
- return false;
1914
- return this.normalizeTxid(txidPart) === this.normalizeTxid(token.txid) && vout === token.outputIndex;
1915
- }
1916
- /**
1917
- * Finds the index of the tx input that spends the given permission token.
1918
- * Handles multiple potential field names for TXID and vout.
1919
- */
1920
- findInputIndexForToken(tx, token) {
1921
- return tx.inputs.findIndex((input) => {
1922
- const txidCandidate = input?.sourceTXID ??
1923
- input?.sourceTxid ??
1924
- input?.sourceTxId ??
1925
- input?.prevTxId ??
1926
- input?.prevTxid ??
1927
- input?.prevTXID ??
1928
- input?.txid ??
1929
- input?.txID;
1930
- const voutCandidate = input?.sourceOutputIndex ?? input?.sourceOutput ?? input?.outputIndex ?? input?.vout ?? input?.prevOutIndex;
1931
- if (typeof txidCandidate === 'string' && typeof voutCandidate === 'number') {
1932
- const cand = this.normalizeTxid(txidCandidate);
1933
- if (cand === this.normalizeTxid(token.txid) && voutCandidate === token.outputIndex)
1934
- return true;
1935
- if (cand === this.reverseHexTxid(token.txid) && voutCandidate === token.outputIndex)
1936
- return true;
1937
- }
1938
- const outpointCandidate = input?.outpoint ?? input?.sourceOutpoint ?? input?.prevOutpoint;
1939
- return typeof outpointCandidate === 'string' && this.tokenMatchesOutpointString(outpointCandidate, token);
1940
- });
2150
+ const match = /^([0-9a-f]{64})\.(0|[1-9]\d*)$/i.exec(outpoint);
2151
+ if (match == null)
2152
+ throw new Error('Permission token outpoint is invalid.');
2153
+ const outputIndex = Number(match[2]);
2154
+ if (!Number.isSafeInteger(outputIndex) || outputIndex > 0xffffffff) {
2155
+ throw new Error('Permission token outpoint is invalid.');
2156
+ }
2157
+ return [match[1].toLowerCase(), outputIndex];
1941
2158
  }
1942
2159
  /** Looks for a DPACP permission token matching origin/domain, privileged, protocol, cpty. */
1943
2160
  async findProtocolToken(originator, privileged, protocolID, counterparty, includeExpired, originatorLookupValues) {
@@ -1948,7 +2165,8 @@ class WalletPermissionsManager {
1948
2165
  basket: BASKET_MAP.protocol,
1949
2166
  tags: this.protocolTokenTags(originTag, privileged, secLevel, protoName, counterparty),
1950
2167
  tagQueryMode: 'all',
1951
- include: 'entire transactions'
2168
+ include: 'entire transactions',
2169
+ limit: 10000
1952
2170
  }, this.adminOriginator);
1953
2171
  for (const out of result.outputs) {
1954
2172
  const token = await this.parseProtocolTokenOutput(result, out, {
@@ -1978,7 +2196,8 @@ class WalletPermissionsManager {
1978
2196
  basket: BASKET_MAP.protocol,
1979
2197
  tags: this.protocolTokenTags(originTag, privileged, secLevel, protoName, counterparty),
1980
2198
  tagQueryMode: 'all',
1981
- include: 'entire transactions'
2199
+ include: 'entire transactions',
2200
+ limit: 10000
1982
2201
  }, this.adminOriginator);
1983
2202
  for (const out of result.outputs) {
1984
2203
  if (seen.has(out.outpoint))
@@ -2004,9 +2223,10 @@ class WalletPermissionsManager {
2004
2223
  for (const originTag of originsToTry) {
2005
2224
  const result = await this.underlying.listOutputs({
2006
2225
  basket: BASKET_MAP.basket,
2007
- tags: [`originator ${originTag}`, `basket ${basket}`],
2226
+ tags: [originTag === undefined ? undefined : `originator ${originTag}`, `basket ${basket}`].filter((tag) => tag !== undefined),
2008
2227
  tagQueryMode: 'all',
2009
- include: 'entire transactions'
2228
+ include: 'entire transactions',
2229
+ limit: 10000
2010
2230
  }, this.adminOriginator);
2011
2231
  for (const out of result.outputs) {
2012
2232
  const token = await this.parseBasketTokenOutput(result, out, originator, basket);
@@ -2025,9 +2245,15 @@ class WalletPermissionsManager {
2025
2245
  for (const originTag of originsToTry) {
2026
2246
  const result = await this.underlying.listOutputs({
2027
2247
  basket: BASKET_MAP.certificate,
2028
- tags: [`originator ${originTag}`, `privileged ${!!privileged}`, `type ${certType}`, `verifier ${verifier}`],
2248
+ tags: [
2249
+ originTag === undefined ? undefined : `originator ${originTag}`,
2250
+ `privileged ${!!privileged}`,
2251
+ `type ${certType}`,
2252
+ `verifier ${verifier}`
2253
+ ].filter((tag) => tag !== undefined),
2029
2254
  tagQueryMode: 'all',
2030
- include: 'entire transactions'
2255
+ include: 'entire transactions',
2256
+ limit: 10000
2031
2257
  }, this.adminOriginator);
2032
2258
  for (const out of result.outputs) {
2033
2259
  const token = await this.parseCertificateTokenOutput(result, out, {
@@ -2052,29 +2278,28 @@ class WalletPermissionsManager {
2052
2278
  for (const originTag of originsToTry) {
2053
2279
  const result = await this.underlying.listOutputs({
2054
2280
  basket: BASKET_MAP.spending,
2055
- tags: [`originator ${originTag}`],
2281
+ tags: originTag === undefined ? [] : [`originator ${originTag}`],
2056
2282
  tagQueryMode: 'all',
2057
- include: 'entire transactions'
2283
+ include: 'entire transactions',
2284
+ limit: 10000
2058
2285
  }, this.adminOriginator);
2059
2286
  for (const out of result.outputs) {
2060
- const [txid, outputIndexStr] = out.outpoint.split('.');
2061
- const tx = this.transactionFromResultBeef(result, txid);
2062
- const dec = sdk_1.PushDrop.decode(tx.outputs[Number(outputIndexStr)].lockingScript);
2063
- if (!dec?.fields || dec.fields.length < 2)
2287
+ const source = await this.authenticatedPermissionTokenSource(result, out, 2);
2288
+ if (source == null)
2064
2289
  continue;
2065
- const domainRaw = dec.fields[0];
2066
- const amtRaw = dec.fields[1];
2067
- const domainDecoded = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(domainRaw));
2290
+ const { tx, txid, outputIndex, fields } = source;
2291
+ const domainRaw = fields[0];
2292
+ const amtRaw = fields[1];
2293
+ const domainDecoded = await this.decryptPermissionTokenText(domainRaw);
2068
2294
  const normalizedDomain = this.normalizeOriginator(domainDecoded);
2069
2295
  if (normalizedDomain !== originator)
2070
2296
  continue;
2071
- const amtDecodedStr = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(amtRaw));
2072
- const authorizedAmount = Number.parseInt(amtDecodedStr, 10);
2297
+ const authorizedAmount = parseCanonicalPermissionInteger(await this.decryptPermissionTokenText(amtRaw), 'Permission spending amount', MAX_MONEY_SATOSHIS);
2073
2298
  return {
2074
2299
  tx: tx.toBEEF(),
2075
- txid: out.outpoint.split('.')[0],
2076
- outputIndex: Number.parseInt(out.outpoint.split('.')[1], 10),
2077
- outputScript: tx.outputs[Number(outputIndexStr)].lockingScript.toHex(),
2300
+ txid,
2301
+ outputIndex,
2302
+ outputScript: tx.outputs[outputIndex].lockingScript.toHex(),
2078
2303
  satoshis: out.satoshis,
2079
2304
  originator,
2080
2305
  rawOriginator: domainDecoded,
@@ -2103,11 +2328,23 @@ class WalletPermissionsManager {
2103
2328
  const labelOrigins = this.buildOriginatorLookupValues(token.rawOriginator, token.originator);
2104
2329
  let total = 0;
2105
2330
  for (const labelOrigin of labelOrigins) {
2106
- const { actions } = await this.underlying.listActions({
2107
- labels: [`admin originator ${labelOrigin}`, `admin month ${this.getCurrentMonthYearUTC()}`],
2108
- labelQueryMode: 'all'
2109
- }, this.adminOriginator);
2110
- total += actions.reduce((a, e) => a - e.satoshis, 0);
2331
+ let offset = 0;
2332
+ let totalActions = 0;
2333
+ do {
2334
+ const result = await this.underlying.listActions({
2335
+ labels: [`admin originator ${labelOrigin}`, `admin month ${this.getCurrentMonthYearUTC()}`],
2336
+ labelQueryMode: 'all',
2337
+ limit: 10000,
2338
+ offset
2339
+ }, this.adminOriginator);
2340
+ total += result.actions.reduce((a, e) => a - e.satoshis, 0);
2341
+ offset += result.actions.length;
2342
+ totalActions = result.totalActions;
2343
+ // A provider that reports more results but returns an empty page must
2344
+ // not trap the wallet in an infinite accounting loop.
2345
+ if (result.actions.length === 0)
2346
+ break;
2347
+ } while (offset < totalActions);
2111
2348
  }
2112
2349
  return total;
2113
2350
  }
@@ -2138,7 +2375,7 @@ class WalletPermissionsManager {
2138
2375
  const tags = this.buildTagsForRequest(r);
2139
2376
  // Build a transaction with exactly one output, no explicit inputs since the wallet
2140
2377
  // can internally fund it from its balance.
2141
- await this.createAction({
2378
+ await this.completePermissionTokenAction({
2142
2379
  description: `Grant ${r.type} permission`,
2143
2380
  outputs: [
2144
2381
  {
@@ -2150,9 +2387,12 @@ class WalletPermissionsManager {
2150
2387
  }
2151
2388
  ],
2152
2389
  options: {
2390
+ // Permission persistence must not inherit network-broadcast latency.
2391
+ // The managed-change planner keeps the queued output available as a
2392
+ // last-resort funding source for the resumed request.
2153
2393
  acceptDelayedBroadcast: true
2154
2394
  }
2155
- }, this.adminOriginator);
2395
+ });
2156
2396
  }
2157
2397
  async mapWithConcurrency(items, concurrency, fn) {
2158
2398
  if (items.length === 0)
@@ -2170,13 +2410,13 @@ class WalletPermissionsManager {
2170
2410
  await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, async () => await worker()));
2171
2411
  return results;
2172
2412
  }
2173
- async runBestEffortBatches(items, chunkSize, runChunk) {
2413
+ async runBestEffortBatches(items, chunkSize, runChunk, strict = false) {
2174
2414
  if (items.length === 0)
2175
2415
  return [];
2176
2416
  const out = [];
2177
2417
  for (let i = 0; i < items.length; i += chunkSize) {
2178
2418
  const chunk = items.slice(i, i + chunkSize);
2179
- out.push(...(await this.runBestEffortChunk(chunk, runChunk)));
2419
+ out.push(...(strict ? await runChunk(chunk) : await this.runBestEffortChunk(chunk, runChunk)));
2180
2420
  }
2181
2421
  return out;
2182
2422
  }
@@ -2184,9 +2424,8 @@ class WalletPermissionsManager {
2184
2424
  try {
2185
2425
  return await runChunk(chunk);
2186
2426
  }
2187
- catch (e) {
2427
+ catch {
2188
2428
  if (chunk.length <= 1) {
2189
- console.error('Permission batch failed:', e);
2190
2429
  return [];
2191
2430
  }
2192
2431
  const mid = Math.ceil(chunk.length / 2);
@@ -2216,27 +2455,27 @@ class WalletPermissionsManager {
2216
2455
  }
2217
2456
  };
2218
2457
  }
2219
- async createPermissionTokensBestEffort(items) {
2458
+ async createPermissionTokensBestEffort(items, strict = false) {
2220
2459
  const CHUNK = 25;
2221
2460
  return await this.runBestEffortBatches(items, CHUNK, async (chunk) => {
2222
2461
  const built = await this.mapWithConcurrency(chunk, 8, async (c) => await this.buildPermissionOutput(c.request, c.expiry, c.amount));
2223
- await this.createAction({
2462
+ await this.completePermissionTokenAction({
2224
2463
  description: `Grant ${built.length} permissions`,
2225
2464
  outputs: built.map(b => b.output),
2226
2465
  options: { acceptDelayedBroadcast: true }
2227
- }, this.adminOriginator);
2466
+ });
2228
2467
  return built.map(b => b.request);
2229
- });
2468
+ }, strict);
2230
2469
  }
2231
- async renewPermissionTokensBestEffort(items) {
2470
+ async renewPermissionTokensBestEffort(items, strict = false) {
2232
2471
  const CHUNK = 15;
2233
2472
  return await this.runBestEffortBatches(items, CHUNK, async (chunk) => {
2234
2473
  const built = await this.mapWithConcurrency(chunk, 8, async (c) => await this.buildPermissionOutput(c.request, c.expiry, c.amount));
2235
2474
  const inputBeef = new sdk_1.Beef();
2236
2475
  for (const c of chunk) {
2237
- inputBeef.mergeBeef(sdk_1.Beef.fromBinary(c.oldToken.tx));
2476
+ inputBeef.mergeBeef(sdk_1.Beef.fromBinaryStrict(c.oldToken.tx));
2238
2477
  }
2239
- const { signableTransaction } = await this.createAction({
2478
+ await this.completePermissionTokenAction({
2240
2479
  description: `Renew ${chunk.length} permissions`,
2241
2480
  inputBEEF: inputBeef.toBinary(),
2242
2481
  inputs: chunk.map((c, i) => ({
@@ -2250,27 +2489,22 @@ class WalletPermissionsManager {
2250
2489
  randomizeOutputs: false,
2251
2490
  signAndProcess: false
2252
2491
  }
2253
- }, this.adminOriginator);
2254
- if (!signableTransaction?.reference || !signableTransaction.tx) {
2255
- throw new Error('Failed to create signable transaction');
2256
- }
2257
- const partialTx = sdk_1.Transaction.fromAtomicBEEF(signableTransaction.tx);
2258
- const pushdrop = new sdk_1.PushDrop(this.underlying);
2259
- const spends = {};
2260
- for (let i = 0; i < chunk.length; i++) {
2261
- const token = chunk[i].oldToken;
2262
- const unlocker = pushdrop.unlock(WalletPermissionsManager.PERM_TOKEN_ENCRYPTION_PROTOCOL, '1', 'self', 'all', false, 1, sdk_1.LockingScript.fromHex(token.outputScript));
2263
- const unlockingScript = await unlocker.sign(partialTx, i);
2264
- spends[i] = { unlockingScript: unlockingScript.toHex() };
2265
- }
2266
- const { txid } = await this.underlying.signAction({
2267
- reference: signableTransaction.reference,
2268
- spends
2269
- });
2270
- if (!txid)
2271
- throw new Error('Failed to finalize renewal transaction');
2492
+ }, chunk.map(item => item.oldToken));
2272
2493
  return built.map(b => b.request);
2273
- });
2494
+ }, strict);
2495
+ }
2496
+ permissionTokenInputSigners(tokens) {
2497
+ const inputSigners = Object.create(null);
2498
+ const pushdrop = new sdk_1.PushDrop(this.underlying);
2499
+ for (const token of tokens) {
2500
+ const outpoint = `${token.txid}.${token.outputIndex}`;
2501
+ const unlocker = pushdrop.unlock(WalletPermissionsManager.PERM_TOKEN_ENCRYPTION_PROTOCOL, '1', 'self', 'all', false, 1, sdk_1.LockingScript.fromHex(token.outputScript));
2502
+ inputSigners[outpoint] = async (transaction, inputIndex) => await unlocker.sign(transaction, inputIndex);
2503
+ }
2504
+ return inputSigners;
2505
+ }
2506
+ async completePermissionTokenAction(args, tokens = []) {
2507
+ return await (0, sdk_1.completeBoundAction)(this, args, { inputSigners: this.permissionTokenInputSigners(tokens) }, this.adminOriginator);
2274
2508
  }
2275
2509
  async coalescePermissionTokens(oldTokens, newScript, opts) {
2276
2510
  if (!oldTokens?.length)
@@ -2281,9 +2515,9 @@ class WalletPermissionsManager {
2281
2515
  // Merge all input token BEEFs into a single BEEF structure
2282
2516
  const inputBeef = new sdk_1.Beef();
2283
2517
  for (const token of oldTokens) {
2284
- inputBeef.mergeBeef(sdk_1.Beef.fromBinary(token.tx));
2518
+ inputBeef.mergeBeef(sdk_1.Beef.fromBinaryStrict(token.tx));
2285
2519
  }
2286
- const { signableTransaction } = await this.createAction({
2520
+ const transaction = await this.completePermissionTokenAction({
2287
2521
  description: opts?.description ?? `Coalesce ${oldTokens.length} permission tokens`,
2288
2522
  inputBEEF: inputBeef.toBinary(),
2289
2523
  inputs: oldTokens.map((t, i) => ({
@@ -2305,29 +2539,8 @@ class WalletPermissionsManager {
2305
2539
  randomizeOutputs: false,
2306
2540
  signAndProcess: false
2307
2541
  }
2308
- }, this.adminOriginator);
2309
- if (!signableTransaction?.reference || !signableTransaction.tx) {
2310
- throw new Error('Failed to create signable transaction');
2311
- }
2312
- // 2) Sign each input - each token needs its own unlocker with the correct locking script
2313
- const partialTx = sdk_1.Transaction.fromAtomicBEEF(signableTransaction.tx);
2314
- const pushdrop = new sdk_1.PushDrop(this.underlying);
2315
- const spends = {};
2316
- for (let i = 0; i < oldTokens.length; i++) {
2317
- const token = oldTokens[i];
2318
- // Each token requires its own unlocker with the specific locking script
2319
- const unlocker = pushdrop.unlock(WalletPermissionsManager.PERM_TOKEN_ENCRYPTION_PROTOCOL, '1', 'self', 'all', false, 1, sdk_1.LockingScript.fromHex(token.outputScript));
2320
- const unlockingScript = await unlocker.sign(partialTx, i);
2321
- spends[i] = { unlockingScript: unlockingScript.toHex() };
2322
- }
2323
- // 3) Finalize the action
2324
- const { txid } = await this.underlying.signAction({
2325
- reference: signableTransaction.reference,
2326
- spends
2327
- });
2328
- if (!txid)
2329
- throw new Error('Failed to finalize coalescing transaction');
2330
- return txid;
2542
+ }, oldTokens);
2543
+ return transaction.id('hex');
2331
2544
  }
2332
2545
  /**
2333
2546
  * Renews a permission token by spending the old token as input and creating a new token output.
@@ -2360,7 +2573,7 @@ class WalletPermissionsManager {
2360
2573
  // 3) For BRC-100, we do a "createAction" with a partial input referencing oldToken
2361
2574
  // plus a single new output. We'll hydrate the template, then signAction for the wallet to finalize.
2362
2575
  const oldOutpoint = `${oldToken.txid}.${oldToken.outputIndex}`;
2363
- const { signableTransaction } = await this.createAction({
2576
+ await this.completePermissionTokenAction({
2364
2577
  description: `Renew ${r.type} permission`,
2365
2578
  inputBEEF: oldToken.tx,
2366
2579
  inputs: [
@@ -2382,18 +2595,7 @@ class WalletPermissionsManager {
2382
2595
  options: {
2383
2596
  acceptDelayedBroadcast: true
2384
2597
  }
2385
- }, this.adminOriginator);
2386
- const tx = sdk_1.Transaction.fromBEEF(signableTransaction.tx);
2387
- const unlocker = new sdk_1.PushDrop(this.underlying).unlock(WalletPermissionsManager.PERM_TOKEN_ENCRYPTION_PROTOCOL, '1', 'self', 'all', false, 1, sdk_1.LockingScript.fromHex(oldToken.outputScript));
2388
- const unlockingScript = await unlocker.sign(tx, 0);
2389
- await this.underlying.signAction({
2390
- reference: signableTransaction.reference,
2391
- spends: {
2392
- 0: {
2393
- unlockingScript: unlockingScript.toHex()
2394
- }
2395
- }
2396
- });
2598
+ }, [oldToken]);
2397
2599
  }
2398
2600
  }
2399
2601
  /**
@@ -2494,7 +2696,10 @@ class WalletPermissionsManager {
2494
2696
  const result = await this.underlying.listOutputs({ basket: BASKET_MAP.protocol, tags, tagQueryMode: 'all', include: 'entire transactions', limit: 10000 }, this.adminOriginator);
2495
2697
  await this.collectProtocolTokens(result, originFilter, seen, tokens);
2496
2698
  }
2497
- return tokens;
2699
+ return tokens.filter(token => (privileged === undefined || token.privileged === privileged) &&
2700
+ (protocolName === undefined || token.protocol === protocolName) &&
2701
+ (protocolSecurityLevel === undefined || token.securityLevel === protocolSecurityLevel) &&
2702
+ (counterparty === undefined || token.counterparty === counterparty));
2498
2703
  }
2499
2704
  /** Builds the base tag array for protocol permission listing. */
2500
2705
  buildProtocolFilterTags({ privileged, protocolName, protocolSecurityLevel, counterparty }) {
@@ -2514,12 +2719,11 @@ class WalletPermissionsManager {
2514
2719
  for (const out of result.outputs) {
2515
2720
  if (seen.has(out.outpoint))
2516
2721
  continue;
2517
- const [txid, outputIndex] = this.parseOutpoint(out.outpoint);
2518
- const tx = this.transactionFromResultBeef(result, txid);
2519
- const dec = sdk_1.PushDrop.decode(tx.outputs[outputIndex].lockingScript);
2520
- if (!dec?.fields || dec.fields.length < 6)
2722
+ const source = await this.authenticatedPermissionTokenSource(result, out, 6);
2723
+ if (source == null)
2521
2724
  continue;
2522
- const f = await this.decryptProtocolTokenFields(dec.fields);
2725
+ const { tx, txid, outputIndex } = source;
2726
+ const f = await this.decryptProtocolTokenFields(source.fields);
2523
2727
  const normalizedDomain = this.normalizeOriginator(f.domainDecoded);
2524
2728
  if (originFilter != null && normalizedDomain !== originFilter.normalized)
2525
2729
  continue;
@@ -2588,25 +2792,24 @@ class WalletPermissionsManager {
2588
2792
  }, this.adminOriginator);
2589
2793
  await this.collectBasketTokens(result, originFilter, seen, tokens);
2590
2794
  }
2591
- return tokens;
2795
+ return params.basket == null ? tokens : tokens.filter(token => token.basketName === params.basket);
2592
2796
  }
2593
2797
  /** Decodes and appends basket permission tokens from a listOutputs result. */
2594
2798
  async collectBasketTokens(result, originFilter, seen, tokens) {
2595
2799
  for (const out of result.outputs) {
2596
2800
  if (seen.has(out.outpoint))
2597
2801
  continue;
2598
- const [txid, outputIndex] = this.parseOutpoint(out.outpoint);
2599
- const tx = this.transactionFromResultBeef(result, txid);
2600
- const dec = sdk_1.PushDrop.decode(tx.outputs[outputIndex].lockingScript);
2601
- if (!dec?.fields || dec.fields.length < 3)
2802
+ const source = await this.authenticatedPermissionTokenSource(result, out, 3);
2803
+ if (source == null)
2602
2804
  continue;
2603
- const [domainRaw, expiryRaw, basketRaw] = dec.fields;
2604
- const domainDecoded = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(domainRaw));
2805
+ const { tx, txid, outputIndex } = source;
2806
+ const [domainRaw, expiryRaw, basketRaw] = source.fields;
2807
+ const domainDecoded = await this.decryptPermissionTokenText(domainRaw);
2605
2808
  const normalizedDomain = this.normalizeOriginator(domainDecoded);
2606
2809
  if (originFilter != null && normalizedDomain !== originFilter.normalized)
2607
2810
  continue;
2608
- const expiryDecoded = Number.parseInt(sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(expiryRaw)), 10);
2609
- const basketDecoded = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(basketRaw));
2811
+ const expiryDecoded = parseCanonicalPermissionInteger(await this.decryptPermissionTokenText(expiryRaw), 'Permission expiry');
2812
+ const basketDecoded = await this.decryptPermissionTokenText(basketRaw);
2610
2813
  seen.add(out.outpoint);
2611
2814
  tokens.push({
2612
2815
  tx: tx.toBEEF(),
@@ -2656,27 +2859,28 @@ class WalletPermissionsManager {
2656
2859
  }, this.adminOriginator);
2657
2860
  const tokens = [];
2658
2861
  for (const out of result.outputs) {
2659
- const [txid, outputIndexStr] = out.outpoint.split('.');
2660
- const tx = this.transactionFromResultBeef(result, txid);
2661
- const dec = sdk_1.PushDrop.decode(tx.outputs[Number(outputIndexStr)].lockingScript);
2662
- if (!dec?.fields || dec.fields.length < 2)
2862
+ const source = await this.authenticatedPermissionTokenSource(result, out, 2);
2863
+ if (source == null)
2663
2864
  continue;
2664
- const [domainRaw, amtRaw] = dec.fields;
2665
- const domainDecoded = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(domainRaw));
2666
- const amtDecodedStr = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(amtRaw));
2667
- const authorizedAmount = Number.parseInt(amtDecodedStr, 10);
2865
+ const { tx, txid, outputIndex, fields } = source;
2866
+ const [domainRaw, amtRaw] = fields;
2867
+ const domainDecoded = await this.decryptPermissionTokenText(domainRaw);
2868
+ const authorizedAmount = parseCanonicalPermissionInteger(await this.decryptPermissionTokenText(amtRaw), 'Permission spending amount', MAX_MONEY_SATOSHIS);
2668
2869
  tokens.push({
2669
2870
  tx: tx.toBEEF(),
2670
- txid: out.outpoint.split('.')[0],
2671
- outputIndex: Number.parseInt(out.outpoint.split('.')[1], 10),
2871
+ txid,
2872
+ outputIndex,
2672
2873
  satoshis: out.satoshis,
2673
- outputScript: tx.outputs[Number(outputIndexStr)].lockingScript.toHex(),
2874
+ outputScript: tx.outputs[outputIndex].lockingScript.toHex(),
2674
2875
  originator: domainDecoded,
2675
2876
  authorizedAmount,
2676
2877
  expiry: 0
2677
2878
  });
2678
2879
  }
2679
- return tokens;
2880
+ if (params.originator == null)
2881
+ return tokens;
2882
+ const normalizedOriginator = this.prepareOriginator(params.originator).normalized;
2883
+ return tokens.filter(token => this.normalizeOriginator(token.originator) === normalizedOriginator);
2680
2884
  }
2681
2885
  /**
2682
2886
  * Returns `true` if the originator already holds a valid spending authorization token
@@ -2720,28 +2924,29 @@ class WalletPermissionsManager {
2720
2924
  const result = await this.underlying.listOutputs({ basket: BASKET_MAP.certificate, tags, tagQueryMode: 'all', include: 'entire transactions', limit: 10000 }, this.adminOriginator);
2721
2925
  await this.collectCertificateTokens(result, originFilter, seen, tokens);
2722
2926
  }
2723
- return tokens;
2927
+ return tokens.filter(token => (params.privileged === undefined || token.privileged === params.privileged) &&
2928
+ (params.certType === undefined || token.certType === params.certType) &&
2929
+ (params.verifier === undefined || token.verifier === params.verifier));
2724
2930
  }
2725
2931
  /** Decodes and appends certificate permission tokens from a listOutputs result. */
2726
2932
  async collectCertificateTokens(result, originFilter, seen, tokens) {
2727
2933
  for (const out of result.outputs) {
2728
2934
  if (seen.has(out.outpoint))
2729
2935
  continue;
2730
- const [txid, outputIndex] = this.parseOutpoint(out.outpoint);
2731
- const tx = this.transactionFromResultBeef(result, txid);
2732
- const dec = sdk_1.PushDrop.decode(tx.outputs[outputIndex].lockingScript);
2733
- if (!dec?.fields || dec.fields.length < 6)
2936
+ const source = await this.authenticatedPermissionTokenSource(result, out, 6);
2937
+ if (source == null)
2734
2938
  continue;
2735
- const [domainRaw, expiryRaw, privRaw, typeRaw, fieldsRaw, verifierRaw] = dec.fields;
2736
- const domainDecoded = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(domainRaw));
2939
+ const { tx, txid, outputIndex } = source;
2940
+ const [domainRaw, expiryRaw, privRaw, typeRaw, fieldsRaw, verifierRaw] = source.fields;
2941
+ const domainDecoded = await this.decryptPermissionTokenText(domainRaw);
2737
2942
  const normalizedDomain = this.normalizeOriginator(domainDecoded);
2738
2943
  if (originFilter != null && normalizedDomain !== originFilter.normalized)
2739
2944
  continue;
2740
- const expiryDecoded = Number.parseInt(sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(expiryRaw)), 10);
2741
- const privDecoded = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(privRaw)) === 'true';
2742
- const typeDecoded = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(typeRaw));
2743
- const verifierDec = sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(verifierRaw));
2744
- const allFields = JSON.parse(sdk_1.Utils.toUTF8(await this.decryptPermissionTokenField(fieldsRaw)));
2945
+ const expiryDecoded = parseCanonicalPermissionInteger(await this.decryptPermissionTokenText(expiryRaw), 'Permission expiry');
2946
+ const privDecoded = parsePermissionBoolean(await this.decryptPermissionTokenText(privRaw), 'Permission privileged flag');
2947
+ const typeDecoded = await this.decryptPermissionTokenText(typeRaw);
2948
+ const verifierDec = await this.decryptPermissionTokenText(verifierRaw);
2949
+ const allFields = parsePermissionCertificateFields(await this.decryptPermissionTokenText(fieldsRaw));
2745
2950
  seen.add(out.outpoint);
2746
2951
  tokens.push({
2747
2952
  tx: tx.toBEEF(),
@@ -2824,9 +3029,9 @@ class WalletPermissionsManager {
2824
3029
  return;
2825
3030
  const inputBeef = new sdk_1.Beef();
2826
3031
  for (const token of oldTokens) {
2827
- inputBeef.mergeBeef(sdk_1.Beef.fromBinary(token.tx));
3032
+ inputBeef.mergeBeef(sdk_1.Beef.fromBinaryStrict(token.tx));
2828
3033
  }
2829
- const { signableTransaction } = await this.createAction({
3034
+ await this.completePermissionTokenAction({
2830
3035
  description: `Revoke ${oldTokens.length} permissions`,
2831
3036
  inputBEEF: inputBeef.toBinary(),
2832
3037
  inputs: oldTokens.map((t, i) => ({
@@ -2839,37 +3044,7 @@ class WalletPermissionsManager {
2839
3044
  randomizeOutputs: false,
2840
3045
  signAndProcess: false
2841
3046
  }
2842
- }, this.adminOriginator);
2843
- if (!signableTransaction?.reference || !signableTransaction.tx) {
2844
- throw new Error('Failed to create signable transaction');
2845
- }
2846
- const tx = sdk_1.Transaction.fromAtomicBEEF(signableTransaction.tx);
2847
- const inputsToSign = oldTokens.map(token => {
2848
- let permInputIndex = this.findInputIndexForToken(tx, token);
2849
- if (permInputIndex === -1 && tx.inputs.length === 1) {
2850
- permInputIndex = 0;
2851
- }
2852
- if (permInputIndex === -1) {
2853
- throw new Error('Unable to locate permission token input for revocation.');
2854
- }
2855
- return { token, permInputIndex };
2856
- });
2857
- const pushdrop = new sdk_1.PushDrop(this.underlying);
2858
- const spends = {};
2859
- const signed = await this.mapWithConcurrency(inputsToSign, 8, async ({ token, permInputIndex }) => {
2860
- const unlocker = pushdrop.unlock(WalletPermissionsManager.PERM_TOKEN_ENCRYPTION_PROTOCOL, '1', 'self', 'all', false, 1, sdk_1.LockingScript.fromHex(token.outputScript));
2861
- const unlockingScript = await unlocker.sign(tx, permInputIndex);
2862
- return { permInputIndex, unlockingScriptHex: unlockingScript.toHex() };
2863
- });
2864
- for (const s of signed) {
2865
- spends[s.permInputIndex] = { unlockingScript: s.unlockingScriptHex };
2866
- }
2867
- const { txid } = await this.underlying.signAction({
2868
- reference: signableTransaction.reference,
2869
- spends
2870
- });
2871
- if (!txid)
2872
- throw new Error('Failed to finalize revoke transaction');
3047
+ }, oldTokens);
2873
3048
  }
2874
3049
  /**
2875
3050
  * Revokes a permission token by spending it with no replacement output.
@@ -2877,7 +3052,7 @@ class WalletPermissionsManager {
2877
3052
  */
2878
3053
  async revokePermission(oldToken) {
2879
3054
  const oldOutpoint = `${oldToken.txid}.${oldToken.outputIndex}`;
2880
- const { signableTransaction } = await this.createAction({
3055
+ await this.completePermissionTokenAction({
2881
3056
  description: 'Revoke permission',
2882
3057
  inputBEEF: oldToken.tx,
2883
3058
  inputs: [
@@ -2890,30 +3065,13 @@ class WalletPermissionsManager {
2890
3065
  options: {
2891
3066
  acceptDelayedBroadcast: true
2892
3067
  }
2893
- }, this.adminOriginator);
2894
- const tx = sdk_1.Transaction.fromBEEF(signableTransaction.tx);
2895
- let permInputIndex = this.findInputIndexForToken(tx, oldToken);
2896
- if (permInputIndex === -1 && tx.inputs.length === 1) {
2897
- permInputIndex = 0;
2898
- }
2899
- if (permInputIndex === -1) {
2900
- throw new Error('Unable to locate permission token input for revocation.');
2901
- }
2902
- const unlocker = new sdk_1.PushDrop(this.underlying).unlock(WalletPermissionsManager.PERM_TOKEN_ENCRYPTION_PROTOCOL, '1', 'self', 'all', false, 1, sdk_1.LockingScript.fromHex(oldToken.outputScript));
2903
- const unlockingScript = await unlocker.sign(tx, permInputIndex);
2904
- await this.underlying.signAction({
2905
- reference: signableTransaction.reference,
2906
- spends: {
2907
- [permInputIndex]: {
2908
- unlockingScript: unlockingScript.toHex()
2909
- }
2910
- }
2911
- });
3068
+ }, [oldToken]);
2912
3069
  }
2913
3070
  /* ---------------------------------------------------------------------
2914
3071
  * 7) BRC-100 WALLET INTERFACE FORWARDING WITH PERMISSION CHECKS
2915
3072
  * --------------------------------------------------------------------- */
2916
3073
  async createAction(args, originator) {
3074
+ const vargs = (0, validationHelpers_1.validateCreateActionArgs)(args);
2917
3075
  // 1) Identify unique P-modules involved (one per schemeID) from both baskets and labels
2918
3076
  const pModulesByScheme = new Map();
2919
3077
  const nonPBaskets = this.collectNonPBaskets(args.outputs, pModulesByScheme);
@@ -2947,13 +3105,24 @@ class WalletPermissionsManager {
2947
3105
  options: modifiedOptions,
2948
3106
  labels: [...(args.labels || []), `admin originator ${originator}`, `admin month ${this.getCurrentMonthYearUTC()}`]
2949
3107
  };
2950
- let createResult = await this.callCreateActionWithPModules(finalArgs, pModulesByScheme, originator);
3108
+ let createResult;
3109
+ try {
3110
+ createResult = await this.callCreateActionWithPModules(finalArgs, pModulesByScheme, originator);
3111
+ }
3112
+ catch (error) {
3113
+ this.forgetSentNoSendActionsInError(error);
3114
+ throw error;
3115
+ }
3116
+ this.forgetSentNoSendActions(createResult.sendWithResults);
2951
3117
  if (createResult.signableTransaction == null)
2952
3118
  return createResult;
2953
- // 7) Parse the signable tx to determine net spend, then gate on spending authorization.
2954
- const tx = sdk_1.Transaction.fromAtomicBEEF(createResult.signableTransaction.tx);
3119
+ // 7) Bind the action reference before parsing any storage-provided transaction
3120
+ // data. This ensures malformed BEEF is still aborted and cannot leave an
3121
+ // untracked action that may later be signed under another originator.
2955
3122
  const reference = createResult.signableTransaction.reference;
2956
- // 7a) SECURITY (GHSA-36f9-7rg5-cpf8) defense-in-depth: confirm every
3123
+ this.bindPendingAction(reference, originator, vargs.isNoSend);
3124
+ // 7a) Parse the signable tx to determine net spend, then gate on spending
3125
+ // authorization. SECURITY (GHSA-36f9-7rg5-cpf8) defense-in-depth: confirm every
2957
3126
  // caller-requested output actually appears in the transaction we are about to
2958
3127
  // authorize and sign. The locking scripts in the signable transaction
2959
3128
  // originate from storage; a malicious or compromised remote storage provider
@@ -2962,34 +3131,66 @@ class WalletPermissionsManager {
2962
3131
  // recipient. The signer (buildSignableTransaction) rejects this at the
2963
3132
  // source; this is an independent check at the permissions layer.
2964
3133
  try {
2965
- this.verifyRequestedOutputsPresent(tx, args);
2966
- }
2967
- catch (err) {
2968
- await this.underlying.abortAction({ reference });
2969
- throw err;
2970
- }
2971
- const { netSpent, lineItems } = this.computeNetSpend(tx, args, originalInputDescriptions, originalOutputDescriptions);
2972
- // 8) If netSpent > 0, require spending authorization. Abort if denied.
2973
- if (netSpent > 0) {
2974
- try {
3134
+ const tx = sdk_1.Transaction.fromAtomicBEEF(createResult.signableTransaction.tx);
3135
+ const resolvedOutputSatoshis = this.verifyRequestedOutputsPresent(tx, args);
3136
+ let { netSpent, lineItems } = this.computeNetSpend(tx, args, originalInputDescriptions, originalOutputDescriptions, resolvedOutputSatoshis);
3137
+ const exactWalletSpend = (0, exactActionSpend_1.getExactActionSpend)(createResult);
3138
+ if (exactWalletSpend !== undefined) {
3139
+ if (!Number.isSafeInteger(exactWalletSpend) ||
3140
+ exactWalletSpend < -MAX_MONEY_SATOSHIS ||
3141
+ exactWalletSpend > MAX_MONEY_SATOSHIS ||
3142
+ exactWalletSpend < netSpent) {
3143
+ throw new Error('Wallet signer returned an invalid exact action-spend amount.');
3144
+ }
3145
+ const serviceCharge = exactWalletSpend - netSpent;
3146
+ if (serviceCharge > 0) {
3147
+ lineItems = [...lineItems, { type: 'output', satoshis: serviceCharge, description: 'Storage service charge' }];
3148
+ }
3149
+ netSpent = exactWalletSpend;
3150
+ }
3151
+ // 8) If netSpent > 0, require spending authorization. Abort if denied.
3152
+ if (netSpent > 0) {
2975
3153
  await this.ensureSpendingAuthorization({
2976
3154
  originator: originator,
2977
3155
  satoshis: netSpent,
2978
3156
  lineItems,
2979
- reason: originalDescription
3157
+ reason: originalDescription,
3158
+ allowRecentGrant: (0, brc177NoSendExpiry_1.parseBrc177NoSendExpiryLabels)(args.labels) == null
2980
3159
  });
2981
3160
  }
2982
- catch (err) {
2983
- await this.underlying.abortAction({ reference });
2984
- throw err;
2985
- }
3161
+ this.pendingActionTemplates.set(reference, tx);
3162
+ }
3163
+ catch (err) {
3164
+ await this.blockAndAbortAction(reference);
3165
+ throw err;
2986
3166
  }
2987
3167
  // 9) Finalize or return the signable transaction based on whether more signatures are needed.
2988
- const vargs = sdk_1.Validation.validateCreateActionArgs(args);
2989
3168
  if (vargs.isSignAction)
2990
3169
  return createResult;
2991
- const signResult = await this.underlying.signAction({ reference, spends: {}, options: args.options }, originator);
2992
- return { ...createResult, ...signResult, signableTransaction: undefined };
3170
+ try {
3171
+ const signResult = await this.underlying.signAction({
3172
+ reference,
3173
+ spends: {},
3174
+ options: { ...args.options, returnTXIDOnly: false }
3175
+ }, originator);
3176
+ this.assertAuthorizedSignResult(reference, {}, signResult);
3177
+ this.clearPendingAction(reference);
3178
+ if (vargs.isNoSend && signResult.txid != null) {
3179
+ this.recordNoSendAction(signResult.txid, originator);
3180
+ }
3181
+ this.forgetSentNoSendActions(signResult.sendWithResults);
3182
+ return {
3183
+ ...createResult,
3184
+ ...signResult,
3185
+ noSendChange: noSendChangeOnSignedTransaction(createResult.noSendChange, signResult.txid),
3186
+ signableTransaction: undefined
3187
+ };
3188
+ }
3189
+ catch (error) {
3190
+ this.forgetSentNoSendActionsInError(error);
3191
+ await this.blockAndAbortAction(reference);
3192
+ throw error;
3193
+ }
2993
3194
  }
2994
3195
  /** Scans outputs to split P-scheme baskets from regular baskets; registers P-modules as a side effect. */
2995
3196
  collectNonPBaskets(outputs, pModulesByScheme) {
@@ -3049,8 +3250,6 @@ class WalletPermissionsManager {
3049
3250
  }
3050
3251
  /** Calls underlying createAction, chaining P-module request/response transforms when needed. */
3051
3252
  async callCreateActionWithPModules(finalArgs, pModulesByScheme, originator) {
3052
- if (pModulesByScheme.size === 0)
3053
- return await this.underlying.createAction(finalArgs, originator);
3054
3253
  const pModules = Array.from(pModulesByScheme.values());
3055
3254
  let transformedArgs = finalArgs;
3056
3255
  for (const module of pModules) {
@@ -3062,10 +3261,17 @@ class WalletPermissionsManager {
3062
3261
  transformedArgs = transformed.args;
3063
3262
  }
3064
3263
  let createResult = await this.underlying.createAction(transformedArgs, originator);
3264
+ const exactWalletSpend = (0, exactActionSpend_1.getExactActionSpend)(createResult);
3065
3265
  for (let i = pModules.length - 1; i >= 0; i--) {
3066
3266
  createResult = await pModules[i].onResponse(createResult, { method: 'createAction', originator: originator });
3067
3267
  }
3068
- return createResult;
3268
+ // Older local wallets may still attach the legacy symbol. Consume it for
3269
+ // authorization, but never return it across a public BRC-100 boundary.
3270
+ const { [exactActionSpend_1.exactActionSpendSymbol]: _legacySpend, ...publicResult } = createResult;
3271
+ if (exactWalletSpend !== undefined) {
3272
+ (0, exactActionSpend_1.setExactActionSpend)(publicResult, exactWalletSpend);
3273
+ }
3274
+ return publicResult;
3069
3275
  }
3070
3276
  /**
3071
3277
  * Computes the net satoshis the originator is spending in a createAction call,
@@ -3088,12 +3294,30 @@ class WalletPermissionsManager {
3088
3294
  * randomized by default, and a caller may legitimately request the same
3089
3295
  * script+amount more than once.
3090
3296
  *
3297
+ * A sendMax output is requested with the `maxPossibleSatoshis` sentinel
3298
+ * (see storage/methods/generateChange); storage's funding step rewrites it
3299
+ * to the actual funded amount before returning the signable transaction, so
3300
+ * it can never be matched by amount. Fixed-amount outputs are matched first,
3301
+ * as an exact (script, satoshis) multiset exactly as before; any
3302
+ * sentinel-valued requested output is then matched by locking script alone
3303
+ * against whatever the fixed-amount pass left unused. Matching the sentinel
3304
+ * only after fixed-amount outputs are claimed keeps a fixed output that
3305
+ * happens to share the sentinel's locking script from being mis-paired with
3306
+ * it. `generateChange` permits at most one `maxPossibleSatoshis` output per
3307
+ * call; more than one sentinel-valued request is simply matched
3308
+ * independently, first-fit, in requested order.
3309
+ *
3310
+ * @returns the resolved actual satoshis for each requested output index
3311
+ * (identical to the request for a fixed-amount output; the real funded
3312
+ * amount for a sendMax sentinel), so callers can bill the real amount
3313
+ * instead of the sentinel.
3091
3314
  * @throws Error if any caller-requested output is absent from the transaction.
3092
3315
  */
3093
3316
  verifyRequestedOutputsPresent(tx, args) {
3094
3317
  const requested = args.outputs || [];
3318
+ const resolved = new Map();
3095
3319
  if (requested.length === 0)
3096
- return;
3320
+ return resolved;
3097
3321
  // All transaction outputs as (script hex, satoshis); each may satisfy at
3098
3322
  // most one requested output.
3099
3323
  const available = tx.outputs.map(o => ({
@@ -3101,27 +3325,53 @@ class WalletPermissionsManager {
3101
3325
  satoshis: o.satoshis,
3102
3326
  used: false
3103
3327
  }));
3328
+ const sentinelIndexes = [];
3329
+ // Pass 1: every fixed-amount request must match an exact (script, satoshis) pair.
3104
3330
  for (let i = 0; i < requested.length; i++) {
3105
- const wantScript = (requested[i].lockingScript ?? '').toLowerCase();
3106
3331
  const wantSats = requested[i].satoshis;
3332
+ if (wantSats === maxPossibleSatoshis_1.maxPossibleSatoshis) {
3333
+ sentinelIndexes.push(i);
3334
+ continue;
3335
+ }
3336
+ const wantScript = (requested[i].lockingScript ?? '').toLowerCase();
3107
3337
  const match = available.find(a => !a.used && a.script === wantScript && a.satoshis === wantSats);
3108
3338
  if (match == null) {
3109
3339
  throw new Error(`The transaction returned for signing does not contain caller-requested output ${i} ` +
3110
3340
  `(locking script and amount). The recipient may have been substituted by storage.`);
3111
3341
  }
3112
3342
  match.used = true;
3343
+ resolved.set(i, (0, validationHelpers_1.validateSatoshis)(match.satoshis, `signable transaction output ${i} satoshis`));
3113
3344
  }
3345
+ // Pass 2: match each sendMax sentinel request by locking script only,
3346
+ // against whatever pass 1 left unused.
3347
+ for (const i of sentinelIndexes) {
3348
+ const wantScript = (requested[i].lockingScript ?? '').toLowerCase();
3349
+ const match = available.find(a => !a.used && a.script === wantScript);
3350
+ if (match == null) {
3351
+ throw new Error(`The transaction returned for signing does not contain caller-requested output ${i} ` +
3352
+ `(locking script and amount). The recipient may have been substituted by storage.`);
3353
+ }
3354
+ match.used = true;
3355
+ resolved.set(i, (0, validationHelpers_1.validateSatoshis)(match.satoshis, `signable transaction output ${i} satoshis`));
3356
+ }
3357
+ return resolved;
3114
3358
  }
3115
- computeNetSpend(tx, args, originalInputDescriptions, originalOutputDescriptions) {
3359
+ computeNetSpend(tx, args, originalInputDescriptions, originalOutputDescriptions, resolvedOutputSatoshis) {
3116
3360
  const lineItems = [];
3117
3361
  // Sum originator-provided inputs:
3118
3362
  let totalInputSatoshis = 0;
3119
3363
  for (const input of tx.inputs) {
3120
- const outpoint = `${input.sourceTXID}.${input.sourceOutputIndex}`;
3364
+ const outpoint = this.inputOutpointForBinding(input);
3121
3365
  const matchingIndex = (args.inputs || []).findIndex(i => i.outpoint === outpoint);
3122
3366
  if (matchingIndex !== -1) {
3123
- const satoshis = input.sourceTransaction.outputs[input.sourceOutputIndex].satoshis;
3124
- totalInputSatoshis += satoshis;
3367
+ if (input.sourceTransaction == null) {
3368
+ throw new Error('Caller-provided action input is missing its authenticated source transaction.');
3369
+ }
3370
+ const sourceOutput = input.sourceTransaction.outputs[input.sourceOutputIndex];
3371
+ if (sourceOutput == null)
3372
+ throw new Error('Caller-provided action input source output is missing.');
3373
+ const satoshis = (0, validationHelpers_1.validateSatoshis)(sourceOutput.satoshis, 'caller input satoshis');
3374
+ totalInputSatoshis = this.checkedSatoshiTotal(totalInputSatoshis, satoshis, 'caller input total');
3125
3375
  lineItems.push({
3126
3376
  type: 'input',
3127
3377
  description: originalInputDescriptions[matchingIndex] || 'No input description provided',
@@ -3129,31 +3379,228 @@ class WalletPermissionsManager {
3129
3379
  });
3130
3380
  }
3131
3381
  }
3132
- // Sum originator-requested outputs:
3133
- const totalOutputSatoshis = (args.outputs || []).reduce((acc, out) => acc + out.satoshis, 0);
3382
+ // Sum originator-requested outputs. A sendMax output's requested satoshis
3383
+ // is the `maxPossibleSatoshis` sentinel, not its real cost; bill the
3384
+ // actual funded amount that verifyRequestedOutputsPresent already resolved
3385
+ // against the signable transaction instead of re-deriving it here (an
3386
+ // independent re-lookup by script could mis-pair a fixed output that
3387
+ // shares the sentinel's locking script).
3388
+ let totalOutputSatoshis = 0;
3134
3389
  for (const outIndex in args.outputs || []) {
3135
- const out = args.outputs[outIndex];
3390
+ const index = Number(outIndex);
3391
+ const resolvedSatoshis = resolvedOutputSatoshis.get(index);
3392
+ if (resolvedSatoshis == null) {
3393
+ throw new Error(`Internal error: requested output ${index} was not resolved against the signable transaction.`);
3394
+ }
3395
+ const satoshis = (0, validationHelpers_1.validateSatoshis)(resolvedSatoshis, 'requested output satoshis');
3396
+ totalOutputSatoshis = this.checkedSatoshiTotal(totalOutputSatoshis, satoshis, 'requested output total');
3136
3397
  lineItems.push({
3137
3398
  type: 'output',
3138
- satoshis: out.satoshis,
3139
- description: originalOutputDescriptions[outIndex] || 'No output description provided'
3399
+ satoshis,
3400
+ description: originalOutputDescriptions[index] || 'No output description provided'
3140
3401
  });
3141
3402
  }
3142
3403
  // Add an entry for the transaction fee:
3143
- const fee = tx.getFee();
3404
+ const fee = (0, validationHelpers_1.validateSatoshis)(tx.getFee(), 'network fee');
3144
3405
  lineItems.push({ type: 'fee', satoshis: fee, description: 'Network fee' });
3145
3406
  /**
3146
3407
  * Net spend = total foreign outflows minus total foreign inflows plus fee.
3147
3408
  * Domestic wallet inputs/change outputs are not counted — they are internal.
3148
3409
  */
3149
- const netSpent = totalOutputSatoshis + fee - totalInputSatoshis;
3410
+ const grossSpent = this.checkedSatoshiTotal(totalOutputSatoshis, fee, 'gross action spend');
3411
+ const netSpent = grossSpent - totalInputSatoshis;
3412
+ if (!Number.isSafeInteger(netSpent) || netSpent < -MAX_MONEY_SATOSHIS || netSpent > MAX_MONEY_SATOSHIS) {
3413
+ throw new Error('Net action spend is outside the supported monetary range.');
3414
+ }
3150
3415
  return { netSpent, lineItems };
3151
3416
  }
3417
+ checkedSatoshiTotal(left, right, label) {
3418
+ const total = left + right;
3419
+ if (!Number.isSafeInteger(total) || total < 0 || total > MAX_MONEY_SATOSHIS) {
3420
+ throw new Error(`${label} is outside the supported monetary range.`);
3421
+ }
3422
+ return total;
3423
+ }
3424
+ inputOutpointForBinding(input) {
3425
+ const embeddedTxid = input.sourceTransaction?.id('hex');
3426
+ const explicitTxid = input.sourceTXID?.toLowerCase();
3427
+ if (explicitTxid != null && embeddedTxid != null && explicitTxid !== embeddedTxid) {
3428
+ throw new Error('Wallet action input source transaction is inconsistent.');
3429
+ }
3430
+ const txid = explicitTxid ?? embeddedTxid;
3431
+ if (txid == null || !/^[0-9a-f]{64}$/.test(txid)) {
3432
+ throw new Error('Wallet action input transaction ID is invalid.');
3433
+ }
3434
+ if (!Number.isSafeInteger(input.sourceOutputIndex) ||
3435
+ input.sourceOutputIndex < 0 ||
3436
+ input.sourceOutputIndex > 0xffffffff) {
3437
+ throw new Error('Wallet action input output index is invalid.');
3438
+ }
3439
+ return `${txid}.${input.sourceOutputIndex}`;
3440
+ }
3441
+ /** Binds a wallet's final result to the exact template that passed authorization. */
3442
+ assertAuthorizedSignResult(reference, spends, result) {
3443
+ const authorized = this.pendingActionTemplates.get(reference);
3444
+ if (authorized == null)
3445
+ throw new Error('The authorized action template is unavailable.');
3446
+ if (result.tx == null)
3447
+ throw new Error('Wallet finalization omitted transaction data required for binding.');
3448
+ const finalized = sdk_1.Transaction.fromAtomicBEEF(result.tx);
3449
+ if (finalized.version !== authorized.version ||
3450
+ finalized.lockTime !== authorized.lockTime ||
3451
+ finalized.inputs.length !== authorized.inputs.length ||
3452
+ finalized.outputs.length !== authorized.outputs.length) {
3453
+ throw new Error('Wallet finalization substituted the authorized transaction template.');
3454
+ }
3455
+ for (let index = 0; index < authorized.inputs.length; index++) {
3456
+ if (this.inputOutpointForBinding(finalized.inputs[index]) !==
3457
+ this.inputOutpointForBinding(authorized.inputs[index]) ||
3458
+ (finalized.inputs[index].sequence ?? 0xffffffff) !== (authorized.inputs[index].sequence ?? 0xffffffff)) {
3459
+ throw new Error('Wallet finalization substituted an authorized transaction input.');
3460
+ }
3461
+ const authorizedScript = authorized.inputs[index].unlockingScript?.toHex() ?? '';
3462
+ if (authorizedScript !== '' && finalized.inputs[index].unlockingScript?.toHex() !== authorizedScript) {
3463
+ throw new Error('Wallet finalization substituted an existing unlocking script.');
3464
+ }
3465
+ }
3466
+ for (let index = 0; index < authorized.outputs.length; index++) {
3467
+ if (finalized.outputs[index].satoshis !== authorized.outputs[index].satoshis ||
3468
+ finalized.outputs[index].lockingScript.toHex() !== authorized.outputs[index].lockingScript.toHex()) {
3469
+ throw new Error('Wallet finalization substituted an authorized transaction output.');
3470
+ }
3471
+ }
3472
+ for (const [indexText, spend] of Object.entries(spends ?? {})) {
3473
+ if (!/^(0|[1-9]\d*)$/.test(indexText))
3474
+ throw new Error('Signed input index is invalid.');
3475
+ const index = Number(indexText);
3476
+ if (!Number.isSafeInteger(index) || finalized.inputs[index] == null) {
3477
+ throw new Error('Signed input index is invalid.');
3478
+ }
3479
+ if (typeof spend?.unlockingScript !== 'string' ||
3480
+ !/^(?:[0-9a-f]{2})*$/i.test(spend.unlockingScript) ||
3481
+ finalized.inputs[index].unlockingScript?.toHex().toLowerCase() !== spend.unlockingScript.toLowerCase()) {
3482
+ throw new Error('Wallet finalization substituted an authorized unlocking script.');
3483
+ }
3484
+ }
3485
+ const finalizedTxid = finalized.id('hex');
3486
+ if (result.txid != null && result.txid.toLowerCase() !== finalizedTxid) {
3487
+ throw new Error('Wallet finalization transaction ID does not match its transaction data.');
3488
+ }
3489
+ }
3490
+ async blockAndAbortAction(reference) {
3491
+ this.blockedActionReferences.add(reference);
3492
+ const result = await this.underlying.abortAction({ reference });
3493
+ if (result.aborted === true)
3494
+ this.clearPendingAction(reference);
3495
+ }
3496
+ assertPendingActionOriginator(reference, originator, allowBlocked) {
3497
+ if (!allowBlocked && this.blockedActionReferences.has(reference)) {
3498
+ throw new WERR_errors_1.WERR_UNAUTHORIZED('This action was blocked after a failed authorization check.');
3499
+ }
3500
+ const expected = this.pendingActionOriginators.get(reference);
3501
+ if (expected == null) {
3502
+ throw new WERR_errors_1.WERR_UNAUTHORIZED('The action reference was not issued by this permissions manager.');
3503
+ }
3504
+ if (expected !== (originator ?? '')) {
3505
+ throw new WERR_errors_1.WERR_UNAUTHORIZED('The action reference belongs to a different originator.');
3506
+ }
3507
+ }
3508
+ bindPendingAction(reference, originator, noSend) {
3509
+ if (this.pendingActionOriginators.has(reference)) {
3510
+ throw new WERR_errors_1.WERR_UNAUTHORIZED('The action reference is already pending.');
3511
+ }
3512
+ this.pendingActionOriginators.set(reference, originator ?? '');
3513
+ if (noSend)
3514
+ this.pendingNoSendReferences.add(reference);
3515
+ }
3516
+ clearPendingAction(reference) {
3517
+ this.pendingActionOriginators.delete(reference);
3518
+ this.pendingActionTemplates.delete(reference);
3519
+ this.blockedActionReferences.delete(reference);
3520
+ this.pendingNoSendReferences.delete(reference);
3521
+ }
3522
+ /** Lets the originator that created a signed no-send action, and only it, abort it. */
3523
+ recordNoSendAction(txid, originator, reference) {
3524
+ const key = txid.toLowerCase();
3525
+ const references = this.noSendActions.get(key)?.references ?? new Set();
3526
+ this.noSendActions.set(key, { originator: originator ?? '', references });
3527
+ if (reference !== undefined) {
3528
+ references.add(reference);
3529
+ this.noSendActionReferences.set(reference, key);
3530
+ }
3531
+ }
3532
+ forgetNoSendAction(key) {
3533
+ const action = this.noSendActions.get(key);
3534
+ if (action == null)
3535
+ return;
3536
+ for (const reference of action.references) {
3537
+ if (this.noSendActionReferences.get(reference) === key)
3538
+ this.noSendActionReferences.delete(reference);
3539
+ }
3540
+ this.noSendActions.delete(key);
3541
+ }
3542
+ /** Positive broadcast/queue results retire ownership; failures remain retryable. */
3543
+ forgetSentNoSendActions(results) {
3544
+ for (const result of results ?? []) {
3545
+ if (result.status === 'sending' || result.status === 'unproven') {
3546
+ this.forgetNoSendAction(result.txid.toLowerCase());
3547
+ }
3548
+ }
3549
+ }
3550
+ forgetSentNoSendActionsInError(error) {
3551
+ // Undelayed mixed batches report successful members alongside failures in
3552
+ // this error. Preserve the error and every member without positive evidence.
3553
+ if (error instanceof WERR_errors_1.WERR_REVIEW_ACTIONS || error instanceof sdk_1.WERR_REVIEW_ACTIONS) {
3554
+ this.forgetSentNoSendActions(error.sendWithResults);
3555
+ }
3556
+ }
3152
3557
  async signAction(...args) {
3153
- return await this.underlying.signAction(...args);
3558
+ const [requestArgs, originator] = args;
3559
+ this.assertPendingActionOriginator(requestArgs.reference, originator, false);
3560
+ // The wallet takes noSend from signAction's options, else from createAction's.
3561
+ const noSend = (requestArgs.options?.noSend ?? this.pendingNoSendReferences.has(requestArgs.reference)) === true;
3562
+ try {
3563
+ const result = await this.underlying.signAction({
3564
+ ...requestArgs,
3565
+ options: { ...requestArgs.options, returnTXIDOnly: false }
3566
+ }, originator);
3567
+ this.assertAuthorizedSignResult(requestArgs.reference, requestArgs.spends, result);
3568
+ this.clearPendingAction(requestArgs.reference);
3569
+ if (noSend && result.txid != null) {
3570
+ this.recordNoSendAction(result.txid, originator, requestArgs.reference);
3571
+ }
3572
+ this.forgetSentNoSendActions(result.sendWithResults);
3573
+ return result;
3574
+ }
3575
+ catch (error) {
3576
+ this.forgetSentNoSendActionsInError(error);
3577
+ await this.blockAndAbortAction(requestArgs.reference);
3578
+ throw error;
3579
+ }
3154
3580
  }
3155
3581
  async abortAction(...args) {
3156
- return await this.underlying.abortAction(...args);
3582
+ const [requestArgs, originator] = args;
3583
+ // Pending references live in memory only. The admin may abort any of the
3584
+ // wallet's actions, including signed noSend actions and earlier sessions'.
3585
+ // A signed no-send action is found by the reference it was signed under or by its txid.
3586
+ const noSendKey = typeof requestArgs.reference === 'string'
3587
+ ? (this.noSendActionReferences.get(requestArgs.reference) ?? requestArgs.reference.toLowerCase())
3588
+ : '';
3589
+ const noSendOriginator = this.noSendActions.get(noSendKey)?.originator;
3590
+ if (originator === undefined || !this.isAdminOriginator(originator)) {
3591
+ if (noSendOriginator === undefined) {
3592
+ this.assertPendingActionOriginator(requestArgs.reference, originator, true);
3593
+ }
3594
+ else if (noSendOriginator !== (originator ?? '')) {
3595
+ throw new WERR_errors_1.WERR_UNAUTHORIZED('The action reference belongs to a different originator.');
3596
+ }
3597
+ }
3598
+ const result = await this.underlying.abortAction(...args);
3599
+ if (result.aborted === true) {
3600
+ this.clearPendingAction(requestArgs.reference);
3601
+ this.forgetNoSendAction(noSendKey);
3602
+ }
3603
+ return result;
3157
3604
  }
3158
3605
  async listActions(...args) {
3159
3606
  const [requestArgs, originator] = args;
@@ -3568,6 +4015,8 @@ class WalletPermissionsManager {
3568
4015
  usageType: 'generic'
3569
4016
  });
3570
4017
  }
4018
+ // The underlying wallet may satisfy this with a caller-installed local trust anchor or the
4019
+ // certificate overlay. This permission gate authorizes resolution, not external certification.
3571
4020
  return await this.underlying.discoverByIdentityKey(...args);
3572
4021
  }
3573
4022
  async discoverByAttributes(...args) {
@@ -3582,6 +4031,8 @@ class WalletPermissionsManager {
3582
4031
  usageType: 'generic'
3583
4032
  });
3584
4033
  }
4034
+ // The underlying wallet may satisfy this with a caller-installed local trust anchor or the
4035
+ // certificate overlay. This permission gate authorizes resolution, not external certification.
3585
4036
  return await this.underlying.discoverByAttributes(...args);
3586
4037
  }
3587
4038
  async isAuthenticated(...args) {
@@ -3768,7 +4219,11 @@ class WalletPermissionsManager {
3768
4219
  }
3769
4220
  return true;
3770
4221
  }
3771
- /** Normalizes and canonicalizes originator domains (e.g., lowercase + drop default ports). */
4222
+ /**
4223
+ * Normalizes originator domains to their lowercase hostname. BRC-100
4224
+ * permission authority is hostname-scoped, so every port shares the same
4225
+ * grants and admin status.
4226
+ */
3772
4227
  normalizeOriginator(originator) {
3773
4228
  if (!originator)
3774
4229
  return '';
@@ -3786,12 +4241,7 @@ class WalletPermissionsManager {
3786
4241
  const hostname = url.hostname.toLowerCase();
3787
4242
  const needsBrackets = hostname.includes(':');
3788
4243
  const baseHost = needsBrackets ? `[${hostname}]` : hostname;
3789
- const port = url.port;
3790
- const defaultPort = WalletPermissionsManager.DEFAULT_PORTS[url.protocol];
3791
- if (port && defaultPort && port === defaultPort) {
3792
- return baseHost;
3793
- }
3794
- return port ? `${baseHost}:${port}` : baseHost;
4244
+ return baseHost;
3795
4245
  }
3796
4246
  catch {
3797
4247
  // Fall back to a conservative lowercase trim if URL parsing fails.
@@ -3822,8 +4272,37 @@ class WalletPermissionsManager {
3822
4272
  if (!trimmed) {
3823
4273
  throw new Error('Originator is required for permission checks.');
3824
4274
  }
4275
+ if (/^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(trimmed)) {
4276
+ throw new Error('Originator must be a domain name with an optional port, without a URL scheme.');
4277
+ }
4278
+ let parsed;
4279
+ try {
4280
+ parsed = new URL(`https://${trimmed}`);
4281
+ }
4282
+ catch {
4283
+ throw new Error('Originator must be a valid domain name with an optional port.');
4284
+ }
4285
+ if (parsed.username !== '' ||
4286
+ parsed.password !== '' ||
4287
+ parsed.pathname !== '/' ||
4288
+ parsed.search !== '' ||
4289
+ parsed.hash !== '') {
4290
+ throw new Error('Originator must not contain credentials, a path, query parameters, or a fragment.');
4291
+ }
4292
+ const hostname = parsed.hostname.toLowerCase();
4293
+ if (hostname.includes(':') || /^\d+(?:\.\d+){3}$/u.test(hostname)) {
4294
+ throw new Error('IP address originators are not permitted.');
4295
+ }
4296
+ if (hostname !== 'localhost' &&
4297
+ !hostname.split('.').every(label => /^[a-z\d](?:[a-z\d-]{0,61}[a-z\d])?$/u.test(label))) {
4298
+ throw new Error('Originator must be a valid DNS hostname.');
4299
+ }
3825
4300
  const normalized = this.normalizeOriginator(trimmed) || trimmed.toLowerCase();
3826
- const lookupValues = Array.from(new Set([trimmed, normalized])).filter(Boolean);
4301
+ // Search both current canonical tags and exact legacy tags first. The
4302
+ // untagged bounded fallback lets a grant minted for another port on this
4303
+ // hostname remain usable; decoded token fields are still authenticated and
4304
+ // compared to `normalized` before acceptance.
4305
+ const lookupValues = Array.from(new Set([trimmed, normalized, undefined]));
3827
4306
  return { normalized, lookupValues };
3828
4307
  }
3829
4308
  /**
@@ -3859,6 +4338,10 @@ class WalletPermissionsManager {
3859
4338
  }
3860
4339
  buildActiveRequestKey(r) {
3861
4340
  const base = this.buildRequestKey(r);
4341
+ if (r.type === 'spending') {
4342
+ this.spendingRequestSequence += 1;
4343
+ return `${base}:request:${this.spendingRequestSequence}`;
4344
+ }
3862
4345
  if (r.type === 'protocol' || r.type === 'basket' || r.type === 'certificate') {
3863
4346
  return `${base}:${r.usageType ?? ''}`;
3864
4347
  }