@bsv/wallet-toolbox 1.1.24 → 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 (194) hide show
  1. package/docs/client.md +2319 -84
  2. package/docs/wallet.md +2319 -84
  3. package/out/src/CWIStyleWalletManager.d.ts +411 -0
  4. package/out/src/CWIStyleWalletManager.d.ts.map +1 -0
  5. package/out/src/CWIStyleWalletManager.js +1131 -0
  6. package/out/src/CWIStyleWalletManager.js.map +1 -0
  7. package/out/src/SetupClient.d.ts +249 -0
  8. package/out/src/SetupClient.d.ts.map +1 -0
  9. package/out/src/SetupClient.js +252 -0
  10. package/out/src/SetupClient.js.map +1 -0
  11. package/out/src/SimpleWalletManager.d.ts +169 -0
  12. package/out/src/SimpleWalletManager.d.ts.map +1 -0
  13. package/out/src/SimpleWalletManager.js +315 -0
  14. package/out/src/SimpleWalletManager.js.map +1 -0
  15. package/out/src/Wallet.d.ts +6 -1
  16. package/out/src/Wallet.d.ts.map +1 -1
  17. package/out/src/Wallet.js +29 -2
  18. package/out/src/Wallet.js.map +1 -1
  19. package/out/src/WalletAuthenticationManager.d.ts +33 -0
  20. package/out/src/WalletAuthenticationManager.d.ts.map +1 -0
  21. package/out/src/WalletAuthenticationManager.js +107 -0
  22. package/out/src/WalletAuthenticationManager.js.map +1 -0
  23. package/out/src/WalletPermissionsManager.d.ts +575 -0
  24. package/out/src/WalletPermissionsManager.d.ts.map +1 -0
  25. package/out/src/WalletPermissionsManager.js +1807 -0
  26. package/out/src/WalletPermissionsManager.js.map +1 -0
  27. package/out/src/WalletSettingsManager.d.ts +59 -0
  28. package/out/src/WalletSettingsManager.d.ts.map +1 -0
  29. package/out/src/WalletSettingsManager.js +168 -0
  30. package/out/src/WalletSettingsManager.js.map +1 -0
  31. package/out/src/__tests/CWIStyleWalletManager.test.d.ts +2 -0
  32. package/out/src/__tests/CWIStyleWalletManager.test.d.ts.map +1 -0
  33. package/out/src/__tests/CWIStyleWalletManager.test.js +472 -0
  34. package/out/src/__tests/CWIStyleWalletManager.test.js.map +1 -0
  35. package/out/src/__tests/WalletPermissionsManager.callbacks.test.d.ts +2 -0
  36. package/out/src/__tests/WalletPermissionsManager.callbacks.test.d.ts.map +1 -0
  37. package/out/src/__tests/WalletPermissionsManager.callbacks.test.js +239 -0
  38. package/out/src/__tests/WalletPermissionsManager.callbacks.test.js.map +1 -0
  39. package/out/src/__tests/WalletPermissionsManager.checks.test.d.ts +2 -0
  40. package/out/src/__tests/WalletPermissionsManager.checks.test.d.ts.map +1 -0
  41. package/out/src/__tests/WalletPermissionsManager.checks.test.js +644 -0
  42. package/out/src/__tests/WalletPermissionsManager.checks.test.js.map +1 -0
  43. package/out/src/__tests/WalletPermissionsManager.encryption.test.d.ts +2 -0
  44. package/out/src/__tests/WalletPermissionsManager.encryption.test.d.ts.map +1 -0
  45. package/out/src/__tests/WalletPermissionsManager.encryption.test.js +295 -0
  46. package/out/src/__tests/WalletPermissionsManager.encryption.test.js.map +1 -0
  47. package/out/src/__tests/WalletPermissionsManager.fixtures.d.ts +82 -0
  48. package/out/src/__tests/WalletPermissionsManager.fixtures.d.ts.map +1 -0
  49. package/out/src/__tests/WalletPermissionsManager.fixtures.js +260 -0
  50. package/out/src/__tests/WalletPermissionsManager.fixtures.js.map +1 -0
  51. package/out/src/__tests/WalletPermissionsManager.flows.test.d.ts +2 -0
  52. package/out/src/__tests/WalletPermissionsManager.flows.test.d.ts.map +1 -0
  53. package/out/src/__tests/WalletPermissionsManager.flows.test.js +389 -0
  54. package/out/src/__tests/WalletPermissionsManager.flows.test.js.map +1 -0
  55. package/out/src/__tests/WalletPermissionsManager.initialization.test.d.ts +2 -0
  56. package/out/src/__tests/WalletPermissionsManager.initialization.test.d.ts.map +1 -0
  57. package/out/src/__tests/WalletPermissionsManager.initialization.test.js +227 -0
  58. package/out/src/__tests/WalletPermissionsManager.initialization.test.js.map +1 -0
  59. package/out/src/__tests/WalletPermissionsManager.proxying.test.d.ts +2 -0
  60. package/out/src/__tests/WalletPermissionsManager.proxying.test.d.ts.map +1 -0
  61. package/out/src/__tests/WalletPermissionsManager.proxying.test.js +566 -0
  62. package/out/src/__tests/WalletPermissionsManager.proxying.test.js.map +1 -0
  63. package/out/src/__tests/WalletPermissionsManager.tokens.test.d.ts +2 -0
  64. package/out/src/__tests/WalletPermissionsManager.tokens.test.d.ts.map +1 -0
  65. package/out/src/__tests/WalletPermissionsManager.tokens.test.js +460 -0
  66. package/out/src/__tests/WalletPermissionsManager.tokens.test.js.map +1 -0
  67. package/out/src/index.all.d.ts +9 -0
  68. package/out/src/index.all.d.ts.map +1 -1
  69. package/out/src/index.all.js +9 -0
  70. package/out/src/index.all.js.map +1 -1
  71. package/out/src/index.client.d.ts +9 -0
  72. package/out/src/index.client.d.ts.map +1 -1
  73. package/out/src/index.client.js +9 -0
  74. package/out/src/index.client.js.map +1 -1
  75. package/out/src/utility/identityUtils.d.ts +31 -0
  76. package/out/src/utility/identityUtils.d.ts.map +1 -0
  77. package/out/src/utility/identityUtils.js +114 -0
  78. package/out/src/utility/identityUtils.js.map +1 -0
  79. package/out/src/wab-client/WABClient.d.ts +38 -0
  80. package/out/src/wab-client/WABClient.d.ts.map +1 -0
  81. package/out/src/wab-client/WABClient.js +95 -0
  82. package/out/src/wab-client/WABClient.js.map +1 -0
  83. package/out/src/wab-client/__tests/WABClient.test.d.ts +2 -0
  84. package/out/src/wab-client/__tests/WABClient.test.d.ts.map +1 -0
  85. package/out/src/wab-client/__tests/WABClient.test.js +47 -0
  86. package/out/src/wab-client/__tests/WABClient.test.js.map +1 -0
  87. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.d.ts +34 -0
  88. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.d.ts.map +1 -0
  89. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.js +16 -0
  90. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.js.map +1 -0
  91. package/out/src/wab-client/auth-method-interactors/PersonaIDInteractor.d.ts +7 -0
  92. package/out/src/wab-client/auth-method-interactors/PersonaIDInteractor.d.ts.map +1 -0
  93. package/out/src/wab-client/auth-method-interactors/PersonaIDInteractor.js +40 -0
  94. package/out/src/wab-client/auth-method-interactors/PersonaIDInteractor.js.map +1 -0
  95. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.d.ts +28 -0
  96. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.d.ts.map +1 -0
  97. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.js +73 -0
  98. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.js.map +1 -0
  99. package/out/test/Wallet/action/abortAction.test.d.ts.map +1 -0
  100. package/out/test/{wallet → Wallet}/action/abortAction.test.js.map +1 -1
  101. package/out/test/Wallet/action/createAction.test.d.ts.map +1 -0
  102. package/out/test/{wallet → Wallet}/action/createAction.test.js.map +1 -1
  103. package/out/test/{wallet → Wallet}/action/createAction2.test.d.ts.map +1 -1
  104. package/out/test/{wallet → Wallet}/action/createAction2.test.js.map +1 -1
  105. package/out/test/Wallet/action/createActionToGenerateBeefs.man.test.d.ts.map +1 -0
  106. package/out/test/{wallet → Wallet}/action/createActionToGenerateBeefs.man.test.js.map +1 -1
  107. package/out/test/Wallet/action/internalizeAction.test.d.ts.map +1 -0
  108. package/out/test/{wallet → Wallet}/action/internalizeAction.test.js.map +1 -1
  109. package/out/test/Wallet/action/relinquishOutput.test.d.ts.map +1 -0
  110. package/out/test/{wallet → Wallet}/action/relinquishOutput.test.js.map +1 -1
  111. package/out/test/Wallet/construct/Wallet.constructor.test.d.ts.map +1 -0
  112. package/out/test/{wallet → Wallet}/construct/Wallet.constructor.test.js.map +1 -1
  113. package/out/test/Wallet/list/listActions.test.d.ts.map +1 -0
  114. package/out/test/{wallet → Wallet}/list/listActions.test.js.map +1 -1
  115. package/out/test/Wallet/list/listActions2.test.d.ts.map +1 -0
  116. package/out/test/{wallet → Wallet}/list/listActions2.test.js.map +1 -1
  117. package/out/test/Wallet/list/listCertificates.test.d.ts.map +1 -0
  118. package/out/test/{wallet → Wallet}/list/listCertificates.test.js.map +1 -1
  119. package/out/test/Wallet/list/listOutputs.test.d.ts.map +1 -0
  120. package/out/test/{wallet → Wallet}/list/listOutputs.test.js.map +1 -1
  121. package/out/test/Wallet/sync/Wallet.sync.test.d.ts.map +1 -0
  122. package/out/test/{wallet → Wallet}/sync/Wallet.sync.test.js.map +1 -1
  123. package/out/tsconfig.all.tsbuildinfo +1 -1
  124. package/package.json +3 -3
  125. package/src/CWIStyleWalletManager.ts +1891 -0
  126. package/src/SimpleWalletManager.ts +553 -0
  127. package/src/Wallet.ts +47 -3
  128. package/src/WalletAuthenticationManager.ts +183 -0
  129. package/src/WalletPermissionsManager.ts +2639 -0
  130. package/src/WalletSettingsManager.ts +241 -0
  131. package/src/__tests/CWIStyleWalletManager.test.ts +709 -0
  132. package/src/__tests/WalletPermissionsManager.callbacks.test.ts +328 -0
  133. package/src/__tests/WalletPermissionsManager.checks.test.ts +857 -0
  134. package/src/__tests/WalletPermissionsManager.encryption.test.ts +407 -0
  135. package/src/__tests/WalletPermissionsManager.fixtures.ts +283 -0
  136. package/src/__tests/WalletPermissionsManager.flows.test.ts +490 -0
  137. package/src/__tests/WalletPermissionsManager.initialization.test.ts +333 -0
  138. package/src/__tests/WalletPermissionsManager.proxying.test.ts +753 -0
  139. package/src/__tests/WalletPermissionsManager.tokens.test.ts +584 -0
  140. package/src/index.all.ts +9 -0
  141. package/src/index.client.ts +9 -0
  142. package/src/utility/identityUtils.ts +170 -0
  143. package/src/wab-client/WABClient.ts +103 -0
  144. package/src/wab-client/__tests/WABClient.test.ts +58 -0
  145. package/src/wab-client/auth-method-interactors/AuthMethodInteractor.ts +47 -0
  146. package/src/wab-client/auth-method-interactors/PersonaIDInteractor.ts +45 -0
  147. package/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.ts +82 -0
  148. package/out/test/wallet/action/abortAction.test.d.ts.map +0 -1
  149. package/out/test/wallet/action/createAction.test.d.ts.map +0 -1
  150. package/out/test/wallet/action/createActionToGenerateBeefs.man.test.d.ts.map +0 -1
  151. package/out/test/wallet/action/internalizeAction.test.d.ts.map +0 -1
  152. package/out/test/wallet/action/relinquishOutput.test.d.ts.map +0 -1
  153. package/out/test/wallet/construct/Wallet.constructor.test.d.ts.map +0 -1
  154. package/out/test/wallet/list/listActions.test.d.ts.map +0 -1
  155. package/out/test/wallet/list/listActions2.test.d.ts.map +0 -1
  156. package/out/test/wallet/list/listCertificates.test.d.ts.map +0 -1
  157. package/out/test/wallet/list/listOutputs.test.d.ts.map +0 -1
  158. package/out/test/wallet/sync/Wallet.sync.test.d.ts.map +0 -1
  159. /package/out/test/{wallet → Wallet}/action/abortAction.test.d.ts +0 -0
  160. /package/out/test/{wallet → Wallet}/action/abortAction.test.js +0 -0
  161. /package/out/test/{wallet → Wallet}/action/createAction.test.d.ts +0 -0
  162. /package/out/test/{wallet → Wallet}/action/createAction.test.js +0 -0
  163. /package/out/test/{wallet → Wallet}/action/createAction2.test.d.ts +0 -0
  164. /package/out/test/{wallet → Wallet}/action/createAction2.test.js +0 -0
  165. /package/out/test/{wallet → Wallet}/action/createActionToGenerateBeefs.man.test.d.ts +0 -0
  166. /package/out/test/{wallet → Wallet}/action/createActionToGenerateBeefs.man.test.js +0 -0
  167. /package/out/test/{wallet → Wallet}/action/internalizeAction.test.d.ts +0 -0
  168. /package/out/test/{wallet → Wallet}/action/internalizeAction.test.js +0 -0
  169. /package/out/test/{wallet → Wallet}/action/relinquishOutput.test.d.ts +0 -0
  170. /package/out/test/{wallet → Wallet}/action/relinquishOutput.test.js +0 -0
  171. /package/out/test/{wallet → Wallet}/construct/Wallet.constructor.test.d.ts +0 -0
  172. /package/out/test/{wallet → Wallet}/construct/Wallet.constructor.test.js +0 -0
  173. /package/out/test/{wallet → Wallet}/list/listActions.test.d.ts +0 -0
  174. /package/out/test/{wallet → Wallet}/list/listActions.test.js +0 -0
  175. /package/out/test/{wallet → Wallet}/list/listActions2.test.d.ts +0 -0
  176. /package/out/test/{wallet → Wallet}/list/listActions2.test.js +0 -0
  177. /package/out/test/{wallet → Wallet}/list/listCertificates.test.d.ts +0 -0
  178. /package/out/test/{wallet → Wallet}/list/listCertificates.test.js +0 -0
  179. /package/out/test/{wallet → Wallet}/list/listOutputs.test.d.ts +0 -0
  180. /package/out/test/{wallet → Wallet}/list/listOutputs.test.js +0 -0
  181. /package/out/test/{wallet → Wallet}/sync/Wallet.sync.test.d.ts +0 -0
  182. /package/out/test/{wallet → Wallet}/sync/Wallet.sync.test.js +0 -0
  183. /package/test/{wallet → Wallet}/action/abortAction.test.ts +0 -0
  184. /package/test/{wallet → Wallet}/action/createAction.test.ts +0 -0
  185. /package/test/{wallet → Wallet}/action/createAction2.test.ts +0 -0
  186. /package/test/{wallet → Wallet}/action/createActionToGenerateBeefs.man.test.ts +0 -0
  187. /package/test/{wallet → Wallet}/action/internalizeAction.test.ts +0 -0
  188. /package/test/{wallet → Wallet}/action/relinquishOutput.test.ts +0 -0
  189. /package/test/{wallet → Wallet}/construct/Wallet.constructor.test.ts +0 -0
  190. /package/test/{wallet → Wallet}/list/listActions.test.ts +0 -0
  191. /package/test/{wallet → Wallet}/list/listActions2.test.ts +0 -0
  192. /package/test/{wallet → Wallet}/list/listCertificates.test.ts +0 -0
  193. /package/test/{wallet → Wallet}/list/listOutputs.test.ts +0 -0
  194. /package/test/{wallet → Wallet}/sync/Wallet.sync.test.ts +0 -0
@@ -0,0 +1,328 @@
1
+ import {
2
+ mockUnderlyingWallet,
3
+ MockedBSV_SDK
4
+ } from './WalletPermissionsManager.fixtures'
5
+ import { WalletPermissionsManager } from '../WalletPermissionsManager'
6
+
7
+ import { jest } from '@jest/globals'
8
+
9
+ // Mock the @bsv/sdk module with our fixture/mocks:
10
+ jest.mock('@bsv/sdk', () => MockedBSV_SDK)
11
+
12
+ describe('WalletPermissionsManager - Callbacks & Event Handling', () => {
13
+ let underlying: ReturnType<typeof mockUnderlyingWallet>
14
+ let manager: WalletPermissionsManager
15
+
16
+ beforeEach(() => {
17
+ underlying = mockUnderlyingWallet()
18
+ // Use default config so that protocol permissions are enforced for testing requests
19
+ manager = new WalletPermissionsManager(underlying, 'admin.domain.com')
20
+ })
21
+
22
+ afterEach(() => {
23
+ jest.clearAllMocks()
24
+ })
25
+
26
+ // -------------------------------------------------------------------------
27
+ // 1) Unit Tests: Callback Registration & Unregistration
28
+ // -------------------------------------------------------------------------
29
+
30
+ it('bindCallback() should register multiple callbacks for the same event, which are called in sequence', async () => {
31
+ const cb1 = jest.fn(() => {})
32
+ const cb2 = jest.fn(() => {})
33
+
34
+ // Bind both to "onProtocolPermissionRequested"
35
+ manager.bindCallback('onProtocolPermissionRequested', cb1)
36
+ manager.bindCallback('onProtocolPermissionRequested', cb2)
37
+
38
+ // Manually trigger the event (private method usage) for direct testing:
39
+ // We'll mimic the manager calling "this.callEvent('onProtocolPermissionRequested', params)"
40
+ // by just calling it ourselves. This is a "unit-level" approach.
41
+ const fakeParam = { type: 'protocol', requestID: 'req-xyz' }
42
+ await (manager as any).callEvent('onProtocolPermissionRequested', fakeParam)
43
+
44
+ // Both callbacks should have been called in sequence with the same param
45
+ expect(cb1).toHaveBeenCalledTimes(1)
46
+ expect(cb2).toHaveBeenCalledTimes(1)
47
+ expect(cb1).toHaveBeenCalledWith(fakeParam)
48
+ expect(cb2).toHaveBeenCalledWith(fakeParam)
49
+
50
+ // Confirm order
51
+ expect(cb1.mock.invocationCallOrder[0]).toBeLessThan(
52
+ cb2.mock.invocationCallOrder[0]
53
+ )
54
+ })
55
+
56
+ it('unbindCallback() by numeric ID should prevent the callback from being called again', async () => {
57
+ const cb1 = jest.fn(() => {})
58
+ const cb2 = jest.fn(() => {})
59
+
60
+ // We get numeric IDs when binding
61
+ const id1 = manager.bindCallback('onProtocolPermissionRequested', cb1)
62
+ manager.bindCallback('onProtocolPermissionRequested', cb2)
63
+
64
+ // Fire once (both should be called)
65
+ const param1 = { requestID: 'req-test-1' }
66
+ await (manager as any).callEvent('onProtocolPermissionRequested', param1)
67
+
68
+ expect(cb1).toHaveBeenCalledTimes(1)
69
+ expect(cb2).toHaveBeenCalledTimes(1)
70
+
71
+ // Unbind cb1 by numeric ID
72
+ manager.unbindCallback('onProtocolPermissionRequested', id1)
73
+
74
+ // Fire again
75
+ const param2 = { requestID: 'req-test-2' }
76
+ await (manager as any).callEvent('onProtocolPermissionRequested', param2)
77
+
78
+ // cb1 should NOT receive the second event
79
+ expect(cb1).toHaveBeenCalledTimes(1)
80
+ // cb2 should still receive it
81
+ expect(cb2).toHaveBeenCalledTimes(2)
82
+ })
83
+
84
+ it('unbindCallback() by function reference should remove the callback', async () => {
85
+ const cb1 = jest.fn(() => {})
86
+ const cb2 = jest.fn(() => {})
87
+ const cb3 = jest.fn(() => {})
88
+
89
+ manager.bindCallback('onProtocolPermissionRequested', cb1)
90
+ manager.bindCallback('onProtocolPermissionRequested', cb2)
91
+ manager.bindCallback('onProtocolPermissionRequested', cb3)
92
+
93
+ // Fire once
94
+ const param1 = { requestID: 'req-first-fire' }
95
+ await (manager as any).callEvent('onProtocolPermissionRequested', param1)
96
+
97
+ expect(cb1).toHaveBeenCalledTimes(1)
98
+ expect(cb2).toHaveBeenCalledTimes(1)
99
+ expect(cb3).toHaveBeenCalledTimes(1)
100
+
101
+ // Unbind cb2 by function reference
102
+ manager.unbindCallback('onProtocolPermissionRequested', cb2)
103
+
104
+ // Fire again
105
+ const param2 = { requestID: 'req-second-fire' }
106
+ await (manager as any).callEvent('onProtocolPermissionRequested', param2)
107
+
108
+ // cb2 should no longer be called
109
+ expect(cb1).toHaveBeenCalledTimes(2)
110
+ expect(cb2).toHaveBeenCalledTimes(1)
111
+ expect(cb3).toHaveBeenCalledTimes(2)
112
+ })
113
+
114
+ it('a failing callback (throwing an error) does not block subsequent callbacks', async () => {
115
+ const goodCb = jest.fn(() => {})
116
+ const badCb = jest.fn().mockImplementation(() => {
117
+ throw new Error('Intentional error')
118
+ })
119
+ const finalCb = jest.fn(() => {})
120
+
121
+ manager.bindCallback('onProtocolPermissionRequested', goodCb)
122
+ manager.bindCallback('onProtocolPermissionRequested', badCb as any)
123
+ manager.bindCallback('onProtocolPermissionRequested', finalCb)
124
+
125
+ const param = { requestID: 'req-err-test' }
126
+ // callEvent should swallow the error from badCb and continue
127
+ await (manager as any).callEvent('onProtocolPermissionRequested', param)
128
+
129
+ // All callbacks are invoked once
130
+ expect(goodCb).toHaveBeenCalledTimes(1)
131
+ expect(badCb).toHaveBeenCalledTimes(1)
132
+ expect(finalCb).toHaveBeenCalledTimes(1)
133
+ })
134
+
135
+ // -------------------------------------------------------------------------
136
+ // 2) Integration Tests: Real permission request flow
137
+ // -------------------------------------------------------------------------
138
+
139
+ it('should trigger onProtocolPermissionRequested with correct params when a non-admin domain requests a protocol operation', async () => {
140
+ const requestedCb = jest.fn(() => {})
141
+
142
+ // We bind to onProtocolPermissionRequested
143
+ manager.bindCallback('onProtocolPermissionRequested', requestedCb)
144
+
145
+ // Attempt an operation that requires protocol permission:
146
+ // e.g., createSignature with level=1 protocol
147
+ const signPromise = manager.createSignature(
148
+ {
149
+ protocolID: [1, 'some-protocol'],
150
+ keyID: '1',
151
+ data: [0x01, 0x02],
152
+ privileged: false
153
+ },
154
+ 'non-admin.example.com'
155
+ )
156
+
157
+ // Wait a tick so the request can be queued
158
+ await new Promise(r => setTimeout(r, 10))
159
+
160
+ // We expect onProtocolPermissionRequested to have been fired once
161
+ expect(requestedCb).toHaveBeenCalledTimes(1)
162
+
163
+ // The callback param should include fields from the `PermissionRequest`
164
+ const callArg = (requestedCb.mock as any).calls[0][0]
165
+ expect(callArg.type).toBe('protocol')
166
+ expect(callArg.originator).toBe('non-admin.example.com')
167
+ expect(callArg.requestID).toMatch(/^proto:non-admin.example.com:false/) // The manager auto-generates an ID
168
+
169
+ // The original sign call is still pending (since we haven't granted or denied).
170
+ // We'll deny it for cleanup:
171
+ manager.denyPermission(callArg.requestID)
172
+
173
+ await expect(signPromise).rejects.toThrow(/Permission denied/)
174
+ })
175
+
176
+ it('should resolve the original caller promise when requests are granted', async () => {
177
+ const requestedCb = jest.fn(() => {})
178
+ manager.bindCallback('onProtocolPermissionRequested', requestedCb)
179
+
180
+ // Start an operation that requires permission
181
+ const signPromise = manager.createSignature(
182
+ {
183
+ protocolID: [1, 'testproto'],
184
+ keyID: '1',
185
+ data: [0xaa],
186
+ privileged: false
187
+ },
188
+ 'nonadmin.com'
189
+ )
190
+
191
+ // Wait for request to appear
192
+ await new Promise(r => setTimeout(r, 10))
193
+ expect(requestedCb).toHaveBeenCalledTimes(1)
194
+
195
+ // Extract the requestID from the callback
196
+ const requestID = (requestedCb.mock as any).calls[0][0].requestID
197
+
198
+ // Now grant the request
199
+ const grantParams = {
200
+ requestID,
201
+ expiry: 123456789,
202
+ ephemeral: true
203
+ }
204
+ await manager.grantPermission(grantParams)
205
+
206
+ // The signPromise should now resolve (meaning the original createSignature call finishes successfully).
207
+ await expect(signPromise).resolves.toBeDefined()
208
+ })
209
+
210
+ it('should reject the original caller promise when permission is denied', async () => {
211
+ const requestedCb = jest.fn(() => {})
212
+
213
+ manager.bindCallback('onProtocolPermissionRequested', requestedCb)
214
+ // Start an operation that requires protocol permission
215
+ const encryptPromise = manager.encrypt(
216
+ {
217
+ protocolID: [1, 'secretproto'],
218
+ keyID: 'session',
219
+ plaintext: [0xff, 0xff],
220
+ privileged: false
221
+ },
222
+ 'unauthorized-domain.com'
223
+ )
224
+
225
+ // Wait to ensure request is triggered
226
+ await new Promise(r => setTimeout(r, 10))
227
+ expect(requestedCb).toHaveBeenCalledTimes(1)
228
+
229
+ const requestID = (requestedCb.mock as any).calls[0][0].requestID
230
+
231
+ // Deny the request
232
+ manager.denyPermission(requestID)
233
+
234
+ // The original encryptPromise should reject
235
+ await expect(encryptPromise).rejects.toThrow(/Permission denied/i)
236
+ })
237
+
238
+ it('multiple pending requests for the same resource should trigger only one onXxxRequested callback', async () => {
239
+ const requestedCb = jest.fn(() => {})
240
+ manager.bindCallback('onProtocolPermissionRequested', requestedCb)
241
+
242
+ // We'll do two calls that require the SAME resource:
243
+ // same originator, same protocolID, same privileged=false, same counterparty
244
+
245
+ const call1 = manager.createSignature(
246
+ {
247
+ protocolID: [1, 'parallel-test'],
248
+ data: [0x01],
249
+ keyID: '1',
250
+ privileged: false
251
+ },
252
+ 'parallel-user.com'
253
+ )
254
+ const call2 = manager.createSignature(
255
+ {
256
+ protocolID: [1, 'parallel-test'],
257
+ data: [0x02],
258
+ keyID: '1',
259
+ privileged: false
260
+ },
261
+ 'parallel-user.com'
262
+ )
263
+
264
+ // Wait for the manager to handle them
265
+ await new Promise(r => setTimeout(r, 10))
266
+
267
+ // Because the resource is identical, only ONE request event should be triggered
268
+ expect(requestedCb).toHaveBeenCalledTimes(1)
269
+
270
+ // We'll grant the request once
271
+ await manager.grantPermission({
272
+ requestID: (requestedCb.mock as any).calls[0][0].requestID,
273
+ ephemeral: true
274
+ })
275
+
276
+ // Both calls should now resolve
277
+ await expect(call1).resolves.toBeDefined()
278
+ await expect(call2).resolves.toBeDefined()
279
+ })
280
+
281
+ it('multiple pending requests for different resources should trigger separate onXxxRequested callbacks', async () => {
282
+ const requestedCb = jest.fn(() => {})
283
+ manager.bindCallback('onProtocolPermissionRequested', requestedCb)
284
+
285
+ // We'll do two calls that require DIFFERENT resources:
286
+ // call1 -> protocolID=[1, 'resourceA']
287
+ // call2 -> protocolID=[1, 'resourceB']
288
+
289
+ const call1 = manager.createSignature(
290
+ {
291
+ protocolID: [1, 'resourceA'],
292
+ data: [0xaa],
293
+ keyID: '1',
294
+ privileged: false
295
+ },
296
+ 'user.com'
297
+ )
298
+
299
+ const call2 = manager.createSignature(
300
+ {
301
+ protocolID: [1, 'resourceB'],
302
+ data: [0xbb],
303
+ keyID: '1',
304
+ privileged: false
305
+ },
306
+ 'user.com'
307
+ )
308
+
309
+ // Wait for them to be triggered
310
+ await new Promise(r => setTimeout(r, 10))
311
+
312
+ // We expect 2 distinct request events
313
+ expect(requestedCb).toHaveBeenCalledTimes(2)
314
+
315
+ // Each request has a distinct resource
316
+ const firstID = (requestedCb.mock as any).calls[0][0].requestID
317
+ const secondID = (requestedCb.mock as any).calls[1][0].requestID
318
+ expect(firstID).not.toBe(secondID)
319
+
320
+ // We'll grant the first, deny the second
321
+ manager.grantPermission({ requestID: firstID, ephemeral: true })
322
+ manager.denyPermission(secondID)
323
+
324
+ // call1 resolves, call2 rejects
325
+ await expect(call1).resolves.toBeDefined()
326
+ await expect(call2).rejects.toThrow(/Permission denied/)
327
+ })
328
+ })