@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.
- package/.claude/settings.local.json +10 -0
- package/.env.template +22 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
- package/.github/ISSUE_TEMPLATE/discussion.md +24 -0
- package/.github/pull_request_template.md +22 -0
- package/.github/workflows/push.yaml +145 -0
- package/.prettierrc +10 -0
- package/CHANGELOG.md +280 -0
- package/CONTRIBUTING.md +89 -0
- package/README.md +43 -0
- package/docs/README.md +85 -0
- package/docs/client.md +19627 -0
- package/docs/monitor.md +953 -0
- package/docs/open-rpc/index.html +46 -0
- package/docs/services.md +6377 -0
- package/docs/setup.md +1268 -0
- package/docs/storage.md +5367 -0
- package/docs/wallet.md +19626 -0
- package/jest.config.ts +25 -0
- package/license.md +28 -0
- package/out/tsconfig.all.tsbuildinfo +1 -0
- package/package.json +63 -0
- package/src/CWIStyleWalletManager.ts +1999 -0
- package/src/Setup.ts +579 -0
- package/src/SetupClient.ts +322 -0
- package/src/SetupWallet.ts +108 -0
- package/src/SimpleWalletManager.ts +526 -0
- package/src/Wallet.ts +1169 -0
- package/src/WalletAuthenticationManager.ts +153 -0
- package/src/WalletLogger.ts +213 -0
- package/src/WalletPermissionsManager.ts +3660 -0
- package/src/WalletSettingsManager.ts +114 -0
- package/src/__tests/CWIStyleWalletManager.test.d.ts.map +1 -0
- package/src/__tests/CWIStyleWalletManager.test.js.map +1 -0
- package/src/__tests/CWIStyleWalletManager.test.ts +675 -0
- package/src/__tests/WalletPermissionsManager.callbacks.test.ts +323 -0
- package/src/__tests/WalletPermissionsManager.checks.test.ts +844 -0
- package/src/__tests/WalletPermissionsManager.encryption.test.ts +412 -0
- package/src/__tests/WalletPermissionsManager.fixtures.ts +307 -0
- package/src/__tests/WalletPermissionsManager.flows.test.ts +462 -0
- package/src/__tests/WalletPermissionsManager.initialization.test.ts +300 -0
- package/src/__tests/WalletPermissionsManager.pmodules.test.ts +798 -0
- package/src/__tests/WalletPermissionsManager.proxying.test.ts +724 -0
- package/src/__tests/WalletPermissionsManager.tokens.test.ts +503 -0
- package/src/index.all.ts +27 -0
- package/src/index.client.ts +25 -0
- package/src/index.mobile.ts +21 -0
- package/src/index.ts +1 -0
- package/src/monitor/Monitor.ts +412 -0
- package/src/monitor/MonitorDaemon.ts +188 -0
- package/src/monitor/README.md +3 -0
- package/src/monitor/__test/MonitorDaemon.man.test.ts +45 -0
- package/src/monitor/tasks/TaskCheckForProofs.ts +243 -0
- package/src/monitor/tasks/TaskCheckNoSends.ts +73 -0
- package/src/monitor/tasks/TaskClock.ts +33 -0
- package/src/monitor/tasks/TaskFailAbandoned.ts +54 -0
- package/src/monitor/tasks/TaskMonitorCallHistory.ts +26 -0
- package/src/monitor/tasks/TaskNewHeader.ts +93 -0
- package/src/monitor/tasks/TaskPurge.ts +68 -0
- package/src/monitor/tasks/TaskReorg.ts +89 -0
- package/src/monitor/tasks/TaskReviewStatus.ts +48 -0
- package/src/monitor/tasks/TaskSendWaiting.ts +122 -0
- package/src/monitor/tasks/TaskSyncWhenIdle.ts +26 -0
- package/src/monitor/tasks/TaskUnFail.ts +151 -0
- package/src/monitor/tasks/WalletMonitorTask.ts +47 -0
- package/src/sdk/CertOpsWallet.ts +18 -0
- package/src/sdk/PrivilegedKeyManager.ts +372 -0
- package/src/sdk/README.md +13 -0
- package/src/sdk/WERR_errors.ts +234 -0
- package/src/sdk/WalletError.ts +170 -0
- package/src/sdk/WalletErrorFromJson.ts +80 -0
- package/src/sdk/WalletServices.interfaces.ts +700 -0
- package/src/sdk/WalletSigner.interfaces.ts +11 -0
- package/src/sdk/WalletStorage.interfaces.ts +606 -0
- package/src/sdk/__test/CertificateLifeCycle.test.ts +131 -0
- package/src/sdk/__test/PrivilegedKeyManager.test.ts +738 -0
- package/src/sdk/__test/WalletError.test.ts +318 -0
- package/src/sdk/__test/validationHelpers.test.ts +21 -0
- package/src/sdk/index.ts +10 -0
- package/src/sdk/types.ts +226 -0
- package/src/services/README.md +11 -0
- package/src/services/ServiceCollection.ts +248 -0
- package/src/services/Services.ts +603 -0
- package/src/services/__tests/ARC.man.test.ts +123 -0
- package/src/services/__tests/ARC.timeout.man.test.ts +79 -0
- package/src/services/__tests/ArcGorillaPool.man.test.ts +108 -0
- package/src/services/__tests/arcServices.test.ts +8 -0
- package/src/services/__tests/bitrails.test.ts +56 -0
- package/src/services/__tests/getMerklePath.test.ts +15 -0
- package/src/services/__tests/getRawTx.test.ts +13 -0
- package/src/services/__tests/postBeef.test.ts +104 -0
- package/src/services/__tests/verifyBeef.test.ts +50 -0
- package/src/services/chaintracker/BHServiceClient.ts +212 -0
- package/src/services/chaintracker/ChaintracksChainTracker.ts +71 -0
- package/src/services/chaintracker/__tests/ChaintracksChainTracker.test.ts +33 -0
- package/src/services/chaintracker/__tests/ChaintracksServiceClient.test.ts +29 -0
- package/src/services/chaintracker/chaintracks/Api/BlockHeaderApi.ts +72 -0
- package/src/services/chaintracker/chaintracks/Api/BulkIngestorApi.ts +83 -0
- package/src/services/chaintracker/chaintracks/Api/BulkStorageApi.ts +92 -0
- package/src/services/chaintracker/chaintracks/Api/ChaintracksApi.ts +64 -0
- package/src/services/chaintracker/chaintracks/Api/ChaintracksClientApi.ts +189 -0
- package/src/services/chaintracker/chaintracks/Api/ChaintracksFetchApi.ts +18 -0
- package/src/services/chaintracker/chaintracks/Api/ChaintracksFsApi.ts +58 -0
- package/src/services/chaintracker/chaintracks/Api/ChaintracksStorageApi.ts +386 -0
- package/src/services/chaintracker/chaintracks/Api/LiveIngestorApi.ts +25 -0
- package/src/services/chaintracker/chaintracks/Chaintracks.ts +609 -0
- package/src/services/chaintracker/chaintracks/ChaintracksService.ts +199 -0
- package/src/services/chaintracker/chaintracks/ChaintracksServiceClient.ts +154 -0
- package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorBase.ts +176 -0
- package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDN.ts +174 -0
- package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorCDNBabbage.ts +18 -0
- package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.ts +113 -0
- package/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainWs.ts +81 -0
- package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorBase.ts +86 -0
- package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorTeranodeP2P.ts +59 -0
- package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainPoll.ts +104 -0
- package/src/services/chaintracker/chaintracks/Ingest/LiveIngestorWhatsOnChainWs.ts +66 -0
- package/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainIngestorWs.ts +566 -0
- package/src/services/chaintracker/chaintracks/Ingest/WhatsOnChainServices.ts +219 -0
- package/src/services/chaintracker/chaintracks/Ingest/__tests/BulkIngestorCDNBabbage.test.ts +54 -0
- package/src/services/chaintracker/chaintracks/Ingest/__tests/LiveIngestorWhatsOnChainPoll.test.ts +33 -0
- package/src/services/chaintracker/chaintracks/Ingest/__tests/WhatsOnChainServices.test.ts +124 -0
- package/src/services/chaintracker/chaintracks/Storage/BulkStorageBase.ts +92 -0
- package/src/services/chaintracker/chaintracks/Storage/ChaintracksKnexMigrations.ts +104 -0
- package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.ts +382 -0
- package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageIdb.ts +574 -0
- package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageKnex.ts +438 -0
- package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageMemory.ts +29 -0
- package/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageNoDb.ts +304 -0
- package/src/services/chaintracker/chaintracks/Storage/__tests/ChaintracksStorageIdb.test.ts +102 -0
- package/src/services/chaintracker/chaintracks/Storage/__tests/ChaintracksStorageKnex.test.ts +45 -0
- package/src/services/chaintracker/chaintracks/__tests/Chaintracks.test.ts +77 -0
- package/src/services/chaintracker/chaintracks/__tests/ChaintracksClientApi.test.ts +192 -0
- package/src/services/chaintracker/chaintracks/__tests/LocalCdnServer.ts +75 -0
- package/src/services/chaintracker/chaintracks/__tests/createIdbChaintracks.test.ts +62 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNetBlockHeaders.json +1 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_0.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_1.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_2.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest349/mainNet_3.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNetBlockHeaders.json +1 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_0.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_1.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_2.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest379/mainNet_3.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNetBlockHeaders.json +1 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_0.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_1.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_2.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest399/mainNet_3.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNetBlockHeaders.json +1 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_0.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_1.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_2.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_3.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest402/mainNet_4.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNetBlockHeaders.json +1 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_0.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_1.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_2.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_3.headers +0 -0
- package/src/services/chaintracker/chaintracks/__tests/data/cdnTest499/mainNet_4.headers +0 -0
- package/src/services/chaintracker/chaintracks/createDefaultIdbChaintracksOptions.ts +92 -0
- package/src/services/chaintracker/chaintracks/createDefaultKnexChaintracksOptions.ts +111 -0
- package/src/services/chaintracker/chaintracks/createDefaultNoDbChaintracksOptions.ts +91 -0
- package/src/services/chaintracker/chaintracks/createIdbChaintracks.ts +60 -0
- package/src/services/chaintracker/chaintracks/createKnexChaintracks.ts +65 -0
- package/src/services/chaintracker/chaintracks/createNoDbChaintracks.ts +60 -0
- package/src/services/chaintracker/chaintracks/index.all.ts +12 -0
- package/src/services/chaintracker/chaintracks/index.client.ts +4 -0
- package/src/services/chaintracker/chaintracks/index.mobile.ts +37 -0
- package/src/services/chaintracker/chaintracks/util/BulkFileDataManager.ts +975 -0
- package/src/services/chaintracker/chaintracks/util/BulkFileDataReader.ts +60 -0
- package/src/services/chaintracker/chaintracks/util/BulkFilesReader.ts +336 -0
- package/src/services/chaintracker/chaintracks/util/BulkHeaderFile.ts +247 -0
- package/src/services/chaintracker/chaintracks/util/ChaintracksFetch.ts +69 -0
- package/src/services/chaintracker/chaintracks/util/ChaintracksFs.ts +141 -0
- package/src/services/chaintracker/chaintracks/util/HeightRange.ts +153 -0
- package/src/services/chaintracker/chaintracks/util/SingleWriterMultiReaderLock.ts +76 -0
- package/src/services/chaintracker/chaintracks/util/__tests/BulkFileDataManager.test.ts +304 -0
- package/src/services/chaintracker/chaintracks/util/__tests/ChaintracksFetch.test.ts +60 -0
- package/src/services/chaintracker/chaintracks/util/__tests/HeightRange.test.ts +67 -0
- package/src/services/chaintracker/chaintracks/util/__tests/SingleWriterMultiReaderLock.test.ts +49 -0
- package/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.ts +573 -0
- package/src/services/chaintracker/chaintracks/util/dirtyHashes.ts +29 -0
- package/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.ts +432 -0
- package/src/services/chaintracker/index.all.ts +4 -0
- package/src/services/chaintracker/index.client.ts +4 -0
- package/src/services/chaintracker/index.mobile.ts +4 -0
- package/src/services/createDefaultWalletServicesOptions.ts +77 -0
- package/src/services/index.ts +1 -0
- package/src/services/processingErrors/arcSuccessError.json +76 -0
- package/src/services/providers/ARC.ts +350 -0
- package/src/services/providers/Bitails.ts +256 -0
- package/src/services/providers/SdkWhatsOnChain.ts +83 -0
- package/src/services/providers/WhatsOnChain.ts +883 -0
- package/src/services/providers/__tests/WhatsOnChain.test.ts +242 -0
- package/src/services/providers/__tests/exchangeRates.test.ts +18 -0
- package/src/services/providers/exchangeRates.ts +265 -0
- package/src/services/providers/getBeefForTxid.ts +369 -0
- package/src/signer/README.md +5 -0
- package/src/signer/WalletSigner.ts +17 -0
- package/src/signer/methods/acquireDirectCertificate.ts +52 -0
- package/src/signer/methods/buildSignableTransaction.ts +183 -0
- package/src/signer/methods/completeSignedTransaction.ts +117 -0
- package/src/signer/methods/createAction.ts +172 -0
- package/src/signer/methods/internalizeAction.ts +106 -0
- package/src/signer/methods/proveCertificate.ts +43 -0
- package/src/signer/methods/signAction.ts +54 -0
- package/src/storage/README.md +14 -0
- package/src/storage/StorageIdb.ts +2304 -0
- package/src/storage/StorageKnex.ts +1425 -0
- package/src/storage/StorageProvider.ts +810 -0
- package/src/storage/StorageReader.ts +194 -0
- package/src/storage/StorageReaderWriter.ts +432 -0
- package/src/storage/StorageSyncReader.ts +34 -0
- package/src/storage/WalletStorageManager.ts +943 -0
- package/src/storage/__test/StorageIdb.test.ts +43 -0
- package/src/storage/__test/WalletStorageManager.test.ts +275 -0
- package/src/storage/__test/adminStats.man.test.ts +89 -0
- package/src/storage/__test/getBeefForTransaction.test.ts +385 -0
- package/src/storage/index.all.ts +11 -0
- package/src/storage/index.client.ts +7 -0
- package/src/storage/index.mobile.ts +6 -0
- package/src/storage/methods/ListActionsSpecOp.ts +70 -0
- package/src/storage/methods/ListOutputsSpecOp.ts +129 -0
- package/src/storage/methods/__test/GenerateChange/generateChangeSdk.test.ts +1057 -0
- package/src/storage/methods/__test/GenerateChange/randomValsUsed1.ts +20 -0
- package/src/storage/methods/__test/offsetKey.test.ts +274 -0
- package/src/storage/methods/attemptToPostReqsToNetwork.ts +389 -0
- package/src/storage/methods/createAction.ts +947 -0
- package/src/storage/methods/generateChange.ts +556 -0
- package/src/storage/methods/getBeefForTransaction.ts +139 -0
- package/src/storage/methods/getSyncChunk.ts +293 -0
- package/src/storage/methods/internalizeAction.ts +562 -0
- package/src/storage/methods/listActionsIdb.ts +183 -0
- package/src/storage/methods/listActionsKnex.ts +226 -0
- package/src/storage/methods/listCertificates.ts +73 -0
- package/src/storage/methods/listOutputsIdb.ts +203 -0
- package/src/storage/methods/listOutputsKnex.ts +263 -0
- package/src/storage/methods/offsetKey.ts +89 -0
- package/src/storage/methods/processAction.ts +420 -0
- package/src/storage/methods/purgeData.ts +251 -0
- package/src/storage/methods/purgeDataIdb.ts +10 -0
- package/src/storage/methods/reviewStatus.ts +101 -0
- package/src/storage/methods/reviewStatusIdb.ts +43 -0
- package/src/storage/methods/utils.Buffer.ts +33 -0
- package/src/storage/methods/utils.ts +56 -0
- package/src/storage/remoting/StorageClient.ts +567 -0
- package/src/storage/remoting/StorageMobile.ts +544 -0
- package/src/storage/remoting/StorageServer.ts +291 -0
- package/src/storage/remoting/__test/StorageClient.test.ts +113 -0
- package/src/storage/schema/KnexMigrations.ts +489 -0
- package/src/storage/schema/StorageIdbSchema.ts +150 -0
- package/src/storage/schema/entities/EntityBase.ts +210 -0
- package/src/storage/schema/entities/EntityCertificate.ts +188 -0
- package/src/storage/schema/entities/EntityCertificateField.ts +136 -0
- package/src/storage/schema/entities/EntityCommission.ts +148 -0
- package/src/storage/schema/entities/EntityOutput.ts +290 -0
- package/src/storage/schema/entities/EntityOutputBasket.ts +153 -0
- package/src/storage/schema/entities/EntityOutputTag.ts +121 -0
- package/src/storage/schema/entities/EntityOutputTagMap.ts +123 -0
- package/src/storage/schema/entities/EntityProvenTx.ts +319 -0
- package/src/storage/schema/entities/EntityProvenTxReq.ts +580 -0
- package/src/storage/schema/entities/EntitySyncState.ts +389 -0
- package/src/storage/schema/entities/EntityTransaction.ts +306 -0
- package/src/storage/schema/entities/EntityTxLabel.ts +121 -0
- package/src/storage/schema/entities/EntityTxLabelMap.ts +123 -0
- package/src/storage/schema/entities/EntityUser.ts +112 -0
- package/src/storage/schema/entities/MergeEntity.ts +73 -0
- package/src/storage/schema/entities/__tests/CertificateFieldTests.test.ts +353 -0
- package/src/storage/schema/entities/__tests/CertificateTests.test.ts +354 -0
- package/src/storage/schema/entities/__tests/CommissionTests.test.ts +371 -0
- package/src/storage/schema/entities/__tests/OutputBasketTests.test.ts +278 -0
- package/src/storage/schema/entities/__tests/OutputTagMapTests.test.ts +242 -0
- package/src/storage/schema/entities/__tests/OutputTagTests.test.ts +288 -0
- package/src/storage/schema/entities/__tests/OutputTests.test.ts +464 -0
- package/src/storage/schema/entities/__tests/ProvenTxReqTests.test.ts +340 -0
- package/src/storage/schema/entities/__tests/ProvenTxTests.test.ts +504 -0
- package/src/storage/schema/entities/__tests/SyncStateTests.test.ts +288 -0
- package/src/storage/schema/entities/__tests/TransactionTests.test.ts +604 -0
- package/src/storage/schema/entities/__tests/TxLabelMapTests.test.ts +361 -0
- package/src/storage/schema/entities/__tests/TxLabelTests.test.ts +198 -0
- package/src/storage/schema/entities/__tests/stampLogTests.test.ts +90 -0
- package/src/storage/schema/entities/__tests/usersTests.test.ts +340 -0
- package/src/storage/schema/entities/index.ts +16 -0
- package/src/storage/schema/tables/TableCertificate.ts +21 -0
- package/src/storage/schema/tables/TableCertificateField.ts +12 -0
- package/src/storage/schema/tables/TableCommission.ts +13 -0
- package/src/storage/schema/tables/TableMonitorEvent.ts +9 -0
- package/src/storage/schema/tables/TableOutput.ts +64 -0
- package/src/storage/schema/tables/TableOutputBasket.ts +12 -0
- package/src/storage/schema/tables/TableOutputTag.ts +10 -0
- package/src/storage/schema/tables/TableOutputTagMap.ts +9 -0
- package/src/storage/schema/tables/TableProvenTx.ts +14 -0
- package/src/storage/schema/tables/TableProvenTxReq.ts +65 -0
- package/src/storage/schema/tables/TableSettings.ts +17 -0
- package/src/storage/schema/tables/TableSyncState.ts +18 -0
- package/src/storage/schema/tables/TableTransaction.ts +54 -0
- package/src/storage/schema/tables/TableTxLabel.ts +10 -0
- package/src/storage/schema/tables/TableTxLabelMap.ts +9 -0
- package/src/storage/schema/tables/TableUser.ts +16 -0
- package/src/storage/schema/tables/index.ts +16 -0
- package/src/storage/sync/StorageMySQLDojoReader.ts +696 -0
- package/src/storage/sync/index.ts +1 -0
- package/src/utility/Format.ts +133 -0
- package/src/utility/README.md +3 -0
- package/src/utility/ReaderUint8Array.ts +187 -0
- package/src/utility/ScriptTemplateBRC29.ts +73 -0
- package/src/utility/__tests/utilityHelpers.noBuffer.test.ts +109 -0
- package/src/utility/aggregateResults.ts +68 -0
- package/src/utility/identityUtils.ts +159 -0
- package/src/utility/index.all.ts +7 -0
- package/src/utility/index.client.ts +7 -0
- package/src/utility/parseTxScriptOffsets.ts +29 -0
- package/src/utility/stampLog.ts +69 -0
- package/src/utility/tscProofToMerklePath.ts +48 -0
- package/src/utility/utilityHelpers.buffer.ts +34 -0
- package/src/utility/utilityHelpers.noBuffer.ts +60 -0
- package/src/utility/utilityHelpers.ts +275 -0
- package/src/wab-client/WABClient.ts +94 -0
- package/src/wab-client/__tests/WABClient.man.test.ts +59 -0
- package/src/wab-client/auth-method-interactors/AuthMethodInteractor.ts +47 -0
- package/src/wab-client/auth-method-interactors/DevConsoleInteractor.ts +73 -0
- package/src/wab-client/auth-method-interactors/PersonaIDInteractor.ts +35 -0
- package/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.ts +72 -0
- package/syncVersions.js +71 -0
- package/test/Wallet/StorageClient/storageClient.man.test.ts +75 -0
- package/test/Wallet/action/abortAction.test.ts +47 -0
- package/test/Wallet/action/createAction.test.ts +299 -0
- package/test/Wallet/action/createAction2.test.ts +1273 -0
- package/test/Wallet/action/createActionToGenerateBeefs.man.test.ts +293 -0
- package/test/Wallet/action/internalizeAction.a.test.ts +286 -0
- package/test/Wallet/action/internalizeAction.test.ts +682 -0
- package/test/Wallet/action/relinquishOutput.test.ts +37 -0
- package/test/Wallet/certificate/acquireCertificate.test.ts +298 -0
- package/test/Wallet/certificate/listCertificates.test.ts +346 -0
- package/test/Wallet/construct/Wallet.constructor.test.ts +57 -0
- package/test/Wallet/get/getHeaderForHeight.test.ts +82 -0
- package/test/Wallet/get/getHeight.test.ts +52 -0
- package/test/Wallet/get/getKnownTxids.test.ts +86 -0
- package/test/Wallet/get/getNetwork.test.ts +27 -0
- package/test/Wallet/get/getVersion.test.ts +27 -0
- package/test/Wallet/list/listActions.test.ts +279 -0
- package/test/Wallet/list/listActions2.test.ts +1381 -0
- package/test/Wallet/list/listCertificates.test.ts +118 -0
- package/test/Wallet/list/listOutputs.test.ts +447 -0
- package/test/Wallet/live/walletLive.man.test.ts +521 -0
- package/test/Wallet/local/localWallet.man.test.ts +93 -0
- package/test/Wallet/local/localWallet2.man.test.ts +277 -0
- package/test/Wallet/signAction/mountaintop.man.test.ts +130 -0
- package/test/Wallet/specOps/specOps.man.test.ts +220 -0
- package/test/Wallet/support/janitor.man.test.ts +40 -0
- package/test/Wallet/support/operations.man.test.ts +407 -0
- package/test/Wallet/support/reqErrorReview.2025.05.06.man.test.ts +347 -0
- package/test/Wallet/sync/Wallet.sync.test.ts +215 -0
- package/test/Wallet/sync/Wallet.updateWalletLegacyTestData.man.test.ts +203 -0
- package/test/Wallet/sync/setActive.test.ts +170 -0
- package/test/WalletClient/LocalKVStore.man.test.ts +114 -0
- package/test/WalletClient/WERR.man.test.ts +35 -0
- package/test/bsv-ts-sdk/LocalKVStore.test.ts +102 -0
- package/test/checkDB.ts +57 -0
- package/test/checkdb +0 -0
- package/test/examples/backup.man.test.ts +59 -0
- package/test/examples/pushdrop.test.ts +282 -0
- package/test/monitor/Monitor.test.ts +620 -0
- package/test/services/Services.test.ts +263 -0
- package/test/storage/KnexMigrations.test.ts +86 -0
- package/test/storage/StorageMySQLDojoReader.man.test.ts +60 -0
- package/test/storage/count.test.ts +177 -0
- package/test/storage/find.test.ts +195 -0
- package/test/storage/findLegacy.test.ts +67 -0
- package/test/storage/idb/allocateChange.test.ts +251 -0
- package/test/storage/idb/count.test.ts +158 -0
- package/test/storage/idb/find.test.ts +177 -0
- package/test/storage/idb/idbSpeed.test.ts +36 -0
- package/test/storage/idb/insert.test.ts +268 -0
- package/test/storage/idb/transactionAbort.test.ts +108 -0
- package/test/storage/idb/update.test.ts +999 -0
- package/test/storage/insert.test.ts +278 -0
- package/test/storage/update.test.ts +1021 -0
- package/test/storage/update2.test.ts +897 -0
- package/test/utils/TestUtilsWalletStorage.ts +2526 -0
- package/test/utils/localWalletMethods.ts +363 -0
- package/test/utils/removeFailedFromDatabase.sql +17 -0
- package/ts2md.json +44 -0
- package/tsconfig.all.json +31 -0
- package/tsconfig.client.json +29 -0
- package/tsconfig.json +17 -0
- package/tsconfig.mobile.json +28 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { defaultHttpClient, HttpClient } from '@bsv/sdk'
|
|
2
|
+
import { ChaintracksFetchApi } from '../Api/ChaintracksFetchApi'
|
|
3
|
+
import { wait } from '../../../../utility/utilityHelpers'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This class implements the ChaintracksFetchApi
|
|
7
|
+
* using the @bsv/sdk `defaultHttpClient`.
|
|
8
|
+
*/
|
|
9
|
+
export class ChaintracksFetch implements ChaintracksFetchApi {
|
|
10
|
+
httpClient: HttpClient = defaultHttpClient()
|
|
11
|
+
|
|
12
|
+
constructor() {}
|
|
13
|
+
|
|
14
|
+
async download(url: string): Promise<Uint8Array> {
|
|
15
|
+
for (let retry = 0; ; retry++) {
|
|
16
|
+
const response = await fetch(url, {
|
|
17
|
+
method: 'GET',
|
|
18
|
+
headers: {
|
|
19
|
+
'Content-Type': 'application/octet-stream'
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
if (response.statusText === 'Too Many Requests' && retry < 3) {
|
|
25
|
+
// WhatsOnChain rate limits requests, so backoff and retry
|
|
26
|
+
await wait(1000 * (retry + 1))
|
|
27
|
+
continue
|
|
28
|
+
}
|
|
29
|
+
throw new Error(`Failed to download from ${url}: ${response.statusText}`)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const data = await response.arrayBuffer()
|
|
33
|
+
|
|
34
|
+
return new Uint8Array(data)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async fetchJson<R>(url: string): Promise<R> {
|
|
39
|
+
const requestJsonOptions = {
|
|
40
|
+
method: 'GET',
|
|
41
|
+
headers: {
|
|
42
|
+
Accept: 'application/json'
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
let json: R
|
|
46
|
+
for (let retry = 0; ; retry++) {
|
|
47
|
+
const response = await fetch(url, requestJsonOptions)
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
if (response.statusText === 'Too Many Requests' && retry < 3) {
|
|
50
|
+
await wait(1000 * (retry + 1))
|
|
51
|
+
continue
|
|
52
|
+
}
|
|
53
|
+
throw new Error(`Failed to fetch JSON from ${url}: ${response.statusText}`)
|
|
54
|
+
}
|
|
55
|
+
json = (await response.json()) as R
|
|
56
|
+
break
|
|
57
|
+
}
|
|
58
|
+
return json
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
pathJoin(baseUrl: string, subpath: string): string {
|
|
62
|
+
// Ensure the subpath doesn't start with a slash to avoid issues
|
|
63
|
+
const cleanSubpath = subpath.replace(/^\/+/, '')
|
|
64
|
+
if (!baseUrl.endsWith('/')) baseUrl += '/'
|
|
65
|
+
// Create a new URL object and append the subpath
|
|
66
|
+
const url = new URL(cleanSubpath, baseUrl)
|
|
67
|
+
return url.toString()
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ChaintracksAppendableFileApi,
|
|
3
|
+
ChaintracksFsApi,
|
|
4
|
+
ChaintracksReadableFileApi,
|
|
5
|
+
ChaintracksWritableFileApi
|
|
6
|
+
} from '../Api/ChaintracksFsApi'
|
|
7
|
+
import { promises as fs } from 'fs'
|
|
8
|
+
import Path from 'path'
|
|
9
|
+
|
|
10
|
+
export abstract class ChaintracksFsStatics {
|
|
11
|
+
static async delete(path: string): Promise<void> {
|
|
12
|
+
await fs.unlink(path)
|
|
13
|
+
}
|
|
14
|
+
static async writeFile(path: string, data: Uint8Array): Promise<void> {
|
|
15
|
+
await this.ensureFoldersExist(path)
|
|
16
|
+
await fs.writeFile(path, Buffer.from(data))
|
|
17
|
+
}
|
|
18
|
+
static async readFile(path: string): Promise<Uint8Array> {
|
|
19
|
+
const buffer = await fs.readFile(path)
|
|
20
|
+
return Uint8Array.from(buffer)
|
|
21
|
+
}
|
|
22
|
+
static async openReadableFile(path: string): Promise<ChaintracksReadableFileApi> {
|
|
23
|
+
return await ChaintracksReadableFile.openAsReadable(path)
|
|
24
|
+
}
|
|
25
|
+
static async openWritableFile(path: string): Promise<ChaintracksWritableFileApi> {
|
|
26
|
+
return await ChaintracksWritableFile.openAsWritable(path)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
static async openAppendableFile(path: string): Promise<ChaintracksAppendableFileApi> {
|
|
30
|
+
return await ChaintracksAppendableFile.openAsAppendable(path)
|
|
31
|
+
}
|
|
32
|
+
static async ensureFoldersExist(path: string): Promise<void> {
|
|
33
|
+
const parsedPath = Path.parse(path)
|
|
34
|
+
await fs.mkdir(parsedPath.dir, { recursive: true })
|
|
35
|
+
}
|
|
36
|
+
static pathJoin(...parts: string[]): string {
|
|
37
|
+
return Path.join(...parts)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* This object is an implementation of the `ChaintracksFsApi` interface
|
|
43
|
+
* using the `fs` package which may not be available in all environments.
|
|
44
|
+
*/
|
|
45
|
+
export const ChaintracksFs: ChaintracksFsApi = ChaintracksFsStatics
|
|
46
|
+
|
|
47
|
+
export class ChaintracksReadableFile implements ChaintracksReadableFileApi {
|
|
48
|
+
path: string
|
|
49
|
+
parsedPath: Path.ParsedPath
|
|
50
|
+
f: fs.FileHandle
|
|
51
|
+
|
|
52
|
+
protected constructor(path: string, f: fs.FileHandle) {
|
|
53
|
+
this.path = path
|
|
54
|
+
this.f = f
|
|
55
|
+
this.parsedPath = Path.parse(path)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async close(): Promise<void> {
|
|
59
|
+
await this.f.close()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async getLength(): Promise<number> {
|
|
63
|
+
const stats = await this.f.stat()
|
|
64
|
+
return stats.size
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async read(length?: number, offset?: number): Promise<Uint8Array> {
|
|
68
|
+
length ||= 80 * 1024 // Default to 80KB if no length is specified
|
|
69
|
+
const buffer = Buffer.alloc(length)
|
|
70
|
+
const rr = await this.f.read(buffer, 0, length, offset || 0)
|
|
71
|
+
const rb = rr.bytesRead < length ? buffer.subarray(0, rr.bytesRead) : buffer
|
|
72
|
+
return Uint8Array.from(rb)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static async openAsReadable(path: string): Promise<ChaintracksReadableFile> {
|
|
76
|
+
const f = await fs.open(path, 'r')
|
|
77
|
+
const file = new ChaintracksReadableFile(path, f)
|
|
78
|
+
return file
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export class ChaintracksWritableFile implements ChaintracksWritableFileApi {
|
|
83
|
+
path: string
|
|
84
|
+
parsedPath: Path.ParsedPath
|
|
85
|
+
f: fs.FileHandle
|
|
86
|
+
foldersEnsured: boolean = false
|
|
87
|
+
|
|
88
|
+
private constructor(path: string, f: fs.FileHandle) {
|
|
89
|
+
this.path = path
|
|
90
|
+
this.f = f
|
|
91
|
+
this.parsedPath = Path.parse(path)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
static async openAsWritable(path: string): Promise<ChaintracksWritableFile> {
|
|
95
|
+
const f = await fs.open(path, 'w')
|
|
96
|
+
const file = new ChaintracksWritableFile(path, f)
|
|
97
|
+
return file
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async close(): Promise<void> {
|
|
101
|
+
await this.f.close()
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async ensureFoldersExist(): Promise<void> {
|
|
105
|
+
if (!this.foldersEnsured) {
|
|
106
|
+
await ChaintracksFsStatics.ensureFoldersExist(this.path)
|
|
107
|
+
this.foldersEnsured = true
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async append(data: Uint8Array): Promise<void> {
|
|
112
|
+
await this.ensureFoldersExist()
|
|
113
|
+
throw new Error('Method not implemented.')
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export class ChaintracksAppendableFile extends ChaintracksReadableFile implements ChaintracksAppendableFileApi {
|
|
118
|
+
foldersEnsured: boolean = false
|
|
119
|
+
|
|
120
|
+
private constructor(path: string, f: fs.FileHandle) {
|
|
121
|
+
super(path, f)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
static async openAsAppendable(path: string): Promise<ChaintracksAppendableFile> {
|
|
125
|
+
const f = await fs.open(path, 'a+')
|
|
126
|
+
const file = new ChaintracksAppendableFile(path, f)
|
|
127
|
+
return file
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async ensureFoldersExist(): Promise<void> {
|
|
131
|
+
if (!this.foldersEnsured) {
|
|
132
|
+
await ChaintracksFsStatics.ensureFoldersExist(this.path)
|
|
133
|
+
this.foldersEnsured = true
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async append(data: Uint8Array): Promise<void> {
|
|
138
|
+
await this.ensureFoldersExist()
|
|
139
|
+
await this.f.write(Buffer.from(data))
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { BlockHeader } from '../../../../sdk/WalletServices.interfaces'
|
|
2
|
+
|
|
3
|
+
export interface HeightRangeApi {
|
|
4
|
+
minHeight: number
|
|
5
|
+
maxHeight: number
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface HeightRanges {
|
|
9
|
+
bulk: HeightRange
|
|
10
|
+
live: HeightRange
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Represents a range of block heights.
|
|
15
|
+
*
|
|
16
|
+
* Operations support integrating contiguous batches of headers,
|
|
17
|
+
*/
|
|
18
|
+
export class HeightRange implements HeightRangeApi {
|
|
19
|
+
constructor(
|
|
20
|
+
public minHeight: number,
|
|
21
|
+
public maxHeight: number
|
|
22
|
+
) {}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* All ranges where maxHeight is less than minHeight are considered empty.
|
|
26
|
+
* The canonical empty range is (0, -1).
|
|
27
|
+
*/
|
|
28
|
+
static readonly empty = new HeightRange(0, -1)
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @returns true iff minHeight is greater than maxHeight.
|
|
32
|
+
*/
|
|
33
|
+
get isEmpty() {
|
|
34
|
+
return this.minHeight > this.maxHeight
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param headers an array of objects with a non-negative integer `height` property.
|
|
39
|
+
* @returns range of height values from the given headers, or the empty range if there are no headers.
|
|
40
|
+
*/
|
|
41
|
+
static from(headers: BlockHeader[]): HeightRange {
|
|
42
|
+
if (headers.length === 0) return HeightRange.empty
|
|
43
|
+
const minHeight = headers.reduce((min, h) => Math.min(min, h.height), headers[0].height)
|
|
44
|
+
const maxHeight = headers.reduce((max, h) => Math.max(max, h.height), headers[0].height)
|
|
45
|
+
return new HeightRange(minHeight, maxHeight)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @returns the number of heights in the range, or 0 if the range is empty.
|
|
50
|
+
*/
|
|
51
|
+
get length() {
|
|
52
|
+
return Math.max(0, this.maxHeight - this.minHeight + 1)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @returns an easy to read string representation of the height range.
|
|
57
|
+
*/
|
|
58
|
+
toString(): string {
|
|
59
|
+
return this.isEmpty ? '<empty>' : `${this.minHeight}-${this.maxHeight}`
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @param range HeightRange or single height value.
|
|
64
|
+
* @returns true if `range` is entirely within this range.
|
|
65
|
+
*/
|
|
66
|
+
contains(range: HeightRange | number) {
|
|
67
|
+
if (typeof range === 'number') {
|
|
68
|
+
return this.minHeight <= range && this.maxHeight >= range
|
|
69
|
+
}
|
|
70
|
+
return this.minHeight <= range.minHeight && this.maxHeight >= range.maxHeight
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Return the intersection with another height range.
|
|
75
|
+
*
|
|
76
|
+
* Intersection with an empty range is always empty.
|
|
77
|
+
*
|
|
78
|
+
* The result is always a single, possibly empty, range.
|
|
79
|
+
* @param range
|
|
80
|
+
* @returns
|
|
81
|
+
*/
|
|
82
|
+
intersect(range: HeightRange) {
|
|
83
|
+
//if (this.isEmpty || range.isEmpty) return HeightRange.empty
|
|
84
|
+
//if (this.maxHeight < range.minHeight || this.minHeight > range.maxHeight) return HeightRange.empty
|
|
85
|
+
const r = new HeightRange(Math.max(this.minHeight, range.minHeight), Math.min(this.maxHeight, range.maxHeight))
|
|
86
|
+
return r
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Return the union with another height range.
|
|
91
|
+
*
|
|
92
|
+
* Only valid if the two ranges overlap or touch, or one is empty.
|
|
93
|
+
*
|
|
94
|
+
* Throws an error if the union would create two disjoint ranges.
|
|
95
|
+
*
|
|
96
|
+
* @param range
|
|
97
|
+
* @returns
|
|
98
|
+
*/
|
|
99
|
+
union(range: HeightRange) {
|
|
100
|
+
if (this.isEmpty) return range.copy()
|
|
101
|
+
if (range.isEmpty) return this.copy()
|
|
102
|
+
if (this.maxHeight + 1 < range.minHeight || range.maxHeight + 1 < this.minHeight)
|
|
103
|
+
throw new Error('Union of ranges with a gap between them is not supported.')
|
|
104
|
+
return new HeightRange(Math.min(this.minHeight, range.minHeight), Math.max(this.maxHeight, range.maxHeight))
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Returns `range` subtracted from this range.
|
|
109
|
+
*
|
|
110
|
+
* Throws an error if the subtraction would create two disjoint ranges.
|
|
111
|
+
*
|
|
112
|
+
* @param range
|
|
113
|
+
* @returns
|
|
114
|
+
*/
|
|
115
|
+
subtract(range: HeightRange) {
|
|
116
|
+
if (this.isEmpty || range.isEmpty) return this.copy()
|
|
117
|
+
if (this.minHeight < range.minHeight && this.maxHeight > range.maxHeight)
|
|
118
|
+
throw new Error('Subtraction of range that creates two disjoint ranges is not supported.')
|
|
119
|
+
if (range.maxHeight < this.minHeight || range.minHeight > this.maxHeight)
|
|
120
|
+
// Leave untouched. Subtracted is either all lower or all higher.
|
|
121
|
+
return this.copy()
|
|
122
|
+
if (range.minHeight <= this.minHeight && range.maxHeight < this.maxHeight)
|
|
123
|
+
// Remove a chunk on the low side.
|
|
124
|
+
return new HeightRange(range.maxHeight + 1, this.maxHeight)
|
|
125
|
+
if (range.minHeight <= this.minHeight && range.maxHeight >= this.maxHeight)
|
|
126
|
+
// Remove the whole thing
|
|
127
|
+
return new HeightRange(this.minHeight, this.minHeight - 1) // empty
|
|
128
|
+
if (range.minHeight <= this.maxHeight && range.maxHeight >= this.maxHeight)
|
|
129
|
+
// Remove a chunk on the high side.
|
|
130
|
+
return new HeightRange(this.minHeight, range.minHeight - 1)
|
|
131
|
+
throw new Error('All cases should have been handled :-) .')
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* If `range` is not empty and this is not empty, returns a new range minHeight
|
|
136
|
+
* replaced by to range.maxHeight + 1.
|
|
137
|
+
*
|
|
138
|
+
* Otherwise returns a copy of this range.
|
|
139
|
+
*
|
|
140
|
+
* This returns the portion of this range that is strictly above `range`.
|
|
141
|
+
*/
|
|
142
|
+
above(range: HeightRange) {
|
|
143
|
+
if (range.isEmpty || this.isEmpty) return this.copy()
|
|
144
|
+
return new HeightRange(range.maxHeight + 1, this.maxHeight)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Return a copy of this range.
|
|
149
|
+
*/
|
|
150
|
+
copy(): HeightRange {
|
|
151
|
+
return new HeightRange(this.minHeight, this.maxHeight)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A reader-writer lock to manage concurrent access.
|
|
3
|
+
* Allows multiple readers or one writer at a time.
|
|
4
|
+
*/
|
|
5
|
+
export class SingleWriterMultiReaderLock {
|
|
6
|
+
private readers: number = 0
|
|
7
|
+
private writerActive: boolean = false
|
|
8
|
+
private readerQueue: Array<() => void> = []
|
|
9
|
+
private writerQueue: Array<() => void> = []
|
|
10
|
+
|
|
11
|
+
private checkQueues(): void {
|
|
12
|
+
if (this.writerActive || this.readers > 0) return
|
|
13
|
+
if (this.writerQueue.length > 0) {
|
|
14
|
+
// If there are waiting writers and no active readers or writers, start the next writer
|
|
15
|
+
const resolve = this.writerQueue.shift()!
|
|
16
|
+
resolve()
|
|
17
|
+
} else if (this.readerQueue.length > 0) {
|
|
18
|
+
// If there are waiting readers and no waiting writers, start all readers
|
|
19
|
+
const readers = this.readerQueue.splice(0)
|
|
20
|
+
for (const resolve of readers) {
|
|
21
|
+
resolve()
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async withReadLock<T>(fn: () => Promise<T>): Promise<T> {
|
|
27
|
+
if (!this.writerActive && this.writerQueue.length === 0) {
|
|
28
|
+
// Fast path: no active writer or waiting writers, proceed immediately
|
|
29
|
+
this.readers++
|
|
30
|
+
try {
|
|
31
|
+
return await fn()
|
|
32
|
+
} finally {
|
|
33
|
+
this.readers--
|
|
34
|
+
this.checkQueues()
|
|
35
|
+
}
|
|
36
|
+
} else {
|
|
37
|
+
// Queue the reader until writers are done
|
|
38
|
+
const promise = new Promise<void>(resolve => {
|
|
39
|
+
this.readerQueue.push(resolve)
|
|
40
|
+
})
|
|
41
|
+
await promise
|
|
42
|
+
this.readers++
|
|
43
|
+
try {
|
|
44
|
+
return await fn()
|
|
45
|
+
} finally {
|
|
46
|
+
this.readers--
|
|
47
|
+
this.checkQueues()
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async withWriteLock<T>(fn: () => Promise<T>): Promise<T> {
|
|
53
|
+
if (!this.writerActive && this.readers === 0) {
|
|
54
|
+
// Fast path: no active writer or readers, proceed immediately
|
|
55
|
+
this.writerActive = true
|
|
56
|
+
try {
|
|
57
|
+
return await fn()
|
|
58
|
+
} finally {
|
|
59
|
+
this.writerActive = false
|
|
60
|
+
this.checkQueues()
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
const promise = new Promise<void>(resolve => {
|
|
64
|
+
this.writerQueue.push(resolve)
|
|
65
|
+
})
|
|
66
|
+
await promise
|
|
67
|
+
this.writerActive = true
|
|
68
|
+
try {
|
|
69
|
+
return await fn()
|
|
70
|
+
} finally {
|
|
71
|
+
this.writerActive = false
|
|
72
|
+
this.checkQueues()
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|