@canton-network/wallet-gateway-remote 1.4.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/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 +60 -4
- 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.map +1 -1
- package/dist/dapp-api/controller.js +54 -24
- 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 +3 -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.test.js +12 -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 +6 -4
- package/dist/user-api/controller.d.ts.map +1 -1
- package/dist/user-api/controller.js +111 -94
- 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 +12 -0
- package/dist/user-api/rpc-gen/index.d.ts.map +1 -1
- package/dist/user-api/rpc-gen/index.js +4 -0
- package/dist/user-api/rpc-gen/typings.d.ts +52 -3
- package/dist/user-api/rpc-gen/typings.d.ts.map +1 -1
- package/dist/utils.d.ts +17 -1
- 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 -4
- package/dist/web/frontend/assets/404-MVLWUPwN.js +5 -0
- package/dist/web/frontend/assets/{activities-NY8oZAkH.js → activities-DaWkmGqA.js} +2 -2
- package/dist/web/frontend/assets/{addIdentityProvider-38ghz3RT.js → addIdentityProvider--rBb0ihb.js} +2 -2
- package/dist/web/frontend/assets/{addNetwork-BaDhbrZl.js → addNetwork-C6UDsRkU.js} +4 -4
- 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-BZ9h_VOJ.js → identityProviders-Dra4qG6t.js} +2 -2
- package/dist/web/frontend/assets/{index-B-HiKugW.js → index-Bm76pXA_.js} +2 -2
- package/dist/web/frontend/assets/index-D1dC4Cl9.js +4477 -0
- package/dist/web/frontend/assets/{login-CqwMEG9J.js → login-BC8a-kD_.js} +2 -2
- package/dist/web/frontend/assets/{networks-BJvRi47M.js → networks-B3ztsogL.js} +2 -2
- package/dist/web/frontend/assets/{reviewIdentityProvider-ySlQnw5R.js → reviewIdentityProvider-Co420Dbk.js} +3 -3
- package/dist/web/frontend/assets/{reviewNetwork-DrVxeHd4.js → reviewNetwork-B-Sh8pCH.js} +3 -3
- package/dist/web/frontend/assets/{settings-BVNkaUyJ.js → settings-DvyUjqLl.js} +1 -1
- package/dist/web/frontend/assets/{state-qAsNw5qf.js → state-Bq65GwdF.js} +1 -1
- package/dist/web/frontend/assets/{utils-BDkHxi8V.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 -3
- 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 +36 -32
- package/dist/web/frontend/assets/404-C7V2yl2z.js +0 -5
- package/dist/web/frontend/assets/addParty-j3JWZX5a.js +0 -41
- package/dist/web/frontend/assets/approve-43nVzAAC.js +0 -21
- package/dist/web/frontend/assets/callback-BBMiCjHR.js +0 -1
- package/dist/web/frontend/assets/index-DoNqknyE.js +0 -4042
|
@@ -0,0 +1,93 @@
|
|
|
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 { describe, expect, it, vi, beforeEach } from 'vitest';
|
|
4
|
+
import { jwtAuth } from './jwtAuth.js';
|
|
5
|
+
import { pino } from 'pino';
|
|
6
|
+
import { sink } from 'pino-test';
|
|
7
|
+
describe('jwtAuth', () => {
|
|
8
|
+
const verifyToken = vi.fn();
|
|
9
|
+
const authService = { verifyToken };
|
|
10
|
+
const logger = pino({ level: 'silent' }, sink());
|
|
11
|
+
let next;
|
|
12
|
+
let status;
|
|
13
|
+
let json;
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
verifyToken.mockReset();
|
|
16
|
+
next = vi.fn();
|
|
17
|
+
status = vi.fn().mockReturnThis();
|
|
18
|
+
json = vi.fn();
|
|
19
|
+
});
|
|
20
|
+
function makeReq(partial) {
|
|
21
|
+
return {
|
|
22
|
+
headers: {},
|
|
23
|
+
query: {},
|
|
24
|
+
...partial,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function makeRes() {
|
|
28
|
+
return { status, json };
|
|
29
|
+
}
|
|
30
|
+
it('sets authContext and calls next when verification succeeds', async () => {
|
|
31
|
+
const ctx = { userId: 'alice', accessToken: 'tok' };
|
|
32
|
+
verifyToken.mockResolvedValue(ctx);
|
|
33
|
+
const req = makeReq({
|
|
34
|
+
headers: { authorization: 'Bearer abc' },
|
|
35
|
+
});
|
|
36
|
+
const res = makeRes();
|
|
37
|
+
const middleware = jwtAuth(authService, logger);
|
|
38
|
+
await middleware(req, res, next);
|
|
39
|
+
expect(verifyToken).toHaveBeenCalledWith('Bearer abc');
|
|
40
|
+
expect(req.authContext).toEqual(ctx);
|
|
41
|
+
expect(next).toHaveBeenCalledOnce();
|
|
42
|
+
expect(status).not.toHaveBeenCalled();
|
|
43
|
+
});
|
|
44
|
+
it('uses Bearer token from query when Authorization header is absent', async () => {
|
|
45
|
+
const ctx = { userId: 'bob', accessToken: 'tok' };
|
|
46
|
+
verifyToken.mockResolvedValue(ctx);
|
|
47
|
+
const req = makeReq({
|
|
48
|
+
query: { token: 'query-jwt' },
|
|
49
|
+
});
|
|
50
|
+
const res = makeRes();
|
|
51
|
+
const middleware = jwtAuth(authService, logger);
|
|
52
|
+
await middleware(req, res, next);
|
|
53
|
+
expect(verifyToken).toHaveBeenCalledWith('Bearer query-jwt');
|
|
54
|
+
expect(req.authContext).toEqual(ctx);
|
|
55
|
+
expect(next).toHaveBeenCalledOnce();
|
|
56
|
+
});
|
|
57
|
+
it('passes undefined to verifyToken when no credentials are present', async () => {
|
|
58
|
+
verifyToken.mockResolvedValue(undefined);
|
|
59
|
+
const req = makeReq({});
|
|
60
|
+
const res = makeRes();
|
|
61
|
+
const middleware = jwtAuth(authService, logger);
|
|
62
|
+
await middleware(req, res, next);
|
|
63
|
+
expect(verifyToken).toHaveBeenCalledWith(undefined);
|
|
64
|
+
expect(req.authContext).toBeUndefined();
|
|
65
|
+
expect(next).toHaveBeenCalledOnce();
|
|
66
|
+
});
|
|
67
|
+
it('returns 401 JSON when verification throws', async () => {
|
|
68
|
+
verifyToken.mockRejectedValue(new Error('bad sig'));
|
|
69
|
+
const req = makeReq({
|
|
70
|
+
headers: { authorization: 'Bearer x' },
|
|
71
|
+
});
|
|
72
|
+
const res = makeRes();
|
|
73
|
+
const middleware = jwtAuth(authService, logger);
|
|
74
|
+
await middleware(req, res, next);
|
|
75
|
+
expect(next).not.toHaveBeenCalled();
|
|
76
|
+
expect(status).toHaveBeenCalledWith(401);
|
|
77
|
+
expect(json).toHaveBeenCalledWith({
|
|
78
|
+
error: 'Invalid or expired token: bad sig',
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
it('stringifies non-Error rejection values in the response', async () => {
|
|
82
|
+
verifyToken.mockRejectedValue('rejected');
|
|
83
|
+
const req = makeReq({
|
|
84
|
+
headers: { authorization: 'Bearer x' },
|
|
85
|
+
});
|
|
86
|
+
const res = makeRes();
|
|
87
|
+
const middleware = jwtAuth(authService, logger);
|
|
88
|
+
await middleware(req, res, next);
|
|
89
|
+
expect(json).toHaveBeenCalledWith({
|
|
90
|
+
error: 'Invalid or expired token: rejected',
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -24,6 +24,18 @@ describe('ipRateLimitKeyGenerator', () => {
|
|
|
24
24
|
};
|
|
25
25
|
expect(ipRateLimitKeyGenerator(req)).toBe('ip:2001:db8:abcd::/56');
|
|
26
26
|
});
|
|
27
|
+
test('falls back to socket.remoteAddress when ip is unset', () => {
|
|
28
|
+
const req = {
|
|
29
|
+
socket: { remoteAddress: '10.0.0.2' },
|
|
30
|
+
};
|
|
31
|
+
expect(ipRateLimitKeyGenerator(req)).toBe('ip:10.0.0.2');
|
|
32
|
+
});
|
|
33
|
+
test('uses unknown when neither ip nor remoteAddress is set', () => {
|
|
34
|
+
const req = {
|
|
35
|
+
socket: {},
|
|
36
|
+
};
|
|
37
|
+
expect(ipRateLimitKeyGenerator(req)).toBe('ip:unknown');
|
|
38
|
+
});
|
|
27
39
|
});
|
|
28
40
|
describe('rateLimitKeyGenerator', () => {
|
|
29
41
|
test('uses authenticated user id when available', () => {
|
|
@@ -12,7 +12,7 @@ export function sessionHandler(store, allowedPaths, logger) {
|
|
|
12
12
|
const context = req.authContext;
|
|
13
13
|
const allowedMethods = allowedPaths[req.baseUrl];
|
|
14
14
|
if (req.method !== 'POST') {
|
|
15
|
-
logger.debug(
|
|
15
|
+
logger.debug(`Skipping authentication for ${req.method} request to ${req.baseUrl}`);
|
|
16
16
|
next();
|
|
17
17
|
}
|
|
18
18
|
else if (allowedMethods &&
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionHandler.test.d.ts","sourceRoot":"","sources":["../../src/middleware/sessionHandler.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,121 @@
|
|
|
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 { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import { pino } from 'pino';
|
|
5
|
+
import { sink } from 'pino-test';
|
|
6
|
+
import { sessionHandler } from './sessionHandler.js';
|
|
7
|
+
describe('sessionHandler', () => {
|
|
8
|
+
const getSession = vi.fn();
|
|
9
|
+
const withAuthContext = vi.fn(() => ({ getSession }));
|
|
10
|
+
const store = { withAuthContext };
|
|
11
|
+
const logger = pino({ level: 'silent' }, sink());
|
|
12
|
+
const allowedPaths = {
|
|
13
|
+
'/api/v0/user': ['addSession', 'listNetworks', 'getUser'],
|
|
14
|
+
'/api/v0/dapp': ['*'],
|
|
15
|
+
};
|
|
16
|
+
let next;
|
|
17
|
+
let status;
|
|
18
|
+
let json;
|
|
19
|
+
const authContext = {
|
|
20
|
+
userId: 'user-1',
|
|
21
|
+
accessToken: 'access-token',
|
|
22
|
+
};
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
getSession.mockReset();
|
|
25
|
+
withAuthContext.mockClear();
|
|
26
|
+
withAuthContext.mockReturnValue({ getSession });
|
|
27
|
+
next = vi.fn();
|
|
28
|
+
status = vi.fn().mockReturnThis();
|
|
29
|
+
json = vi.fn();
|
|
30
|
+
});
|
|
31
|
+
function makeReq(partial) {
|
|
32
|
+
return {
|
|
33
|
+
method: 'POST',
|
|
34
|
+
baseUrl: '/api/v0/user',
|
|
35
|
+
body: { method: 'listWallets' },
|
|
36
|
+
authContext,
|
|
37
|
+
...partial,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function makeRes() {
|
|
41
|
+
return { status, json };
|
|
42
|
+
}
|
|
43
|
+
it('skips session check for non-POST requests', async () => {
|
|
44
|
+
const req = makeReq({ method: 'GET' });
|
|
45
|
+
const res = makeRes();
|
|
46
|
+
const middleware = sessionHandler(store, allowedPaths, logger);
|
|
47
|
+
await middleware(req, res, next);
|
|
48
|
+
expect(withAuthContext).not.toHaveBeenCalled();
|
|
49
|
+
expect(next).toHaveBeenCalledOnce();
|
|
50
|
+
expect(status).not.toHaveBeenCalled();
|
|
51
|
+
});
|
|
52
|
+
it('allows unauthenticated POST when the RPC method is on the allow list', async () => {
|
|
53
|
+
const req = makeReq({ body: { method: 'addSession' } });
|
|
54
|
+
const res = makeRes();
|
|
55
|
+
const middleware = sessionHandler(store, allowedPaths, logger);
|
|
56
|
+
await middleware(req, res, next);
|
|
57
|
+
expect(withAuthContext).not.toHaveBeenCalled();
|
|
58
|
+
expect(next).toHaveBeenCalledOnce();
|
|
59
|
+
expect(status).not.toHaveBeenCalled();
|
|
60
|
+
});
|
|
61
|
+
it('allows unauthenticated POST when the path uses a wildcard allow list', async () => {
|
|
62
|
+
const req = makeReq({
|
|
63
|
+
baseUrl: '/api/v0/dapp',
|
|
64
|
+
body: { method: 'connect' },
|
|
65
|
+
});
|
|
66
|
+
const res = makeRes();
|
|
67
|
+
const middleware = sessionHandler(store, allowedPaths, logger);
|
|
68
|
+
await middleware(req, res, next);
|
|
69
|
+
expect(withAuthContext).not.toHaveBeenCalled();
|
|
70
|
+
expect(next).toHaveBeenCalledOnce();
|
|
71
|
+
});
|
|
72
|
+
it('calls next when an active session exists for a protected method', async () => {
|
|
73
|
+
getSession.mockResolvedValue({
|
|
74
|
+
id: 'session-1',
|
|
75
|
+
network: 'network1',
|
|
76
|
+
accessToken: 'session-token',
|
|
77
|
+
});
|
|
78
|
+
const req = makeReq({ body: { method: 'listWallets' } });
|
|
79
|
+
const res = makeRes();
|
|
80
|
+
const middleware = sessionHandler(store, allowedPaths, logger);
|
|
81
|
+
await middleware(req, res, next);
|
|
82
|
+
expect(withAuthContext).toHaveBeenCalledWith(authContext);
|
|
83
|
+
expect(getSession).toHaveBeenCalled();
|
|
84
|
+
expect(next).toHaveBeenCalledOnce();
|
|
85
|
+
expect(status).not.toHaveBeenCalled();
|
|
86
|
+
});
|
|
87
|
+
it('returns 401 when no session exists for a protected method', async () => {
|
|
88
|
+
getSession.mockResolvedValue(undefined);
|
|
89
|
+
const req = makeReq({ body: { method: 'listWallets' } });
|
|
90
|
+
const res = makeRes();
|
|
91
|
+
const middleware = sessionHandler(store, allowedPaths, logger);
|
|
92
|
+
await middleware(req, res, next);
|
|
93
|
+
expect(withAuthContext).toHaveBeenCalledWith(authContext);
|
|
94
|
+
expect(next).not.toHaveBeenCalled();
|
|
95
|
+
expect(status).toHaveBeenCalledWith(401);
|
|
96
|
+
expect(json).toHaveBeenCalledWith({
|
|
97
|
+
error: 'No active session found',
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
it('requires a session when the path is not in the allow list config', async () => {
|
|
101
|
+
getSession.mockResolvedValue(undefined);
|
|
102
|
+
const req = makeReq({
|
|
103
|
+
baseUrl: '/api/v0/other',
|
|
104
|
+
body: { method: 'addSession' },
|
|
105
|
+
});
|
|
106
|
+
const res = makeRes();
|
|
107
|
+
const middleware = sessionHandler(store, allowedPaths, logger);
|
|
108
|
+
await middleware(req, res, next);
|
|
109
|
+
expect(withAuthContext).toHaveBeenCalledWith(authContext);
|
|
110
|
+
expect(status).toHaveBeenCalledWith(401);
|
|
111
|
+
});
|
|
112
|
+
it('requires a session when the RPC method is not on the path allow list', async () => {
|
|
113
|
+
getSession.mockResolvedValue(undefined);
|
|
114
|
+
const req = makeReq({ body: { method: 'removeSession' } });
|
|
115
|
+
const res = makeRes();
|
|
116
|
+
const middleware = sessionHandler(store, allowedPaths, logger);
|
|
117
|
+
await middleware(req, res, next);
|
|
118
|
+
expect(withAuthContext).toHaveBeenCalledWith(authContext);
|
|
119
|
+
expect(status).toHaveBeenCalledWith(401);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationService.test.d.ts","sourceRoot":"","sources":["../../src/notification/NotificationService.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,110 @@
|
|
|
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 { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import pino from 'pino';
|
|
5
|
+
import { consecutive, once, sink } from 'pino-test';
|
|
6
|
+
import { NotificationService } from './NotificationService.js';
|
|
7
|
+
describe('NotificationService', () => {
|
|
8
|
+
let mockLogger;
|
|
9
|
+
let logStream;
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
logStream = sink();
|
|
12
|
+
mockLogger = pino({ level: 'debug' }, logStream);
|
|
13
|
+
});
|
|
14
|
+
it('creates a notifier for a new notifierId', () => {
|
|
15
|
+
const service = new NotificationService(mockLogger);
|
|
16
|
+
const notifier = service.getNotifier('user-1');
|
|
17
|
+
expect(notifier).toBeDefined();
|
|
18
|
+
expect(typeof notifier.on).toBe('function');
|
|
19
|
+
expect(typeof notifier.emit).toBe('function');
|
|
20
|
+
expect(typeof notifier.removeListener).toBe('function');
|
|
21
|
+
});
|
|
22
|
+
it('returns the same notifier instance for the same notifierId', () => {
|
|
23
|
+
const service = new NotificationService(mockLogger);
|
|
24
|
+
const notifier1 = service.getNotifier('user-1');
|
|
25
|
+
const notifier2 = service.getNotifier('user-1');
|
|
26
|
+
expect(notifier1).toBe(notifier2);
|
|
27
|
+
});
|
|
28
|
+
it('returns different notifier instances for different notifierIds', () => {
|
|
29
|
+
const service = new NotificationService(mockLogger);
|
|
30
|
+
const notifier1 = service.getNotifier('user-1');
|
|
31
|
+
const notifier2 = service.getNotifier('user-2');
|
|
32
|
+
expect(notifier1).not.toBe(notifier2);
|
|
33
|
+
});
|
|
34
|
+
it('calls listeners when an event is emitted', () => {
|
|
35
|
+
const service = new NotificationService(mockLogger);
|
|
36
|
+
const notifier = service.getNotifier('user-1');
|
|
37
|
+
const listener = vi.fn();
|
|
38
|
+
notifier.on('txChanged', listener);
|
|
39
|
+
const result = notifier.emit('txChanged', { id: 123 });
|
|
40
|
+
expect(result).toBe(true);
|
|
41
|
+
expect(listener).toHaveBeenCalledTimes(1);
|
|
42
|
+
expect(listener).toHaveBeenCalledWith({ id: 123 });
|
|
43
|
+
});
|
|
44
|
+
it('returns false when emitting an event with no listeners', async () => {
|
|
45
|
+
const service = new NotificationService(mockLogger);
|
|
46
|
+
const notifier = service.getNotifier('user-1');
|
|
47
|
+
const result = notifier.emit('unknown-event');
|
|
48
|
+
expect(result).toBe(false);
|
|
49
|
+
await once(logStream, {
|
|
50
|
+
level: 20,
|
|
51
|
+
event: 'unknown-event',
|
|
52
|
+
args: [],
|
|
53
|
+
msg: 'Notifier emitted event: unknown-event for user-1',
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
it('logs every emitted event', async () => {
|
|
57
|
+
const service = new NotificationService(mockLogger);
|
|
58
|
+
const notifier = service.getNotifier('user-1');
|
|
59
|
+
notifier.emit('txChanged', { id: 123 });
|
|
60
|
+
await once(logStream, {
|
|
61
|
+
level: 20,
|
|
62
|
+
event: 'txChanged',
|
|
63
|
+
args: [{ id: 123 }],
|
|
64
|
+
msg: 'Notifier emitted event: txChanged for user-1',
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
it('removes listeners with removeListener', () => {
|
|
68
|
+
const service = new NotificationService(mockLogger);
|
|
69
|
+
const notifier = service.getNotifier('user-1');
|
|
70
|
+
const listener = vi.fn();
|
|
71
|
+
notifier.on('txChanged', listener);
|
|
72
|
+
notifier.removeListener('txChanged', listener);
|
|
73
|
+
const result = notifier.emit('txChanged', { id: 123 });
|
|
74
|
+
expect(result).toBe(false);
|
|
75
|
+
expect(listener).not.toHaveBeenCalled();
|
|
76
|
+
});
|
|
77
|
+
it('keeps listeners isolated between notifiers', () => {
|
|
78
|
+
const service = new NotificationService(mockLogger);
|
|
79
|
+
const notifier1 = service.getNotifier('user-1');
|
|
80
|
+
const notifier2 = service.getNotifier('user-2');
|
|
81
|
+
const listener1 = vi.fn();
|
|
82
|
+
const listener2 = vi.fn();
|
|
83
|
+
notifier1.on('txChanged', listener1);
|
|
84
|
+
notifier2.on('txChanged', listener2);
|
|
85
|
+
notifier1.emit('txChanged', { id: 1 });
|
|
86
|
+
expect(listener1).toHaveBeenCalledWith({ id: 1 });
|
|
87
|
+
expect(listener2).not.toHaveBeenCalled();
|
|
88
|
+
});
|
|
89
|
+
it('logs with the correct notifierId for each notifier', async () => {
|
|
90
|
+
const service = new NotificationService(mockLogger);
|
|
91
|
+
const notifier1 = service.getNotifier('user-1');
|
|
92
|
+
const notifier2 = service.getNotifier('user-2');
|
|
93
|
+
notifier1.emit('txChanged');
|
|
94
|
+
notifier2.emit('statusChanged');
|
|
95
|
+
await consecutive(logStream, [
|
|
96
|
+
{
|
|
97
|
+
level: 20,
|
|
98
|
+
event: 'txChanged',
|
|
99
|
+
args: [],
|
|
100
|
+
msg: 'Notifier emitted event: txChanged for user-1',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
level: 20,
|
|
104
|
+
event: 'statusChanged',
|
|
105
|
+
args: [],
|
|
106
|
+
msg: 'Notifier emitted event: statusChanged for user-2',
|
|
107
|
+
},
|
|
108
|
+
]);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { SigningDriverInterface, SigningProvider } from '@canton-network/core-signing-lib';
|
|
2
|
+
/**
|
|
3
|
+
* Signing drivers registered at Wallet Gateway startup.
|
|
4
|
+
* Partial because only configured providers are present (e.g. Dfns when env vars are set).
|
|
5
|
+
*/
|
|
6
|
+
export type SigningDrivers = Partial<Record<SigningProvider, SigningDriverInterface>>;
|
|
7
|
+
//# sourceMappingURL=signing-drivers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signing-drivers.d.ts","sourceRoot":"","sources":["../../src/signing/signing-drivers.ts"],"names":[],"mappings":"AAGA,OAAO,EACH,sBAAsB,EACtB,eAAe,EAClB,MAAM,kCAAkC,CAAA;AAEzC;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,CAChC,MAAM,CAAC,eAAe,EAAE,sBAAsB,CAAC,CAClD,CAAA"}
|
|
@@ -3,9 +3,8 @@ import { Logger } from 'pino';
|
|
|
3
3
|
import { NotificationService } from '../notification/NotificationService.js';
|
|
4
4
|
import { AuthContext } from '@canton-network/core-wallet-auth';
|
|
5
5
|
import { KernelInfo } from '../config/Config.js';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
export declare const userController: (kernelInfo: KernelInfo, userUrl: string, store: Store, notificationService: NotificationService, authContext: AuthContext | undefined, drivers: AvailableSigningDrivers, _logger: Logger, adminUserId?: string) => {
|
|
6
|
+
import type { SigningDrivers } from '../signing/signing-drivers.js';
|
|
7
|
+
export declare const userController: (kernelInfo: KernelInfo, userUrl: string, store: Store, notificationService: NotificationService, authContext: AuthContext | undefined, drivers: SigningDrivers, _logger: Logger, adminUserId?: string) => {
|
|
9
8
|
addNetwork: import("./rpc-gen/typings.js").AddNetwork;
|
|
10
9
|
removeNetwork: import("./rpc-gen/typings.js").RemoveNetwork;
|
|
11
10
|
listNetworks: import("./rpc-gen/typings.js").ListNetworks;
|
|
@@ -34,6 +33,9 @@ export declare const userController: (kernelInfo: KernelInfo, userUrl: string, s
|
|
|
34
33
|
listTransactions: import("./rpc-gen/typings.js").ListTransactions;
|
|
35
34
|
deleteTransaction: import("./rpc-gen/typings.js").DeleteTransaction;
|
|
36
35
|
getUser: import("./rpc-gen/typings.js").GetUser;
|
|
36
|
+
generateApiKey: import("./rpc-gen/typings.js").GenerateApiKey;
|
|
37
|
+
listApiKeys: import("./rpc-gen/typings.js").ListApiKeys;
|
|
38
|
+
removeApiKey: import("./rpc-gen/typings.js").RemoveApiKey;
|
|
39
|
+
listSigningProviderVaults: import("./rpc-gen/typings.js").ListSigningProviderVaults;
|
|
37
40
|
};
|
|
38
|
-
export {};
|
|
39
41
|
//# sourceMappingURL=controller.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/user-api/controller.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/user-api/controller.ts"],"names":[],"mappings":"AA+CA,OAAO,EAAE,KAAK,EAAW,MAAM,mCAAmC,CAAA;AAClE,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAC7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAA;AAC5E,OAAO,EAEH,WAAW,EAKd,MAAM,kCAAkC,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAEhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAYnE,eAAO,MAAM,cAAc,GACvB,YAAY,UAAU,EACtB,SAAS,MAAM,EACf,OAAO,KAAK,EACZ,qBAAqB,mBAAmB,EACxC,aAAa,WAAW,GAAG,SAAS,EACpC,SAAS,cAAc,EACvB,SAAS,MAAM,EACf,cAAc,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4hCvB,CAAA"}
|