@canton-network/wallet-gateway-remote 1.3.0 → 1.5.0
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/README.md +1 -1
- package/dist/auth/jwt-auth-service.d.ts.map +1 -1
- package/dist/auth/jwt-auth-service.js +6 -5
- package/dist/auth/jwt-auth-service.test.d.ts +2 -0
- package/dist/auth/jwt-auth-service.test.d.ts.map +1 -0
- package/dist/auth/jwt-auth-service.test.js +259 -0
- package/dist/auth/jwt-unsafe-auth-service.test.d.ts +2 -0
- package/dist/auth/jwt-unsafe-auth-service.test.d.ts.map +1 -0
- package/dist/auth/jwt-unsafe-auth-service.test.js +120 -0
- package/dist/config/Config.d.ts +64 -8
- package/dist/config/Config.d.ts.map +1 -1
- package/dist/config/Config.js +1 -0
- package/dist/config/ConfigUtils.d.ts.map +1 -1
- package/dist/config/ConfigUtils.js +3 -0
- package/dist/dapp-api/controller.d.ts +1 -0
- package/dist/dapp-api/controller.d.ts.map +1 -1
- package/dist/dapp-api/controller.js +87 -26
- package/dist/dapp-api/controller.test.d.ts +2 -0
- package/dist/dapp-api/controller.test.d.ts.map +1 -0
- package/dist/dapp-api/controller.test.js +516 -0
- package/dist/dapp-api/rpc-gen/index.d.ts +3 -0
- package/dist/dapp-api/rpc-gen/index.d.ts.map +1 -1
- package/dist/dapp-api/rpc-gen/index.js +1 -0
- package/dist/dapp-api/rpc-gen/typings.d.ts +99 -14
- package/dist/dapp-api/rpc-gen/typings.d.ts.map +1 -1
- package/dist/dapp-api/server.d.ts.map +1 -1
- package/dist/dapp-api/server.js +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +4 -6
- package/dist/ledger/transaction-service.d.ts +14 -11
- package/dist/ledger/transaction-service.d.ts.map +1 -1
- package/dist/ledger/transaction-service.js +95 -8
- package/dist/ledger/transaction-service.test.d.ts +2 -0
- package/dist/ledger/transaction-service.test.d.ts.map +1 -0
- package/dist/ledger/transaction-service.test.js +356 -0
- package/dist/ledger/wallet-allocation/signing-providers/fireblocks-wallet-allocator.d.ts +5 -2
- package/dist/ledger/wallet-allocation/signing-providers/fireblocks-wallet-allocator.d.ts.map +1 -1
- package/dist/ledger/wallet-allocation/signing-providers/fireblocks-wallet-allocator.js +7 -6
- package/dist/ledger/wallet-allocation/wallet-allocation-service.d.ts +11 -5
- package/dist/ledger/wallet-allocation/wallet-allocation-service.d.ts.map +1 -1
- package/dist/ledger/wallet-allocation/wallet-allocation-service.js +28 -14
- package/dist/ledger/wallet-allocation/wallet-allocation-service.test.js +550 -19
- package/dist/ledger/wallet-sync-service.js +3 -3
- package/dist/middleware/apiKeyAuth.d.ts +6 -0
- package/dist/middleware/apiKeyAuth.d.ts.map +1 -0
- package/dist/middleware/apiKeyAuth.js +88 -0
- package/dist/middleware/apiKeyAuth.test.d.ts +2 -0
- package/dist/middleware/apiKeyAuth.test.d.ts.map +1 -0
- package/dist/middleware/apiKeyAuth.test.js +126 -0
- package/dist/middleware/jsonRpcHandler.d.ts +11 -1
- package/dist/middleware/jsonRpcHandler.d.ts.map +1 -1
- package/dist/middleware/jsonRpcHandler.js +14 -15
- package/dist/middleware/jsonRpcHandler.test.d.ts +2 -0
- package/dist/middleware/jsonRpcHandler.test.d.ts.map +1 -0
- package/dist/middleware/jsonRpcHandler.test.js +254 -0
- package/dist/middleware/jwtAuth.d.ts.map +1 -1
- package/dist/middleware/jwtAuth.js +4 -0
- package/dist/middleware/jwtAuth.test.d.ts +2 -0
- package/dist/middleware/jwtAuth.test.d.ts.map +1 -0
- package/dist/middleware/jwtAuth.test.js +93 -0
- package/dist/middleware/rateLimit.js +2 -2
- package/dist/middleware/rateLimit.test.js +26 -0
- package/dist/middleware/sessionHandler.js +1 -1
- package/dist/middleware/sessionHandler.test.d.ts +2 -0
- package/dist/middleware/sessionHandler.test.d.ts.map +1 -0
- package/dist/middleware/sessionHandler.test.js +121 -0
- package/dist/notification/NotificationService.test.d.ts +2 -0
- package/dist/notification/NotificationService.test.d.ts.map +1 -0
- package/dist/notification/NotificationService.test.js +110 -0
- package/dist/signing/signing-drivers.d.ts +7 -0
- package/dist/signing/signing-drivers.d.ts.map +1 -0
- package/dist/signing/signing-drivers.js +3 -0
- package/dist/user-api/controller.d.ts +12 -4
- package/dist/user-api/controller.d.ts.map +1 -1
- package/dist/user-api/controller.js +330 -95
- package/dist/user-api/controller.test.d.ts +2 -0
- package/dist/user-api/controller.test.d.ts.map +1 -0
- package/dist/user-api/controller.test.js +862 -0
- package/dist/user-api/rpc-gen/index.d.ts +30 -0
- package/dist/user-api/rpc-gen/index.d.ts.map +1 -1
- package/dist/user-api/rpc-gen/index.js +10 -0
- package/dist/user-api/rpc-gen/typings.d.ts +170 -25
- package/dist/user-api/rpc-gen/typings.d.ts.map +1 -1
- package/dist/user-api/server.test.js +53 -0
- package/dist/utils.d.ts +19 -5
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +53 -2
- package/dist/utils.test.d.ts +2 -0
- package/dist/utils.test.d.ts.map +1 -0
- package/dist/utils.test.js +24 -0
- package/dist/web/frontend/404/index.html +2 -2
- package/dist/web/frontend/activities/index.html +3 -3
- package/dist/web/frontend/approve/index.html +4 -5
- package/dist/web/frontend/assets/404-MVLWUPwN.js +5 -0
- package/dist/web/frontend/assets/activities-DaWkmGqA.js +61 -0
- package/dist/web/frontend/assets/addIdentityProvider--rBb0ihb.js +28 -0
- package/dist/web/frontend/assets/addNetwork-C6UDsRkU.js +38 -0
- package/dist/web/frontend/assets/addParty-B3fFD1eM.js +45 -0
- package/dist/web/frontend/assets/approve-WbGL4E82.js +21 -0
- package/dist/web/frontend/assets/callback--tihEryB.js +1 -0
- package/dist/web/frontend/assets/identityProviders-Dra4qG6t.js +71 -0
- package/dist/web/frontend/assets/index-Bm76pXA_.js +91 -0
- package/dist/web/frontend/assets/index-D1dC4Cl9.js +4477 -0
- package/dist/web/frontend/assets/login-BC8a-kD_.js +10 -0
- package/dist/web/frontend/assets/networks-B3ztsogL.js +73 -0
- package/dist/web/frontend/assets/reviewIdentityProvider-Co420Dbk.js +43 -0
- package/dist/web/frontend/assets/reviewNetwork-B-Sh8pCH.js +43 -0
- package/dist/web/frontend/assets/{settings-B1ga2TK0.js → settings-DvyUjqLl.js} +1 -1
- package/dist/web/frontend/assets/state-Bq65GwdF.js +1 -0
- package/dist/web/frontend/assets/{utils-CT9Hzi7v.js → utils-B2iziW8V.js} +1 -1
- package/dist/web/frontend/callback/index.html +2 -2
- package/dist/web/frontend/identity-providers/add/index.html +3 -3
- package/dist/web/frontend/identity-providers/index.html +3 -3
- package/dist/web/frontend/identity-providers/review/index.html +3 -3
- package/dist/web/frontend/index.html +1 -1
- package/dist/web/frontend/login/index.html +3 -4
- package/dist/web/frontend/networks/add/index.html +3 -3
- package/dist/web/frontend/networks/index.html +3 -3
- package/dist/web/frontend/networks/review/index.html +3 -3
- package/dist/web/frontend/parties/add/index.html +5 -5
- package/dist/web/frontend/parties/index.html +4 -4
- package/dist/web/frontend/settings/index.html +3 -3
- package/package.json +40 -33
- package/dist/web/frontend/assets/404-B-o9ppJB.js +0 -5
- package/dist/web/frontend/assets/activities-CGjCIjUH.js +0 -61
- package/dist/web/frontend/assets/addIdentityProvider-CR4Wm9Tl.js +0 -28
- package/dist/web/frontend/assets/addNetwork-Dx0-SN4j.js +0 -38
- package/dist/web/frontend/assets/addParty-COhk_rFn.js +0 -41
- package/dist/web/frontend/assets/approve-B2w66l0J.js +0 -21
- package/dist/web/frontend/assets/callback-BTVon_yQ.js +0 -1
- package/dist/web/frontend/assets/identityProviders-CK8zSrd3.js +0 -71
- package/dist/web/frontend/assets/index-CF4BKzgl.js +0 -91
- package/dist/web/frontend/assets/index-DWz_3f3y.js +0 -1
- package/dist/web/frontend/assets/index-_pMHlJoE.js +0 -4042
- package/dist/web/frontend/assets/login-CVoPNVDw.js +0 -10
- package/dist/web/frontend/assets/networks-D1nPvUzM.js +0 -73
- package/dist/web/frontend/assets/reviewIdentityProvider-CNSf2qQv.js +0 -43
- package/dist/web/frontend/assets/reviewNetwork-DGLK-Ume.js +0 -43
- package/dist/web/frontend/assets/state-B2k3ak7d.js +0 -1
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
// Copyright (c) 2025-2026 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import { pino } from 'pino';
|
|
5
|
+
import { sink } from 'pino-test';
|
|
6
|
+
import { PartyLevelRight, } from '@canton-network/core-wallet-store';
|
|
7
|
+
import { StoreInternal } from '@canton-network/core-wallet-store-inmemory';
|
|
8
|
+
import { SigningProvider } from '@canton-network/core-signing-lib';
|
|
9
|
+
import { NotificationService } from '../notification/NotificationService.js';
|
|
10
|
+
import { dappController } from './controller.js';
|
|
11
|
+
const ledgerMocks = vi.hoisted(() => ({
|
|
12
|
+
getWithRetry: vi.fn(),
|
|
13
|
+
postWithRetry: vi.fn(),
|
|
14
|
+
getSynchronizerId: vi.fn(),
|
|
15
|
+
}));
|
|
16
|
+
const mockNetworkStatus = vi.hoisted(() => vi.fn().mockResolvedValue({
|
|
17
|
+
isConnected: true,
|
|
18
|
+
reason: undefined,
|
|
19
|
+
cantonVersion: '3.4',
|
|
20
|
+
}));
|
|
21
|
+
const mockUuidV4 = vi.hoisted(() => vi.fn());
|
|
22
|
+
vi.mock('@canton-network/core-ledger-client', async (importOriginal) => {
|
|
23
|
+
const actual = await importOriginal();
|
|
24
|
+
return {
|
|
25
|
+
...actual,
|
|
26
|
+
LedgerClient: vi.fn(function LedgerClientMock() {
|
|
27
|
+
return {
|
|
28
|
+
getWithRetry: ledgerMocks.getWithRetry,
|
|
29
|
+
postWithRetry: ledgerMocks.postWithRetry,
|
|
30
|
+
getSynchronizerId: ledgerMocks.getSynchronizerId,
|
|
31
|
+
};
|
|
32
|
+
}),
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
vi.mock('../utils.js', async (importOriginal) => {
|
|
36
|
+
const actual = await importOriginal();
|
|
37
|
+
return {
|
|
38
|
+
...actual,
|
|
39
|
+
networkStatus: mockNetworkStatus,
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
vi.mock('uuid', () => ({
|
|
43
|
+
v4: mockUuidV4,
|
|
44
|
+
}));
|
|
45
|
+
const kernelInfo = {
|
|
46
|
+
id: 'kernel-test',
|
|
47
|
+
clientType: 'browser',
|
|
48
|
+
};
|
|
49
|
+
const dappUrl = 'https://dapp.api.example';
|
|
50
|
+
const userUrl = 'https://user.api.example';
|
|
51
|
+
const origin = 'https://dapp.example';
|
|
52
|
+
const idp = {
|
|
53
|
+
id: 'idp1',
|
|
54
|
+
type: 'oauth',
|
|
55
|
+
issuer: 'http://auth',
|
|
56
|
+
configUrl: 'http://auth/.well-known/openid-configuration',
|
|
57
|
+
};
|
|
58
|
+
const storeNetwork = {
|
|
59
|
+
id: 'network1',
|
|
60
|
+
name: 'testnet',
|
|
61
|
+
synchronizerId: 'sync1::fingerprint',
|
|
62
|
+
description: 'Test',
|
|
63
|
+
identityProviderId: 'idp1',
|
|
64
|
+
ledgerApi: { baseUrl: 'http://ledger.test' },
|
|
65
|
+
auth: {
|
|
66
|
+
method: 'authorization_code',
|
|
67
|
+
clientId: 'cid',
|
|
68
|
+
scope: 'scope',
|
|
69
|
+
audience: 'aud',
|
|
70
|
+
},
|
|
71
|
+
adminAuth: {
|
|
72
|
+
method: 'client_credentials',
|
|
73
|
+
clientId: 'admin-cid',
|
|
74
|
+
clientSecret: 'admin-secret',
|
|
75
|
+
audience: 'admin-aud',
|
|
76
|
+
scope: 'admin-scope',
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
const auth = {
|
|
80
|
+
userId: 'user-1',
|
|
81
|
+
accessToken: 'access-token-1',
|
|
82
|
+
};
|
|
83
|
+
const session = {
|
|
84
|
+
id: 'session-1',
|
|
85
|
+
network: 'network1',
|
|
86
|
+
accessToken: 'session-token',
|
|
87
|
+
};
|
|
88
|
+
const primaryWallet = {
|
|
89
|
+
primary: true,
|
|
90
|
+
partyId: 'party::namespace',
|
|
91
|
+
status: 'allocated',
|
|
92
|
+
hint: 'party',
|
|
93
|
+
signingProviderId: SigningProvider.WALLET_KERNEL,
|
|
94
|
+
publicKey: 'wallet-public-key',
|
|
95
|
+
namespace: 'namespace',
|
|
96
|
+
networkId: 'network1',
|
|
97
|
+
rights: [PartyLevelRight.CanActAs],
|
|
98
|
+
};
|
|
99
|
+
async function createStore(logger, context, options = {}) {
|
|
100
|
+
const { withSession = true, withWallet = true } = options;
|
|
101
|
+
const store = new StoreInternal({ idps: [idp], networks: [storeNetwork] }, logger, context);
|
|
102
|
+
if (context && withSession) {
|
|
103
|
+
await store.setSession(session);
|
|
104
|
+
}
|
|
105
|
+
if (context && withWallet) {
|
|
106
|
+
await store.addWallet(primaryWallet);
|
|
107
|
+
}
|
|
108
|
+
return store;
|
|
109
|
+
}
|
|
110
|
+
function createController(store, notificationService, logger, context, requestOrigin = origin) {
|
|
111
|
+
return dappController(kernelInfo, dappUrl, userUrl, store, notificationService, logger, requestOrigin, context);
|
|
112
|
+
}
|
|
113
|
+
describe('dappController', () => {
|
|
114
|
+
let logger;
|
|
115
|
+
let notificationService;
|
|
116
|
+
beforeEach(() => {
|
|
117
|
+
logger = pino({ level: 'silent' }, sink());
|
|
118
|
+
notificationService = new NotificationService(logger);
|
|
119
|
+
ledgerMocks.getWithRetry.mockReset();
|
|
120
|
+
ledgerMocks.postWithRetry.mockReset();
|
|
121
|
+
ledgerMocks.getSynchronizerId.mockReset();
|
|
122
|
+
ledgerMocks.getSynchronizerId.mockResolvedValue('sync-from-ledger');
|
|
123
|
+
mockNetworkStatus.mockReset();
|
|
124
|
+
mockNetworkStatus.mockResolvedValue({
|
|
125
|
+
isConnected: true,
|
|
126
|
+
reason: undefined,
|
|
127
|
+
cantonVersion: '3.4',
|
|
128
|
+
});
|
|
129
|
+
mockUuidV4.mockReset();
|
|
130
|
+
});
|
|
131
|
+
afterEach(() => {
|
|
132
|
+
vi.clearAllMocks();
|
|
133
|
+
});
|
|
134
|
+
describe('connect', () => {
|
|
135
|
+
it('returns unauthenticated when there is no auth context', async () => {
|
|
136
|
+
const store = await createStore(logger, auth, {
|
|
137
|
+
withSession: false,
|
|
138
|
+
});
|
|
139
|
+
const controller = createController(store, notificationService, logger, undefined);
|
|
140
|
+
await expect(controller.connect()).resolves.toEqual({
|
|
141
|
+
isConnected: false,
|
|
142
|
+
isNetworkConnected: false,
|
|
143
|
+
networkReason: 'Unauthenticated',
|
|
144
|
+
userUrl: `${userUrl}/login/`,
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
it('returns unauthenticated when there is no session', async () => {
|
|
148
|
+
const store = await createStore(logger, auth, {
|
|
149
|
+
withSession: false,
|
|
150
|
+
});
|
|
151
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
152
|
+
await expect(controller.connect()).resolves.toEqual({
|
|
153
|
+
isConnected: false,
|
|
154
|
+
isNetworkConnected: false,
|
|
155
|
+
networkReason: 'Unauthenticated',
|
|
156
|
+
userUrl: `${userUrl}/login/`,
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
it('connects and emits statusChanged and connected', async () => {
|
|
160
|
+
const store = await createStore(logger, auth);
|
|
161
|
+
const notifier = notificationService.getNotifier(auth.userId);
|
|
162
|
+
const emitSpy = vi.spyOn(notifier, 'emit');
|
|
163
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
164
|
+
const result = await controller.connect();
|
|
165
|
+
expect(result).toMatchObject({
|
|
166
|
+
isConnected: true,
|
|
167
|
+
reason: 'OK',
|
|
168
|
+
isNetworkConnected: true,
|
|
169
|
+
networkReason: 'OK',
|
|
170
|
+
userUrl: `${userUrl}/login/`,
|
|
171
|
+
});
|
|
172
|
+
expect(mockNetworkStatus).toHaveBeenCalled();
|
|
173
|
+
expect(emitSpy).toHaveBeenCalledWith('statusChanged', expect.objectContaining({
|
|
174
|
+
connection: expect.objectContaining({
|
|
175
|
+
isConnected: true,
|
|
176
|
+
}),
|
|
177
|
+
session: {
|
|
178
|
+
accessToken: auth.accessToken,
|
|
179
|
+
userId: auth.userId,
|
|
180
|
+
},
|
|
181
|
+
}));
|
|
182
|
+
expect(emitSpy).toHaveBeenCalledWith('connected', expect.objectContaining({
|
|
183
|
+
provider: expect.objectContaining({ id: kernelInfo.id }),
|
|
184
|
+
}));
|
|
185
|
+
});
|
|
186
|
+
it('reflects disconnected ledger in network status', async () => {
|
|
187
|
+
mockNetworkStatus.mockResolvedValue({
|
|
188
|
+
isConnected: false,
|
|
189
|
+
reason: 'Ledger unreachable',
|
|
190
|
+
});
|
|
191
|
+
const store = await createStore(logger, auth);
|
|
192
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
193
|
+
const result = await controller.connect();
|
|
194
|
+
expect(result).toMatchObject({
|
|
195
|
+
isConnected: true,
|
|
196
|
+
isNetworkConnected: false,
|
|
197
|
+
networkReason: 'Ledger unreachable',
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
describe('disconnect', () => {
|
|
202
|
+
it('returns null when there is no auth context', async () => {
|
|
203
|
+
const store = await createStore(logger, auth);
|
|
204
|
+
const removeSessionSpy = vi.spyOn(store, 'removeSession');
|
|
205
|
+
const controller = createController(store, notificationService, logger, undefined);
|
|
206
|
+
await expect(controller.disconnect()).resolves.toBeNull();
|
|
207
|
+
expect(removeSessionSpy).not.toHaveBeenCalled();
|
|
208
|
+
});
|
|
209
|
+
it('removes the session and emits statusChanged', async () => {
|
|
210
|
+
const store = await createStore(logger, auth);
|
|
211
|
+
const notifier = notificationService.getNotifier(auth.userId);
|
|
212
|
+
const emitSpy = vi.spyOn(notifier, 'emit');
|
|
213
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
214
|
+
await controller.disconnect();
|
|
215
|
+
await expect(store.getSession()).resolves.toBeUndefined();
|
|
216
|
+
expect(emitSpy).toHaveBeenCalledWith('statusChanged', expect.objectContaining({
|
|
217
|
+
connection: expect.objectContaining({
|
|
218
|
+
isConnected: false,
|
|
219
|
+
reason: 'disconnect',
|
|
220
|
+
}),
|
|
221
|
+
}));
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
describe('isConnected', () => {
|
|
225
|
+
it('returns unauthenticated when there is no session', async () => {
|
|
226
|
+
const store = await createStore(logger, auth, {
|
|
227
|
+
withSession: false,
|
|
228
|
+
});
|
|
229
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
230
|
+
await expect(controller.isConnected()).resolves.toEqual({
|
|
231
|
+
isConnected: false,
|
|
232
|
+
isNetworkConnected: false,
|
|
233
|
+
networkReason: 'Unauthenticated',
|
|
234
|
+
userUrl: `${userUrl}/login/`,
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
it('returns connected status when authenticated', async () => {
|
|
238
|
+
const store = await createStore(logger, auth);
|
|
239
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
240
|
+
await expect(controller.isConnected()).resolves.toEqual({
|
|
241
|
+
isConnected: true,
|
|
242
|
+
reason: 'OK',
|
|
243
|
+
isNetworkConnected: true,
|
|
244
|
+
networkReason: 'OK',
|
|
245
|
+
userUrl: `${userUrl}/login/`,
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
describe('status', () => {
|
|
250
|
+
it('returns unauthenticated status when there is no session', async () => {
|
|
251
|
+
const store = await createStore(logger, auth, {
|
|
252
|
+
withSession: false,
|
|
253
|
+
});
|
|
254
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
255
|
+
const result = await controller.status();
|
|
256
|
+
expect(result.connection).toMatchObject({
|
|
257
|
+
isConnected: false,
|
|
258
|
+
reason: 'Unauthenticated',
|
|
259
|
+
});
|
|
260
|
+
expect(result.network).toBeUndefined();
|
|
261
|
+
});
|
|
262
|
+
it('returns full status when authenticated', async () => {
|
|
263
|
+
const store = await createStore(logger, auth);
|
|
264
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
265
|
+
const result = await controller.status();
|
|
266
|
+
expect(result).toMatchObject({
|
|
267
|
+
provider: expect.objectContaining({ id: kernelInfo.id }),
|
|
268
|
+
connection: {
|
|
269
|
+
isConnected: true,
|
|
270
|
+
reason: 'OK',
|
|
271
|
+
isNetworkConnected: true,
|
|
272
|
+
networkReason: 'OK',
|
|
273
|
+
},
|
|
274
|
+
network: {
|
|
275
|
+
networkId: storeNetwork.id,
|
|
276
|
+
ledgerApi: storeNetwork.ledgerApi.baseUrl,
|
|
277
|
+
accessToken: auth.accessToken,
|
|
278
|
+
},
|
|
279
|
+
session: {
|
|
280
|
+
id: session.id,
|
|
281
|
+
accessToken: auth.accessToken,
|
|
282
|
+
userId: auth.userId,
|
|
283
|
+
},
|
|
284
|
+
userUrl: `${userUrl}/login/`,
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
describe('ledgerApi', () => {
|
|
289
|
+
it('performs GET via ledger client', async () => {
|
|
290
|
+
ledgerMocks.getWithRetry.mockResolvedValueOnce({ ok: true });
|
|
291
|
+
const store = await createStore(logger, auth);
|
|
292
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
293
|
+
const result = await controller.ledgerApi({
|
|
294
|
+
requestMethod: 'get',
|
|
295
|
+
resource: '/v2/parties',
|
|
296
|
+
path: { partyId: 'party::x' },
|
|
297
|
+
query: { limit: '10' },
|
|
298
|
+
});
|
|
299
|
+
expect(ledgerMocks.getWithRetry).toHaveBeenCalledWith('/v2/parties', undefined, {
|
|
300
|
+
path: { partyId: 'party::x' },
|
|
301
|
+
query: { limit: '10' },
|
|
302
|
+
});
|
|
303
|
+
expect(result).toEqual({ ok: true });
|
|
304
|
+
});
|
|
305
|
+
it('performs POST via ledger client', async () => {
|
|
306
|
+
ledgerMocks.postWithRetry.mockResolvedValueOnce({ created: true });
|
|
307
|
+
const store = await createStore(logger, auth);
|
|
308
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
309
|
+
const result = await controller.ledgerApi({
|
|
310
|
+
requestMethod: 'post',
|
|
311
|
+
resource: '/v2/commands/submit-and-wait',
|
|
312
|
+
body: { commands: [] },
|
|
313
|
+
query: { wait: 'true' },
|
|
314
|
+
});
|
|
315
|
+
expect(ledgerMocks.postWithRetry).toHaveBeenCalledWith('/v2/commands/submit-and-wait', { commands: [] }, undefined, { query: { wait: 'true' }, path: {} });
|
|
316
|
+
expect(result).toEqual({ created: true });
|
|
317
|
+
});
|
|
318
|
+
it('throws for unsupported request methods', async () => {
|
|
319
|
+
const store = await createStore(logger, auth);
|
|
320
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
321
|
+
await expect(controller.ledgerApi({
|
|
322
|
+
requestMethod: 'patch',
|
|
323
|
+
resource: '/v2/parties',
|
|
324
|
+
})).rejects.toThrow('Unsupported request method: patch');
|
|
325
|
+
});
|
|
326
|
+
it('throws when auth context is missing', async () => {
|
|
327
|
+
const store = await createStore(logger, auth);
|
|
328
|
+
const controller = createController(store, notificationService, logger, undefined);
|
|
329
|
+
await expect(controller.ledgerApi({
|
|
330
|
+
requestMethod: 'get',
|
|
331
|
+
resource: '/v2/parties',
|
|
332
|
+
})).rejects.toThrow();
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
describe('prepareExecute', () => {
|
|
336
|
+
const prepareParams = {
|
|
337
|
+
commands: [
|
|
338
|
+
{
|
|
339
|
+
CreateCommand: {
|
|
340
|
+
templateId: 'pkg:Mod:T',
|
|
341
|
+
createArguments: {},
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
],
|
|
345
|
+
};
|
|
346
|
+
it('throws when auth context is missing', async () => {
|
|
347
|
+
const store = await createStore(logger, auth);
|
|
348
|
+
const controller = createController(store, notificationService, logger, undefined);
|
|
349
|
+
await expect(controller.prepareExecute(prepareParams)).rejects.toThrow('Unauthenticated context');
|
|
350
|
+
});
|
|
351
|
+
it('throws when there is no primary wallet', async () => {
|
|
352
|
+
const store = await createStore(logger, auth, { withWallet: false });
|
|
353
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
354
|
+
await expect(controller.prepareExecute(prepareParams)).rejects.toThrow('No primary wallet found');
|
|
355
|
+
});
|
|
356
|
+
it('prepares a transaction and returns the approve URL', async () => {
|
|
357
|
+
mockUuidV4.mockReturnValueOnce('generated-command-id');
|
|
358
|
+
mockUuidV4.mockReturnValueOnce('transaction-id');
|
|
359
|
+
ledgerMocks.postWithRetry.mockResolvedValueOnce({
|
|
360
|
+
preparedTransaction: 'prepared-blob',
|
|
361
|
+
preparedTransactionHash: 'hash',
|
|
362
|
+
});
|
|
363
|
+
const store = await createStore(logger, auth);
|
|
364
|
+
const setTransactionSpy = vi.spyOn(store, 'setTransaction');
|
|
365
|
+
const notifier = notificationService.getNotifier(auth.userId);
|
|
366
|
+
const emitSpy = vi.spyOn(notifier, 'emit');
|
|
367
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
368
|
+
const result = await controller.prepareExecute(prepareParams);
|
|
369
|
+
expect(emitSpy).toHaveBeenCalledWith('txChanged', {
|
|
370
|
+
status: 'pending',
|
|
371
|
+
commandId: 'generated-command-id',
|
|
372
|
+
});
|
|
373
|
+
expect(ledgerMocks.postWithRetry).toHaveBeenCalledWith('/v2/interactive-submission/prepare', expect.any(Object));
|
|
374
|
+
expect(setTransactionSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
375
|
+
id: 'transaction-id',
|
|
376
|
+
commandId: 'generated-command-id',
|
|
377
|
+
status: 'pending',
|
|
378
|
+
preparedTransaction: 'prepared-blob',
|
|
379
|
+
preparedTransactionHash: 'hash',
|
|
380
|
+
origin,
|
|
381
|
+
}));
|
|
382
|
+
expect(result.userUrl).toBe(`${userUrl}/approve/index.html?transactionId=transaction-id&commandId=generated-command-id&closeafteraction`);
|
|
383
|
+
});
|
|
384
|
+
it('uses the provided commandId when present', async () => {
|
|
385
|
+
mockUuidV4.mockReturnValueOnce('transaction-id');
|
|
386
|
+
ledgerMocks.postWithRetry.mockResolvedValueOnce({
|
|
387
|
+
preparedTransaction: 'prepared-blob',
|
|
388
|
+
preparedTransactionHash: 'hash',
|
|
389
|
+
});
|
|
390
|
+
const store = await createStore(logger, auth);
|
|
391
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
392
|
+
await controller.prepareExecute({
|
|
393
|
+
...prepareParams,
|
|
394
|
+
commandId: 'existing-command-id',
|
|
395
|
+
});
|
|
396
|
+
expect(mockUuidV4).toHaveBeenCalledOnce();
|
|
397
|
+
expect(ledgerMocks.postWithRetry.mock.calls[0][1]).toMatchObject({
|
|
398
|
+
commandId: 'existing-command-id',
|
|
399
|
+
});
|
|
400
|
+
});
|
|
401
|
+
it('fetches synchronizerId from ledger when not on network', async () => {
|
|
402
|
+
const networkWithoutSync = {
|
|
403
|
+
...storeNetwork,
|
|
404
|
+
synchronizerId: undefined,
|
|
405
|
+
};
|
|
406
|
+
const store = new StoreInternal({ idps: [idp], networks: [networkWithoutSync] }, logger, auth);
|
|
407
|
+
await store.setSession(session);
|
|
408
|
+
await store.addWallet(primaryWallet);
|
|
409
|
+
mockUuidV4.mockReturnValueOnce('cmd-id');
|
|
410
|
+
mockUuidV4.mockReturnValueOnce('tx-id');
|
|
411
|
+
ledgerMocks.postWithRetry.mockResolvedValueOnce({
|
|
412
|
+
preparedTransaction: 'blob',
|
|
413
|
+
preparedTransactionHash: 'hash',
|
|
414
|
+
});
|
|
415
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
416
|
+
await controller.prepareExecute(prepareParams);
|
|
417
|
+
expect(ledgerMocks.getSynchronizerId).toHaveBeenCalled();
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
describe('signMessage', () => {
|
|
421
|
+
it('throws when message is missing', async () => {
|
|
422
|
+
const store = await createStore(logger, auth);
|
|
423
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
424
|
+
await expect(controller.signMessage({ message: '' })).rejects.toThrow('Message is required');
|
|
425
|
+
});
|
|
426
|
+
it('throws when auth context is missing', async () => {
|
|
427
|
+
const store = await createStore(logger, auth);
|
|
428
|
+
const controller = createController(store, notificationService, logger, undefined);
|
|
429
|
+
await expect(controller.signMessage({ message: 'hello' })).rejects.toThrow('Unauthenticated context');
|
|
430
|
+
});
|
|
431
|
+
it('throws when there is no primary wallet', async () => {
|
|
432
|
+
const store = await createStore(logger, auth, { withWallet: false });
|
|
433
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
434
|
+
await expect(controller.signMessage({ message: 'hello' })).rejects.toThrow('No primary wallet found');
|
|
435
|
+
});
|
|
436
|
+
it('stores a pending message and returns the sign URL', async () => {
|
|
437
|
+
mockUuidV4.mockReturnValueOnce('message-id');
|
|
438
|
+
const store = await createStore(logger, auth);
|
|
439
|
+
const setMessageSpy = vi.spyOn(store, 'setMessageRaw');
|
|
440
|
+
const notifier = notificationService.getNotifier(auth.userId);
|
|
441
|
+
const emitSpy = vi.spyOn(notifier, 'emit');
|
|
442
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
443
|
+
const result = await controller.signMessage({ message: 'hello' });
|
|
444
|
+
expect(setMessageSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
445
|
+
id: 'message-id',
|
|
446
|
+
status: 'pending',
|
|
447
|
+
userId: auth.userId,
|
|
448
|
+
partyId: primaryWallet.partyId,
|
|
449
|
+
publicKey: primaryWallet.publicKey,
|
|
450
|
+
message: 'hello',
|
|
451
|
+
origin,
|
|
452
|
+
}));
|
|
453
|
+
expect(emitSpy).toHaveBeenCalledWith('messageSignature', {
|
|
454
|
+
status: 'pending',
|
|
455
|
+
messageId: 'message-id',
|
|
456
|
+
});
|
|
457
|
+
expect(result).toEqual({
|
|
458
|
+
messageId: 'message-id',
|
|
459
|
+
userUrl: `${userUrl}/sign-message/index.html?messageId=message-id&closeafteraction`,
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
});
|
|
463
|
+
describe('accounts', () => {
|
|
464
|
+
it('lists accounts from the store', async () => {
|
|
465
|
+
const store = await createStore(logger, auth);
|
|
466
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
467
|
+
const accounts = await controller.listAccounts();
|
|
468
|
+
expect(accounts).toHaveLength(1);
|
|
469
|
+
expect(accounts[0]?.partyId).toBe(primaryWallet.partyId);
|
|
470
|
+
});
|
|
471
|
+
it('returns the primary account', async () => {
|
|
472
|
+
const store = await createStore(logger, auth);
|
|
473
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
474
|
+
await expect(controller.getPrimaryAccount()).resolves.toEqual(primaryWallet);
|
|
475
|
+
});
|
|
476
|
+
it('throws when there is no primary account', async () => {
|
|
477
|
+
const store = await createStore(logger, auth, { withWallet: false });
|
|
478
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
479
|
+
await expect(controller.getPrimaryAccount()).rejects.toThrow('No primary wallet found');
|
|
480
|
+
});
|
|
481
|
+
it('returns the active network with access token when authenticated', async () => {
|
|
482
|
+
const store = await createStore(logger, auth);
|
|
483
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
484
|
+
await expect(controller.getActiveNetwork()).resolves.toEqual({
|
|
485
|
+
networkId: storeNetwork.id,
|
|
486
|
+
ledgerApi: storeNetwork.ledgerApi.baseUrl,
|
|
487
|
+
accessToken: auth.accessToken,
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
it('returns the active network without access token when unauthenticated', async () => {
|
|
491
|
+
const store = await createStore(logger, auth);
|
|
492
|
+
const controller = createController(store, notificationService, logger, undefined);
|
|
493
|
+
await expect(controller.getActiveNetwork()).resolves.toEqual({
|
|
494
|
+
networkId: storeNetwork.id,
|
|
495
|
+
ledgerApi: storeNetwork.ledgerApi.baseUrl,
|
|
496
|
+
});
|
|
497
|
+
});
|
|
498
|
+
});
|
|
499
|
+
describe('event-only methods', () => {
|
|
500
|
+
it.each([
|
|
501
|
+
'connected',
|
|
502
|
+
'onStatusChanged',
|
|
503
|
+
'accountsChanged',
|
|
504
|
+
'txChanged',
|
|
505
|
+
])('%s throws Only for events', async (method) => {
|
|
506
|
+
const store = await createStore(logger, auth);
|
|
507
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
508
|
+
await expect(controller[method]()).rejects.toThrow('Only for events.');
|
|
509
|
+
});
|
|
510
|
+
it('messageSignature throws Only for events', async () => {
|
|
511
|
+
const store = await createStore(logger, auth);
|
|
512
|
+
const controller = createController(store, notificationService, logger, auth);
|
|
513
|
+
expect(() => controller.messageSignature()).toThrow('Only for events.');
|
|
514
|
+
});
|
|
515
|
+
});
|
|
516
|
+
});
|
|
@@ -12,6 +12,7 @@ import { AccountsChanged } from './typings.js';
|
|
|
12
12
|
import { GetPrimaryAccount } from './typings.js';
|
|
13
13
|
import { ListAccounts } from './typings.js';
|
|
14
14
|
import { TxChanged } from './typings.js';
|
|
15
|
+
import { MessageSignature } from './typings.js';
|
|
15
16
|
export type Methods = {
|
|
16
17
|
status: Status;
|
|
17
18
|
connect: Connect;
|
|
@@ -27,6 +28,7 @@ export type Methods = {
|
|
|
27
28
|
getPrimaryAccount: GetPrimaryAccount;
|
|
28
29
|
listAccounts: ListAccounts;
|
|
29
30
|
txChanged: TxChanged;
|
|
31
|
+
messageSignature: MessageSignature;
|
|
30
32
|
};
|
|
31
33
|
declare function buildController(methods: Methods): {
|
|
32
34
|
status: Status;
|
|
@@ -43,6 +45,7 @@ declare function buildController(methods: Methods): {
|
|
|
43
45
|
getPrimaryAccount: GetPrimaryAccount;
|
|
44
46
|
listAccounts: ListAccounts;
|
|
45
47
|
txChanged: TxChanged;
|
|
48
|
+
messageSignature: MessageSignature;
|
|
46
49
|
};
|
|
47
50
|
export default buildController;
|
|
48
51
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dapp-api/rpc-gen/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dapp-api/rpc-gen/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAE/C,MAAM,MAAM,OAAO,GAAG;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,UAAU,CAAA;IACtB,WAAW,EAAE,WAAW,CAAA;IACxB,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,cAAc,EAAE,cAAc,CAAA;IAC9B,WAAW,EAAE,WAAW,CAAA;IACxB,SAAS,EAAE,SAAS,CAAA;IACpB,SAAS,EAAE,SAAS,CAAA;IACpB,eAAe,EAAE,eAAe,CAAA;IAChC,eAAe,EAAE,eAAe,CAAA;IAChC,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,YAAY,EAAE,YAAY,CAAA;IAC1B,SAAS,EAAE,SAAS,CAAA;IACpB,gBAAgB,EAAE,gBAAgB,CAAA;CACrC,CAAA;AAED,iBAAS,eAAe,CAAC,OAAO,EAAE,OAAO;;;;;;;;;;;;;;;;EAkBxC;AAED,eAAe,eAAe,CAAA"}
|