@bopen-io/wallet-toolbox 1.7.18

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 (390) hide show
  1. package/.claude/settings.local.json +10 -0
  2. package/.env.template +22 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  4. package/.github/ISSUE_TEMPLATE/discussion.md +24 -0
  5. package/.github/pull_request_template.md +22 -0
  6. package/.github/workflows/push.yaml +145 -0
  7. package/.prettierrc +10 -0
  8. package/CHANGELOG.md +280 -0
  9. package/CONTRIBUTING.md +89 -0
  10. package/README.md +43 -0
  11. package/docs/README.md +85 -0
  12. package/docs/client.md +19627 -0
  13. package/docs/monitor.md +953 -0
  14. package/docs/open-rpc/index.html +46 -0
  15. package/docs/services.md +6377 -0
  16. package/docs/setup.md +1268 -0
  17. package/docs/storage.md +5367 -0
  18. package/docs/wallet.md +19626 -0
  19. package/jest.config.ts +25 -0
  20. package/license.md +28 -0
  21. package/out/tsconfig.all.tsbuildinfo +1 -0
  22. package/package.json +63 -0
  23. package/src/CWIStyleWalletManager.ts +1999 -0
  24. package/src/Setup.ts +579 -0
  25. package/src/SetupClient.ts +322 -0
  26. package/src/SetupWallet.ts +108 -0
  27. package/src/SimpleWalletManager.ts +526 -0
  28. package/src/Wallet.ts +1169 -0
  29. package/src/WalletAuthenticationManager.ts +153 -0
  30. package/src/WalletLogger.ts +213 -0
  31. package/src/WalletPermissionsManager.ts +3660 -0
  32. package/src/WalletSettingsManager.ts +114 -0
  33. package/src/__tests/CWIStyleWalletManager.test.d.ts.map +1 -0
  34. package/src/__tests/CWIStyleWalletManager.test.js.map +1 -0
  35. package/src/__tests/CWIStyleWalletManager.test.ts +675 -0
  36. package/src/__tests/WalletPermissionsManager.callbacks.test.ts +323 -0
  37. package/src/__tests/WalletPermissionsManager.checks.test.ts +844 -0
  38. package/src/__tests/WalletPermissionsManager.encryption.test.ts +412 -0
  39. package/src/__tests/WalletPermissionsManager.fixtures.ts +307 -0
  40. package/src/__tests/WalletPermissionsManager.flows.test.ts +462 -0
  41. package/src/__tests/WalletPermissionsManager.initialization.test.ts +300 -0
  42. package/src/__tests/WalletPermissionsManager.pmodules.test.ts +798 -0
  43. package/src/__tests/WalletPermissionsManager.proxying.test.ts +724 -0
  44. package/src/__tests/WalletPermissionsManager.tokens.test.ts +503 -0
  45. package/src/index.all.ts +27 -0
  46. package/src/index.client.ts +25 -0
  47. package/src/index.mobile.ts +21 -0
  48. package/src/index.ts +1 -0
  49. package/src/monitor/Monitor.ts +412 -0
  50. package/src/monitor/MonitorDaemon.ts +188 -0
  51. package/src/monitor/README.md +3 -0
  52. package/src/monitor/__test/MonitorDaemon.man.test.ts +45 -0
  53. package/src/monitor/tasks/TaskCheckForProofs.ts +243 -0
  54. package/src/monitor/tasks/TaskCheckNoSends.ts +73 -0
  55. package/src/monitor/tasks/TaskClock.ts +33 -0
  56. package/src/monitor/tasks/TaskFailAbandoned.ts +54 -0
  57. package/src/monitor/tasks/TaskMonitorCallHistory.ts +26 -0
  58. package/src/monitor/tasks/TaskNewHeader.ts +93 -0
  59. package/src/monitor/tasks/TaskPurge.ts +68 -0
  60. package/src/monitor/tasks/TaskReorg.ts +89 -0
  61. package/src/monitor/tasks/TaskReviewStatus.ts +48 -0
  62. package/src/monitor/tasks/TaskSendWaiting.ts +122 -0
  63. package/src/monitor/tasks/TaskSyncWhenIdle.ts +26 -0
  64. package/src/monitor/tasks/TaskUnFail.ts +151 -0
  65. package/src/monitor/tasks/WalletMonitorTask.ts +47 -0
  66. package/src/sdk/CertOpsWallet.ts +18 -0
  67. package/src/sdk/PrivilegedKeyManager.ts +372 -0
  68. package/src/sdk/README.md +13 -0
  69. package/src/sdk/WERR_errors.ts +234 -0
  70. package/src/sdk/WalletError.ts +170 -0
  71. package/src/sdk/WalletErrorFromJson.ts +80 -0
  72. package/src/sdk/WalletServices.interfaces.ts +700 -0
  73. package/src/sdk/WalletSigner.interfaces.ts +11 -0
  74. package/src/sdk/WalletStorage.interfaces.ts +606 -0
  75. package/src/sdk/__test/CertificateLifeCycle.test.ts +131 -0
  76. package/src/sdk/__test/PrivilegedKeyManager.test.ts +738 -0
  77. package/src/sdk/__test/WalletError.test.ts +318 -0
  78. package/src/sdk/__test/validationHelpers.test.ts +21 -0
  79. package/src/sdk/index.ts +10 -0
  80. package/src/sdk/types.ts +226 -0
  81. package/src/services/README.md +11 -0
  82. package/src/services/ServiceCollection.ts +248 -0
  83. package/src/services/Services.ts +603 -0
  84. package/src/services/__tests/ARC.man.test.ts +123 -0
  85. package/src/services/__tests/ARC.timeout.man.test.ts +79 -0
  86. package/src/services/__tests/ArcGorillaPool.man.test.ts +108 -0
  87. package/src/services/__tests/arcServices.test.ts +8 -0
  88. package/src/services/__tests/bitrails.test.ts +56 -0
  89. package/src/services/__tests/getMerklePath.test.ts +15 -0
  90. package/src/services/__tests/getRawTx.test.ts +13 -0
  91. package/src/services/__tests/postBeef.test.ts +104 -0
  92. package/src/services/__tests/verifyBeef.test.ts +50 -0
  93. package/src/services/chaintracker/BHServiceClient.ts +212 -0
  94. package/src/services/chaintracker/ChaintracksChainTracker.ts +71 -0
  95. package/src/services/chaintracker/__tests/ChaintracksChainTracker.test.ts +33 -0
  96. package/src/services/chaintracker/__tests/ChaintracksServiceClient.test.ts +29 -0
  97. package/src/services/chaintracker/chaintracks/Api/BlockHeaderApi.ts +72 -0
  98. package/src/services/chaintracker/chaintracks/Api/BulkIngestorApi.ts +83 -0
  99. package/src/services/chaintracker/chaintracks/Api/BulkStorageApi.ts +92 -0
  100. package/src/services/chaintracker/chaintracks/Api/ChaintracksApi.ts +64 -0
  101. package/src/services/chaintracker/chaintracks/Api/ChaintracksClientApi.ts +189 -0
  102. package/src/services/chaintracker/chaintracks/Api/ChaintracksFetchApi.ts +18 -0
  103. package/src/services/chaintracker/chaintracks/Api/ChaintracksFsApi.ts +58 -0
  104. package/src/services/chaintracker/chaintracks/Api/ChaintracksStorageApi.ts +386 -0
  105. package/src/services/chaintracker/chaintracks/Api/LiveIngestorApi.ts +25 -0
  106. package/src/services/chaintracker/chaintracks/Chaintracks.ts +609 -0
  107. package/src/services/chaintracker/chaintracks/ChaintracksService.ts +199 -0
  108. package/src/services/chaintracker/chaintracks/ChaintracksServiceClient.ts +154 -0
  109. package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorBase.ts +176 -0
  110. package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDN.ts +174 -0
  111. package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDNBabbage.ts +18 -0
  112. package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.ts +113 -0
  113. package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainWs.ts +81 -0
  114. package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorBase.ts +86 -0
  115. package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorTeranodeP2P.ts +59 -0
  116. package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.ts +104 -0
  117. package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainWs.ts +66 -0
  118. package/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.ts +566 -0
  119. package/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.ts +219 -0
  120. package/src/services/chaintracker/chaintracks/Ingest/__tests/BulkIngestorCDNBabbage.test.ts +54 -0
  121. package/src/services/chaintracker/chaintracks/Ingest/__tests/LiveIngestorWhatsOnChainPoll.test.ts +33 -0
  122. package/src/services/chaintracker/chaintracks/Ingest/__tests/WhatsOnChainServices.test.ts +124 -0
  123. package/src/services/chaintracker/chaintracks/Storage/BulkStorageBase.ts +92 -0
  124. package/src/services/chaintracker/chaintracks/Storage/ChaintracksKnexMigrations.ts +104 -0
  125. package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.ts +382 -0
  126. package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageIdb.ts +574 -0
  127. package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.ts +438 -0
  128. package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageMemory.ts +29 -0
  129. package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.ts +304 -0
  130. package/src/services/chaintracker/chaintracks/Storage/__tests/ChaintracksStorageIdb.test.ts +102 -0
  131. package/src/services/chaintracker/chaintracks/Storage/__tests/ChaintracksStorageKnex.test.ts +45 -0
  132. package/src/services/chaintracker/chaintracks/__tests/Chaintracks.test.ts +77 -0
  133. package/src/services/chaintracker/chaintracks/__tests/ChaintracksClientApi.test.ts +192 -0
  134. package/src/services/chaintracker/chaintracks/__tests/LocalCdnServer.ts +75 -0
  135. package/src/services/chaintracker/chaintracks/__tests/createIdbChaintracks.test.ts +62 -0
  136. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNetBlockHeaders.json +1 -0
  137. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_0.headers +0 -0
  138. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_1.headers +0 -0
  139. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_2.headers +0 -0
  140. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_3.headers +0 -0
  141. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNetBlockHeaders.json +1 -0
  142. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_0.headers +0 -0
  143. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_1.headers +0 -0
  144. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_2.headers +0 -0
  145. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_3.headers +0 -0
  146. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNetBlockHeaders.json +1 -0
  147. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_0.headers +0 -0
  148. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_1.headers +0 -0
  149. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_2.headers +0 -0
  150. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_3.headers +0 -0
  151. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNetBlockHeaders.json +1 -0
  152. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_0.headers +0 -0
  153. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_1.headers +0 -0
  154. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_2.headers +0 -0
  155. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_3.headers +0 -0
  156. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_4.headers +0 -0
  157. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNetBlockHeaders.json +1 -0
  158. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_0.headers +0 -0
  159. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_1.headers +0 -0
  160. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_2.headers +0 -0
  161. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_3.headers +0 -0
  162. package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_4.headers +0 -0
  163. package/src/services/chaintracker/chaintracks/createDefaultIdbChaintracksOptions.ts +92 -0
  164. package/src/services/chaintracker/chaintracks/createDefaultKnexChaintracksOptions.ts +111 -0
  165. package/src/services/chaintracker/chaintracks/createDefaultNoDbChaintracksOptions.ts +91 -0
  166. package/src/services/chaintracker/chaintracks/createIdbChaintracks.ts +60 -0
  167. package/src/services/chaintracker/chaintracks/createKnexChaintracks.ts +65 -0
  168. package/src/services/chaintracker/chaintracks/createNoDbChaintracks.ts +60 -0
  169. package/src/services/chaintracker/chaintracks/index.all.ts +12 -0
  170. package/src/services/chaintracker/chaintracks/index.client.ts +4 -0
  171. package/src/services/chaintracker/chaintracks/index.mobile.ts +37 -0
  172. package/src/services/chaintracker/chaintracks/util/BulkFileDataManager.ts +975 -0
  173. package/src/services/chaintracker/chaintracks/util/BulkFileDataReader.ts +60 -0
  174. package/src/services/chaintracker/chaintracks/util/BulkFilesReader.ts +336 -0
  175. package/src/services/chaintracker/chaintracks/util/BulkHeaderFile.ts +247 -0
  176. package/src/services/chaintracker/chaintracks/util/ChaintracksFetch.ts +69 -0
  177. package/src/services/chaintracker/chaintracks/util/ChaintracksFs.ts +141 -0
  178. package/src/services/chaintracker/chaintracks/util/HeightRange.ts +153 -0
  179. package/src/services/chaintracker/chaintracks/util/SingleWriterMultiReaderLock.ts +76 -0
  180. package/src/services/chaintracker/chaintracks/util/__tests/BulkFileDataManager.test.ts +304 -0
  181. package/src/services/chaintracker/chaintracks/util/__tests/ChaintracksFetch.test.ts +60 -0
  182. package/src/services/chaintracker/chaintracks/util/__tests/HeightRange.test.ts +67 -0
  183. package/src/services/chaintracker/chaintracks/util/__tests/SingleWriterMultiReaderLock.test.ts +49 -0
  184. package/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.ts +573 -0
  185. package/src/services/chaintracker/chaintracks/util/dirtyHashes.ts +29 -0
  186. package/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.ts +432 -0
  187. package/src/services/chaintracker/index.all.ts +4 -0
  188. package/src/services/chaintracker/index.client.ts +4 -0
  189. package/src/services/chaintracker/index.mobile.ts +4 -0
  190. package/src/services/createDefaultWalletServicesOptions.ts +77 -0
  191. package/src/services/index.ts +1 -0
  192. package/src/services/processingErrors/arcSuccessError.json +76 -0
  193. package/src/services/providers/ARC.ts +350 -0
  194. package/src/services/providers/Bitails.ts +256 -0
  195. package/src/services/providers/SdkWhatsOnChain.ts +83 -0
  196. package/src/services/providers/WhatsOnChain.ts +883 -0
  197. package/src/services/providers/__tests/WhatsOnChain.test.ts +242 -0
  198. package/src/services/providers/__tests/exchangeRates.test.ts +18 -0
  199. package/src/services/providers/exchangeRates.ts +265 -0
  200. package/src/services/providers/getBeefForTxid.ts +369 -0
  201. package/src/signer/README.md +5 -0
  202. package/src/signer/WalletSigner.ts +17 -0
  203. package/src/signer/methods/acquireDirectCertificate.ts +52 -0
  204. package/src/signer/methods/buildSignableTransaction.ts +183 -0
  205. package/src/signer/methods/completeSignedTransaction.ts +117 -0
  206. package/src/signer/methods/createAction.ts +172 -0
  207. package/src/signer/methods/internalizeAction.ts +106 -0
  208. package/src/signer/methods/proveCertificate.ts +43 -0
  209. package/src/signer/methods/signAction.ts +54 -0
  210. package/src/storage/README.md +14 -0
  211. package/src/storage/StorageIdb.ts +2304 -0
  212. package/src/storage/StorageKnex.ts +1425 -0
  213. package/src/storage/StorageProvider.ts +810 -0
  214. package/src/storage/StorageReader.ts +194 -0
  215. package/src/storage/StorageReaderWriter.ts +432 -0
  216. package/src/storage/StorageSyncReader.ts +34 -0
  217. package/src/storage/WalletStorageManager.ts +943 -0
  218. package/src/storage/__test/StorageIdb.test.ts +43 -0
  219. package/src/storage/__test/WalletStorageManager.test.ts +275 -0
  220. package/src/storage/__test/adminStats.man.test.ts +89 -0
  221. package/src/storage/__test/getBeefForTransaction.test.ts +385 -0
  222. package/src/storage/index.all.ts +11 -0
  223. package/src/storage/index.client.ts +7 -0
  224. package/src/storage/index.mobile.ts +6 -0
  225. package/src/storage/methods/ListActionsSpecOp.ts +70 -0
  226. package/src/storage/methods/ListOutputsSpecOp.ts +129 -0
  227. package/src/storage/methods/__test/GenerateChange/generateChangeSdk.test.ts +1057 -0
  228. package/src/storage/methods/__test/GenerateChange/randomValsUsed1.ts +20 -0
  229. package/src/storage/methods/__test/offsetKey.test.ts +274 -0
  230. package/src/storage/methods/attemptToPostReqsToNetwork.ts +389 -0
  231. package/src/storage/methods/createAction.ts +947 -0
  232. package/src/storage/methods/generateChange.ts +556 -0
  233. package/src/storage/methods/getBeefForTransaction.ts +139 -0
  234. package/src/storage/methods/getSyncChunk.ts +293 -0
  235. package/src/storage/methods/internalizeAction.ts +562 -0
  236. package/src/storage/methods/listActionsIdb.ts +183 -0
  237. package/src/storage/methods/listActionsKnex.ts +226 -0
  238. package/src/storage/methods/listCertificates.ts +73 -0
  239. package/src/storage/methods/listOutputsIdb.ts +203 -0
  240. package/src/storage/methods/listOutputsKnex.ts +263 -0
  241. package/src/storage/methods/offsetKey.ts +89 -0
  242. package/src/storage/methods/processAction.ts +420 -0
  243. package/src/storage/methods/purgeData.ts +251 -0
  244. package/src/storage/methods/purgeDataIdb.ts +10 -0
  245. package/src/storage/methods/reviewStatus.ts +101 -0
  246. package/src/storage/methods/reviewStatusIdb.ts +43 -0
  247. package/src/storage/methods/utils.Buffer.ts +33 -0
  248. package/src/storage/methods/utils.ts +56 -0
  249. package/src/storage/remoting/StorageClient.ts +567 -0
  250. package/src/storage/remoting/StorageMobile.ts +544 -0
  251. package/src/storage/remoting/StorageServer.ts +291 -0
  252. package/src/storage/remoting/__test/StorageClient.test.ts +113 -0
  253. package/src/storage/schema/KnexMigrations.ts +489 -0
  254. package/src/storage/schema/StorageIdbSchema.ts +150 -0
  255. package/src/storage/schema/entities/EntityBase.ts +210 -0
  256. package/src/storage/schema/entities/EntityCertificate.ts +188 -0
  257. package/src/storage/schema/entities/EntityCertificateField.ts +136 -0
  258. package/src/storage/schema/entities/EntityCommission.ts +148 -0
  259. package/src/storage/schema/entities/EntityOutput.ts +290 -0
  260. package/src/storage/schema/entities/EntityOutputBasket.ts +153 -0
  261. package/src/storage/schema/entities/EntityOutputTag.ts +121 -0
  262. package/src/storage/schema/entities/EntityOutputTagMap.ts +123 -0
  263. package/src/storage/schema/entities/EntityProvenTx.ts +319 -0
  264. package/src/storage/schema/entities/EntityProvenTxReq.ts +580 -0
  265. package/src/storage/schema/entities/EntitySyncState.ts +389 -0
  266. package/src/storage/schema/entities/EntityTransaction.ts +306 -0
  267. package/src/storage/schema/entities/EntityTxLabel.ts +121 -0
  268. package/src/storage/schema/entities/EntityTxLabelMap.ts +123 -0
  269. package/src/storage/schema/entities/EntityUser.ts +112 -0
  270. package/src/storage/schema/entities/MergeEntity.ts +73 -0
  271. package/src/storage/schema/entities/__tests/CertificateFieldTests.test.ts +353 -0
  272. package/src/storage/schema/entities/__tests/CertificateTests.test.ts +354 -0
  273. package/src/storage/schema/entities/__tests/CommissionTests.test.ts +371 -0
  274. package/src/storage/schema/entities/__tests/OutputBasketTests.test.ts +278 -0
  275. package/src/storage/schema/entities/__tests/OutputTagMapTests.test.ts +242 -0
  276. package/src/storage/schema/entities/__tests/OutputTagTests.test.ts +288 -0
  277. package/src/storage/schema/entities/__tests/OutputTests.test.ts +464 -0
  278. package/src/storage/schema/entities/__tests/ProvenTxReqTests.test.ts +340 -0
  279. package/src/storage/schema/entities/__tests/ProvenTxTests.test.ts +504 -0
  280. package/src/storage/schema/entities/__tests/SyncStateTests.test.ts +288 -0
  281. package/src/storage/schema/entities/__tests/TransactionTests.test.ts +604 -0
  282. package/src/storage/schema/entities/__tests/TxLabelMapTests.test.ts +361 -0
  283. package/src/storage/schema/entities/__tests/TxLabelTests.test.ts +198 -0
  284. package/src/storage/schema/entities/__tests/stampLogTests.test.ts +90 -0
  285. package/src/storage/schema/entities/__tests/usersTests.test.ts +340 -0
  286. package/src/storage/schema/entities/index.ts +16 -0
  287. package/src/storage/schema/tables/TableCertificate.ts +21 -0
  288. package/src/storage/schema/tables/TableCertificateField.ts +12 -0
  289. package/src/storage/schema/tables/TableCommission.ts +13 -0
  290. package/src/storage/schema/tables/TableMonitorEvent.ts +9 -0
  291. package/src/storage/schema/tables/TableOutput.ts +64 -0
  292. package/src/storage/schema/tables/TableOutputBasket.ts +12 -0
  293. package/src/storage/schema/tables/TableOutputTag.ts +10 -0
  294. package/src/storage/schema/tables/TableOutputTagMap.ts +9 -0
  295. package/src/storage/schema/tables/TableProvenTx.ts +14 -0
  296. package/src/storage/schema/tables/TableProvenTxReq.ts +65 -0
  297. package/src/storage/schema/tables/TableSettings.ts +17 -0
  298. package/src/storage/schema/tables/TableSyncState.ts +18 -0
  299. package/src/storage/schema/tables/TableTransaction.ts +54 -0
  300. package/src/storage/schema/tables/TableTxLabel.ts +10 -0
  301. package/src/storage/schema/tables/TableTxLabelMap.ts +9 -0
  302. package/src/storage/schema/tables/TableUser.ts +16 -0
  303. package/src/storage/schema/tables/index.ts +16 -0
  304. package/src/storage/sync/StorageMySQLDojoReader.ts +696 -0
  305. package/src/storage/sync/index.ts +1 -0
  306. package/src/utility/Format.ts +133 -0
  307. package/src/utility/README.md +3 -0
  308. package/src/utility/ReaderUint8Array.ts +187 -0
  309. package/src/utility/ScriptTemplateBRC29.ts +73 -0
  310. package/src/utility/__tests/utilityHelpers.noBuffer.test.ts +109 -0
  311. package/src/utility/aggregateResults.ts +68 -0
  312. package/src/utility/identityUtils.ts +159 -0
  313. package/src/utility/index.all.ts +7 -0
  314. package/src/utility/index.client.ts +7 -0
  315. package/src/utility/parseTxScriptOffsets.ts +29 -0
  316. package/src/utility/stampLog.ts +69 -0
  317. package/src/utility/tscProofToMerklePath.ts +48 -0
  318. package/src/utility/utilityHelpers.buffer.ts +34 -0
  319. package/src/utility/utilityHelpers.noBuffer.ts +60 -0
  320. package/src/utility/utilityHelpers.ts +275 -0
  321. package/src/wab-client/WABClient.ts +94 -0
  322. package/src/wab-client/__tests/WABClient.man.test.ts +59 -0
  323. package/src/wab-client/auth-method-interactors/AuthMethodInteractor.ts +47 -0
  324. package/src/wab-client/auth-method-interactors/DevConsoleInteractor.ts +73 -0
  325. package/src/wab-client/auth-method-interactors/PersonaIDInteractor.ts +35 -0
  326. package/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.ts +72 -0
  327. package/syncVersions.js +71 -0
  328. package/test/Wallet/StorageClient/storageClient.man.test.ts +75 -0
  329. package/test/Wallet/action/abortAction.test.ts +47 -0
  330. package/test/Wallet/action/createAction.test.ts +299 -0
  331. package/test/Wallet/action/createAction2.test.ts +1273 -0
  332. package/test/Wallet/action/createActionToGenerateBeefs.man.test.ts +293 -0
  333. package/test/Wallet/action/internalizeAction.a.test.ts +286 -0
  334. package/test/Wallet/action/internalizeAction.test.ts +682 -0
  335. package/test/Wallet/action/relinquishOutput.test.ts +37 -0
  336. package/test/Wallet/certificate/acquireCertificate.test.ts +298 -0
  337. package/test/Wallet/certificate/listCertificates.test.ts +346 -0
  338. package/test/Wallet/construct/Wallet.constructor.test.ts +57 -0
  339. package/test/Wallet/get/getHeaderForHeight.test.ts +82 -0
  340. package/test/Wallet/get/getHeight.test.ts +52 -0
  341. package/test/Wallet/get/getKnownTxids.test.ts +86 -0
  342. package/test/Wallet/get/getNetwork.test.ts +27 -0
  343. package/test/Wallet/get/getVersion.test.ts +27 -0
  344. package/test/Wallet/list/listActions.test.ts +279 -0
  345. package/test/Wallet/list/listActions2.test.ts +1381 -0
  346. package/test/Wallet/list/listCertificates.test.ts +118 -0
  347. package/test/Wallet/list/listOutputs.test.ts +447 -0
  348. package/test/Wallet/live/walletLive.man.test.ts +521 -0
  349. package/test/Wallet/local/localWallet.man.test.ts +93 -0
  350. package/test/Wallet/local/localWallet2.man.test.ts +277 -0
  351. package/test/Wallet/signAction/mountaintop.man.test.ts +130 -0
  352. package/test/Wallet/specOps/specOps.man.test.ts +220 -0
  353. package/test/Wallet/support/janitor.man.test.ts +40 -0
  354. package/test/Wallet/support/operations.man.test.ts +407 -0
  355. package/test/Wallet/support/reqErrorReview.2025.05.06.man.test.ts +347 -0
  356. package/test/Wallet/sync/Wallet.sync.test.ts +215 -0
  357. package/test/Wallet/sync/Wallet.updateWalletLegacyTestData.man.test.ts +203 -0
  358. package/test/Wallet/sync/setActive.test.ts +170 -0
  359. package/test/WalletClient/LocalKVStore.man.test.ts +114 -0
  360. package/test/WalletClient/WERR.man.test.ts +35 -0
  361. package/test/bsv-ts-sdk/LocalKVStore.test.ts +102 -0
  362. package/test/checkDB.ts +57 -0
  363. package/test/checkdb +0 -0
  364. package/test/examples/backup.man.test.ts +59 -0
  365. package/test/examples/pushdrop.test.ts +282 -0
  366. package/test/monitor/Monitor.test.ts +620 -0
  367. package/test/services/Services.test.ts +263 -0
  368. package/test/storage/KnexMigrations.test.ts +86 -0
  369. package/test/storage/StorageMySQLDojoReader.man.test.ts +60 -0
  370. package/test/storage/count.test.ts +177 -0
  371. package/test/storage/find.test.ts +195 -0
  372. package/test/storage/findLegacy.test.ts +67 -0
  373. package/test/storage/idb/allocateChange.test.ts +251 -0
  374. package/test/storage/idb/count.test.ts +158 -0
  375. package/test/storage/idb/find.test.ts +177 -0
  376. package/test/storage/idb/idbSpeed.test.ts +36 -0
  377. package/test/storage/idb/insert.test.ts +268 -0
  378. package/test/storage/idb/transactionAbort.test.ts +108 -0
  379. package/test/storage/idb/update.test.ts +999 -0
  380. package/test/storage/insert.test.ts +278 -0
  381. package/test/storage/update.test.ts +1021 -0
  382. package/test/storage/update2.test.ts +897 -0
  383. package/test/utils/TestUtilsWalletStorage.ts +2526 -0
  384. package/test/utils/localWalletMethods.ts +363 -0
  385. package/test/utils/removeFailedFromDatabase.sql +17 -0
  386. package/ts2md.json +44 -0
  387. package/tsconfig.all.json +31 -0
  388. package/tsconfig.client.json +29 -0
  389. package/tsconfig.json +17 -0
  390. package/tsconfig.mobile.json +28 -0
@@ -0,0 +1,462 @@
1
+ import { mockUnderlyingWallet, MockedBSV_SDK } from './WalletPermissionsManager.fixtures'
2
+ import { WalletPermissionsManager, PermissionToken } from '../WalletPermissionsManager'
3
+
4
+ import { jest } from '@jest/globals'
5
+
6
+ // We mock the underlying @bsv/sdk references with our test fixtures:
7
+ jest.mock('@bsv/sdk', () => MockedBSV_SDK)
8
+
9
+ /**
10
+ * A lightweight helper that forces the manager to never find any on-chain token.
11
+ * We do this so we can reliably test the request flow (i.e., that it truly initiates
12
+ * a new permission request if no token is found).
13
+ */
14
+ function mockNoTokensFound(manager: WalletPermissionsManager) {
15
+ jest.spyOn(manager as any, 'findProtocolToken').mockResolvedValue(undefined)
16
+ jest.spyOn(manager as any, 'findBasketToken').mockResolvedValue(undefined)
17
+ jest.spyOn(manager as any, 'findCertificateToken').mockResolvedValue(undefined)
18
+ jest.spyOn(manager as any, 'findSpendingToken').mockResolvedValue(undefined)
19
+ }
20
+
21
+ describe('WalletPermissionsManager - Permission Request Flow & Active Requests', () => {
22
+ let underlying: ReturnType<typeof mockUnderlyingWallet>
23
+ let manager: WalletPermissionsManager
24
+
25
+ beforeEach(() => {
26
+ underlying = mockUnderlyingWallet()
27
+ manager = new WalletPermissionsManager(underlying, 'admin.test.com')
28
+ })
29
+
30
+ afterEach(() => {
31
+ jest.clearAllMocks()
32
+ })
33
+
34
+ /**
35
+ * UNIT TESTS
36
+ */
37
+ describe('Unit Tests: requestPermissionFlow & activeRequests map', () => {
38
+ it('should coalesce parallel requests for the same resource into a single user prompt', async () => {
39
+ // We want to test the underlying private method "requestPermissionFlow" indirectly
40
+ // or we can test it via a public method that calls it. We'll do so via ensureProtocolPermission.
41
+
42
+ // Force no token found => triggers a request flow
43
+ mockNoTokensFound(manager)
44
+
45
+ // Spy on the manager's "onProtocolPermissionRequested" callbacks
46
+ const requestCallback = jest.fn(() => {})
47
+ manager.bindCallback('onProtocolPermissionRequested', requestCallback)
48
+
49
+ // Make two parallel calls for the same resource
50
+ const callA = manager.ensureProtocolPermission({
51
+ originator: 'example.com',
52
+ privileged: false,
53
+ protocolID: [1, 'someproto'],
54
+ counterparty: 'self',
55
+ reason: 'UnitTest - same resource A',
56
+ seekPermission: true,
57
+ usageType: 'signing'
58
+ })
59
+
60
+ const callB = manager.ensureProtocolPermission({
61
+ originator: 'example.com',
62
+ privileged: false,
63
+ protocolID: [1, 'someproto'],
64
+ counterparty: 'self',
65
+ reason: 'UnitTest - same resource B',
66
+ seekPermission: true,
67
+ usageType: 'signing'
68
+ })
69
+
70
+ // Wait a short moment for the async request flow to trigger
71
+ await new Promise(res => setTimeout(res, 5))
72
+
73
+ // We expect only one "onProtocolPermissionRequested" event for both calls
74
+ expect(requestCallback).toHaveBeenCalledTimes(1)
75
+
76
+ // Now let's deny the request:
77
+ // Grab the requestID that the manager gave us from the callback param
78
+ const callbackArg = (requestCallback.mock as any).calls[0][0]
79
+ const requestID = callbackArg.requestID
80
+ expect(typeof requestID).toBe('string') // manager-generated
81
+
82
+ // Deny the request
83
+ await manager.denyPermission(requestID)
84
+
85
+ // Both calls should reject
86
+ await expect(callA).rejects.toThrow(/Permission denied/)
87
+ await expect(callB).rejects.toThrow(/Permission denied/)
88
+
89
+ // Confirm activeRequests map is empty after denial
90
+ const activeRequests = (manager as any).activeRequests as Map<string, any[]>
91
+ expect(activeRequests.size).toBe(0)
92
+ })
93
+
94
+ it('should generate two distinct user prompts for two different permission requests', async () => {
95
+ // Force no tokens
96
+ mockNoTokensFound(manager)
97
+
98
+ // Spy on basket & protocol request callbacks
99
+ const protocolRequestCb = jest.fn(() => {})
100
+ const basketRequestCb = jest.fn(() => {})
101
+ manager.bindCallback('onProtocolPermissionRequested', protocolRequestCb)
102
+ manager.bindCallback('onBasketAccessRequested', basketRequestCb)
103
+
104
+ // Make one call for protocol usage
105
+ const pCall = manager.ensureProtocolPermission({
106
+ originator: 'example.com',
107
+ privileged: false,
108
+ protocolID: [1, 'proto-A'],
109
+ counterparty: 'self',
110
+ reason: 'Different request A',
111
+ seekPermission: true,
112
+ usageType: 'signing'
113
+ })
114
+
115
+ // Make a second call for basket usage
116
+ const bCall = manager.ensureBasketAccess({
117
+ originator: 'example.com',
118
+ basket: 'some-basket',
119
+ reason: 'Different request B',
120
+ seekPermission: true,
121
+ usageType: 'insertion'
122
+ })
123
+
124
+ // Wait a moment for them to trigger
125
+ await new Promise(res => setTimeout(res, 5))
126
+
127
+ // We expect one protocol request AND one basket request
128
+ expect(protocolRequestCb).toHaveBeenCalledTimes(1)
129
+ expect(basketRequestCb).toHaveBeenCalledTimes(1)
130
+
131
+ // Deny protocol request
132
+ const pReqID = (protocolRequestCb.mock as any).calls[0][0].requestID
133
+ await manager.denyPermission(pReqID)
134
+
135
+ // Deny basket request
136
+ const bReqID = (basketRequestCb.mock as any).calls[0][0].requestID
137
+ await manager.denyPermission(bReqID)
138
+
139
+ // Both calls should have rejected
140
+ await expect(pCall).rejects.toThrow(/Permission denied/)
141
+ await expect(bCall).rejects.toThrow(/Permission denied/)
142
+
143
+ // activeRequests is empty
144
+ const activeRequests = (manager as any).activeRequests as Map<string, any[]>
145
+ expect(activeRequests.size).toBe(0)
146
+ })
147
+
148
+ it('should resolve all parallel requests when permission is granted, referencing the same requestID', async () => {
149
+ // No tokens => triggers request flow
150
+ mockNoTokensFound(manager)
151
+
152
+ const requestCb = jest.fn(() => {})
153
+ manager.bindCallback('onProtocolPermissionRequested', requestCb)
154
+
155
+ // Parallel calls
156
+ const promiseA = manager.ensureProtocolPermission({
157
+ originator: 'example.com',
158
+ privileged: false,
159
+ protocolID: [1, 'proto-X'],
160
+ counterparty: 'anyone',
161
+ reason: 'Test parallel grant A',
162
+ seekPermission: true,
163
+ usageType: 'encrypting'
164
+ })
165
+
166
+ const promiseB = manager.ensureProtocolPermission({
167
+ originator: 'example.com',
168
+ privileged: false,
169
+ protocolID: [1, 'proto-X'],
170
+ counterparty: 'anyone',
171
+ reason: 'Test parallel grant B',
172
+ seekPermission: true,
173
+ usageType: 'encrypting'
174
+ })
175
+
176
+ // Let the request event fire
177
+ await new Promise(res => setTimeout(res, 5))
178
+ expect(requestCb).toHaveBeenCalledTimes(1)
179
+
180
+ // Extract the requestID from the callback
181
+ const { requestID } = (requestCb.mock as any).calls[0][0]
182
+ // Now we grant permission for that same requestID
183
+ // Because ephemeral is false by default, the manager will attempt to create on-chain tokens
184
+ // We'll mock the internal createPermissionOnChain so it doesn't blow up
185
+ const createOnChainSpy = jest.spyOn(manager as any, 'createPermissionOnChain').mockResolvedValue(undefined)
186
+
187
+ await manager.grantPermission({ requestID })
188
+
189
+ // Both calls should resolve with `true` (the manager returns a boolean)
190
+ await expect(promiseA).resolves.toBe(true)
191
+ await expect(promiseB).resolves.toBe(true)
192
+
193
+ // activeRequests map is empty
194
+ const activeRequests = (manager as any).activeRequests as Map<string, any[]>
195
+ expect(activeRequests.size).toBe(0)
196
+
197
+ // The manager tried to create an on-chain permission token once
198
+ expect(createOnChainSpy).toHaveBeenCalledTimes(1)
199
+ })
200
+
201
+ it('should reject only the matching request queue on deny if requestID is specified', async () => {
202
+ // This scenario tests the manager's partial denial logic where we pass { requestID }
203
+ // to only reject the queued requests with that ID, leaving others (with a different requestID)
204
+ // in the queue.
205
+
206
+ mockNoTokensFound(manager)
207
+
208
+ // We do two separate calls for the same resource but at different times, resulting in separate queues.
209
+ // Actually, the manager normally merges them into one queue if the resource is the same.
210
+ // So let's do two different resources to ensure we get two separate keys.
211
+ const protoCb = jest.fn(() => {})
212
+ manager.bindCallback('onProtocolPermissionRequested', protoCb)
213
+
214
+ // Resource 1
215
+ const p1Promise = manager.ensureProtocolPermission({
216
+ originator: 'siteA.com',
217
+ privileged: false,
218
+ protocolID: [1, 'proto-siteA'],
219
+ counterparty: 'self',
220
+ usageType: 'encrypting'
221
+ })
222
+ await new Promise(res => setTimeout(res, 5))
223
+ const p1ReqID = (protoCb.mock as any).calls[0][0].requestID
224
+ // At this point, resource 1 is pending in activeRequests. We'll not resolve it yet.
225
+
226
+ // Resource 2
227
+ const p2Promise = manager.ensureProtocolPermission({
228
+ originator: 'siteB.com',
229
+ privileged: false,
230
+ protocolID: [1, 'proto-siteB'],
231
+ counterparty: 'self',
232
+ usageType: 'encrypting'
233
+ })
234
+ await new Promise(res => setTimeout(res, 5))
235
+ // the second call triggers a second onProtocolPermissionRequested callback
236
+ expect(protoCb).toHaveBeenCalledTimes(2)
237
+ const p2ReqID = (protoCb.mock as any).calls[1][0].requestID
238
+
239
+ // Deny the second request only
240
+ await manager.denyPermission(p2ReqID)
241
+ await expect(p2Promise).rejects.toThrow(/Permission denied/)
242
+
243
+ // But the first request is still waiting
244
+ const activeRequests = (manager as any).activeRequests as Map<string, any[]>
245
+ expect(activeRequests.size).toBe(1)
246
+
247
+ // Now let's deny the first request too
248
+ await manager.denyPermission(p1ReqID)
249
+ await expect(p1Promise).rejects.toThrow(/Permission denied/)
250
+
251
+ // The queue is empty now
252
+ expect(activeRequests.size).toBe(0)
253
+ })
254
+ })
255
+
256
+ /**
257
+ * INTEGRATION TESTS
258
+ */
259
+ describe('Integration Tests: ephemeral vs. persistent tokens', () => {
260
+ it('should not create a token if ephemeral=true, so subsequent calls re-trigger the request', async () => {
261
+ // We'll do a "protocol" permission scenario:
262
+ mockNoTokensFound(manager)
263
+
264
+ // Bind the request callback
265
+ const requestCb = jest.fn(() => {})
266
+ manager.bindCallback('onProtocolPermissionRequested', requestCb)
267
+
268
+ // Force any on-chain creation attempt to be spied on
269
+ const createTokenSpy = jest.spyOn(manager as any, 'createPermissionOnChain')
270
+
271
+ // 1) Call ensureProtocolPermission => triggers request
272
+ const pCall1 = manager.ensureProtocolPermission({
273
+ originator: 'appdomain.com',
274
+ privileged: false,
275
+ protocolID: [1, 'ephemeral-proto'],
276
+ counterparty: 'self',
277
+ reason: 'test ephemeral #1',
278
+ usageType: 'signing'
279
+ })
280
+
281
+ // Wait for request callback
282
+ await new Promise(res => setTimeout(res, 5))
283
+ expect(requestCb).toHaveBeenCalledTimes(1)
284
+ const reqID1 = (requestCb.mock as any).calls[0][0].requestID
285
+
286
+ // Grant ephemeral
287
+ await manager.grantPermission({
288
+ requestID: reqID1,
289
+ ephemeral: true
290
+ })
291
+
292
+ // pCall1 is resolved
293
+ await expect(pCall1).resolves.toBe(true)
294
+
295
+ // Because ephemeral=true, we do NOT create an on-chain token
296
+ expect(createTokenSpy).not.toHaveBeenCalled()
297
+
298
+ // Clear cache to actually run again
299
+ ;(manager as any).permissionCache = new Map()
300
+
301
+ // 2) Immediately call ensureProtocolPermission again for the same resource
302
+ // Because ephemeral usage didn't store a token, it should re-prompt.
303
+ const pCall2 = manager.ensureProtocolPermission({
304
+ originator: 'appdomain.com',
305
+ privileged: false,
306
+ protocolID: [1, 'ephemeral-proto'],
307
+ counterparty: 'self',
308
+ reason: 'test ephemeral #2',
309
+ usageType: 'signing'
310
+ })
311
+
312
+ await new Promise(res => setTimeout(res, 5))
313
+ // We expect a new request callback
314
+ expect(requestCb).toHaveBeenCalledTimes(2)
315
+
316
+ // We'll deny the second request
317
+ const reqID2 = (requestCb.mock as any).calls[1][0].requestID
318
+ await manager.denyPermission(reqID2)
319
+
320
+ await expect(pCall2).rejects.toThrow(/Permission denied/)
321
+ })
322
+
323
+ it('should create a token if ephemeral=false, so subsequent calls do not re-trigger if unexpired', async () => {
324
+ // We want the manager to truly create a token. We'll confirm that
325
+ // subsequent calls for the same resource skip user prompt.
326
+
327
+ mockNoTokensFound(manager)
328
+ // We'll also ensure no token is found "the first time."
329
+ // But on subsequent calls, we can mock that the manager sees the newly created token.
330
+
331
+ // Let's spy on "createPermissionOnChain" so we can intercept the new token
332
+ const createTokenSpy = jest.spyOn(manager as any, 'createPermissionOnChain').mockResolvedValue(undefined) // no real on-chain creation
333
+
334
+ // Spy on "findProtocolToken" so we can simulate that the second time it's called,
335
+ // there's a valid token. We'll do this by setting the mock to return undefined the first time,
336
+ // and a valid token the second time (or we can just rely on the manager's logic).
337
+ let firstFindCall = true
338
+ jest.spyOn(manager as any, 'findProtocolToken').mockImplementation(async () => {
339
+ if (firstFindCall) {
340
+ firstFindCall = false
341
+ return undefined // first time triggers request
342
+ }
343
+ // second time => pretend we found a valid token
344
+ const mockToken: PermissionToken = {
345
+ tx: [],
346
+ txid: 'abcdef',
347
+ outputIndex: 0,
348
+ outputScript: '00',
349
+ satoshis: 1,
350
+ originator: 'persistentdomain.com',
351
+ expiry: Math.floor(Date.now() / 1000) + 3600, // unexpired
352
+ privileged: false,
353
+ protocol: 'persist-proto',
354
+ securityLevel: 1,
355
+ counterparty: 'self'
356
+ }
357
+ return mockToken
358
+ })
359
+
360
+ // We'll observe the request callback
361
+ const requestCb = jest.fn(() => {})
362
+ manager.bindCallback('onProtocolPermissionRequested', requestCb)
363
+
364
+ // 1) First call => no token => triggers request
365
+ const call1 = manager.ensureProtocolPermission({
366
+ originator: 'persistentdomain.com',
367
+ privileged: false,
368
+ protocolID: [1, 'persist-proto'],
369
+ counterparty: 'self',
370
+ reason: 'test persistent #1',
371
+ usageType: 'signing'
372
+ })
373
+ await new Promise(res => setTimeout(res, 5))
374
+ expect(requestCb).toHaveBeenCalledTimes(1)
375
+
376
+ // Grant ephemeral=false => triggers createPermissionOnChain
377
+ const reqID = (requestCb.mock as any).calls[0][0].requestID
378
+ await manager.grantPermission({ requestID: reqID, ephemeral: false })
379
+ await expect(call1).resolves.toBe(true)
380
+
381
+ expect(createTokenSpy).toHaveBeenCalledTimes(1)
382
+
383
+ // 2) Second call => the manager should find the token we just "created" => no request prompt
384
+ const call2 = manager.ensureProtocolPermission({
385
+ originator: 'persistentdomain.com',
386
+ privileged: false,
387
+ protocolID: [1, 'persist-proto'],
388
+ counterparty: 'self',
389
+ reason: 'test persistent #2',
390
+ usageType: 'signing'
391
+ })
392
+
393
+ // We do not expect a new user prompt => requestCb remains at 1
394
+ await new Promise(res => setTimeout(res, 5))
395
+ expect(requestCb).toHaveBeenCalledTimes(1)
396
+
397
+ // The second call should resolve immediately, no prompt
398
+ await expect(call2).resolves.toBe(true)
399
+ })
400
+
401
+ it('should handle renewal if the found token is expired, passing previousToken in the request', async () => {
402
+ // We'll test the "renewal" flow:
403
+ // If the manager finds a token but it's expired, it sets { renewal: true, previousToken } in the request.
404
+
405
+ // We'll mock findProtocolToken to return an expired token
406
+ const expiredToken: PermissionToken = {
407
+ tx: [],
408
+ txid: 'expiredTxid123',
409
+ outputIndex: 0,
410
+ outputScript: '76a914xxxx...88ac',
411
+ satoshis: 1,
412
+ originator: 'renewme.com',
413
+ expiry: Math.floor(Date.now() / 1000) - 100, // in the past
414
+ privileged: false,
415
+ protocol: 'renew-proto',
416
+ securityLevel: 1,
417
+ counterparty: 'self'
418
+ }
419
+ jest.spyOn(manager as any, 'findProtocolToken').mockResolvedValue(expiredToken)
420
+
421
+ // Spy on request callback
422
+ const requestCb = jest.fn(() => {})
423
+ manager.bindCallback('onProtocolPermissionRequested', requestCb)
424
+
425
+ // We'll also spy on "renewPermissionOnChain" to see if it's called
426
+ const renewSpy = jest.spyOn(manager as any, 'renewPermissionOnChain').mockResolvedValue(undefined)
427
+
428
+ // Call ensureProtocolPermission => sees expired token => triggers request with renewal
429
+ const promise = manager.ensureProtocolPermission({
430
+ originator: 'renewme.com',
431
+ privileged: false,
432
+ protocolID: [1, 'renew-proto'],
433
+ counterparty: 'self',
434
+ reason: 'test renewal',
435
+ usageType: 'encrypting'
436
+ })
437
+
438
+ // Wait for request callback
439
+ await new Promise(res => setTimeout(res, 10))
440
+ expect(requestCb).toHaveBeenCalledTimes(1)
441
+
442
+ // Confirm the callback param includes `renewal=true` and `previousToken=expiredToken`
443
+ const { renewal, previousToken } = (requestCb.mock as any).calls[0][0]
444
+ expect(renewal).toBe(true)
445
+ expect(previousToken.txid).toBe('expiredTxid123')
446
+
447
+ // Grant ephemeral=false => manager calls renewPermissionOnChain
448
+ const { requestID } = (requestCb.mock as any).calls[0][0]
449
+ await manager.grantPermission({ requestID, ephemeral: false })
450
+
451
+ await expect(promise).resolves.toBe(true)
452
+ expect(renewSpy).toHaveBeenCalledTimes(1)
453
+ // The first arg is the old token, second is request, etc.
454
+ expect(renewSpy).toHaveBeenCalledWith(
455
+ expiredToken,
456
+ expect.objectContaining({ originator: 'renewme.com' }),
457
+ expect.any(Number),
458
+ undefined
459
+ )
460
+ })
461
+ })
462
+ })