@canton-network/wallet-gateway-remote 0.8.0 → 0.9.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/config/Config.d.ts +17 -4
- package/dist/config/Config.d.ts.map +1 -1
- package/dist/config/Config.js +9 -2
- package/dist/config/ConfigUtils.d.ts +5 -1
- package/dist/config/ConfigUtils.d.ts.map +1 -1
- package/dist/config/ConfigUtils.js +7 -0
- package/dist/dapp-api/controller.d.ts +1 -1
- package/dist/dapp-api/controller.d.ts.map +1 -1
- package/dist/dapp-api/controller.js +41 -37
- package/dist/dapp-api/server.d.ts +2 -2
- package/dist/dapp-api/server.d.ts.map +1 -1
- package/dist/dapp-api/server.js +6 -4
- package/dist/dapp-api/server.test.js +3 -4
- package/dist/example-config.d.ts +8 -2
- package/dist/example-config.d.ts.map +1 -1
- package/dist/example-config.js +8 -2
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +18 -7
- package/dist/ledger/party-allocation-service.d.ts.map +1 -1
- package/dist/ledger/party-allocation-service.js +19 -3
- package/dist/ledger/party-allocation-service.test.js +2 -7
- package/dist/user-api/controller.d.ts +2 -1
- package/dist/user-api/controller.d.ts.map +1 -1
- package/dist/user-api/controller.js +63 -19
- package/dist/user-api/rpc-gen/index.d.ts +3 -0
- package/dist/user-api/rpc-gen/index.d.ts.map +1 -1
- package/dist/user-api/rpc-gen/index.js +1 -0
- package/dist/user-api/rpc-gen/typings.d.ts +14 -0
- package/dist/user-api/rpc-gen/typings.d.ts.map +1 -1
- package/dist/user-api/server.d.ts +1 -1
- package/dist/user-api/server.d.ts.map +1 -1
- package/dist/user-api/server.js +2 -2
- package/dist/user-api/server.test.js +3 -2
- package/dist/utils.d.ts +14 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +24 -0
- package/dist/web/frontend/404/index.html +3 -3
- package/dist/web/frontend/approve/index.html +4 -4
- package/dist/web/frontend/assets/404-ByuA12V-.js +16 -0
- package/dist/web/frontend/assets/approve-1AiBNNVx.js +180 -0
- package/dist/web/frontend/assets/callback-EvjAE_ta.js +1 -0
- package/dist/web/frontend/assets/index-CgbJtyud.css +1 -0
- package/dist/web/frontend/assets/index-Dso-o8qY.js +1000 -0
- package/dist/web/frontend/assets/login-DK5Zn8Bu.js +159 -0
- package/dist/web/frontend/assets/settings-CJev4gQV.js +26 -0
- package/dist/web/frontend/assets/state-BrOG8A8b.js +1 -0
- package/dist/web/frontend/assets/wallets-ZsA9bw7p.js +240 -0
- package/dist/web/frontend/callback/index.html +3 -3
- package/dist/web/frontend/index.html +2 -2
- package/dist/web/frontend/login/index.html +4 -4
- package/dist/web/frontend/settings/index.html +4 -4
- package/dist/web/frontend/wallets/index.html +4 -4
- package/dist/web/server.d.ts +1 -1
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +5 -1
- package/package.json +43 -38
- package/dist/web/frontend/assets/404-CK2XmoLz.js +0 -16
- package/dist/web/frontend/assets/approve-C-O7VrUc.js +0 -163
- package/dist/web/frontend/assets/callback-Bgkm99UY.js +0 -1
- package/dist/web/frontend/assets/index-BVQSWRTn.js +0 -1041
- package/dist/web/frontend/assets/index-HEe9--Xd.css +0 -5
- package/dist/web/frontend/assets/login-FaVg_LJv.js +0 -159
- package/dist/web/frontend/assets/settings-YzEHE3VQ.js +0 -26
- package/dist/web/frontend/assets/state-xH49VD_k.js +0 -9
- package/dist/web/frontend/assets/wallets-CsSlR4-u.js +0 -244
package/dist/config/Config.d.ts
CHANGED
|
@@ -2,15 +2,27 @@ import { z } from 'zod';
|
|
|
2
2
|
export declare const kernelInfoSchema: z.ZodObject<{
|
|
3
3
|
id: z.ZodString;
|
|
4
4
|
clientType: z.ZodUnion<readonly [z.ZodLiteral<"browser">, z.ZodLiteral<"desktop">, z.ZodLiteral<"mobile">, z.ZodLiteral<"remote">]>;
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
}, z.core.$strip>;
|
|
6
|
+
export declare const serverConfigSchema: z.ZodObject<{
|
|
7
|
+
host: z.ZodString;
|
|
8
|
+
port: z.ZodNumber;
|
|
9
|
+
tls: z.ZodBoolean;
|
|
10
|
+
dappPath: z.ZodDefault<z.ZodString>;
|
|
11
|
+
userPath: z.ZodDefault<z.ZodString>;
|
|
12
|
+
allowedOrigins: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<"*">, z.ZodArray<z.ZodString>]>>;
|
|
7
13
|
}, z.core.$strip>;
|
|
8
14
|
export declare const configSchema: z.ZodObject<{
|
|
9
15
|
kernel: z.ZodObject<{
|
|
10
16
|
id: z.ZodString;
|
|
11
17
|
clientType: z.ZodUnion<readonly [z.ZodLiteral<"browser">, z.ZodLiteral<"desktop">, z.ZodLiteral<"mobile">, z.ZodLiteral<"remote">]>;
|
|
12
|
-
|
|
13
|
-
|
|
18
|
+
}, z.core.$strip>;
|
|
19
|
+
server: z.ZodObject<{
|
|
20
|
+
host: z.ZodString;
|
|
21
|
+
port: z.ZodNumber;
|
|
22
|
+
tls: z.ZodBoolean;
|
|
23
|
+
dappPath: z.ZodDefault<z.ZodString>;
|
|
24
|
+
userPath: z.ZodDefault<z.ZodString>;
|
|
25
|
+
allowedOrigins: z.ZodDefault<z.ZodUnion<readonly [z.ZodLiteral<"*">, z.ZodArray<z.ZodString>]>>;
|
|
14
26
|
}, z.core.$strip>;
|
|
15
27
|
store: z.ZodObject<{
|
|
16
28
|
connection: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -102,5 +114,6 @@ export declare const configSchema: z.ZodObject<{
|
|
|
102
114
|
}, z.core.$strip>;
|
|
103
115
|
}, z.core.$strip>;
|
|
104
116
|
export type KernelInfo = z.infer<typeof kernelInfoSchema>;
|
|
117
|
+
export type ServerConfig = z.infer<typeof serverConfigSchema>;
|
|
105
118
|
export type Config = z.infer<typeof configSchema>;
|
|
106
119
|
//# sourceMappingURL=Config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Config.d.ts","sourceRoot":"","sources":["../../src/config/Config.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,eAAO,MAAM,gBAAgB
|
|
1
|
+
{"version":3,"file":"Config.d.ts","sourceRoot":"","sources":["../../src/config/Config.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,eAAO,MAAM,gBAAgB;;;iBAQ3B,CAAA;AAEF,eAAO,MAAM,kBAAkB;;;;;;;iBAO7B,CAAA;AAEF,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAKvB,CAAA;AAEF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAA;AACzD,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAC7D,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA"}
|
package/dist/config/Config.js
CHANGED
|
@@ -11,11 +11,18 @@ export const kernelInfoSchema = z.object({
|
|
|
11
11
|
z.literal('mobile'),
|
|
12
12
|
z.literal('remote'),
|
|
13
13
|
]),
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
});
|
|
15
|
+
export const serverConfigSchema = z.object({
|
|
16
|
+
host: z.string(),
|
|
17
|
+
port: z.number(),
|
|
18
|
+
tls: z.boolean(),
|
|
19
|
+
dappPath: z.string().default('/api/v0/dapp'),
|
|
20
|
+
userPath: z.string().default('/api/v0/user'),
|
|
21
|
+
allowedOrigins: z.union([z.literal('*'), z.array(z.string())]).default('*'),
|
|
16
22
|
});
|
|
17
23
|
export const configSchema = z.object({
|
|
18
24
|
kernel: kernelInfoSchema,
|
|
25
|
+
server: serverConfigSchema,
|
|
19
26
|
store: storeConfigSchema,
|
|
20
27
|
signingStore: signingStoreConfigSchema,
|
|
21
28
|
});
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import { Config } from './Config.js';
|
|
1
|
+
import { Config, ServerConfig } from './Config.js';
|
|
2
2
|
export declare class ConfigUtils {
|
|
3
3
|
static loadConfigFile(filePath: string): Config;
|
|
4
4
|
}
|
|
5
|
+
export declare const deriveKernelUrls: (serverConfig: ServerConfig) => {
|
|
6
|
+
dappUrl: string;
|
|
7
|
+
userUrl: string;
|
|
8
|
+
};
|
|
5
9
|
//# sourceMappingURL=ConfigUtils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfigUtils.d.ts","sourceRoot":"","sources":["../../src/config/ConfigUtils.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAgB,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"ConfigUtils.d.ts","sourceRoot":"","sources":["../../src/config/ConfigUtils.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAgB,YAAY,EAAE,MAAM,aAAa,CAAA;AAEhE,qBAAa,WAAW;IACpB,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;CAoDlD;AAgDD,eAAO,MAAM,gBAAgB,GACzB,cAAc,YAAY,KAC3B;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAOpC,CAAA"}
|
|
@@ -70,3 +70,10 @@ function validateNetworkAuthMethods(config) {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
+
export const deriveKernelUrls = (serverConfig) => {
|
|
74
|
+
const protocol = serverConfig.tls ? 'https' : 'http';
|
|
75
|
+
const dappUrl = `${protocol}://${serverConfig.host}:${serverConfig.port}${serverConfig.dappPath}`;
|
|
76
|
+
// userUrl is the base URL for the web frontend (no path)
|
|
77
|
+
const userUrl = `${protocol}://${serverConfig.host}:${serverConfig.port}`;
|
|
78
|
+
return { dappUrl, userUrl };
|
|
79
|
+
};
|
|
@@ -3,7 +3,7 @@ import { Store } from '@canton-network/core-wallet-store';
|
|
|
3
3
|
import { NotificationService } from '../notification/NotificationService.js';
|
|
4
4
|
import { KernelInfo as KernelInfoConfig } from '../config/Config.js';
|
|
5
5
|
import { Logger } from 'pino';
|
|
6
|
-
export declare const dappController: (kernelInfo: KernelInfoConfig, store: Store, notificationService: NotificationService, _logger: Logger, context?: AuthContext) => {
|
|
6
|
+
export declare const dappController: (kernelInfo: KernelInfoConfig, dappUrl: string, userUrl: string, store: Store, notificationService: NotificationService, _logger: Logger, context?: AuthContext) => {
|
|
7
7
|
status: import("./rpc-gen/typings.js").Status;
|
|
8
8
|
connect: import("./rpc-gen/typings.js").Connect;
|
|
9
9
|
disconnect: import("./rpc-gen/typings.js").Disconnect;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/dapp-api/controller.ts"],"names":[],"mappings":"AAIA,OAAO,EAAmB,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAQ/E,OAAO,EAAE,KAAK,EAAE,MAAM,mCAAmC,CAAA;AAQzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAA;AAC5E,OAAO,EAAE,UAAU,IAAI,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACpE,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAG7B,eAAO,MAAM,cAAc,GACvB,YAAY,gBAAgB,EAC5B,OAAO,KAAK,EACZ,qBAAqB,mBAAmB,EACxC,SAAS,MAAM,EACf,UAAU,WAAW;;;;;;;;;;;;;CAkNxB,CAAA"}
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/dapp-api/controller.ts"],"names":[],"mappings":"AAIA,OAAO,EAAmB,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAQ/E,OAAO,EAAE,KAAK,EAAE,MAAM,mCAAmC,CAAA;AAQzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAA;AAC5E,OAAO,EAAE,UAAU,IAAI,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AACpE,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAG7B,eAAO,MAAM,cAAc,GACvB,YAAY,gBAAgB,EAC5B,SAAS,MAAM,EACf,SAAS,MAAM,EACf,OAAO,KAAK,EACZ,qBAAqB,mBAAmB,EACxC,SAAS,MAAM,EACf,UAAU,WAAW;;;;;;;;;;;;;CAkNxB,CAAA"}
|
|
@@ -5,12 +5,12 @@ import { assertConnected } from '@canton-network/core-wallet-auth';
|
|
|
5
5
|
import buildController from './rpc-gen/index.js';
|
|
6
6
|
import { LedgerClient, } from '@canton-network/core-ledger-client';
|
|
7
7
|
import { v4 } from 'uuid';
|
|
8
|
-
import { networkStatus } from '../utils.js';
|
|
9
|
-
export const dappController = (kernelInfo, store, notificationService, _logger, context) => {
|
|
8
|
+
import { networkStatus, ledgerPrepareParams } from '../utils.js';
|
|
9
|
+
export const dappController = (kernelInfo, dappUrl, userUrl, store, notificationService, _logger, context) => {
|
|
10
10
|
const logger = _logger.child({ component: 'dapp-controller' });
|
|
11
11
|
return buildController({
|
|
12
12
|
connect: async () => {
|
|
13
|
-
if (!context) {
|
|
13
|
+
if (!context || !(await store.getSession())) {
|
|
14
14
|
return {
|
|
15
15
|
sessionToken: '',
|
|
16
16
|
status: {
|
|
@@ -18,12 +18,17 @@ export const dappController = (kernelInfo, store, notificationService, _logger,
|
|
|
18
18
|
isConnected: false,
|
|
19
19
|
isNetworkConnected: false,
|
|
20
20
|
networkReason: 'Unauthenticated',
|
|
21
|
-
userUrl:
|
|
21
|
+
userUrl: `${userUrl}/login/`,
|
|
22
22
|
},
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
const network = await store.getCurrentNetwork();
|
|
26
|
-
const ledgerClient = new LedgerClient(
|
|
26
|
+
const ledgerClient = new LedgerClient({
|
|
27
|
+
baseUrl: new URL(network.ledgerApi.baseUrl),
|
|
28
|
+
logger,
|
|
29
|
+
isAdmin: false,
|
|
30
|
+
accessToken: context.accessToken,
|
|
31
|
+
});
|
|
27
32
|
const status = await networkStatus(ledgerClient);
|
|
28
33
|
return {
|
|
29
34
|
sessionToken: context.accessToken,
|
|
@@ -32,7 +37,7 @@ export const dappController = (kernelInfo, store, notificationService, _logger,
|
|
|
32
37
|
isConnected: true,
|
|
33
38
|
isNetworkConnected: status.isConnected,
|
|
34
39
|
networkReason: status.reason ? status.reason : 'OK',
|
|
35
|
-
userUrl:
|
|
40
|
+
userUrl: `${userUrl}/login/`,
|
|
36
41
|
},
|
|
37
42
|
};
|
|
38
43
|
},
|
|
@@ -48,7 +53,7 @@ export const dappController = (kernelInfo, store, notificationService, _logger,
|
|
|
48
53
|
isConnected: false,
|
|
49
54
|
isNetworkConnected: false,
|
|
50
55
|
networkReason: 'Unauthenticated',
|
|
51
|
-
userUrl:
|
|
56
|
+
userUrl: `${userUrl}/login/`,
|
|
52
57
|
});
|
|
53
58
|
}
|
|
54
59
|
return null;
|
|
@@ -56,7 +61,12 @@ export const dappController = (kernelInfo, store, notificationService, _logger,
|
|
|
56
61
|
darsAvailable: async () => ({ dars: ['default-dar'] }),
|
|
57
62
|
ledgerApi: async (params) => {
|
|
58
63
|
const network = await store.getCurrentNetwork();
|
|
59
|
-
const ledgerClient = new LedgerClient(
|
|
64
|
+
const ledgerClient = new LedgerClient({
|
|
65
|
+
baseUrl: new URL(network.ledgerApi.baseUrl),
|
|
66
|
+
logger,
|
|
67
|
+
isAdmin: false,
|
|
68
|
+
accessToken: assertConnected(context).accessToken,
|
|
69
|
+
});
|
|
60
70
|
let result;
|
|
61
71
|
switch (params.requestMethod) {
|
|
62
72
|
case 'GET':
|
|
@@ -83,7 +93,12 @@ export const dappController = (kernelInfo, store, notificationService, _logger,
|
|
|
83
93
|
if (wallet === undefined) {
|
|
84
94
|
throw new Error('No primary wallet found');
|
|
85
95
|
}
|
|
86
|
-
const ledgerClient = new LedgerClient(
|
|
96
|
+
const ledgerClient = new LedgerClient({
|
|
97
|
+
baseUrl: new URL(network.ledgerApi.baseUrl),
|
|
98
|
+
logger,
|
|
99
|
+
isAdmin: false,
|
|
100
|
+
accessToken: context.accessToken,
|
|
101
|
+
});
|
|
87
102
|
const userId = context.userId;
|
|
88
103
|
const notifier = notificationService.getNotifier(userId);
|
|
89
104
|
params.commandId = params.commandId || v4();
|
|
@@ -97,11 +112,11 @@ export const dappController = (kernelInfo, store, notificationService, _logger,
|
|
|
97
112
|
status: 'pending',
|
|
98
113
|
preparedTransaction,
|
|
99
114
|
preparedTransactionHash,
|
|
100
|
-
payload: params
|
|
115
|
+
payload: params,
|
|
116
|
+
createdAt: new Date(),
|
|
101
117
|
});
|
|
102
118
|
return {
|
|
103
|
-
|
|
104
|
-
userUrl: `http://localhost:3030/approve/index.html?commandId=${commandId}`,
|
|
119
|
+
userUrl: `${userUrl}/approve/index.html?commandId=${commandId}`,
|
|
105
120
|
};
|
|
106
121
|
},
|
|
107
122
|
prepareReturn: async (params) => {
|
|
@@ -113,11 +128,16 @@ export const dappController = (kernelInfo, store, notificationService, _logger,
|
|
|
113
128
|
if (wallet === undefined) {
|
|
114
129
|
throw new Error('No primary wallet found');
|
|
115
130
|
}
|
|
116
|
-
const ledgerClient = new LedgerClient(
|
|
131
|
+
const ledgerClient = new LedgerClient({
|
|
132
|
+
baseUrl: new URL(network.ledgerApi.baseUrl),
|
|
133
|
+
logger,
|
|
134
|
+
isAdmin: false,
|
|
135
|
+
accessToken: context.accessToken,
|
|
136
|
+
});
|
|
117
137
|
return prepareSubmission(context.userId, wallet.partyId, network.synchronizerId, params, ledgerClient);
|
|
118
138
|
},
|
|
119
139
|
status: async () => {
|
|
120
|
-
if (!context) {
|
|
140
|
+
if (!context || !(await store.getSession())) {
|
|
121
141
|
return {
|
|
122
142
|
kernel: kernelInfo,
|
|
123
143
|
isConnected: false,
|
|
@@ -126,7 +146,12 @@ export const dappController = (kernelInfo, store, notificationService, _logger,
|
|
|
126
146
|
};
|
|
127
147
|
}
|
|
128
148
|
const network = await store.getCurrentNetwork();
|
|
129
|
-
const ledgerClient = new LedgerClient(
|
|
149
|
+
const ledgerClient = new LedgerClient({
|
|
150
|
+
baseUrl: new URL(network.ledgerApi.baseUrl),
|
|
151
|
+
logger,
|
|
152
|
+
isAdmin: false,
|
|
153
|
+
accessToken: context.accessToken,
|
|
154
|
+
});
|
|
130
155
|
const status = await networkStatus(ledgerClient);
|
|
131
156
|
return {
|
|
132
157
|
kernel: kernelInfo,
|
|
@@ -155,26 +180,5 @@ export const dappController = (kernelInfo, store, notificationService, _logger,
|
|
|
155
180
|
});
|
|
156
181
|
};
|
|
157
182
|
async function prepareSubmission(userId, partyId, synchronizerId, params, ledgerClient) {
|
|
158
|
-
|
|
159
|
-
const disclosedContracts = params.disclosedContracts?.map((d) => {
|
|
160
|
-
return {
|
|
161
|
-
templateId: d.templateId || '',
|
|
162
|
-
contractId: d.contractId || '',
|
|
163
|
-
createdEventBlob: d.createdEventBlob,
|
|
164
|
-
synchronizerId: d.synchronizerId || '',
|
|
165
|
-
};
|
|
166
|
-
}) || [];
|
|
167
|
-
const prepareParams = {
|
|
168
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- because OpenRPC codegen type is incompatible with ledger codegen type
|
|
169
|
-
commands: params.commands,
|
|
170
|
-
commandId: params.commandId || v4(),
|
|
171
|
-
userId,
|
|
172
|
-
actAs: params.actAs || [partyId],
|
|
173
|
-
readAs: params.readAs || [],
|
|
174
|
-
disclosedContracts,
|
|
175
|
-
synchronizerId,
|
|
176
|
-
verboseHashing: false,
|
|
177
|
-
packageIdSelectionPreference: params.packageIdSelectionPreference || [],
|
|
178
|
-
};
|
|
179
|
-
return await ledgerClient.postWithRetry('/v2/interactive-submission/prepare', prepareParams);
|
|
183
|
+
return await ledgerClient.postWithRetry('/v2/interactive-submission/prepare', ledgerPrepareParams(userId, partyId, synchronizerId, params));
|
|
180
184
|
}
|
|
@@ -4,6 +4,6 @@ import { Store } from '@canton-network/core-wallet-store';
|
|
|
4
4
|
import { AuthService, AuthAware } from '@canton-network/core-wallet-auth';
|
|
5
5
|
import { Server } from 'http';
|
|
6
6
|
import { NotificationService } from '../notification/NotificationService.js';
|
|
7
|
-
import { KernelInfo } from '../config/Config.js';
|
|
8
|
-
export declare const dapp: (route: string, app: express.Express, logger: Logger, server: Server, kernelInfo: KernelInfo, notificationService: NotificationService, authService: AuthService, store: Store & AuthAware<Store>) => Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>;
|
|
7
|
+
import { KernelInfo, ServerConfig } from '../config/Config.js';
|
|
8
|
+
export declare const dapp: (route: string, app: express.Express, logger: Logger, server: Server, kernelInfo: KernelInfo, dappUrl: string, userUrl: string, serverConfig: ServerConfig, notificationService: NotificationService, authService: AuthService, store: Store & AuthAware<Store>) => Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>;
|
|
9
9
|
//# sourceMappingURL=server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/dapp-api/server.ts"],"names":[],"mappings":"AAGA,OAAO,OAAO,MAAM,SAAS,CAAA;AAG7B,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAG7B,OAAO,EAAE,KAAK,EAAE,MAAM,mCAAmC,CAAA;AACzD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAA;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAE7B,OAAO,EACH,mBAAmB,EAEtB,MAAM,wCAAwC,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/dapp-api/server.ts"],"names":[],"mappings":"AAGA,OAAO,OAAO,MAAM,SAAS,CAAA;AAG7B,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAG7B,OAAO,EAAE,KAAK,EAAE,MAAM,mCAAmC,CAAA;AACzD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAA;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAE7B,OAAO,EACH,mBAAmB,EAEtB,MAAM,wCAAwC,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAE9D,eAAO,MAAM,IAAI,GACb,OAAO,MAAM,EACb,KAAK,OAAO,CAAC,OAAO,EACpB,QAAQ,MAAM,EACd,QAAQ,MAAM,EACd,YAAY,UAAU,EACtB,SAAS,MAAM,EACf,SAAS,MAAM,EACf,cAAc,YAAY,EAC1B,qBAAqB,mBAAmB,EACxC,aAAa,WAAW,EACxB,OAAO,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,wFA6ElC,CAAA"}
|
package/dist/dapp-api/server.js
CHANGED
|
@@ -4,15 +4,17 @@ import cors from 'cors';
|
|
|
4
4
|
import { dappController } from './controller.js';
|
|
5
5
|
import { jsonRpcHandler } from '../middleware/jsonRpcHandler.js';
|
|
6
6
|
import { Server as SocketIoServer } from 'socket.io';
|
|
7
|
-
export const dapp = (route, app, logger, server, kernelInfo, notificationService, authService, store) => {
|
|
8
|
-
app.use(cors(
|
|
7
|
+
export const dapp = (route, app, logger, server, kernelInfo, dappUrl, userUrl, serverConfig, notificationService, authService, store) => {
|
|
8
|
+
app.use(cors({
|
|
9
|
+
origin: serverConfig.allowedOrigins,
|
|
10
|
+
}));
|
|
9
11
|
app.use(route, (req, res, next) => jsonRpcHandler({
|
|
10
|
-
controller: dappController(kernelInfo, store.withAuthContext(req.authContext), notificationService, logger, req.authContext),
|
|
12
|
+
controller: dappController(kernelInfo, dappUrl, userUrl, store.withAuthContext(req.authContext), notificationService, logger, req.authContext),
|
|
11
13
|
logger,
|
|
12
14
|
})(req, res, next));
|
|
13
15
|
const io = new SocketIoServer(server, {
|
|
14
16
|
cors: {
|
|
15
|
-
origin:
|
|
17
|
+
origin: serverConfig.allowedOrigins,
|
|
16
18
|
methods: ['GET', 'POST'],
|
|
17
19
|
},
|
|
18
20
|
});
|
|
@@ -6,7 +6,7 @@ import request from 'supertest';
|
|
|
6
6
|
import express from 'express';
|
|
7
7
|
import { dapp } from './server.js';
|
|
8
8
|
import { StoreInternal } from '@canton-network/core-wallet-store-inmemory';
|
|
9
|
-
import { ConfigUtils } from '../config/ConfigUtils.js';
|
|
9
|
+
import { ConfigUtils, deriveKernelUrls } from '../config/ConfigUtils.js';
|
|
10
10
|
import { pino } from 'pino';
|
|
11
11
|
import { sink } from 'pino-test';
|
|
12
12
|
import { createServer } from 'http';
|
|
@@ -30,7 +30,8 @@ test('call connect rpc', async () => {
|
|
|
30
30
|
app.use(cors());
|
|
31
31
|
app.use(express.json());
|
|
32
32
|
const server = createServer(app);
|
|
33
|
-
const
|
|
33
|
+
const { dappUrl, userUrl } = deriveKernelUrls(config.server);
|
|
34
|
+
const response = await request(dapp('/api/v0/dapp', app, pino(sink()), server, config.kernel, dappUrl, userUrl, config.server, notificationService, authService, store))
|
|
34
35
|
.post('/api/v0/dapp')
|
|
35
36
|
.send({ jsonrpc: '2.0', id: 0, method: 'connect', params: [] })
|
|
36
37
|
.set('Accept', 'application/json');
|
|
@@ -44,8 +45,6 @@ test('call connect rpc', async () => {
|
|
|
44
45
|
kernel: {
|
|
45
46
|
id: 'remote-da',
|
|
46
47
|
clientType: 'remote',
|
|
47
|
-
url: 'http://localhost:3030/api/v0/dapp',
|
|
48
|
-
userUrl: 'http://localhost:3030',
|
|
49
48
|
},
|
|
50
49
|
isConnected: false,
|
|
51
50
|
isNetworkConnected: false,
|
package/dist/example-config.d.ts
CHANGED
|
@@ -2,8 +2,14 @@ declare const _default: {
|
|
|
2
2
|
kernel: {
|
|
3
3
|
id: string;
|
|
4
4
|
clientType: "remote";
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
};
|
|
6
|
+
server: {
|
|
7
|
+
host: string;
|
|
8
|
+
port: number;
|
|
9
|
+
tls: false;
|
|
10
|
+
dappPath: string;
|
|
11
|
+
userPath: string;
|
|
12
|
+
allowedOrigins: string[];
|
|
7
13
|
};
|
|
8
14
|
signingStore: {
|
|
9
15
|
connection: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"example-config.d.ts","sourceRoot":"","sources":["../src/example-config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"example-config.d.ts","sourceRoot":"","sources":["../src/example-config.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKA,wBA0FkB"}
|
package/dist/example-config.js
CHANGED
|
@@ -4,8 +4,14 @@ export default {
|
|
|
4
4
|
kernel: {
|
|
5
5
|
id: 'remote-da',
|
|
6
6
|
clientType: 'remote',
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
},
|
|
8
|
+
server: {
|
|
9
|
+
host: 'localhost',
|
|
10
|
+
port: 3030,
|
|
11
|
+
tls: false,
|
|
12
|
+
dappPath: '/api/v0/dapp',
|
|
13
|
+
userPath: '/api/v0/user',
|
|
14
|
+
allowedOrigins: ['http://localhost:8080'],
|
|
9
15
|
},
|
|
10
16
|
signingStore: {
|
|
11
17
|
connection: {
|
package/dist/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAsB7B,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAsB7B,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AA2GvC,wBAAsB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAwGhE"}
|
package/dist/init.js
CHANGED
|
@@ -15,6 +15,7 @@ import { jwtAuthService } from './auth/jwt-auth-service.js';
|
|
|
15
15
|
import express from 'express';
|
|
16
16
|
import { jwtAuth } from './middleware/jwtAuth.js';
|
|
17
17
|
import { rpcRateLimit } from './middleware/rateLimit.js';
|
|
18
|
+
import { deriveKernelUrls } from './config/ConfigUtils.js';
|
|
18
19
|
import { existsSync, readFileSync } from 'fs';
|
|
19
20
|
import path from 'path';
|
|
20
21
|
let isReady = false;
|
|
@@ -88,10 +89,14 @@ async function initializeSigningDatabase(config, logger) {
|
|
|
88
89
|
return new SigningStoreSql(db, logger);
|
|
89
90
|
}
|
|
90
91
|
export async function initialize(opts, logger) {
|
|
91
|
-
const
|
|
92
|
+
const config = ConfigUtils.loadConfigFile(opts.config);
|
|
93
|
+
// Use CLI port override or config port
|
|
94
|
+
const port = opts.port ? Number(opts.port) : config.server.port;
|
|
95
|
+
const host = config.server.host;
|
|
96
|
+
const protocol = config.server.tls ? 'https' : 'http';
|
|
92
97
|
const app = express();
|
|
93
|
-
const server = app.listen(port, () => {
|
|
94
|
-
logger.info(`Remote Wallet Gateway starting on
|
|
98
|
+
const server = app.listen(port, host, () => {
|
|
99
|
+
logger.info(`Remote Wallet Gateway starting on ${protocol}://${host}:${port}`);
|
|
95
100
|
});
|
|
96
101
|
app.use('/healthz', rpcRateLimit, (_req, res) => res.status(200).send('OK'));
|
|
97
102
|
app.use('/readyz', rpcRateLimit, (_req, res) => {
|
|
@@ -103,7 +108,6 @@ export async function initialize(opts, logger) {
|
|
|
103
108
|
}
|
|
104
109
|
});
|
|
105
110
|
const notificationService = new NotificationService(logger);
|
|
106
|
-
const config = ConfigUtils.loadConfigFile(opts.config);
|
|
107
111
|
const store = await initializeDatabase(config, logger);
|
|
108
112
|
const signingStore = await initializeSigningDatabase(config, logger);
|
|
109
113
|
const authService = jwtAuthService(store, logger);
|
|
@@ -134,12 +138,19 @@ export async function initialize(opts, logger) {
|
|
|
134
138
|
app.use('/api/*splat', express.json());
|
|
135
139
|
app.use('/api/*splat', rpcRateLimit);
|
|
136
140
|
app.use('/api/*splat', jwtAuth(authService, logger));
|
|
141
|
+
// Override config port with CLI parameter port if provided, then derive URLs
|
|
142
|
+
const serverConfigWithOverride = {
|
|
143
|
+
...config.server,
|
|
144
|
+
port, // Use the actual port we're listening on
|
|
145
|
+
};
|
|
146
|
+
const { dappUrl, userUrl } = deriveKernelUrls(serverConfigWithOverride);
|
|
147
|
+
const kernelInfo = config.kernel;
|
|
137
148
|
// register dapp API handlers
|
|
138
|
-
dapp(
|
|
149
|
+
dapp(config.server.dappPath, app, logger, server, kernelInfo, dappUrl, userUrl, config.server, notificationService, authService, store);
|
|
139
150
|
// register user API handlers
|
|
140
|
-
user(
|
|
151
|
+
user(config.server.userPath, app, logger, kernelInfo, userUrl, notificationService, drivers, store);
|
|
141
152
|
// register web handler
|
|
142
|
-
web(app, server);
|
|
153
|
+
web(app, server, config.server.userPath);
|
|
143
154
|
isReady = true;
|
|
144
155
|
logger.info('Wallet Gateway initialization complete');
|
|
145
156
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"party-allocation-service.d.ts","sourceRoot":"","sources":["../../src/ledger/party-allocation-service.ts"],"names":[],"mappings":"AAGA,OAAO,EACH,2BAA2B,
|
|
1
|
+
{"version":3,"file":"party-allocation-service.d.ts","sourceRoot":"","sources":["../../src/ledger/party-allocation-service.ts"],"names":[],"mappings":"AAGA,OAAO,EACH,2BAA2B,EAE9B,MAAM,oCAAoC,CAAA;AAE3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAA;AACtE,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAE7B,MAAM,MAAM,cAAc,GAAG;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,KAAK,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;AAEpD;;GAEG;AACH,qBAAa,sBAAsB;IAC/B,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,cAAc,CAAoB;gBAE9B,EACR,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,MAAM,EACN,WAAW,GACd,EAAE;QACC,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,mBAAmB,EAAE,mBAAmB,CAAA;QACxC,aAAa,EAAE,MAAM,CAAA;QACrB,MAAM,EAAE,MAAM,CAAA;QACd,WAAW,CAAC,EAAE,MAAM,CAAA;KACvB;IAYD;;;;OAIG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAE1E;;;;;;OAMG;IACG,aAAa,CACf,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,WAAW,GAC7B,OAAO,CAAC,cAAc,CAAC;IAoB1B;;;OAGG;IACH,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAenD;;;;OAIG;IACG,4BAA4B,CAC9B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAClB,OAAO,CAAC,2BAA2B,CAAC;IAevC;;;;;;OAMG;IACG,+BAA+B,CACjC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EAAE,EACtB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC;YAgCJ,qBAAqB;YAuBrB,qBAAqB;CAsCtC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Copyright (c) 2025 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
-
import { LedgerClient,
|
|
3
|
+
import { LedgerClient, } from '@canton-network/core-ledger-client';
|
|
4
|
+
import { createHash } from 'node:crypto';
|
|
4
5
|
/**
|
|
5
6
|
* This service provides an abstraction for Canton party allocation that seamlessly handles both internal and external parties.
|
|
6
7
|
*/
|
|
@@ -8,7 +9,13 @@ export class PartyAllocationService {
|
|
|
8
9
|
constructor({ synchronizerId, accessTokenProvider, httpLedgerUrl, logger, accessToken, }) {
|
|
9
10
|
this.logger = logger;
|
|
10
11
|
this.synchronizerId = synchronizerId;
|
|
11
|
-
this.ledgerClient = new LedgerClient(
|
|
12
|
+
this.ledgerClient = new LedgerClient({
|
|
13
|
+
baseUrl: new URL(httpLedgerUrl),
|
|
14
|
+
logger: this.logger,
|
|
15
|
+
isAdmin: true,
|
|
16
|
+
accessToken: accessToken ?? '',
|
|
17
|
+
accessTokenProvider: accessTokenProvider,
|
|
18
|
+
});
|
|
12
19
|
}
|
|
13
20
|
async allocateParty(userId, hint, publicKey, signingCallback) {
|
|
14
21
|
if (publicKey !== undefined && signingCallback !== undefined) {
|
|
@@ -19,7 +26,16 @@ export class PartyAllocationService {
|
|
|
19
26
|
}
|
|
20
27
|
}
|
|
21
28
|
createFingerprintFromKey(publicKey) {
|
|
22
|
-
|
|
29
|
+
// Hash purpose codes can be looked up in the Canton codebase:
|
|
30
|
+
// https://github.com/DACH-NY/canton/blob/62e9ccd3f1743d2c9422d863cfc2ca800405c71b/community/base/src/main/scala/com/digitalasset/canton/crypto/HashPurpose.scala#L52
|
|
31
|
+
const hashPurpose = 12; // For `PublicKeyFingerprint`
|
|
32
|
+
const keyBytes = Buffer.from(publicKey, 'base64');
|
|
33
|
+
const hashInput = Buffer.alloc(4 + keyBytes.length);
|
|
34
|
+
hashInput.writeUInt32BE(hashPurpose, 0);
|
|
35
|
+
Buffer.from(keyBytes).copy(hashInput, 4);
|
|
36
|
+
const hash = createHash('sha256').update(hashInput).digest();
|
|
37
|
+
const multiprefix = Buffer.from([0x12, 0x20]);
|
|
38
|
+
return Buffer.concat([multiprefix, hash]).toString('hex');
|
|
23
39
|
}
|
|
24
40
|
async generateTopologyTransactions(hint, publicKey) {
|
|
25
41
|
const synchronizerId = this.synchronizerId ?? (await this.ledgerClient.getSynchronizerId());
|
|
@@ -6,12 +6,6 @@ import { sink } from 'pino-test';
|
|
|
6
6
|
const mockLedgerGet = jest.fn();
|
|
7
7
|
const mockLedgerPost = jest.fn();
|
|
8
8
|
const mockLedgerGrantUserRights = jest.fn();
|
|
9
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
|
-
const MockTopologyWriteService = jest.fn();
|
|
11
|
-
// Add static method to the mock class
|
|
12
|
-
MockTopologyWriteService.createFingerprintFromKey = jest
|
|
13
|
-
.fn()
|
|
14
|
-
.mockReturnValue('mypublickey');
|
|
15
9
|
jest.unstable_mockModule('@canton-network/core-ledger-client', () => ({
|
|
16
10
|
Signature: jest.fn(),
|
|
17
11
|
SignatureFormat: jest.fn(),
|
|
@@ -34,7 +28,6 @@ jest.unstable_mockModule('@canton-network/core-ledger-client', () => ({
|
|
|
34
28
|
.mockResolvedValue({ partyId: 'party2::mypublickey' }),
|
|
35
29
|
};
|
|
36
30
|
}),
|
|
37
|
-
TopologyWriteService: MockTopologyWriteService,
|
|
38
31
|
}));
|
|
39
32
|
describe('PartyAllocationService', () => {
|
|
40
33
|
const network = {
|
|
@@ -80,7 +73,9 @@ describe('PartyAllocationService', () => {
|
|
|
80
73
|
httpLedgerUrl: network.ledgerApi.baseUrl,
|
|
81
74
|
logger: mockLogger,
|
|
82
75
|
});
|
|
76
|
+
jest.spyOn(service, 'createFingerprintFromKey').mockReturnValue('mypublickey');
|
|
83
77
|
});
|
|
78
|
+
afterEach(() => jest.restoreAllMocks());
|
|
84
79
|
it('allocates an internal party', async () => {
|
|
85
80
|
mockLedgerGet.mockResolvedValueOnce({ participantId: 'participantid' });
|
|
86
81
|
mockLedgerPost.mockResolvedValueOnce({
|
|
@@ -5,7 +5,7 @@ import { AuthContext } from '@canton-network/core-wallet-auth';
|
|
|
5
5
|
import { KernelInfo } from '../config/Config.js';
|
|
6
6
|
import { SigningDriverInterface, SigningProvider } from '@canton-network/core-signing-lib';
|
|
7
7
|
type AvailableSigningDrivers = Partial<Record<SigningProvider, SigningDriverInterface>>;
|
|
8
|
-
export declare const userController: (kernelInfo: KernelInfo, store: Store, notificationService: NotificationService, authContext: AuthContext | undefined, drivers: AvailableSigningDrivers, _logger: Logger) => {
|
|
8
|
+
export declare const userController: (kernelInfo: KernelInfo, userUrl: string, store: Store, notificationService: NotificationService, authContext: AuthContext | undefined, drivers: AvailableSigningDrivers, _logger: Logger) => {
|
|
9
9
|
addNetwork: import("./rpc-gen/typings.js").AddNetwork;
|
|
10
10
|
removeNetwork: import("./rpc-gen/typings.js").RemoveNetwork;
|
|
11
11
|
listNetworks: import("./rpc-gen/typings.js").ListNetworks;
|
|
@@ -23,6 +23,7 @@ export declare const userController: (kernelInfo: KernelInfo, store: Store, noti
|
|
|
23
23
|
removeSession: import("./rpc-gen/typings.js").RemoveSession;
|
|
24
24
|
listSessions: import("./rpc-gen/typings.js").ListSessions;
|
|
25
25
|
getTransaction: import("./rpc-gen/typings.js").GetTransaction;
|
|
26
|
+
listTransactions: import("./rpc-gen/typings.js").ListTransactions;
|
|
26
27
|
};
|
|
27
28
|
export {};
|
|
28
29
|
//# 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":"AAyBA,OAAO,EACH,KAAK,EAIR,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAC7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAA;AAC5E,OAAO,EAGH,WAAW,EAId,MAAM,kCAAkC,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,EACH,sBAAsB,EACtB,eAAe,EAClB,MAAM,kCAAkC,CAAA;AAazC,KAAK,uBAAuB,GAAG,OAAO,CAClC,MAAM,CAAC,eAAe,EAAE,sBAAsB,CAAC,CAClD,CAAA;AAED,eAAO,MAAM,cAAc,GACvB,YAAY,UAAU,EACtB,SAAS,MAAM,EACf,OAAO,KAAK,EACZ,qBAAqB,mBAAmB,EACxC,aAAa,WAAW,GAAG,SAAS,EACpC,SAAS,uBAAuB,EAChC,SAAS,MAAM;;;;;;;;;;;;;;;;;;;CA6oBlB,CAAA"}
|