@bsv/wallet-toolbox 1.7.17 → 1.7.19

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.
@@ -1,5 +1,14 @@
1
1
  const { Validation } = jest.requireActual('@bsv/sdk')
2
2
 
3
+ const existingFetch = (globalThis as any).fetch
4
+ if (!existingFetch || !(existingFetch as any)._isMockFunction) {
5
+ ;(globalThis as any).fetch = jest.fn(async () => ({
6
+ ok: false,
7
+ status: 404,
8
+ json: async () => ({})
9
+ }))
10
+ }
11
+
3
12
  /**
4
13
  * A permissions manager testing mock/stub file for:
5
14
  * 1) The `@bsv/sdk` library: Transaction, LockingScript, PushDrop, Utils, Random, etc.
@@ -35,6 +35,163 @@ describe('WalletPermissionsManager - Permission Request Flow & Active Requests',
35
35
  * UNIT TESTS
36
36
  */
37
37
  describe('Unit Tests: requestPermissionFlow & activeRequests map', () => {
38
+ it('should coalesce level-2 protocol requests for the same counterparty into a single grouped permission prompt based on manifest.json', async () => {
39
+ mockNoTokensFound(manager)
40
+
41
+ jest.spyOn(manager as any, 'fetchManifestGroupPermissions').mockResolvedValue({
42
+ protocolPermissions: [
43
+ {
44
+ protocolID: [2, 'l2-proto-A'],
45
+ counterparty: '',
46
+ description: 'A'
47
+ },
48
+ {
49
+ protocolID: [2, 'l2-proto-B'],
50
+ counterparty: 'peer-123',
51
+ description: 'B'
52
+ },
53
+ {
54
+ protocolID: [2, 'l2-proto-C'],
55
+ counterparty: 'peer-999',
56
+ description: 'C'
57
+ },
58
+ {
59
+ protocolID: [1, 'l1-proto-D'],
60
+ counterparty: 'peer-123',
61
+ description: 'D'
62
+ }
63
+ ]
64
+ })
65
+
66
+ const groupRequestCallback = jest.fn(() => {})
67
+ manager.bindCallback('onGroupedPermissionRequested', groupRequestCallback)
68
+
69
+ const callA = manager.ensureProtocolPermission({
70
+ originator: 'example.com',
71
+ privileged: false,
72
+ protocolID: [2, 'l2-proto-A'],
73
+ counterparty: 'peer-123',
74
+ reason: 'UnitTest - L2 A',
75
+ seekPermission: true,
76
+ usageType: 'signing'
77
+ })
78
+
79
+ const callB = manager.ensureProtocolPermission({
80
+ originator: 'example.com',
81
+ privileged: false,
82
+ protocolID: [2, 'l2-proto-B'],
83
+ counterparty: 'peer-123',
84
+ reason: 'UnitTest - L2 B',
85
+ seekPermission: true,
86
+ usageType: 'signing'
87
+ })
88
+
89
+ await new Promise(res => setTimeout(res, 5))
90
+
91
+ expect(groupRequestCallback).toHaveBeenCalledTimes(1)
92
+ const callbackArg = (groupRequestCallback.mock as any).calls[0][0]
93
+ const requestID = callbackArg.requestID
94
+ expect(typeof requestID).toBe('string')
95
+ expect(requestID).toMatch(/^group-peer:/)
96
+
97
+ const activeRequests = (manager as any).activeRequests as Map<string, any>
98
+ const queued = activeRequests.get(requestID)
99
+ expect(queued.request.permissions.protocolPermissions.length).toBe(2)
100
+ expect(queued.request.permissions.protocolPermissions).toEqual(
101
+ expect.arrayContaining([
102
+ expect.objectContaining({ protocolID: [2, 'l2-proto-A'], counterparty: 'peer-123' }),
103
+ expect.objectContaining({ protocolID: [2, 'l2-proto-B'], counterparty: 'peer-123' })
104
+ ])
105
+ )
106
+
107
+ await manager.denyGroupedPermission(requestID)
108
+
109
+ await expect(callA).rejects.toThrow(/denied/i)
110
+ await expect(callB).rejects.toThrow(/denied/i)
111
+
112
+ expect(activeRequests.size).toBe(0)
113
+ })
114
+
115
+ it('should create separate grouped permission requests for different peers (no cross-peer grouping)', async () => {
116
+ mockNoTokensFound(manager)
117
+
118
+ jest.spyOn(manager as any, 'fetchManifestGroupPermissions').mockResolvedValue({
119
+ protocolPermissions: [
120
+ {
121
+ protocolID: [2, 'l2-proto-B'],
122
+ counterparty: 'peer-123',
123
+ description: 'B'
124
+ },
125
+ {
126
+ protocolID: [2, 'l2-proto-C'],
127
+ counterparty: 'peer-999',
128
+ description: 'C'
129
+ }
130
+ ]
131
+ })
132
+
133
+ const groupRequestCallback = jest.fn(() => {})
134
+ manager.bindCallback('onGroupedPermissionRequested', groupRequestCallback)
135
+
136
+ const callB = manager.ensureProtocolPermission({
137
+ originator: 'example.com',
138
+ privileged: false,
139
+ protocolID: [2, 'l2-proto-B'],
140
+ counterparty: 'peer-123',
141
+ reason: 'UnitTest - L2 B peer-123',
142
+ seekPermission: true,
143
+ usageType: 'signing'
144
+ })
145
+
146
+ const callC = manager.ensureProtocolPermission({
147
+ originator: 'example.com',
148
+ privileged: false,
149
+ protocolID: [2, 'l2-proto-C'],
150
+ counterparty: 'peer-999',
151
+ reason: 'UnitTest - L2 C peer-999',
152
+ seekPermission: true,
153
+ usageType: 'signing'
154
+ })
155
+
156
+ await new Promise(res => setTimeout(res, 5))
157
+
158
+ expect(groupRequestCallback).toHaveBeenCalledTimes(2)
159
+ const requestID1 = (groupRequestCallback.mock as any).calls[0][0].requestID
160
+ const requestID2 = (groupRequestCallback.mock as any).calls[1][0].requestID
161
+
162
+ expect(requestID1).not.toBe(requestID2)
163
+ expect(requestID1).toMatch(/^group-peer:/)
164
+ expect(requestID2).toMatch(/^group-peer:/)
165
+
166
+ const activeRequests = (manager as any).activeRequests as Map<string, any>
167
+ expect(activeRequests.size).toBe(2)
168
+
169
+ const queued1 = activeRequests.get(requestID1)
170
+ const queued2 = activeRequests.get(requestID2)
171
+
172
+ expect(queued1.request.permissions.protocolPermissions).toEqual(
173
+ expect.arrayContaining([expect.objectContaining({ protocolID: [2, 'l2-proto-B'], counterparty: 'peer-123' })])
174
+ )
175
+ expect(queued1.request.permissions.protocolPermissions).not.toEqual(
176
+ expect.arrayContaining([expect.objectContaining({ protocolID: [2, 'l2-proto-C'], counterparty: 'peer-999' })])
177
+ )
178
+
179
+ expect(queued2.request.permissions.protocolPermissions).toEqual(
180
+ expect.arrayContaining([expect.objectContaining({ protocolID: [2, 'l2-proto-C'], counterparty: 'peer-999' })])
181
+ )
182
+ expect(queued2.request.permissions.protocolPermissions).not.toEqual(
183
+ expect.arrayContaining([expect.objectContaining({ protocolID: [2, 'l2-proto-B'], counterparty: 'peer-123' })])
184
+ )
185
+
186
+ await manager.denyGroupedPermission(requestID1)
187
+ await manager.denyGroupedPermission(requestID2)
188
+
189
+ await expect(callB).rejects.toThrow(/denied/i)
190
+ await expect(callC).rejects.toThrow(/denied/i)
191
+
192
+ expect(activeRequests.size).toBe(0)
193
+ })
194
+
38
195
  it('should coalesce parallel requests for the same resource into a single user prompt', async () => {
39
196
  // We want to test the underlying private method "requestPermissionFlow" indirectly
40
197
  // or we can test it via a public method that calls it. We'll do so via ensureProtocolPermission.