@bsv/wallet-toolbox 1.1.23 → 1.1.25

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 (201) hide show
  1. package/docs/client.md +2404 -870
  2. package/docs/setup.md +102 -134
  3. package/docs/wallet.md +2404 -870
  4. package/out/src/CWIStyleWalletManager.d.ts +411 -0
  5. package/out/src/CWIStyleWalletManager.d.ts.map +1 -0
  6. package/out/src/CWIStyleWalletManager.js +1131 -0
  7. package/out/src/CWIStyleWalletManager.js.map +1 -0
  8. package/out/src/Setup.d.ts +252 -8
  9. package/out/src/Setup.d.ts.map +1 -1
  10. package/out/src/Setup.js +299 -5
  11. package/out/src/Setup.js.map +1 -1
  12. package/out/src/SetupClient.d.ts +2 -16
  13. package/out/src/SetupClient.d.ts.map +1 -1
  14. package/out/src/SetupClient.js +8 -72
  15. package/out/src/SetupClient.js.map +1 -1
  16. package/out/src/SimpleWalletManager.d.ts +169 -0
  17. package/out/src/SimpleWalletManager.d.ts.map +1 -0
  18. package/out/src/SimpleWalletManager.js +315 -0
  19. package/out/src/SimpleWalletManager.js.map +1 -0
  20. package/out/src/Wallet.d.ts +6 -1
  21. package/out/src/Wallet.d.ts.map +1 -1
  22. package/out/src/Wallet.js +29 -2
  23. package/out/src/Wallet.js.map +1 -1
  24. package/out/src/WalletAuthenticationManager.d.ts +33 -0
  25. package/out/src/WalletAuthenticationManager.d.ts.map +1 -0
  26. package/out/src/WalletAuthenticationManager.js +107 -0
  27. package/out/src/WalletAuthenticationManager.js.map +1 -0
  28. package/out/src/WalletPermissionsManager.d.ts +575 -0
  29. package/out/src/WalletPermissionsManager.d.ts.map +1 -0
  30. package/out/src/WalletPermissionsManager.js +1807 -0
  31. package/out/src/WalletPermissionsManager.js.map +1 -0
  32. package/out/src/WalletSettingsManager.d.ts +59 -0
  33. package/out/src/WalletSettingsManager.d.ts.map +1 -0
  34. package/out/src/WalletSettingsManager.js +168 -0
  35. package/out/src/WalletSettingsManager.js.map +1 -0
  36. package/out/src/__tests/CWIStyleWalletManager.test.d.ts +2 -0
  37. package/out/src/__tests/CWIStyleWalletManager.test.d.ts.map +1 -0
  38. package/out/src/__tests/CWIStyleWalletManager.test.js +472 -0
  39. package/out/src/__tests/CWIStyleWalletManager.test.js.map +1 -0
  40. package/out/src/__tests/WalletPermissionsManager.callbacks.test.d.ts +2 -0
  41. package/out/src/__tests/WalletPermissionsManager.callbacks.test.d.ts.map +1 -0
  42. package/out/src/__tests/WalletPermissionsManager.callbacks.test.js +239 -0
  43. package/out/src/__tests/WalletPermissionsManager.callbacks.test.js.map +1 -0
  44. package/out/src/__tests/WalletPermissionsManager.checks.test.d.ts +2 -0
  45. package/out/src/__tests/WalletPermissionsManager.checks.test.d.ts.map +1 -0
  46. package/out/src/__tests/WalletPermissionsManager.checks.test.js +644 -0
  47. package/out/src/__tests/WalletPermissionsManager.checks.test.js.map +1 -0
  48. package/out/src/__tests/WalletPermissionsManager.encryption.test.d.ts +2 -0
  49. package/out/src/__tests/WalletPermissionsManager.encryption.test.d.ts.map +1 -0
  50. package/out/src/__tests/WalletPermissionsManager.encryption.test.js +295 -0
  51. package/out/src/__tests/WalletPermissionsManager.encryption.test.js.map +1 -0
  52. package/out/src/__tests/WalletPermissionsManager.fixtures.d.ts +82 -0
  53. package/out/src/__tests/WalletPermissionsManager.fixtures.d.ts.map +1 -0
  54. package/out/src/__tests/WalletPermissionsManager.fixtures.js +260 -0
  55. package/out/src/__tests/WalletPermissionsManager.fixtures.js.map +1 -0
  56. package/out/src/__tests/WalletPermissionsManager.flows.test.d.ts +2 -0
  57. package/out/src/__tests/WalletPermissionsManager.flows.test.d.ts.map +1 -0
  58. package/out/src/__tests/WalletPermissionsManager.flows.test.js +389 -0
  59. package/out/src/__tests/WalletPermissionsManager.flows.test.js.map +1 -0
  60. package/out/src/__tests/WalletPermissionsManager.initialization.test.d.ts +2 -0
  61. package/out/src/__tests/WalletPermissionsManager.initialization.test.d.ts.map +1 -0
  62. package/out/src/__tests/WalletPermissionsManager.initialization.test.js +227 -0
  63. package/out/src/__tests/WalletPermissionsManager.initialization.test.js.map +1 -0
  64. package/out/src/__tests/WalletPermissionsManager.proxying.test.d.ts +2 -0
  65. package/out/src/__tests/WalletPermissionsManager.proxying.test.d.ts.map +1 -0
  66. package/out/src/__tests/WalletPermissionsManager.proxying.test.js +566 -0
  67. package/out/src/__tests/WalletPermissionsManager.proxying.test.js.map +1 -0
  68. package/out/src/__tests/WalletPermissionsManager.tokens.test.d.ts +2 -0
  69. package/out/src/__tests/WalletPermissionsManager.tokens.test.d.ts.map +1 -0
  70. package/out/src/__tests/WalletPermissionsManager.tokens.test.js +460 -0
  71. package/out/src/__tests/WalletPermissionsManager.tokens.test.js.map +1 -0
  72. package/out/src/index.all.d.ts +9 -1
  73. package/out/src/index.all.d.ts.map +1 -1
  74. package/out/src/index.all.js +10 -3
  75. package/out/src/index.all.js.map +1 -1
  76. package/out/src/index.client.d.ts +9 -1
  77. package/out/src/index.client.d.ts.map +1 -1
  78. package/out/src/index.client.js +10 -3
  79. package/out/src/index.client.js.map +1 -1
  80. package/out/src/utility/identityUtils.d.ts +31 -0
  81. package/out/src/utility/identityUtils.d.ts.map +1 -0
  82. package/out/src/utility/identityUtils.js +114 -0
  83. package/out/src/utility/identityUtils.js.map +1 -0
  84. package/out/src/wab-client/WABClient.d.ts +38 -0
  85. package/out/src/wab-client/WABClient.d.ts.map +1 -0
  86. package/out/src/wab-client/WABClient.js +95 -0
  87. package/out/src/wab-client/WABClient.js.map +1 -0
  88. package/out/src/wab-client/__tests/WABClient.test.d.ts +2 -0
  89. package/out/src/wab-client/__tests/WABClient.test.d.ts.map +1 -0
  90. package/out/src/wab-client/__tests/WABClient.test.js +47 -0
  91. package/out/src/wab-client/__tests/WABClient.test.js.map +1 -0
  92. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.d.ts +34 -0
  93. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.d.ts.map +1 -0
  94. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.js +16 -0
  95. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.js.map +1 -0
  96. package/out/src/wab-client/auth-method-interactors/PersonaIDInteractor.d.ts +7 -0
  97. package/out/src/wab-client/auth-method-interactors/PersonaIDInteractor.d.ts.map +1 -0
  98. package/out/src/wab-client/auth-method-interactors/PersonaIDInteractor.js +40 -0
  99. package/out/src/wab-client/auth-method-interactors/PersonaIDInteractor.js.map +1 -0
  100. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.d.ts +28 -0
  101. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.d.ts.map +1 -0
  102. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.js +73 -0
  103. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.js.map +1 -0
  104. package/out/test/Wallet/action/abortAction.test.d.ts.map +1 -0
  105. package/out/test/{wallet → Wallet}/action/abortAction.test.js.map +1 -1
  106. package/out/test/Wallet/action/createAction.test.d.ts.map +1 -0
  107. package/out/test/{wallet → Wallet}/action/createAction.test.js.map +1 -1
  108. package/out/test/{wallet → Wallet}/action/createAction2.test.d.ts.map +1 -1
  109. package/out/test/{wallet → Wallet}/action/createAction2.test.js.map +1 -1
  110. package/out/test/Wallet/action/createActionToGenerateBeefs.man.test.d.ts.map +1 -0
  111. package/out/test/{wallet → Wallet}/action/createActionToGenerateBeefs.man.test.js.map +1 -1
  112. package/out/test/Wallet/action/internalizeAction.test.d.ts.map +1 -0
  113. package/out/test/{wallet → Wallet}/action/internalizeAction.test.js.map +1 -1
  114. package/out/test/Wallet/action/relinquishOutput.test.d.ts.map +1 -0
  115. package/out/test/{wallet → Wallet}/action/relinquishOutput.test.js.map +1 -1
  116. package/out/test/Wallet/construct/Wallet.constructor.test.d.ts.map +1 -0
  117. package/out/test/{wallet → Wallet}/construct/Wallet.constructor.test.js.map +1 -1
  118. package/out/test/Wallet/list/listActions.test.d.ts.map +1 -0
  119. package/out/test/{wallet → Wallet}/list/listActions.test.js.map +1 -1
  120. package/out/test/Wallet/list/listActions2.test.d.ts.map +1 -0
  121. package/out/test/{wallet → Wallet}/list/listActions2.test.js.map +1 -1
  122. package/out/test/Wallet/list/listCertificates.test.d.ts.map +1 -0
  123. package/out/test/{wallet → Wallet}/list/listCertificates.test.js.map +1 -1
  124. package/out/test/Wallet/list/listOutputs.test.d.ts.map +1 -0
  125. package/out/test/{wallet → Wallet}/list/listOutputs.test.js.map +1 -1
  126. package/out/test/Wallet/sync/Wallet.sync.test.d.ts.map +1 -0
  127. package/out/test/{wallet → Wallet}/sync/Wallet.sync.test.js.map +1 -1
  128. package/out/tsconfig.all.tsbuildinfo +1 -1
  129. package/package.json +3 -3
  130. package/src/CWIStyleWalletManager.ts +1891 -0
  131. package/src/Setup.ts +514 -8
  132. package/src/SimpleWalletManager.ts +553 -0
  133. package/src/Wallet.ts +47 -3
  134. package/src/WalletAuthenticationManager.ts +183 -0
  135. package/src/WalletPermissionsManager.ts +2639 -0
  136. package/src/WalletSettingsManager.ts +241 -0
  137. package/src/__tests/CWIStyleWalletManager.test.ts +709 -0
  138. package/src/__tests/WalletPermissionsManager.callbacks.test.ts +328 -0
  139. package/src/__tests/WalletPermissionsManager.checks.test.ts +857 -0
  140. package/src/__tests/WalletPermissionsManager.encryption.test.ts +407 -0
  141. package/src/__tests/WalletPermissionsManager.fixtures.ts +283 -0
  142. package/src/__tests/WalletPermissionsManager.flows.test.ts +490 -0
  143. package/src/__tests/WalletPermissionsManager.initialization.test.ts +333 -0
  144. package/src/__tests/WalletPermissionsManager.proxying.test.ts +753 -0
  145. package/src/__tests/WalletPermissionsManager.tokens.test.ts +584 -0
  146. package/src/index.all.ts +9 -9
  147. package/src/index.client.ts +9 -1
  148. package/src/utility/identityUtils.ts +170 -0
  149. package/src/wab-client/WABClient.ts +103 -0
  150. package/src/wab-client/__tests/WABClient.test.ts +58 -0
  151. package/src/wab-client/auth-method-interactors/AuthMethodInteractor.ts +47 -0
  152. package/src/wab-client/auth-method-interactors/PersonaIDInteractor.ts +45 -0
  153. package/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.ts +82 -0
  154. package/out/test/wallet/action/abortAction.test.d.ts.map +0 -1
  155. package/out/test/wallet/action/createAction.test.d.ts.map +0 -1
  156. package/out/test/wallet/action/createActionToGenerateBeefs.man.test.d.ts.map +0 -1
  157. package/out/test/wallet/action/internalizeAction.test.d.ts.map +0 -1
  158. package/out/test/wallet/action/relinquishOutput.test.d.ts.map +0 -1
  159. package/out/test/wallet/construct/Wallet.constructor.test.d.ts.map +0 -1
  160. package/out/test/wallet/list/listActions.test.d.ts.map +0 -1
  161. package/out/test/wallet/list/listActions2.test.d.ts.map +0 -1
  162. package/out/test/wallet/list/listCertificates.test.d.ts.map +0 -1
  163. package/out/test/wallet/list/listOutputs.test.d.ts.map +0 -1
  164. package/out/test/wallet/sync/Wallet.sync.test.d.ts.map +0 -1
  165. package/src/SetupClient.ts +0 -532
  166. /package/out/test/{wallet → Wallet}/action/abortAction.test.d.ts +0 -0
  167. /package/out/test/{wallet → Wallet}/action/abortAction.test.js +0 -0
  168. /package/out/test/{wallet → Wallet}/action/createAction.test.d.ts +0 -0
  169. /package/out/test/{wallet → Wallet}/action/createAction.test.js +0 -0
  170. /package/out/test/{wallet → Wallet}/action/createAction2.test.d.ts +0 -0
  171. /package/out/test/{wallet → Wallet}/action/createAction2.test.js +0 -0
  172. /package/out/test/{wallet → Wallet}/action/createActionToGenerateBeefs.man.test.d.ts +0 -0
  173. /package/out/test/{wallet → Wallet}/action/createActionToGenerateBeefs.man.test.js +0 -0
  174. /package/out/test/{wallet → Wallet}/action/internalizeAction.test.d.ts +0 -0
  175. /package/out/test/{wallet → Wallet}/action/internalizeAction.test.js +0 -0
  176. /package/out/test/{wallet → Wallet}/action/relinquishOutput.test.d.ts +0 -0
  177. /package/out/test/{wallet → Wallet}/action/relinquishOutput.test.js +0 -0
  178. /package/out/test/{wallet → Wallet}/construct/Wallet.constructor.test.d.ts +0 -0
  179. /package/out/test/{wallet → Wallet}/construct/Wallet.constructor.test.js +0 -0
  180. /package/out/test/{wallet → Wallet}/list/listActions.test.d.ts +0 -0
  181. /package/out/test/{wallet → Wallet}/list/listActions.test.js +0 -0
  182. /package/out/test/{wallet → Wallet}/list/listActions2.test.d.ts +0 -0
  183. /package/out/test/{wallet → Wallet}/list/listActions2.test.js +0 -0
  184. /package/out/test/{wallet → Wallet}/list/listCertificates.test.d.ts +0 -0
  185. /package/out/test/{wallet → Wallet}/list/listCertificates.test.js +0 -0
  186. /package/out/test/{wallet → Wallet}/list/listOutputs.test.d.ts +0 -0
  187. /package/out/test/{wallet → Wallet}/list/listOutputs.test.js +0 -0
  188. /package/out/test/{wallet → Wallet}/sync/Wallet.sync.test.d.ts +0 -0
  189. /package/out/test/{wallet → Wallet}/sync/Wallet.sync.test.js +0 -0
  190. /package/test/{wallet → Wallet}/action/abortAction.test.ts +0 -0
  191. /package/test/{wallet → Wallet}/action/createAction.test.ts +0 -0
  192. /package/test/{wallet → Wallet}/action/createAction2.test.ts +0 -0
  193. /package/test/{wallet → Wallet}/action/createActionToGenerateBeefs.man.test.ts +0 -0
  194. /package/test/{wallet → Wallet}/action/internalizeAction.test.ts +0 -0
  195. /package/test/{wallet → Wallet}/action/relinquishOutput.test.ts +0 -0
  196. /package/test/{wallet → Wallet}/construct/Wallet.constructor.test.ts +0 -0
  197. /package/test/{wallet → Wallet}/list/listActions.test.ts +0 -0
  198. /package/test/{wallet → Wallet}/list/listActions2.test.ts +0 -0
  199. /package/test/{wallet → Wallet}/list/listCertificates.test.ts +0 -0
  200. /package/test/{wallet → Wallet}/list/listOutputs.test.ts +0 -0
  201. /package/test/{wallet → Wallet}/sync/Wallet.sync.test.ts +0 -0
@@ -0,0 +1,260 @@
1
+ "use strict";
2
+ /**
3
+ * A permissions manager testing mock/stub file for:
4
+ * 1) The `@bsv/sdk` library: Transaction, LockingScript, PushDrop, Utils, Random, etc.
5
+ * 2) A BRC-100 `WalletInterface` (the underlying wallet).
6
+ *
7
+ * This file bypasses real validation/logic in `@bsv/sdk`, returning placeholders and
8
+ * stubs to prevent test-time errors such as "Invalid Atomic BEEF prefix."
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.MockedBSV_SDK = exports.MockRandom = exports.MockUtils = exports.MockPushDrop = exports.MockLockingScript = exports.MockTransaction = void 0;
12
+ exports.mockUnderlyingWallet = mockUnderlyingWallet;
13
+ /* ---------------------------------------------------------------------------
14
+ * 1) Partial Mocks for @bsv/sdk
15
+ * -------------------------------------------------------------------------*/
16
+ /**
17
+ * A minimal mock for `Transaction` that won't throw "Invalid Atomic BEEF prefix."
18
+ * We override the static methods so they do not do real parsing/validation.
19
+ */
20
+ class MockTransaction {
21
+ constructor() {
22
+ this.inputs = [{}];
23
+ this.outputs = [];
24
+ this.fee = 0;
25
+ }
26
+ static fromAtomicBEEF() {
27
+ // Mocked below
28
+ }
29
+ static fromBEEF(beef) {
30
+ // Same approach as above
31
+ return new MockTransaction();
32
+ }
33
+ getFee() {
34
+ return this.fee;
35
+ }
36
+ }
37
+ exports.MockTransaction = MockTransaction;
38
+ ;
39
+ MockTransaction.fromAtomicBEEF = jest.fn(() => {
40
+ // We skip real validation, returning a MockTransaction with minimal structure.
41
+ const tx = new MockTransaction();
42
+ return tx;
43
+ });
44
+ /**
45
+ * Mocks for `LockingScript`. If your code calls e.g. LockingScript.fromHex, we can just
46
+ * store the hex and do nothing else.
47
+ */
48
+ class MockLockingScript {
49
+ constructor(hex) {
50
+ this.hex = hex;
51
+ }
52
+ toHex() {
53
+ return this.hex;
54
+ }
55
+ static fromHex(hex) {
56
+ return new MockLockingScript(hex);
57
+ }
58
+ }
59
+ exports.MockLockingScript = MockLockingScript;
60
+ /**
61
+ * We stub out all methods: `decode()`, `lock()`, `unlock()`.
62
+ */
63
+ class MockPushDrop {
64
+ // Typically we might store the wallet reference, but we can skip for now.
65
+ constructor() {
66
+ //
67
+ }
68
+ // Decodes a LockingScript into some {fields: number[][], protocol...} or undefined
69
+ static decode(script) {
70
+ // If you rely on a real format, parse or store a pattern.
71
+ // For now, returning a minimal stub: empty fields
72
+ if (!script || !script.hex)
73
+ return undefined;
74
+ if (script.hex.includes('some script')) {
75
+ // When needed, return some fields
76
+ return {
77
+ fields: [
78
+ [],
79
+ [],
80
+ [],
81
+ [],
82
+ [],
83
+ [],
84
+ [] // 7 fields should always be enough...
85
+ ]
86
+ };
87
+ }
88
+ // Just pretend we always decode to a single empty field array
89
+ return { fields: [] };
90
+ }
91
+ lock(fields, protocolID, keyID, counterparty, singleSignature, anyoneCanPay) {
92
+ return new MockLockingScript('deadbeef');
93
+ }
94
+ unlock(protocolID, keyID, counterparty, sighashType, enforceReplayProtection, sigSize, lockingScript) {
95
+ // In real usage, it would handle signature logic. We'll return a minimal stub.
96
+ return {
97
+ sign: async (tx, vin) => {
98
+ // produce a minimal unlocking script
99
+ return new MockLockingScript('mockUnlockingScript');
100
+ }
101
+ };
102
+ }
103
+ }
104
+ exports.MockPushDrop = MockPushDrop;
105
+ /**
106
+ * Mocks for Utils, e.g. toHex, toUTF8, fromUTF8, etc.
107
+ * We can provide minimal stubs that won't break your code.
108
+ */
109
+ exports.MockUtils = {
110
+ toHex: (data) => {
111
+ // Converts an array of numbers to a hexadecimal string.
112
+ return data.map(num => num.toString(16).padStart(2, '0')).join('');
113
+ },
114
+ toArray: (str, encoding = 'utf8') => {
115
+ // Converts a string to an array of numbers based on the encoding.
116
+ if (encoding === 'hex') {
117
+ const arr = [];
118
+ for (let i = 0; i < str.length; i += 2) {
119
+ arr.push(parseInt(str.substr(i, 2), 16));
120
+ }
121
+ return arr;
122
+ }
123
+ else if (encoding === 'base64') {
124
+ const binaryStr = atob(str);
125
+ return Array.from(binaryStr, char => char.charCodeAt(0));
126
+ }
127
+ else if (encoding === 'utf8') {
128
+ return Array.from(str, char => char.charCodeAt(0));
129
+ }
130
+ else {
131
+ throw new Error('Unsupported encoding: ' + encoding);
132
+ }
133
+ },
134
+ toUTF8: (arr) => {
135
+ // Converts an array of numbers to a UTF-8 string.
136
+ return String.fromCharCode(...arr);
137
+ }
138
+ };
139
+ /**
140
+ * Mocks for Random
141
+ */
142
+ const MockRandom = (size) => {
143
+ return [...require('crypto').randomBytes(size)];
144
+ };
145
+ exports.MockRandom = MockRandom;
146
+ /**
147
+ * Overriding the real classes with our mocks.
148
+ */
149
+ exports.MockedBSV_SDK = {
150
+ Transaction: MockTransaction,
151
+ LockingScript: MockLockingScript,
152
+ PushDrop: MockPushDrop,
153
+ Utils: exports.MockUtils,
154
+ Random: exports.MockRandom
155
+ };
156
+ /* ---------------------------------------------------------------------------
157
+ * 2) A full mock for the BRC-100 WalletInterface
158
+ * -------------------------------------------------------------------------*/
159
+ /**
160
+ * A helper function returning a Jest-mocked `WalletInterface`.
161
+ * This ensures all required methods exist and return plausible values.
162
+ *
163
+ * - By default, `createAction` returns a signableTransaction with empty arrays,
164
+ * so that the manager can call `Transaction.fromAtomicBEEF([])` without throwing.
165
+ * - You can override or chain .mockResolvedValueOnce(...) inside individual tests
166
+ * if you want more specific behavior in certain test steps.
167
+ */
168
+ function mockUnderlyingWallet() {
169
+ return {
170
+ getPublicKey: jest.fn().mockResolvedValue({ publicKey: '029999...' }),
171
+ revealCounterpartyKeyLinkage: jest.fn().mockResolvedValue({
172
+ encryptedLinkage: [1, 2, 3],
173
+ encryptedLinkageProof: [4, 5, 6],
174
+ prover: '02abcdef...',
175
+ verifier: '02cccccc...',
176
+ counterparty: '02bbbbbb...',
177
+ revelationTime: new Date().toISOString()
178
+ }),
179
+ revealSpecificKeyLinkage: jest.fn().mockResolvedValue({
180
+ encryptedLinkage: [1, 2, 3],
181
+ encryptedLinkageProof: [4, 5, 6],
182
+ prover: '02abcdef...',
183
+ verifier: '02cccccc...',
184
+ counterparty: '02bbbbbb...',
185
+ protocolID: [1, 'test-protocol'],
186
+ keyID: 'testKey',
187
+ proofType: 1
188
+ }),
189
+ encrypt: jest.fn().mockResolvedValue({ ciphertext: [42, 42, 42] }),
190
+ decrypt: jest.fn().mockResolvedValue({ plaintext: [42, 42] }),
191
+ createHmac: jest.fn().mockResolvedValue({ hmac: [0xaa] }),
192
+ verifyHmac: jest.fn().mockResolvedValue({ valid: true }),
193
+ createSignature: jest.fn().mockResolvedValue({ signature: [0x30, 0x44] }),
194
+ verifySignature: jest.fn().mockResolvedValue({ valid: true }),
195
+ createAction: jest.fn(async (x) => {
196
+ if (x.options && x.options.signAndProcess === true) {
197
+ return {
198
+ tx: []
199
+ };
200
+ }
201
+ return {
202
+ signableTransaction: {
203
+ tx: [],
204
+ reference: 'mockReference'
205
+ }
206
+ };
207
+ }),
208
+ signAction: jest.fn().mockResolvedValue({
209
+ txid: 'fake-txid',
210
+ tx: []
211
+ }),
212
+ abortAction: jest.fn().mockResolvedValue({ aborted: true }),
213
+ listActions: jest.fn().mockResolvedValue({
214
+ totalActions: 0,
215
+ actions: []
216
+ }),
217
+ internalizeAction: jest.fn().mockResolvedValue({ accepted: true }),
218
+ listOutputs: jest.fn().mockResolvedValue({
219
+ totalOutputs: 0,
220
+ outputs: []
221
+ }),
222
+ relinquishOutput: jest.fn().mockResolvedValue({ relinquished: true }),
223
+ acquireCertificate: jest.fn().mockResolvedValue({
224
+ type: 'some-cert-type',
225
+ subject: '02aaaaaaaaaa...',
226
+ serialNumber: 'serial123',
227
+ certifier: '02ccccccccccc...',
228
+ revocationOutpoint: 'some.txid.1',
229
+ signature: 'deadbeef',
230
+ fields: { name: 'Alice', dob: '1990-01-01' }
231
+ }),
232
+ listCertificates: jest.fn().mockResolvedValue({
233
+ totalCertificates: 0,
234
+ certificates: []
235
+ }),
236
+ proveCertificate: jest.fn().mockResolvedValue({
237
+ keyringForVerifier: {},
238
+ certificate: undefined,
239
+ verifier: undefined
240
+ }),
241
+ relinquishCertificate: jest.fn().mockResolvedValue({ relinquished: true }),
242
+ discoverByIdentityKey: jest.fn().mockResolvedValue({
243
+ totalCertificates: 0,
244
+ certificates: []
245
+ }),
246
+ discoverByAttributes: jest.fn().mockResolvedValue({
247
+ totalCertificates: 0,
248
+ certificates: []
249
+ }),
250
+ isAuthenticated: jest.fn().mockResolvedValue({ authenticated: true }),
251
+ waitForAuthentication: jest.fn().mockResolvedValue({ authenticated: true }),
252
+ getHeight: jest.fn().mockResolvedValue({ height: 777777 }),
253
+ getHeaderForHeight: jest.fn().mockResolvedValue({
254
+ header: '000000000000abc...'
255
+ }),
256
+ getNetwork: jest.fn().mockResolvedValue({ network: 'testnet' }),
257
+ getVersion: jest.fn().mockResolvedValue({ version: 'vendor-1.0.0' })
258
+ };
259
+ }
260
+ //# sourceMappingURL=WalletPermissionsManager.fixtures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WalletPermissionsManager.fixtures.js","sourceRoot":"","sources":["../../../src/__tests/WalletPermissionsManager.fixtures.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=WalletPermissionsManager.flows.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WalletPermissionsManager.flows.test.d.ts","sourceRoot":"","sources":["../../../src/__tests/WalletPermissionsManager.flows.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,389 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const WalletPermissionsManager_fixtures_1 = require("./WalletPermissionsManager.fixtures");
4
+ const WalletPermissionsManager_1 = require("../WalletPermissionsManager");
5
+ const globals_1 = require("@jest/globals");
6
+ // We mock the underlying @bsv/sdk references with our test fixtures:
7
+ globals_1.jest.mock('@bsv/sdk', () => WalletPermissionsManager_fixtures_1.MockedBSV_SDK);
8
+ /**
9
+ * A lightweight helper that forces the manager to never find any on-chain token.
10
+ * We do this so we can reliably test the request flow (i.e., that it truly initiates
11
+ * a new permission request if no token is found).
12
+ */
13
+ function mockNoTokensFound(manager) {
14
+ globals_1.jest.spyOn(manager, 'findProtocolToken').mockResolvedValue(undefined);
15
+ globals_1.jest.spyOn(manager, 'findBasketToken').mockResolvedValue(undefined);
16
+ globals_1.jest
17
+ .spyOn(manager, 'findCertificateToken')
18
+ .mockResolvedValue(undefined);
19
+ globals_1.jest.spyOn(manager, 'findSpendingToken').mockResolvedValue(undefined);
20
+ }
21
+ describe('WalletPermissionsManager - Permission Request Flow & Active Requests', () => {
22
+ let underlying;
23
+ let manager;
24
+ beforeEach(() => {
25
+ underlying = (0, WalletPermissionsManager_fixtures_1.mockUnderlyingWallet)();
26
+ manager = new WalletPermissionsManager_1.WalletPermissionsManager(underlying, 'admin.test.com');
27
+ });
28
+ afterEach(() => {
29
+ globals_1.jest.clearAllMocks();
30
+ });
31
+ /**
32
+ * UNIT TESTS
33
+ */
34
+ describe('Unit Tests: requestPermissionFlow & activeRequests map', () => {
35
+ it('should coalesce parallel requests for the same resource into a single user prompt', async () => {
36
+ // We want to test the underlying private method "requestPermissionFlow" indirectly
37
+ // or we can test it via a public method that calls it. We'll do so via ensureProtocolPermission.
38
+ // Force no token found => triggers a request flow
39
+ mockNoTokensFound(manager);
40
+ // Spy on the manager's "onProtocolPermissionRequested" callbacks
41
+ const requestCallback = globals_1.jest.fn(() => { });
42
+ manager.bindCallback('onProtocolPermissionRequested', requestCallback);
43
+ // Make two parallel calls for the same resource
44
+ const callA = manager.ensureProtocolPermission({
45
+ originator: 'example.com',
46
+ privileged: false,
47
+ protocolID: [1, 'someproto'],
48
+ counterparty: 'self',
49
+ reason: 'UnitTest - same resource A',
50
+ seekPermission: true,
51
+ usageType: 'signing'
52
+ });
53
+ const callB = manager.ensureProtocolPermission({
54
+ originator: 'example.com',
55
+ privileged: false,
56
+ protocolID: [1, 'someproto'],
57
+ counterparty: 'self',
58
+ reason: 'UnitTest - same resource B',
59
+ seekPermission: true,
60
+ usageType: 'signing'
61
+ });
62
+ // Wait a short moment for the async request flow to trigger
63
+ await new Promise(res => setTimeout(res, 5));
64
+ // We expect only one "onProtocolPermissionRequested" event for both calls
65
+ expect(requestCallback).toHaveBeenCalledTimes(1);
66
+ // Now let's deny the request:
67
+ // Grab the requestID that the manager gave us from the callback param
68
+ const callbackArg = requestCallback.mock.calls[0][0];
69
+ const requestID = callbackArg.requestID;
70
+ expect(typeof requestID).toBe('string'); // manager-generated
71
+ // Deny the request
72
+ await manager.denyPermission(requestID);
73
+ // Both calls should reject
74
+ await expect(callA).rejects.toThrow(/Permission denied/);
75
+ await expect(callB).rejects.toThrow(/Permission denied/);
76
+ // Confirm activeRequests map is empty after denial
77
+ const activeRequests = manager.activeRequests;
78
+ expect(activeRequests.size).toBe(0);
79
+ });
80
+ it('should generate two distinct user prompts for two different permission requests', async () => {
81
+ // Force no tokens
82
+ mockNoTokensFound(manager);
83
+ // Spy on basket & protocol request callbacks
84
+ const protocolRequestCb = globals_1.jest.fn(() => { });
85
+ const basketRequestCb = globals_1.jest.fn(() => { });
86
+ manager.bindCallback('onProtocolPermissionRequested', protocolRequestCb);
87
+ manager.bindCallback('onBasketAccessRequested', basketRequestCb);
88
+ // Make one call for protocol usage
89
+ const pCall = manager.ensureProtocolPermission({
90
+ originator: 'example.com',
91
+ privileged: false,
92
+ protocolID: [1, 'proto-A'],
93
+ counterparty: 'self',
94
+ reason: 'Different request A',
95
+ seekPermission: true,
96
+ usageType: 'signing'
97
+ });
98
+ // Make a second call for basket usage
99
+ const bCall = manager.ensureBasketAccess({
100
+ originator: 'example.com',
101
+ basket: 'some-basket',
102
+ reason: 'Different request B',
103
+ seekPermission: true,
104
+ usageType: 'insertion'
105
+ });
106
+ // Wait a moment for them to trigger
107
+ await new Promise(res => setTimeout(res, 5));
108
+ // We expect one protocol request AND one basket request
109
+ expect(protocolRequestCb).toHaveBeenCalledTimes(1);
110
+ expect(basketRequestCb).toHaveBeenCalledTimes(1);
111
+ // Deny protocol request
112
+ const pReqID = protocolRequestCb.mock.calls[0][0].requestID;
113
+ await manager.denyPermission(pReqID);
114
+ // Deny basket request
115
+ const bReqID = basketRequestCb.mock.calls[0][0].requestID;
116
+ await manager.denyPermission(bReqID);
117
+ // Both calls should have rejected
118
+ await expect(pCall).rejects.toThrow(/Permission denied/);
119
+ await expect(bCall).rejects.toThrow(/Permission denied/);
120
+ // activeRequests is empty
121
+ const activeRequests = manager.activeRequests;
122
+ expect(activeRequests.size).toBe(0);
123
+ });
124
+ it('should resolve all parallel requests when permission is granted, referencing the same requestID', async () => {
125
+ // No tokens => triggers request flow
126
+ mockNoTokensFound(manager);
127
+ const requestCb = globals_1.jest.fn(() => { });
128
+ manager.bindCallback('onProtocolPermissionRequested', requestCb);
129
+ // Parallel calls
130
+ const promiseA = manager.ensureProtocolPermission({
131
+ originator: 'example.com',
132
+ privileged: false,
133
+ protocolID: [1, 'proto-X'],
134
+ counterparty: 'anyone',
135
+ reason: 'Test parallel grant A',
136
+ seekPermission: true,
137
+ usageType: 'encrypting'
138
+ });
139
+ const promiseB = manager.ensureProtocolPermission({
140
+ originator: 'example.com',
141
+ privileged: false,
142
+ protocolID: [1, 'proto-X'],
143
+ counterparty: 'anyone',
144
+ reason: 'Test parallel grant B',
145
+ seekPermission: true,
146
+ usageType: 'encrypting'
147
+ });
148
+ // Let the request event fire
149
+ await new Promise(res => setTimeout(res, 5));
150
+ expect(requestCb).toHaveBeenCalledTimes(1);
151
+ // Extract the requestID from the callback
152
+ const { requestID } = requestCb.mock.calls[0][0];
153
+ // Now we grant permission for that same requestID
154
+ // Because ephemeral is false by default, the manager will attempt to create on-chain tokens
155
+ // We'll mock the internal createPermissionOnChain so it doesn't blow up
156
+ const createOnChainSpy = globals_1.jest
157
+ .spyOn(manager, 'createPermissionOnChain')
158
+ .mockResolvedValue(undefined);
159
+ await manager.grantPermission({ requestID });
160
+ // Both calls should resolve with `true` (the manager returns a boolean)
161
+ await expect(promiseA).resolves.toBe(true);
162
+ await expect(promiseB).resolves.toBe(true);
163
+ // activeRequests map is empty
164
+ const activeRequests = manager.activeRequests;
165
+ expect(activeRequests.size).toBe(0);
166
+ // The manager tried to create an on-chain permission token once
167
+ expect(createOnChainSpy).toHaveBeenCalledTimes(1);
168
+ });
169
+ it('should reject only the matching request queue on deny if requestID is specified', async () => {
170
+ // This scenario tests the manager's partial denial logic where we pass { requestID }
171
+ // to only reject the queued requests with that ID, leaving others (with a different requestID)
172
+ // in the queue.
173
+ mockNoTokensFound(manager);
174
+ // We do two separate calls for the same resource but at different times, resulting in separate queues.
175
+ // Actually, the manager normally merges them into one queue if the resource is the same.
176
+ // So let's do two different resources to ensure we get two separate keys.
177
+ const protoCb = globals_1.jest.fn(() => { });
178
+ manager.bindCallback('onProtocolPermissionRequested', protoCb);
179
+ // Resource 1
180
+ const p1Promise = manager.ensureProtocolPermission({
181
+ originator: 'siteA.com',
182
+ privileged: false,
183
+ protocolID: [1, 'proto-siteA'],
184
+ counterparty: 'self',
185
+ usageType: 'encrypting'
186
+ });
187
+ await new Promise(res => setTimeout(res, 5));
188
+ const p1ReqID = protoCb.mock.calls[0][0].requestID;
189
+ // At this point, resource 1 is pending in activeRequests. We'll not resolve it yet.
190
+ // Resource 2
191
+ const p2Promise = manager.ensureProtocolPermission({
192
+ originator: 'siteB.com',
193
+ privileged: false,
194
+ protocolID: [1, 'proto-siteB'],
195
+ counterparty: 'self',
196
+ usageType: 'encrypting'
197
+ });
198
+ await new Promise(res => setTimeout(res, 5));
199
+ // the second call triggers a second onProtocolPermissionRequested callback
200
+ expect(protoCb).toHaveBeenCalledTimes(2);
201
+ const p2ReqID = protoCb.mock.calls[1][0].requestID;
202
+ // Deny the second request only
203
+ await manager.denyPermission(p2ReqID);
204
+ await expect(p2Promise).rejects.toThrow(/Permission denied/);
205
+ // But the first request is still waiting
206
+ const activeRequests = manager.activeRequests;
207
+ expect(activeRequests.size).toBe(1);
208
+ // Now let's deny the first request too
209
+ await manager.denyPermission(p1ReqID);
210
+ await expect(p1Promise).rejects.toThrow(/Permission denied/);
211
+ // The queue is empty now
212
+ expect(activeRequests.size).toBe(0);
213
+ });
214
+ });
215
+ /**
216
+ * INTEGRATION TESTS
217
+ */
218
+ describe('Integration Tests: ephemeral vs. persistent tokens', () => {
219
+ it('should not create a token if ephemeral=true, so subsequent calls re-trigger the request', async () => {
220
+ // We'll do a "protocol" permission scenario:
221
+ mockNoTokensFound(manager);
222
+ // Bind the request callback
223
+ const requestCb = globals_1.jest.fn(() => { });
224
+ manager.bindCallback('onProtocolPermissionRequested', requestCb);
225
+ // Force any on-chain creation attempt to be spied on
226
+ const createTokenSpy = globals_1.jest.spyOn(manager, 'createPermissionOnChain');
227
+ // 1) Call ensureProtocolPermission => triggers request
228
+ const pCall1 = manager.ensureProtocolPermission({
229
+ originator: 'appdomain.com',
230
+ privileged: false,
231
+ protocolID: [1, 'ephemeral-proto'],
232
+ counterparty: 'self',
233
+ reason: 'test ephemeral #1',
234
+ usageType: 'signing'
235
+ });
236
+ // Wait for request callback
237
+ await new Promise(res => setTimeout(res, 5));
238
+ expect(requestCb).toHaveBeenCalledTimes(1);
239
+ const reqID1 = requestCb.mock.calls[0][0].requestID;
240
+ // Grant ephemeral
241
+ await manager.grantPermission({
242
+ requestID: reqID1,
243
+ ephemeral: true
244
+ });
245
+ // pCall1 is resolved
246
+ await expect(pCall1).resolves.toBe(true);
247
+ // Because ephemeral=true, we do NOT create an on-chain token
248
+ expect(createTokenSpy).not.toHaveBeenCalled();
249
+ // 2) Immediately call ensureProtocolPermission again for the same resource
250
+ // Because ephemeral usage didn't store a token, it should re-prompt.
251
+ const pCall2 = manager.ensureProtocolPermission({
252
+ originator: 'appdomain.com',
253
+ privileged: false,
254
+ protocolID: [1, 'ephemeral-proto'],
255
+ counterparty: 'self',
256
+ reason: 'test ephemeral #2',
257
+ usageType: 'signing'
258
+ });
259
+ await new Promise(res => setTimeout(res, 5));
260
+ // We expect a new request callback
261
+ expect(requestCb).toHaveBeenCalledTimes(2);
262
+ // We'll deny the second request
263
+ const reqID2 = requestCb.mock.calls[1][0].requestID;
264
+ await manager.denyPermission(reqID2);
265
+ await expect(pCall2).rejects.toThrow(/Permission denied/);
266
+ });
267
+ it('should create a token if ephemeral=false, so subsequent calls do not re-trigger if unexpired', async () => {
268
+ // We want the manager to truly create a token. We'll confirm that
269
+ // subsequent calls for the same resource skip user prompt.
270
+ mockNoTokensFound(manager);
271
+ // We'll also ensure no token is found "the first time."
272
+ // But on subsequent calls, we can mock that the manager sees the newly created token.
273
+ // Let's spy on "createPermissionOnChain" so we can intercept the new token
274
+ const createTokenSpy = globals_1.jest
275
+ .spyOn(manager, 'createPermissionOnChain')
276
+ .mockResolvedValue(undefined); // no real on-chain creation
277
+ // Spy on "findProtocolToken" so we can simulate that the second time it's called,
278
+ // there's a valid token. We'll do this by setting the mock to return undefined the first time,
279
+ // and a valid token the second time (or we can just rely on the manager's logic).
280
+ let firstFindCall = true;
281
+ globals_1.jest
282
+ .spyOn(manager, 'findProtocolToken')
283
+ .mockImplementation(async () => {
284
+ if (firstFindCall) {
285
+ firstFindCall = false;
286
+ return undefined; // first time triggers request
287
+ }
288
+ // second time => pretend we found a valid token
289
+ const mockToken = {
290
+ txid: 'abcdef',
291
+ outputIndex: 0,
292
+ outputScript: '00',
293
+ satoshis: 1,
294
+ originator: 'persistentdomain.com',
295
+ expiry: Math.floor(Date.now() / 1000) + 3600, // unexpired
296
+ privileged: false,
297
+ protocol: 'persist-proto',
298
+ securityLevel: 1,
299
+ counterparty: 'self'
300
+ };
301
+ return mockToken;
302
+ });
303
+ // We'll observe the request callback
304
+ const requestCb = globals_1.jest.fn(() => { });
305
+ manager.bindCallback('onProtocolPermissionRequested', requestCb);
306
+ // 1) First call => no token => triggers request
307
+ const call1 = manager.ensureProtocolPermission({
308
+ originator: 'persistentdomain.com',
309
+ privileged: false,
310
+ protocolID: [1, 'persist-proto'],
311
+ counterparty: 'self',
312
+ reason: 'test persistent #1',
313
+ usageType: 'signing'
314
+ });
315
+ await new Promise(res => setTimeout(res, 5));
316
+ expect(requestCb).toHaveBeenCalledTimes(1);
317
+ // Grant ephemeral=false => triggers createPermissionOnChain
318
+ const reqID = requestCb.mock.calls[0][0].requestID;
319
+ await manager.grantPermission({ requestID: reqID, ephemeral: false });
320
+ await expect(call1).resolves.toBe(true);
321
+ expect(createTokenSpy).toHaveBeenCalledTimes(1);
322
+ // 2) Second call => the manager should find the token we just "created" => no request prompt
323
+ const call2 = manager.ensureProtocolPermission({
324
+ originator: 'persistentdomain.com',
325
+ privileged: false,
326
+ protocolID: [1, 'persist-proto'],
327
+ counterparty: 'self',
328
+ reason: 'test persistent #2',
329
+ usageType: 'signing'
330
+ });
331
+ // We do not expect a new user prompt => requestCb remains at 1
332
+ await new Promise(res => setTimeout(res, 5));
333
+ expect(requestCb).toHaveBeenCalledTimes(1);
334
+ // The second call should resolve immediately, no prompt
335
+ await expect(call2).resolves.toBe(true);
336
+ });
337
+ it('should handle renewal if the found token is expired, passing previousToken in the request', async () => {
338
+ // We'll test the "renewal" flow:
339
+ // If the manager finds a token but it's expired, it sets { renewal: true, previousToken } in the request.
340
+ // We'll mock findProtocolToken to return an expired token
341
+ const expiredToken = {
342
+ txid: 'expiredTxid123',
343
+ outputIndex: 0,
344
+ outputScript: '76a914xxxx...88ac',
345
+ satoshis: 1,
346
+ originator: 'renewme.com',
347
+ expiry: Math.floor(Date.now() / 1000) - 100, // in the past
348
+ privileged: false,
349
+ protocol: 'renew-proto',
350
+ securityLevel: 1,
351
+ counterparty: 'self'
352
+ };
353
+ globals_1.jest
354
+ .spyOn(manager, 'findProtocolToken')
355
+ .mockResolvedValue(expiredToken);
356
+ // Spy on request callback
357
+ const requestCb = globals_1.jest.fn(() => { });
358
+ manager.bindCallback('onProtocolPermissionRequested', requestCb);
359
+ // We'll also spy on "renewPermissionOnChain" to see if it's called
360
+ const renewSpy = globals_1.jest
361
+ .spyOn(manager, 'renewPermissionOnChain')
362
+ .mockResolvedValue(undefined);
363
+ // Call ensureProtocolPermission => sees expired token => triggers request with renewal
364
+ const promise = manager.ensureProtocolPermission({
365
+ originator: 'renewme.com',
366
+ privileged: false,
367
+ protocolID: [1, 'renew-proto'],
368
+ counterparty: 'self',
369
+ reason: 'test renewal',
370
+ usageType: 'encrypting'
371
+ });
372
+ // Wait for request callback
373
+ await new Promise(res => setTimeout(res, 10));
374
+ expect(requestCb).toHaveBeenCalledTimes(1);
375
+ // Confirm the callback param includes `renewal=true` and `previousToken=expiredToken`
376
+ const { renewal, previousToken } = requestCb.mock.calls[0][0];
377
+ expect(renewal).toBe(true);
378
+ expect(previousToken.txid).toBe('expiredTxid123');
379
+ // Grant ephemeral=false => manager calls renewPermissionOnChain
380
+ const { requestID } = requestCb.mock.calls[0][0];
381
+ await manager.grantPermission({ requestID, ephemeral: false });
382
+ await expect(promise).resolves.toBe(true);
383
+ expect(renewSpy).toHaveBeenCalledTimes(1);
384
+ // The first arg is the old token, second is request, etc.
385
+ expect(renewSpy).toHaveBeenCalledWith(expiredToken, expect.objectContaining({ originator: 'renewme.com' }), expect.any(Number), undefined);
386
+ });
387
+ });
388
+ });
389
+ //# sourceMappingURL=WalletPermissionsManager.flows.test.js.map