@bsv/wallet-toolbox-mobile 2.4.2 → 2.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/out/src/CWIStyleWalletManager.d.ts +52 -5
  2. package/out/src/CWIStyleWalletManager.d.ts.map +1 -1
  3. package/out/src/CWIStyleWalletManager.js +500 -128
  4. package/out/src/CWIStyleWalletManager.js.map +1 -1
  5. package/out/src/Wallet.d.ts +8 -0
  6. package/out/src/Wallet.d.ts.map +1 -1
  7. package/out/src/Wallet.js +23 -9
  8. package/out/src/Wallet.js.map +1 -1
  9. package/out/src/WalletAuthenticationManager.d.ts +20 -6
  10. package/out/src/WalletAuthenticationManager.d.ts.map +1 -1
  11. package/out/src/WalletAuthenticationManager.js +214 -34
  12. package/out/src/WalletAuthenticationManager.js.map +1 -1
  13. package/out/src/WalletPermissionsManager.d.ts +15 -0
  14. package/out/src/WalletPermissionsManager.d.ts.map +1 -1
  15. package/out/src/WalletPermissionsManager.js +76 -28
  16. package/out/src/WalletPermissionsManager.js.map +1 -1
  17. package/out/src/index.mobile.d.ts +1 -0
  18. package/out/src/index.mobile.d.ts.map +1 -1
  19. package/out/src/index.mobile.js +1 -0
  20. package/out/src/index.mobile.js.map +1 -1
  21. package/out/src/monitor/Monitor.d.ts.map +1 -1
  22. package/out/src/monitor/Monitor.js +4 -3
  23. package/out/src/monitor/Monitor.js.map +1 -1
  24. package/out/src/monitor/tasks/TaskCleanupActionBatches.d.ts +13 -0
  25. package/out/src/monitor/tasks/TaskCleanupActionBatches.d.ts.map +1 -0
  26. package/out/src/monitor/tasks/TaskCleanupActionBatches.js +24 -0
  27. package/out/src/monitor/tasks/TaskCleanupActionBatches.js.map +1 -0
  28. package/out/src/sdk/ActionBatch.interfaces.d.ts +105 -0
  29. package/out/src/sdk/ActionBatch.interfaces.d.ts.map +1 -0
  30. package/out/src/sdk/ActionBatch.interfaces.js +3 -0
  31. package/out/src/sdk/ActionBatch.interfaces.js.map +1 -0
  32. package/out/src/sdk/WalletStorage.interfaces.d.ts +18 -1
  33. package/out/src/sdk/WalletStorage.interfaces.d.ts.map +1 -1
  34. package/out/src/sdk/index.d.ts +1 -0
  35. package/out/src/sdk/index.d.ts.map +1 -1
  36. package/out/src/sdk/index.js +1 -0
  37. package/out/src/sdk/index.js.map +1 -1
  38. package/out/src/signer/actionBatch/ActionBatchPlanner.d.ts +28 -0
  39. package/out/src/signer/actionBatch/ActionBatchPlanner.d.ts.map +1 -0
  40. package/out/src/signer/actionBatch/ActionBatchPlanner.js +313 -0
  41. package/out/src/signer/actionBatch/ActionBatchPlanner.js.map +1 -0
  42. package/out/src/signer/actionBatch/ActionBatchWorkspace.d.ts +33 -0
  43. package/out/src/signer/actionBatch/ActionBatchWorkspace.d.ts.map +1 -0
  44. package/out/src/signer/actionBatch/ActionBatchWorkspace.js +693 -0
  45. package/out/src/signer/actionBatch/ActionBatchWorkspace.js.map +1 -0
  46. package/out/src/signer/methods/buildSignableTransaction.d.ts.map +1 -1
  47. package/out/src/signer/methods/buildSignableTransaction.js +2 -1
  48. package/out/src/signer/methods/buildSignableTransaction.js.map +1 -1
  49. package/out/src/signer/methods/createAction.d.ts.map +1 -1
  50. package/out/src/signer/methods/createAction.js +4 -1
  51. package/out/src/signer/methods/createAction.js.map +1 -1
  52. package/out/src/storage/StorageProvider.d.ts +28 -0
  53. package/out/src/storage/StorageProvider.d.ts.map +1 -1
  54. package/out/src/storage/StorageProvider.js +49 -0
  55. package/out/src/storage/StorageProvider.js.map +1 -1
  56. package/out/src/storage/WalletStorageManager.d.ts +8 -0
  57. package/out/src/storage/WalletStorageManager.d.ts.map +1 -1
  58. package/out/src/storage/WalletStorageManager.js +24 -0
  59. package/out/src/storage/WalletStorageManager.js.map +1 -1
  60. package/out/src/storage/methods/actionBatch.d.ts +14 -0
  61. package/out/src/storage/methods/actionBatch.d.ts.map +1 -0
  62. package/out/src/storage/methods/actionBatch.js +644 -0
  63. package/out/src/storage/methods/actionBatch.js.map +1 -0
  64. package/out/src/storage/methods/actionBatchBlobs.d.ts +12 -0
  65. package/out/src/storage/methods/actionBatchBlobs.d.ts.map +1 -0
  66. package/out/src/storage/methods/actionBatchBlobs.js +121 -0
  67. package/out/src/storage/methods/actionBatchBlobs.js.map +1 -0
  68. package/out/src/storage/methods/actionBatchValidation.d.ts +15 -0
  69. package/out/src/storage/methods/actionBatchValidation.d.ts.map +1 -0
  70. package/out/src/storage/methods/actionBatchValidation.js +310 -0
  71. package/out/src/storage/methods/actionBatchValidation.js.map +1 -0
  72. package/out/src/storage/methods/actionPlanning.d.ts +12 -0
  73. package/out/src/storage/methods/actionPlanning.d.ts.map +1 -0
  74. package/out/src/storage/methods/actionPlanning.js +48 -0
  75. package/out/src/storage/methods/actionPlanning.js.map +1 -0
  76. package/out/src/storage/methods/createAction.d.ts.map +1 -1
  77. package/out/src/storage/methods/createAction.js +9 -25
  78. package/out/src/storage/methods/createAction.js.map +1 -1
  79. package/out/src/storage/remoting/StorageClientBase.d.ts +9 -0
  80. package/out/src/storage/remoting/StorageClientBase.d.ts.map +1 -1
  81. package/out/src/storage/remoting/StorageClientBase.js +36 -1
  82. package/out/src/storage/remoting/StorageClientBase.js.map +1 -1
  83. package/out/src/storage/schema/tables/TableActionBatch.d.ts +24 -0
  84. package/out/src/storage/schema/tables/TableActionBatch.d.ts.map +1 -0
  85. package/out/src/storage/schema/tables/TableActionBatch.js +3 -0
  86. package/out/src/storage/schema/tables/TableActionBatch.js.map +1 -0
  87. package/out/src/storage/schema/tables/index.d.ts +1 -0
  88. package/out/src/storage/schema/tables/index.d.ts.map +1 -1
  89. package/out/src/storage/schema/tables/index.js +1 -0
  90. package/out/src/storage/schema/tables/index.js.map +1 -1
  91. package/out/src/utility/actionBatchDigest.d.ts +9 -0
  92. package/out/src/utility/actionBatchDigest.d.ts.map +1 -0
  93. package/out/src/utility/actionBatchDigest.js +48 -0
  94. package/out/src/utility/actionBatchDigest.js.map +1 -0
  95. package/out/src/utility/beefForTxids.d.ts +9 -0
  96. package/out/src/utility/beefForTxids.d.ts.map +1 -0
  97. package/out/src/utility/beefForTxids.js +35 -0
  98. package/out/src/utility/beefForTxids.js.map +1 -0
  99. package/out/src/wab-client/WABClient.d.ts +36 -90
  100. package/out/src/wab-client/WABClient.d.ts.map +1 -1
  101. package/out/src/wab-client/WABClient.js +103 -151
  102. package/out/src/wab-client/WABClient.js.map +1 -1
  103. package/out/src/wab-client/WABTransport.d.ts +53 -0
  104. package/out/src/wab-client/WABTransport.d.ts.map +1 -0
  105. package/out/src/wab-client/WABTransport.js +300 -0
  106. package/out/src/wab-client/WABTransport.js.map +1 -0
  107. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.d.ts +10 -10
  108. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.d.ts.map +1 -1
  109. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.js +16 -21
  110. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.js.map +1 -1
  111. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.d.ts +2 -1
  112. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.d.ts.map +1 -1
  113. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.js +14 -0
  114. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.js.map +1 -1
  115. package/package.json +8 -3
@@ -91,6 +91,14 @@ class WalletPermissionsManager {
91
91
  /** Cache recently confirmed permissions to avoid repeated lookups. */
92
92
  permissionCache = new Map();
93
93
  recentGrants = new Map();
94
+ /**
95
+ * Token mints currently being written on-chain, keyed by permission cache
96
+ * key. A granted permission is only cached once its token finishes minting
97
+ * (network seconds); ensures arriving in that window await the in-flight
98
+ * mint instead of re-prompting the user for a permission they just granted.
99
+ * Stored promises never reject.
100
+ */
101
+ mintsInFlight = new Map();
94
102
  manifestCache = new Map();
95
103
  manifestFetchInProgress = new Map();
96
104
  static MANIFEST_CACHE_TTL_MS = 5 * 60 * 1000;
@@ -391,26 +399,45 @@ class WalletPermissionsManager {
391
399
  }
392
400
  this.activeRequests.delete(params.requestID);
393
401
  // 3) If `ephemeral !== true`, we create or renew an on-chain token
394
- if (!params.ephemeral) {
395
- const request = matching.request;
396
- if (request.renewal) {
397
- // renewal => spend the old token, produce a new one
398
- await this.renewPermissionOnChain(request.previousToken, request, params.expiry || 0, // default: never expires
399
- params.amount);
400
- }
401
- else {
402
- // brand-new permission token
403
- await this.createPermissionOnChain(request, params.expiry || 0, // default: never expires
404
- params.amount);
405
- }
406
- }
407
402
  // Only cache non-ephemeral permissions
408
403
  // Ephemeral permissions should not be cached as they are one-time authorizations
409
404
  if (!params.ephemeral) {
405
+ const request = matching.request;
410
406
  const expiry = params.expiry || 0; // default: never expires
411
- const key = this.buildRequestKey(matching.request);
407
+ const key = this.buildRequestKey(request);
408
+ // Several first-contact prompts for the same permission can stack up
409
+ // before any token exists (e.g. one per usage type). Granting them all
410
+ // should yield ONE token: if an identical non-renewal grant just minted
411
+ // (or is minting), don't mint a duplicate. Spending authorizations are
412
+ // excluded — their tokens carry amounts, so every grant is honored.
413
+ let skipDuplicateMint = !request.renewal &&
414
+ request.type !== 'spending' &&
415
+ (this.isPermissionCached(key) || this.isRecentlyGranted(key) || this.mintsInFlight.has(key));
416
+ if (skipDuplicateMint) {
417
+ const inFlight = this.mintsInFlight.get(key);
418
+ if (inFlight != null) {
419
+ await inFlight;
420
+ // The awaited mint may have failed; only skip if it landed.
421
+ skipDuplicateMint = this.isPermissionCached(key) || this.isRecentlyGranted(key);
422
+ }
423
+ }
424
+ if (!skipDuplicateMint) {
425
+ const mint = request.renewal
426
+ ? this.renewPermissionOnChain(request.previousToken, request, expiry, params.amount)
427
+ : this.createPermissionOnChain(request, expiry, params.amount);
428
+ // Publish the in-flight mint so concurrent ensures for the same
429
+ // permission wait for it instead of re-prompting (stored promise
430
+ // never rejects; failures still propagate to this caller below).
431
+ this.mintsInFlight.set(key, mint.then(() => { }, () => { }));
432
+ try {
433
+ await mint;
434
+ }
435
+ finally {
436
+ this.mintsInFlight.delete(key);
437
+ }
438
+ }
412
439
  this.cachePermission(key, expiry);
413
- this.markRecentGrant(matching.request);
440
+ this.markRecentGrant(request);
414
441
  }
415
442
  }
416
443
  /**
@@ -426,8 +453,12 @@ class WalletPermissionsManager {
426
453
  throw new Error('Request ID not found.');
427
454
  }
428
455
  // 2) Reject all matching requests, deleting the entry
456
+ // Denials carry the canonical machine-readable code so applications can
457
+ // distinguish user denial from other failures (matches denyActiveRequest).
458
+ const err = new Error('Permission denied.');
459
+ err.code = 'ERR_PERMISSION_DENIED';
429
460
  for (const x of matching.pending) {
430
- x.reject(new Error('Permission denied.'));
461
+ x.reject(err);
431
462
  }
432
463
  this.activeRequests.delete(requestID);
433
464
  }
@@ -673,7 +704,7 @@ class WalletPermissionsManager {
673
704
  if (!privileged && this.isWhitelistedCounterpartyProtocol(counterparty, protocolID))
674
705
  return true;
675
706
  const cacheKey = this.buildRequestKey({ type: 'protocol', originator, privileged, protocolID, counterparty });
676
- if (this.isPermissionCached(cacheKey) || this.isRecentlyGranted(cacheKey))
707
+ if (await this.hasRecentOrPendingGrant(cacheKey))
677
708
  return true;
678
709
  // 4) Attempt to find a valid token in the internal basket
679
710
  const token = await this.findProtocolToken(originator, privileged, protocolID, counterparty, /* includeExpired= */ true, lookupValues);
@@ -713,7 +744,7 @@ class WalletPermissionsManager {
713
744
  if (!this.isBasketUsageRequired(usageType))
714
745
  return true;
715
746
  const cacheKey = this.buildRequestKey({ type: 'basket', originator, basket });
716
- if (this.isPermissionCached(cacheKey) || this.isRecentlyGranted(cacheKey))
747
+ if (await this.hasRecentOrPendingGrant(cacheKey))
717
748
  return true;
718
749
  const token = await this.findBasketToken(originator, basket, true, lookupValues);
719
750
  if (token == null) {
@@ -762,10 +793,7 @@ class WalletPermissionsManager {
762
793
  privileged,
763
794
  certificate: { verifier, certType, fields }
764
795
  });
765
- if (this.isPermissionCached(cacheKey)) {
766
- return true;
767
- }
768
- if (this.isRecentlyGranted(cacheKey)) {
796
+ if (await this.hasRecentOrPendingGrant(cacheKey)) {
769
797
  return true;
770
798
  }
771
799
  const token = await this.findCertificateToken(originator, privileged, verifier, certType, fields,
@@ -816,7 +844,10 @@ class WalletPermissionsManager {
816
844
  return true;
817
845
  }
818
846
  const cacheKey = this.buildRequestKey({ type: 'spending', originator, spending: { satoshis } });
819
- if (this.isPermissionCached(cacheKey)) {
847
+ // Spending keys are amount-scoped. The recent-grant window this adds sits
848
+ // inside the pre-existing permissionCache window grantPermission already
849
+ // wrote for spending, so accounting exposure is unchanged.
850
+ if (await this.hasRecentOrPendingGrant(cacheKey)) {
820
851
  return true;
821
852
  }
822
853
  const token = await this.findSpendingToken(originator, lookupValues);
@@ -1025,11 +1056,13 @@ class WalletPermissionsManager {
1025
1056
  (async () => {
1026
1057
  if (groupPermissions.spendingAuthorization == null)
1027
1058
  return undefined;
1028
- const hasAuth = await this.hasSpendingAuthorization({
1029
- originator,
1030
- satoshis: groupPermissions.spendingAuthorization.amount
1031
- });
1032
- return hasAuth ? undefined : groupPermissions.spendingAuthorization;
1059
+ // A standing authorization is a grant regardless of how much of the
1060
+ // monthly allowance has been used — exhaustion is handled by renewal
1061
+ // at spend time. Checking remaining headroom here re-requests (and,
1062
+ // if approved, re-mints) spending after any monthly usage.
1063
+ const { normalized, lookupValues } = this.prepareOriginator(originator);
1064
+ const token = await this.findSpendingToken(normalized, lookupValues);
1065
+ return token != null ? undefined : groupPermissions.spendingAuthorization;
1033
1066
  })(),
1034
1067
  (async () => {
1035
1068
  const protocolChecks = await Promise.all((groupPermissions.protocolPermissions || []).map(async (p) => {
@@ -3553,6 +3586,21 @@ class WalletPermissionsManager {
3553
3586
  return true;
3554
3587
  return false;
3555
3588
  }
3589
+ /**
3590
+ * Whether the permission is satisfied without consulting on-chain tokens:
3591
+ * cached, recently granted, or — when the user just granted it and its
3592
+ * token is still minting — after the in-flight mint settles. Spares the
3593
+ * user a duplicate prompt for a grant they already made moments ago.
3594
+ */
3595
+ async hasRecentOrPendingGrant(cacheKey) {
3596
+ if (this.isPermissionCached(cacheKey) || this.isRecentlyGranted(cacheKey))
3597
+ return true;
3598
+ const inFlight = this.mintsInFlight.get(cacheKey);
3599
+ if (inFlight == null)
3600
+ return false;
3601
+ await inFlight;
3602
+ return this.isPermissionCached(cacheKey) || this.isRecentlyGranted(cacheKey);
3603
+ }
3556
3604
  /**
3557
3605
  * Returns true if we have a cached record that the permission identified by
3558
3606
  * `key` is valid and unexpired.