@yuants/app-virtual-exchange 0.0.1

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.
@@ -0,0 +1 @@
1
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,144 @@
1
+ import { Terminal } from '@yuants/protocol';
2
+ import { readSecret, writeSecret } from '@yuants/secret';
3
+ import { escapeSQL, requestSQL } from '@yuants/sql';
4
+ import { defer, mergeMap, retry, timer } from 'rxjs';
5
+ const terminal = Terminal.fromNodeEnv();
6
+ const mapAccountIdToCredential = new Map();
7
+ // 1. RegisterExchangeCredential
8
+ terminal.server.provideService('RegisterExchangeCredential', {
9
+ type: 'object',
10
+ required: ['type', 'payload'],
11
+ properties: {
12
+ type: { type: 'string' },
13
+ payload: { type: 'object' },
14
+ },
15
+ }, async (msg) => {
16
+ const credential = msg.req;
17
+ const secretData = new TextEncoder().encode(JSON.stringify(credential));
18
+ await writeSecret(terminal, terminal.keyPair.public_key, { type: 'exchange_credential' }, secretData);
19
+ return { res: { code: 0, message: 'OK' } };
20
+ });
21
+ // 2. ListExchangeCredential
22
+ terminal.server.provideService('ListExchangeCredential', {}, async () => {
23
+ const secrets = await requestSQL(terminal, `select * from secret where tags->>'type' = 'exchange_credential' and reader = ${escapeSQL(terminal.keyPair.public_key)}`);
24
+ const credentials = [];
25
+ for (const secret of secrets) {
26
+ try {
27
+ const decrypted = await readSecret(terminal, secret);
28
+ const credential = JSON.parse(new TextDecoder().decode(decrypted));
29
+ credentials.push(credential);
30
+ }
31
+ catch (e) {
32
+ console.error('Failed to decrypt secret', e);
33
+ }
34
+ }
35
+ return { res: { code: 0, message: 'OK', data: credentials } };
36
+ });
37
+ // 9. Background listWatch
38
+ const updateIndex = async () => {
39
+ const secrets = await requestSQL(terminal, `select * from secret where tags->>'type' = 'exchange_credential' and reader = ${escapeSQL(terminal.keyPair.public_key)}`);
40
+ for (const secret of secrets) {
41
+ try {
42
+ const decrypted = await readSecret(terminal, secret);
43
+ const credential = JSON.parse(new TextDecoder().decode(decrypted));
44
+ // Call ListAccounts to get account_ids
45
+ const res = await terminal.client.requestForResponse('ListAccounts', { credential });
46
+ if (res.code === 0 && res.data) {
47
+ for (const account of res.data) {
48
+ mapAccountIdToCredential.set(account.account_id, credential);
49
+ }
50
+ }
51
+ }
52
+ catch (e) {
53
+ console.error('Failed to process secret', e);
54
+ }
55
+ }
56
+ };
57
+ // Run updateIndex periodically
58
+ timer(0, 60000)
59
+ .pipe(mergeMap(() => defer(updateIndex).pipe(retry({ delay: 5000 }))))
60
+ .subscribe();
61
+ // 7. QueryAccounts
62
+ terminal.server.provideService('QueryAccounts', {}, async () => {
63
+ return { res: { code: 0, message: 'OK', data: Array.from(mapAccountIdToCredential.keys()) } };
64
+ });
65
+ // 8. QueryAccountInfo
66
+ terminal.server.provideService('QueryAccountInfo', {
67
+ type: 'object',
68
+ required: ['account_id'],
69
+ properties: {
70
+ account_id: { type: 'string' },
71
+ },
72
+ }, async (msg) => {
73
+ const credential = mapAccountIdToCredential.get(msg.req.account_id);
74
+ if (!credential) {
75
+ return { res: { code: 404, message: 'Account not found' } };
76
+ }
77
+ const res = await terminal.client.requestForResponse('GetAccountInfo', { credential, account_id: msg.req.account_id });
78
+ return { res };
79
+ });
80
+ // 10. Proxy Orders
81
+ // SubmitOrder
82
+ terminal.server.provideService('SubmitOrder', {
83
+ type: 'object',
84
+ required: ['order'],
85
+ properties: {
86
+ order: { type: 'object' },
87
+ },
88
+ }, async (msg) => {
89
+ const credential = mapAccountIdToCredential.get(msg.req.order.account_id);
90
+ if (!credential) {
91
+ return { res: { code: 404, message: 'Account not found' } };
92
+ }
93
+ const res = await terminal.client.requestForResponse('SubmitOrder', { credential, order: msg.req.order });
94
+ return { res };
95
+ });
96
+ // ModifyOrder
97
+ terminal.server.provideService('ModifyOrder', {
98
+ type: 'object',
99
+ required: ['order'],
100
+ properties: {
101
+ order: { type: 'object' },
102
+ },
103
+ }, async (msg) => {
104
+ const credential = mapAccountIdToCredential.get(msg.req.order.account_id);
105
+ if (!credential) {
106
+ return { res: { code: 404, message: 'Account not found' } };
107
+ }
108
+ const res = await terminal.client.requestForResponse('ModifyOrder', { credential, order: msg.req.order });
109
+ return { res };
110
+ });
111
+ // CancelOrder
112
+ terminal.server.provideService('CancelOrder', {
113
+ type: 'object',
114
+ required: ['order'],
115
+ properties: {
116
+ order: { type: 'object' },
117
+ },
118
+ }, async (msg) => {
119
+ const credential = mapAccountIdToCredential.get(msg.req.order.account_id);
120
+ if (!credential) {
121
+ return { res: { code: 404, message: 'Account not found' } };
122
+ }
123
+ const res = await terminal.client.requestForResponse('CancelOrder', { credential, order: msg.req.order });
124
+ return { res };
125
+ });
126
+ // ListOrders
127
+ terminal.server.provideService('ListOrders', {
128
+ type: 'object',
129
+ required: ['account_id'],
130
+ properties: {
131
+ account_id: { type: 'string' },
132
+ },
133
+ }, async (msg) => {
134
+ const credential = mapAccountIdToCredential.get(msg.req.account_id);
135
+ if (!credential) {
136
+ return { res: { code: 404, message: 'Account not found' } };
137
+ }
138
+ const res = await terminal.client.requestForResponse('ListOrders', {
139
+ credential,
140
+ account_id: msg.req.account_id,
141
+ });
142
+ return { res };
143
+ });
144
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAW,UAAU,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAErD,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;AAOxC,MAAM,wBAAwB,GAAG,IAAI,GAAG,EAA+B,CAAC;AAExE,gCAAgC;AAChC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAC5B,4BAA4B,EAC5B;IACE,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC;IAC7B,UAAU,EAAE;QACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACxB,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAC5B;CACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;IACZ,MAAM,UAAU,GAAG,GAAG,CAAC,GAAG,CAAC;IAC3B,MAAM,UAAU,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;IACxE,MAAM,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,qBAAqB,EAAE,EAAE,UAAU,CAAC,CAAC;IACtG,OAAO,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;AAC7C,CAAC,CACF,CAAC;AAEF,4BAA4B;AAC5B,QAAQ,CAAC,MAAM,CAAC,cAAc,CAA8B,wBAAwB,EAAE,EAAE,EAAE,KAAK,IAAI,EAAE;IACnG,MAAM,OAAO,GAAG,MAAM,UAAU,CAC9B,QAAQ,EACR,iFAAiF,SAAS,CACxF,QAAQ,CAAC,OAAO,CAAC,UAAU,CAC5B,EAAE,CACJ,CAAC;IACF,MAAM,WAAW,GAA0B,EAAE,CAAC;IAC9C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;QAC5B,IAAI;YACF,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACrD,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;YACnE,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;SAC9B;QAAC,OAAO,CAAC,EAAE;YACV,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,CAAC,CAAC,CAAC;SAC9C;KACF;IACD,OAAO,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,CAAC;AAChE,CAAC,CAAC,CAAC;AAEH,0BAA0B;AAC1B,MAAM,WAAW,GAAG,KAAK,IAAI,EAAE;IAC7B,MAAM,OAAO,GAAG,MAAM,UAAU,CAC9B,QAAQ,EACR,iFAAiF,SAAS,CACxF,QAAQ,CAAC,OAAO,CAAC,UAAU,CAC5B,EAAE,CACJ,CAAC;IACF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;QAC5B,IAAI;YACF,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACrD,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAwB,CAAC;YAE1F,uCAAuC;YACvC,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,kBAAkB,CAGlD,cAAc,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;YAElC,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE;gBAC9B,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,IAAI,EAAE;oBAC9B,wBAAwB,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;iBAC9D;aACF;SACF;QAAC,OAAO,CAAC,EAAE;YACV,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,CAAC,CAAC,CAAC;SAC9C;KACF;AACH,CAAC,CAAC;AAEF,+BAA+B;AAC/B,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;KACZ,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;KACrE,SAAS,EAAE,CAAC;AAEf,mBAAmB;AACnB,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAiB,eAAe,EAAE,EAAE,EAAE,KAAK,IAAI,EAAE;IAC7E,OAAO,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;AAChG,CAAC,CAAC,CAAC;AAEH,sBAAsB;AACtB,QAAQ,CAAC,MAAM,CAAC,cAAc,CAC5B,kBAAkB,EAClB;IACE,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,YAAY,CAAC;IACxB,UAAU,EAAE;QACV,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAC/B;CACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;IACZ,MAAM,UAAU,GAAG,wBAAwB,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACpE,IAAI,CAAC,UAAU,EAAE;QACf,OAAO,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAAE,CAAC;KAC7D;IACD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,kBAAkB,CAGlD,gBAAgB,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;IACpE,OAAO,EAAE,GAAG,EAAE,CAAC;AACjB,CAAC,CACF,CAAC;AAEF,mBAAmB;AACnB,cAAc;AACd,QAAQ,CAAC,MAAM,CAAC,cAAc,CAC5B,aAAa,EACb;IACE,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,OAAO,CAAC;IACnB,UAAU,EAAE;QACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAC1B;CACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;IACZ,MAAM,UAAU,GAAG,wBAAwB,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC1E,IAAI,CAAC,UAAU,EAAE;QACf,OAAO,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAAE,CAAC;KAC7D;IACD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,kBAAkB,CAGlD,aAAa,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;IACvD,OAAO,EAAE,GAAG,EAAE,CAAC;AACjB,CAAC,CACF,CAAC;AAEF,cAAc;AACd,QAAQ,CAAC,MAAM,CAAC,cAAc,CAC5B,aAAa,EACb;IACE,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,OAAO,CAAC;IACnB,UAAU,EAAE;QACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAC1B;CACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;IACZ,MAAM,UAAU,GAAG,wBAAwB,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC1E,IAAI,CAAC,UAAU,EAAE;QACf,OAAO,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAAE,CAAC;KAC7D;IACD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,kBAAkB,CAGlD,aAAa,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;IACvD,OAAO,EAAE,GAAG,EAAE,CAAC;AACjB,CAAC,CACF,CAAC;AAEF,cAAc;AACd,QAAQ,CAAC,MAAM,CAAC,cAAc,CAC5B,aAAa,EACb;IACE,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,OAAO,CAAC;IACnB,UAAU,EAAE;QACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAC1B;CACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;IACZ,MAAM,UAAU,GAAG,wBAAwB,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC1E,IAAI,CAAC,UAAU,EAAE;QACf,OAAO,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAAE,CAAC;KAC7D;IACD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,kBAAkB,CAGlD,aAAa,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;IACvD,OAAO,EAAE,GAAG,EAAE,CAAC;AACjB,CAAC,CACF,CAAC;AAEF,aAAa;AACb,QAAQ,CAAC,MAAM,CAAC,cAAc,CAC5B,YAAY,EACZ;IACE,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,YAAY,CAAC;IACxB,UAAU,EAAE;QACV,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;KAC/B;CACF,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;IACZ,MAAM,UAAU,GAAG,wBAAwB,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACpE,IAAI,CAAC,UAAU,EAAE;QACf,OAAO,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAAE,CAAC;KAC7D;IACD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,kBAAkB,CAGlD,YAAY,EAAE;QACd,UAAU;QACV,UAAU,EAAE,GAAG,CAAC,GAAG,CAAC,UAAU;KAC/B,CAAC,CAAC;IACH,OAAO,EAAE,GAAG,EAAE,CAAC;AACjB,CAAC,CACF,CAAC","sourcesContent":["import { IAccountInfo } from '@yuants/data-account';\nimport { IOrder, ITypedCredential } from '@yuants/data-order';\nimport { Terminal } from '@yuants/protocol';\nimport { ISecret, readSecret, writeSecret } from '@yuants/secret';\nimport { escapeSQL, requestSQL } from '@yuants/sql';\nimport { defer, mergeMap, retry, timer } from 'rxjs';\n\nconst terminal = Terminal.fromNodeEnv();\n\ninterface IExchangeCredential {\n type: string;\n payload: any;\n}\n\nconst mapAccountIdToCredential = new Map<string, IExchangeCredential>();\n\n// 1. RegisterExchangeCredential\nterminal.server.provideService<IExchangeCredential, void>(\n 'RegisterExchangeCredential',\n {\n type: 'object',\n required: ['type', 'payload'],\n properties: {\n type: { type: 'string' },\n payload: { type: 'object' },\n },\n },\n async (msg) => {\n const credential = msg.req;\n const secretData = new TextEncoder().encode(JSON.stringify(credential));\n await writeSecret(terminal, terminal.keyPair.public_key, { type: 'exchange_credential' }, secretData);\n return { res: { code: 0, message: 'OK' } };\n },\n);\n\n// 2. ListExchangeCredential\nterminal.server.provideService<void, IExchangeCredential[]>('ListExchangeCredential', {}, async () => {\n const secrets = await requestSQL<ISecret[]>(\n terminal,\n `select * from secret where tags->>'type' = 'exchange_credential' and reader = ${escapeSQL(\n terminal.keyPair.public_key,\n )}`,\n );\n const credentials: IExchangeCredential[] = [];\n for (const secret of secrets) {\n try {\n const decrypted = await readSecret(terminal, secret);\n const credential = JSON.parse(new TextDecoder().decode(decrypted));\n credentials.push(credential);\n } catch (e) {\n console.error('Failed to decrypt secret', e);\n }\n }\n return { res: { code: 0, message: 'OK', data: credentials } };\n});\n\n// 9. Background listWatch\nconst updateIndex = async () => {\n const secrets = await requestSQL<ISecret[]>(\n terminal,\n `select * from secret where tags->>'type' = 'exchange_credential' and reader = ${escapeSQL(\n terminal.keyPair.public_key,\n )}`,\n );\n for (const secret of secrets) {\n try {\n const decrypted = await readSecret(terminal, secret);\n const credential = JSON.parse(new TextDecoder().decode(decrypted)) as IExchangeCredential;\n\n // Call ListAccounts to get account_ids\n const res = await terminal.client.requestForResponse<\n { credential: ITypedCredential<any> },\n Array<{ account_id: string }>\n >('ListAccounts', { credential });\n\n if (res.code === 0 && res.data) {\n for (const account of res.data) {\n mapAccountIdToCredential.set(account.account_id, credential);\n }\n }\n } catch (e) {\n console.error('Failed to process secret', e);\n }\n }\n};\n\n// Run updateIndex periodically\ntimer(0, 60000)\n .pipe(mergeMap(() => defer(updateIndex).pipe(retry({ delay: 5000 }))))\n .subscribe();\n\n// 7. QueryAccounts\nterminal.server.provideService<void, string[]>('QueryAccounts', {}, async () => {\n return { res: { code: 0, message: 'OK', data: Array.from(mapAccountIdToCredential.keys()) } };\n});\n\n// 8. QueryAccountInfo\nterminal.server.provideService<{ account_id: string }, IAccountInfo>(\n 'QueryAccountInfo',\n {\n type: 'object',\n required: ['account_id'],\n properties: {\n account_id: { type: 'string' },\n },\n },\n async (msg) => {\n const credential = mapAccountIdToCredential.get(msg.req.account_id);\n if (!credential) {\n return { res: { code: 404, message: 'Account not found' } };\n }\n const res = await terminal.client.requestForResponse<\n { credential: ITypedCredential<any>; account_id: string },\n IAccountInfo\n >('GetAccountInfo', { credential, account_id: msg.req.account_id });\n return { res };\n },\n);\n\n// 10. Proxy Orders\n// SubmitOrder\nterminal.server.provideService<{ order: IOrder }, { order_id: string }>(\n 'SubmitOrder',\n {\n type: 'object',\n required: ['order'],\n properties: {\n order: { type: 'object' },\n },\n },\n async (msg) => {\n const credential = mapAccountIdToCredential.get(msg.req.order.account_id);\n if (!credential) {\n return { res: { code: 404, message: 'Account not found' } };\n }\n const res = await terminal.client.requestForResponse<\n { credential: ITypedCredential<any>; order: IOrder },\n { order_id: string }\n >('SubmitOrder', { credential, order: msg.req.order });\n return { res };\n },\n);\n\n// ModifyOrder\nterminal.server.provideService<{ order: IOrder }, void>(\n 'ModifyOrder',\n {\n type: 'object',\n required: ['order'],\n properties: {\n order: { type: 'object' },\n },\n },\n async (msg) => {\n const credential = mapAccountIdToCredential.get(msg.req.order.account_id);\n if (!credential) {\n return { res: { code: 404, message: 'Account not found' } };\n }\n const res = await terminal.client.requestForResponse<\n { credential: ITypedCredential<any>; order: IOrder },\n void\n >('ModifyOrder', { credential, order: msg.req.order });\n return { res };\n },\n);\n\n// CancelOrder\nterminal.server.provideService<{ order: IOrder }, void>(\n 'CancelOrder',\n {\n type: 'object',\n required: ['order'],\n properties: {\n order: { type: 'object' },\n },\n },\n async (msg) => {\n const credential = mapAccountIdToCredential.get(msg.req.order.account_id);\n if (!credential) {\n return { res: { code: 404, message: 'Account not found' } };\n }\n const res = await terminal.client.requestForResponse<\n { credential: ITypedCredential<any>; order: IOrder },\n void\n >('CancelOrder', { credential, order: msg.req.order });\n return { res };\n },\n);\n\n// ListOrders\nterminal.server.provideService<{ account_id: string }, { orders: IOrder[] }>(\n 'ListOrders',\n {\n type: 'object',\n required: ['account_id'],\n properties: {\n account_id: { type: 'string' },\n },\n },\n async (msg) => {\n const credential = mapAccountIdToCredential.get(msg.req.account_id);\n if (!credential) {\n return { res: { code: 404, message: 'Account not found' } };\n }\n const res = await terminal.client.requestForResponse<\n { credential: ITypedCredential<any>; account_id: string },\n { orders: IOrder[] }\n >('ListOrders', {\n credential,\n account_id: msg.req.account_id,\n });\n return { res };\n },\n);\n"]}
package/lib/index.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/lib/index.js ADDED
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const protocol_1 = require("@yuants/protocol");
4
+ const secret_1 = require("@yuants/secret");
5
+ const sql_1 = require("@yuants/sql");
6
+ const rxjs_1 = require("rxjs");
7
+ const terminal = protocol_1.Terminal.fromNodeEnv();
8
+ const mapAccountIdToCredential = new Map();
9
+ // 1. RegisterExchangeCredential
10
+ terminal.server.provideService('RegisterExchangeCredential', {
11
+ type: 'object',
12
+ required: ['type', 'payload'],
13
+ properties: {
14
+ type: { type: 'string' },
15
+ payload: { type: 'object' },
16
+ },
17
+ }, async (msg) => {
18
+ const credential = msg.req;
19
+ const secretData = new TextEncoder().encode(JSON.stringify(credential));
20
+ await (0, secret_1.writeSecret)(terminal, terminal.keyPair.public_key, { type: 'exchange_credential' }, secretData);
21
+ return { res: { code: 0, message: 'OK' } };
22
+ });
23
+ // 2. ListExchangeCredential
24
+ terminal.server.provideService('ListExchangeCredential', {}, async () => {
25
+ const secrets = await (0, sql_1.requestSQL)(terminal, `select * from secret where tags->>'type' = 'exchange_credential' and reader = ${(0, sql_1.escapeSQL)(terminal.keyPair.public_key)}`);
26
+ const credentials = [];
27
+ for (const secret of secrets) {
28
+ try {
29
+ const decrypted = await (0, secret_1.readSecret)(terminal, secret);
30
+ const credential = JSON.parse(new TextDecoder().decode(decrypted));
31
+ credentials.push(credential);
32
+ }
33
+ catch (e) {
34
+ console.error('Failed to decrypt secret', e);
35
+ }
36
+ }
37
+ return { res: { code: 0, message: 'OK', data: credentials } };
38
+ });
39
+ // 9. Background listWatch
40
+ const updateIndex = async () => {
41
+ const secrets = await (0, sql_1.requestSQL)(terminal, `select * from secret where tags->>'type' = 'exchange_credential' and reader = ${(0, sql_1.escapeSQL)(terminal.keyPair.public_key)}`);
42
+ for (const secret of secrets) {
43
+ try {
44
+ const decrypted = await (0, secret_1.readSecret)(terminal, secret);
45
+ const credential = JSON.parse(new TextDecoder().decode(decrypted));
46
+ // Call ListAccounts to get account_ids
47
+ const res = await terminal.client.requestForResponse('ListAccounts', { credential });
48
+ if (res.code === 0 && res.data) {
49
+ for (const account of res.data) {
50
+ mapAccountIdToCredential.set(account.account_id, credential);
51
+ }
52
+ }
53
+ }
54
+ catch (e) {
55
+ console.error('Failed to process secret', e);
56
+ }
57
+ }
58
+ };
59
+ // Run updateIndex periodically
60
+ (0, rxjs_1.timer)(0, 60000)
61
+ .pipe((0, rxjs_1.mergeMap)(() => (0, rxjs_1.defer)(updateIndex).pipe((0, rxjs_1.retry)({ delay: 5000 }))))
62
+ .subscribe();
63
+ // 7. QueryAccounts
64
+ terminal.server.provideService('QueryAccounts', {}, async () => {
65
+ return { res: { code: 0, message: 'OK', data: Array.from(mapAccountIdToCredential.keys()) } };
66
+ });
67
+ // 8. QueryAccountInfo
68
+ terminal.server.provideService('QueryAccountInfo', {
69
+ type: 'object',
70
+ required: ['account_id'],
71
+ properties: {
72
+ account_id: { type: 'string' },
73
+ },
74
+ }, async (msg) => {
75
+ const credential = mapAccountIdToCredential.get(msg.req.account_id);
76
+ if (!credential) {
77
+ return { res: { code: 404, message: 'Account not found' } };
78
+ }
79
+ const res = await terminal.client.requestForResponse('GetAccountInfo', { credential, account_id: msg.req.account_id });
80
+ return { res };
81
+ });
82
+ // 10. Proxy Orders
83
+ // SubmitOrder
84
+ terminal.server.provideService('SubmitOrder', {
85
+ type: 'object',
86
+ required: ['order'],
87
+ properties: {
88
+ order: { type: 'object' },
89
+ },
90
+ }, async (msg) => {
91
+ const credential = mapAccountIdToCredential.get(msg.req.order.account_id);
92
+ if (!credential) {
93
+ return { res: { code: 404, message: 'Account not found' } };
94
+ }
95
+ const res = await terminal.client.requestForResponse('SubmitOrder', { credential, order: msg.req.order });
96
+ return { res };
97
+ });
98
+ // ModifyOrder
99
+ terminal.server.provideService('ModifyOrder', {
100
+ type: 'object',
101
+ required: ['order'],
102
+ properties: {
103
+ order: { type: 'object' },
104
+ },
105
+ }, async (msg) => {
106
+ const credential = mapAccountIdToCredential.get(msg.req.order.account_id);
107
+ if (!credential) {
108
+ return { res: { code: 404, message: 'Account not found' } };
109
+ }
110
+ const res = await terminal.client.requestForResponse('ModifyOrder', { credential, order: msg.req.order });
111
+ return { res };
112
+ });
113
+ // CancelOrder
114
+ terminal.server.provideService('CancelOrder', {
115
+ type: 'object',
116
+ required: ['order'],
117
+ properties: {
118
+ order: { type: 'object' },
119
+ },
120
+ }, async (msg) => {
121
+ const credential = mapAccountIdToCredential.get(msg.req.order.account_id);
122
+ if (!credential) {
123
+ return { res: { code: 404, message: 'Account not found' } };
124
+ }
125
+ const res = await terminal.client.requestForResponse('CancelOrder', { credential, order: msg.req.order });
126
+ return { res };
127
+ });
128
+ // ListOrders
129
+ terminal.server.provideService('ListOrders', {
130
+ type: 'object',
131
+ required: ['account_id'],
132
+ properties: {
133
+ account_id: { type: 'string' },
134
+ },
135
+ }, async (msg) => {
136
+ const credential = mapAccountIdToCredential.get(msg.req.account_id);
137
+ if (!credential) {
138
+ return { res: { code: 404, message: 'Account not found' } };
139
+ }
140
+ const res = await terminal.client.requestForResponse('ListOrders', {
141
+ credential,
142
+ account_id: msg.req.account_id,
143
+ });
144
+ return { res };
145
+ });
146
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { IAccountInfo } from '@yuants/data-account';\nimport { IOrder, ITypedCredential } from '@yuants/data-order';\nimport { Terminal } from '@yuants/protocol';\nimport { ISecret, readSecret, writeSecret } from '@yuants/secret';\nimport { escapeSQL, requestSQL } from '@yuants/sql';\nimport { defer, mergeMap, retry, timer } from 'rxjs';\n\nconst terminal = Terminal.fromNodeEnv();\n\ninterface IExchangeCredential {\n type: string;\n payload: any;\n}\n\nconst mapAccountIdToCredential = new Map<string, IExchangeCredential>();\n\n// 1. RegisterExchangeCredential\nterminal.server.provideService<IExchangeCredential, void>(\n 'RegisterExchangeCredential',\n {\n type: 'object',\n required: ['type', 'payload'],\n properties: {\n type: { type: 'string' },\n payload: { type: 'object' },\n },\n },\n async (msg) => {\n const credential = msg.req;\n const secretData = new TextEncoder().encode(JSON.stringify(credential));\n await writeSecret(terminal, terminal.keyPair.public_key, { type: 'exchange_credential' }, secretData);\n return { res: { code: 0, message: 'OK' } };\n },\n);\n\n// 2. ListExchangeCredential\nterminal.server.provideService<void, IExchangeCredential[]>('ListExchangeCredential', {}, async () => {\n const secrets = await requestSQL<ISecret[]>(\n terminal,\n `select * from secret where tags->>'type' = 'exchange_credential' and reader = ${escapeSQL(\n terminal.keyPair.public_key,\n )}`,\n );\n const credentials: IExchangeCredential[] = [];\n for (const secret of secrets) {\n try {\n const decrypted = await readSecret(terminal, secret);\n const credential = JSON.parse(new TextDecoder().decode(decrypted));\n credentials.push(credential);\n } catch (e) {\n console.error('Failed to decrypt secret', e);\n }\n }\n return { res: { code: 0, message: 'OK', data: credentials } };\n});\n\n// 9. Background listWatch\nconst updateIndex = async () => {\n const secrets = await requestSQL<ISecret[]>(\n terminal,\n `select * from secret where tags->>'type' = 'exchange_credential' and reader = ${escapeSQL(\n terminal.keyPair.public_key,\n )}`,\n );\n for (const secret of secrets) {\n try {\n const decrypted = await readSecret(terminal, secret);\n const credential = JSON.parse(new TextDecoder().decode(decrypted)) as IExchangeCredential;\n\n // Call ListAccounts to get account_ids\n const res = await terminal.client.requestForResponse<\n { credential: ITypedCredential<any> },\n Array<{ account_id: string }>\n >('ListAccounts', { credential });\n\n if (res.code === 0 && res.data) {\n for (const account of res.data) {\n mapAccountIdToCredential.set(account.account_id, credential);\n }\n }\n } catch (e) {\n console.error('Failed to process secret', e);\n }\n }\n};\n\n// Run updateIndex periodically\ntimer(0, 60000)\n .pipe(mergeMap(() => defer(updateIndex).pipe(retry({ delay: 5000 }))))\n .subscribe();\n\n// 7. QueryAccounts\nterminal.server.provideService<void, string[]>('QueryAccounts', {}, async () => {\n return { res: { code: 0, message: 'OK', data: Array.from(mapAccountIdToCredential.keys()) } };\n});\n\n// 8. QueryAccountInfo\nterminal.server.provideService<{ account_id: string }, IAccountInfo>(\n 'QueryAccountInfo',\n {\n type: 'object',\n required: ['account_id'],\n properties: {\n account_id: { type: 'string' },\n },\n },\n async (msg) => {\n const credential = mapAccountIdToCredential.get(msg.req.account_id);\n if (!credential) {\n return { res: { code: 404, message: 'Account not found' } };\n }\n const res = await terminal.client.requestForResponse<\n { credential: ITypedCredential<any>; account_id: string },\n IAccountInfo\n >('GetAccountInfo', { credential, account_id: msg.req.account_id });\n return { res };\n },\n);\n\n// 10. Proxy Orders\n// SubmitOrder\nterminal.server.provideService<{ order: IOrder }, { order_id: string }>(\n 'SubmitOrder',\n {\n type: 'object',\n required: ['order'],\n properties: {\n order: { type: 'object' },\n },\n },\n async (msg) => {\n const credential = mapAccountIdToCredential.get(msg.req.order.account_id);\n if (!credential) {\n return { res: { code: 404, message: 'Account not found' } };\n }\n const res = await terminal.client.requestForResponse<\n { credential: ITypedCredential<any>; order: IOrder },\n { order_id: string }\n >('SubmitOrder', { credential, order: msg.req.order });\n return { res };\n },\n);\n\n// ModifyOrder\nterminal.server.provideService<{ order: IOrder }, void>(\n 'ModifyOrder',\n {\n type: 'object',\n required: ['order'],\n properties: {\n order: { type: 'object' },\n },\n },\n async (msg) => {\n const credential = mapAccountIdToCredential.get(msg.req.order.account_id);\n if (!credential) {\n return { res: { code: 404, message: 'Account not found' } };\n }\n const res = await terminal.client.requestForResponse<\n { credential: ITypedCredential<any>; order: IOrder },\n void\n >('ModifyOrder', { credential, order: msg.req.order });\n return { res };\n },\n);\n\n// CancelOrder\nterminal.server.provideService<{ order: IOrder }, void>(\n 'CancelOrder',\n {\n type: 'object',\n required: ['order'],\n properties: {\n order: { type: 'object' },\n },\n },\n async (msg) => {\n const credential = mapAccountIdToCredential.get(msg.req.order.account_id);\n if (!credential) {\n return { res: { code: 404, message: 'Account not found' } };\n }\n const res = await terminal.client.requestForResponse<\n { credential: ITypedCredential<any>; order: IOrder },\n void\n >('CancelOrder', { credential, order: msg.req.order });\n return { res };\n },\n);\n\n// ListOrders\nterminal.server.provideService<{ account_id: string }, { orders: IOrder[] }>(\n 'ListOrders',\n {\n type: 'object',\n required: ['account_id'],\n properties: {\n account_id: { type: 'string' },\n },\n },\n async (msg) => {\n const credential = mapAccountIdToCredential.get(msg.req.account_id);\n if (!credential) {\n return { res: { code: 404, message: 'Account not found' } };\n }\n const res = await terminal.client.requestForResponse<\n { credential: ITypedCredential<any>; account_id: string },\n { orders: IOrder[] }\n >('ListOrders', {\n credential,\n account_id: msg.req.account_id,\n });\n return { res };\n },\n);\n"]}
@@ -0,0 +1,11 @@
1
+ // This file is read by tools that parse documentation comments conforming to the TSDoc standard.
2
+ // It should be published with your NPM package. It should not be tracked by Git.
3
+ {
4
+ "tsdocVersion": "0.12",
5
+ "toolPackages": [
6
+ {
7
+ "packageName": "@microsoft/api-extractor",
8
+ "packageVersion": "7.30.1"
9
+ }
10
+ ]
11
+ }
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@yuants/app-virtual-exchange",
3
+ "version": "0.0.1",
4
+ "main": "lib/index.js",
5
+ "files": [
6
+ "dist",
7
+ "lib",
8
+ "temp"
9
+ ],
10
+ "dependencies": {
11
+ "@yuants/protocol": "0.52.0",
12
+ "@yuants/utils": "0.11.0",
13
+ "@yuants/data-account": "0.8.0",
14
+ "@yuants/data-order": "0.6.2",
15
+ "@yuants/secret": "0.3.9",
16
+ "@yuants/sql": "0.9.26",
17
+ "rxjs": "~7.5.6",
18
+ "ajv": "~8.12.0"
19
+ },
20
+ "devDependencies": {
21
+ "@microsoft/api-extractor": "~7.30.0",
22
+ "@rushstack/heft": "~0.47.5",
23
+ "@rushstack/heft-jest-plugin": "~0.16.8",
24
+ "@rushstack/heft-node-rig": "~1.10.7",
25
+ "@types/heft-jest": "1.0.3",
26
+ "@types/node": "22",
27
+ "@yuants/tool-kit": "0.2.1",
28
+ "typescript": "~4.7.4"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public",
32
+ "registry": "https://registry.npmjs.org"
33
+ },
34
+ "scripts": {
35
+ "build": "heft test --clean && api-extractor run --local && yuan-toolkit post-build"
36
+ }
37
+ }
@@ -0,0 +1,177 @@
1
+ {
2
+ "metadata": {
3
+ "toolPackage": "@microsoft/api-extractor",
4
+ "toolVersion": "7.30.1",
5
+ "schemaVersion": 1009,
6
+ "oldestForwardsCompatibleVersion": 1001,
7
+ "tsdocConfig": {
8
+ "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json",
9
+ "noStandardTags": true,
10
+ "tagDefinitions": [
11
+ {
12
+ "tagName": "@alpha",
13
+ "syntaxKind": "modifier"
14
+ },
15
+ {
16
+ "tagName": "@beta",
17
+ "syntaxKind": "modifier"
18
+ },
19
+ {
20
+ "tagName": "@defaultValue",
21
+ "syntaxKind": "block"
22
+ },
23
+ {
24
+ "tagName": "@decorator",
25
+ "syntaxKind": "block",
26
+ "allowMultiple": true
27
+ },
28
+ {
29
+ "tagName": "@deprecated",
30
+ "syntaxKind": "block"
31
+ },
32
+ {
33
+ "tagName": "@eventProperty",
34
+ "syntaxKind": "modifier"
35
+ },
36
+ {
37
+ "tagName": "@example",
38
+ "syntaxKind": "block",
39
+ "allowMultiple": true
40
+ },
41
+ {
42
+ "tagName": "@experimental",
43
+ "syntaxKind": "modifier"
44
+ },
45
+ {
46
+ "tagName": "@inheritDoc",
47
+ "syntaxKind": "inline"
48
+ },
49
+ {
50
+ "tagName": "@internal",
51
+ "syntaxKind": "modifier"
52
+ },
53
+ {
54
+ "tagName": "@label",
55
+ "syntaxKind": "inline"
56
+ },
57
+ {
58
+ "tagName": "@link",
59
+ "syntaxKind": "inline",
60
+ "allowMultiple": true
61
+ },
62
+ {
63
+ "tagName": "@override",
64
+ "syntaxKind": "modifier"
65
+ },
66
+ {
67
+ "tagName": "@packageDocumentation",
68
+ "syntaxKind": "modifier"
69
+ },
70
+ {
71
+ "tagName": "@param",
72
+ "syntaxKind": "block",
73
+ "allowMultiple": true
74
+ },
75
+ {
76
+ "tagName": "@privateRemarks",
77
+ "syntaxKind": "block"
78
+ },
79
+ {
80
+ "tagName": "@public",
81
+ "syntaxKind": "modifier"
82
+ },
83
+ {
84
+ "tagName": "@readonly",
85
+ "syntaxKind": "modifier"
86
+ },
87
+ {
88
+ "tagName": "@remarks",
89
+ "syntaxKind": "block"
90
+ },
91
+ {
92
+ "tagName": "@returns",
93
+ "syntaxKind": "block"
94
+ },
95
+ {
96
+ "tagName": "@sealed",
97
+ "syntaxKind": "modifier"
98
+ },
99
+ {
100
+ "tagName": "@see",
101
+ "syntaxKind": "block"
102
+ },
103
+ {
104
+ "tagName": "@throws",
105
+ "syntaxKind": "block",
106
+ "allowMultiple": true
107
+ },
108
+ {
109
+ "tagName": "@typeParam",
110
+ "syntaxKind": "block",
111
+ "allowMultiple": true
112
+ },
113
+ {
114
+ "tagName": "@virtual",
115
+ "syntaxKind": "modifier"
116
+ },
117
+ {
118
+ "tagName": "@betaDocumentation",
119
+ "syntaxKind": "modifier"
120
+ },
121
+ {
122
+ "tagName": "@internalRemarks",
123
+ "syntaxKind": "block"
124
+ },
125
+ {
126
+ "tagName": "@preapproved",
127
+ "syntaxKind": "modifier"
128
+ }
129
+ ],
130
+ "supportForTags": {
131
+ "@alpha": true,
132
+ "@beta": true,
133
+ "@defaultValue": true,
134
+ "@decorator": true,
135
+ "@deprecated": true,
136
+ "@eventProperty": true,
137
+ "@example": true,
138
+ "@experimental": true,
139
+ "@inheritDoc": true,
140
+ "@internal": true,
141
+ "@label": true,
142
+ "@link": true,
143
+ "@override": true,
144
+ "@packageDocumentation": true,
145
+ "@param": true,
146
+ "@privateRemarks": true,
147
+ "@public": true,
148
+ "@readonly": true,
149
+ "@remarks": true,
150
+ "@returns": true,
151
+ "@sealed": true,
152
+ "@see": true,
153
+ "@throws": true,
154
+ "@typeParam": true,
155
+ "@virtual": true,
156
+ "@betaDocumentation": true,
157
+ "@internalRemarks": true,
158
+ "@preapproved": true
159
+ },
160
+ "reportUnsupportedHtmlElements": false
161
+ }
162
+ },
163
+ "kind": "Package",
164
+ "canonicalReference": "@yuants/app-virtual-exchange!",
165
+ "docComment": "",
166
+ "name": "@yuants/app-virtual-exchange",
167
+ "preserveMemberOrder": false,
168
+ "members": [
169
+ {
170
+ "kind": "EntryPoint",
171
+ "canonicalReference": "@yuants/app-virtual-exchange!",
172
+ "name": "",
173
+ "preserveMemberOrder": false,
174
+ "members": []
175
+ }
176
+ ]
177
+ }
@@ -0,0 +1,9 @@
1
+ ## API Report File for "@yuants/app-virtual-exchange"
2
+
3
+ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
4
+
5
+ ```ts
6
+
7
+ // (No @packageDocumentation comment for this package)
8
+
9
+ ```
@@ -0,0 +1,18 @@
1
+ {
2
+ "apps/virtual-exchange/api-extractor.json": "62f4fd324425b9a235f0c117975967aab09ced0c",
3
+ "apps/virtual-exchange/config/jest.config.json": "4bb17bde3ee911163a3edb36a6eb71491d80b1bd",
4
+ "apps/virtual-exchange/config/rig.json": "f6c7b5537dc77a3170ba9f008bae3b6c3ee11956",
5
+ "apps/virtual-exchange/config/typescript.json": "854907e8a821f2050f6533368db160c649c25348",
6
+ "apps/virtual-exchange/etc/app-virtual-exchange.api.md": "6cb40ec1fa2d40a31a7b0dd3f02b8b24a4d7c4de",
7
+ "apps/virtual-exchange/package.json": "b6f1b1495aad9a7a71dc9da5785701936226597a",
8
+ "apps/virtual-exchange/src/index.ts": "b15b3d037aded3e7c8aa9d6f84aa16b5915b87e2",
9
+ "apps/virtual-exchange/tsconfig.json": "22f94ca28b507f8ddcc21b9053158eefd3f726a9",
10
+ "apps/virtual-exchange/.rush/temp/shrinkwrap-deps.json": "8c5c8eb58b6b8757344017c67c08f71d4e6dd4d7",
11
+ "libraries/protocol/temp/package-deps.json": "52d2a645608a17915da897e48a70b415312a94fb",
12
+ "libraries/utils/temp/package-deps.json": "c58f1ca8f498315d9a0219ca8c498299a41d297b",
13
+ "libraries/data-account/temp/package-deps.json": "459a552a5ff4304fff00dfd369bb0746bd33cf5f",
14
+ "libraries/data-order/temp/package-deps.json": "0e063d2c14a4c5cfb23756143c3f399f545b496d",
15
+ "libraries/secret/temp/package-deps.json": "b3fb9c757cd7bd23783f34ba9b9abea8d7c56680",
16
+ "libraries/sql/temp/package-deps.json": "f718628b404248148aaa692928681b1087ccc7ba",
17
+ "tools/toolkit/temp/package-deps.json": "23e053490eb8feade23e4d45de4e54883e322711"
18
+ }