@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.
- package/dist/app-virtual-exchange.d.ts +1 -0
- package/dist/index.js +144 -0
- package/dist/index.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +146 -0
- package/lib/index.js.map +1 -0
- package/lib/tsdoc-metadata.json +11 -0
- package/package.json +37 -0
- package/temp/app-virtual-exchange.api.json +177 -0
- package/temp/app-virtual-exchange.api.md +9 -0
- package/temp/package-deps.json +18 -0
|
@@ -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 @@
|
|
|
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
|
package/lib/index.js.map
ADDED
|
@@ -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,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
|
+
}
|