@grvt/client 1.5.0-alpha.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/ws/ws.d.ts +12 -2
- package/ws/ws.js +130 -11
package/package.json
CHANGED
package/ws/ws.d.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import type { TWSRequest } from './interfaces';
|
|
2
|
+
export declare class WSError extends Error {
|
|
3
|
+
code?: number;
|
|
4
|
+
status?: number;
|
|
5
|
+
constructor(response: {
|
|
6
|
+
status?: number;
|
|
7
|
+
code?: number;
|
|
8
|
+
message?: string;
|
|
9
|
+
});
|
|
10
|
+
}
|
|
2
11
|
interface IOptions {
|
|
3
12
|
url: string | URL;
|
|
4
13
|
protocols?: string | string[];
|
|
@@ -46,14 +55,15 @@ export declare class WS {
|
|
|
46
55
|
private readonly _onCloses;
|
|
47
56
|
onClose(callback: (e: CloseEvent) => void): () => void;
|
|
48
57
|
private readonly _onErrors;
|
|
49
|
-
onError(callback: (e: Event) => void): () => void;
|
|
58
|
+
onError(callback: (e: Event | WSError) => void): () => void;
|
|
50
59
|
private _subscribeCurrentPairs;
|
|
51
60
|
private _subscribe;
|
|
52
61
|
/**
|
|
53
62
|
* Only supports one feed
|
|
54
63
|
*/
|
|
55
64
|
subscribe(_options: TWSRequest): string;
|
|
56
|
-
|
|
65
|
+
subscribes(...subscriptions: TWSRequest[]): string[];
|
|
66
|
+
unsubscribe(...pairedConsumerKeys: string[]): this;
|
|
57
67
|
connect(): this;
|
|
58
68
|
disconnect(): this;
|
|
59
69
|
ready(delay?: number): Promise<unknown>;
|
package/ws/ws.js
CHANGED
|
@@ -20,7 +20,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
20
20
|
return t;
|
|
21
21
|
};
|
|
22
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.WS = void 0;
|
|
23
|
+
exports.WS = exports.WSError = void 0;
|
|
24
24
|
const ws_candlestick_feed_data_v_1_1 = require("../interfaces/codegen/schema-maps/ws_candlestick_feed_data_v_1");
|
|
25
25
|
const ws_deposit_feed_data_v_1_1 = require("../interfaces/codegen/schema-maps/ws_deposit_feed_data_v_1");
|
|
26
26
|
const ws_fill_feed_data_v_1_1 = require("../interfaces/codegen/schema-maps/ws_fill_feed_data_v_1");
|
|
@@ -36,6 +36,15 @@ const ws_transfer_feed_data_v_1_1 = require("../interfaces/codegen/schema-maps/w
|
|
|
36
36
|
const ws_withdrawal_feed_data_v_1_1 = require("../interfaces/codegen/schema-maps/ws_withdrawal_feed_data_v_1");
|
|
37
37
|
const utils_1 = require("../utils");
|
|
38
38
|
const interfaces_1 = require("./interfaces");
|
|
39
|
+
class WSError extends Error {
|
|
40
|
+
constructor(response) {
|
|
41
|
+
super(response.message);
|
|
42
|
+
this.name = 'WSError';
|
|
43
|
+
this.code = response.code;
|
|
44
|
+
this.status = response.status;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.WSError = WSError;
|
|
39
48
|
const omitZeroStr = (str) => str === '0' ? '' : str;
|
|
40
49
|
class WS {
|
|
41
50
|
get _ws() {
|
|
@@ -140,7 +149,7 @@ class WS {
|
|
|
140
149
|
reconnect();
|
|
141
150
|
});
|
|
142
151
|
currentWs.addEventListener('message', (e) => {
|
|
143
|
-
var _a, _b, _c, _d, _e, _f;
|
|
152
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
144
153
|
// only keep the latest ws
|
|
145
154
|
if (currentWs !== this.__ws) {
|
|
146
155
|
this._close(currentWs);
|
|
@@ -152,17 +161,33 @@ class WS {
|
|
|
152
161
|
}
|
|
153
162
|
const message = utils_1.JsonUtils.parse(e.data);
|
|
154
163
|
/**
|
|
155
|
-
*
|
|
164
|
+
* Handle error response
|
|
156
165
|
*/
|
|
157
|
-
if (message.status
|
|
166
|
+
if ((_b = (_a = message.status) !== null && _a !== void 0 ? _a : message.c) !== null && _b !== void 0 ? _b : message.code) {
|
|
167
|
+
/**
|
|
168
|
+
* Ignore 1003 response "Request could not be processed due to malformed syntax"
|
|
169
|
+
* This happens when client send
|
|
170
|
+
*/
|
|
171
|
+
const code = (_c = message.c) !== null && _c !== void 0 ? _c : message.code;
|
|
172
|
+
if (code !== 1003) {
|
|
173
|
+
const error = new WSError(Object.assign(Object.assign({}, message), { code, message: (_d = message.m) !== null && _d !== void 0 ? _d : message.message }));
|
|
174
|
+
if (this._onErrors.length) {
|
|
175
|
+
for (const onError of this._onErrors) {
|
|
176
|
+
onError(error);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
console.error(error);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
158
183
|
return;
|
|
159
184
|
}
|
|
160
|
-
const stream = message.s = (
|
|
185
|
+
const stream = message.s = (_f = (_e = message.s) === null || _e === void 0 ? void 0 : _e.replace) === null || _f === void 0 ? void 0 : _f.call(_e, `${this._version}.`, '');
|
|
161
186
|
const result = this._messageLiteToFull(message);
|
|
162
187
|
// no entity found
|
|
163
188
|
if (!result) {
|
|
164
189
|
// if no entity found and not a subscription message
|
|
165
|
-
if (!((
|
|
190
|
+
if (!((_g = message.s1) === null || _g === void 0 ? void 0 : _g.length)) {
|
|
166
191
|
console.warn('Error: something went wrong with message', message);
|
|
167
192
|
}
|
|
168
193
|
return;
|
|
@@ -171,7 +196,7 @@ class WS {
|
|
|
171
196
|
console.warn('Error: cannot parse stream or feed from message', message);
|
|
172
197
|
return;
|
|
173
198
|
}
|
|
174
|
-
const instrument = (
|
|
199
|
+
const instrument = (_k = (_j = (_h = result === null || result === void 0 ? void 0 : result.legs) === null || _h === void 0 ? void 0 : _h[0]) === null || _j === void 0 ? void 0 : _j.instrument) !== null && _k !== void 0 ? _k : result === null || result === void 0 ? void 0 : result.instrument;
|
|
175
200
|
/**
|
|
176
201
|
* Handle subscriptions with instrument
|
|
177
202
|
*/
|
|
@@ -634,12 +659,24 @@ class WS {
|
|
|
634
659
|
}
|
|
635
660
|
_subscribeCurrentPairs() {
|
|
636
661
|
const pairs = Object.keys(this._pairs);
|
|
637
|
-
|
|
662
|
+
const groupStreams = {};
|
|
663
|
+
// keep last primary stream
|
|
664
|
+
for (const pair of pairs.reverse()) {
|
|
638
665
|
const { stream, feed } = this._parsePair(pair);
|
|
666
|
+
if (!groupStreams[stream]) {
|
|
667
|
+
groupStreams[stream] = [];
|
|
668
|
+
}
|
|
669
|
+
const primaryFeed = feed.split('@')[0];
|
|
670
|
+
if (!groupStreams[stream].some((f) => f.startsWith(`${primaryFeed}@`))) {
|
|
671
|
+
groupStreams[stream].push(feed);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
const streams = Object.keys(groupStreams);
|
|
675
|
+
for (const stream of streams) {
|
|
639
676
|
this._sendMessage({
|
|
640
677
|
method: 'subscribe',
|
|
641
678
|
stream,
|
|
642
|
-
feed: [
|
|
679
|
+
feed: groupStreams[stream]
|
|
643
680
|
});
|
|
644
681
|
}
|
|
645
682
|
}
|
|
@@ -696,8 +733,90 @@ class WS {
|
|
|
696
733
|
void this._subscribe(pair, subscribePayload).catch(onError);
|
|
697
734
|
return this._addConsumer(pair, onMessage);
|
|
698
735
|
}
|
|
699
|
-
|
|
700
|
-
|
|
736
|
+
subscribes(...subscriptions) {
|
|
737
|
+
var _a;
|
|
738
|
+
if (!subscriptions.length) {
|
|
739
|
+
return [];
|
|
740
|
+
}
|
|
741
|
+
const pairs = [];
|
|
742
|
+
const payloads = [];
|
|
743
|
+
const groupStreams = {};
|
|
744
|
+
for (const subscription of subscriptions) {
|
|
745
|
+
const { onData: onMessage, onError } = subscription, options = __rest(subscription, ["onData", "onError"]);
|
|
746
|
+
const subscribePayload = this._parseStream(options);
|
|
747
|
+
const stream = subscribePayload === null || subscribePayload === void 0 ? void 0 : subscribePayload.stream;
|
|
748
|
+
const feed = (_a = subscribePayload === null || subscribePayload === void 0 ? void 0 : subscribePayload.feed) === null || _a === void 0 ? void 0 : _a[0];
|
|
749
|
+
if (!stream || !feed) {
|
|
750
|
+
throw new Error('Unknown stream or feed');
|
|
751
|
+
}
|
|
752
|
+
if (!groupStreams[stream]) {
|
|
753
|
+
groupStreams[stream] = [];
|
|
754
|
+
}
|
|
755
|
+
const primaryFeed = feed.split('@')[0];
|
|
756
|
+
if (groupStreams[stream].some((f) => f.startsWith(`${primaryFeed}@`))) {
|
|
757
|
+
throw new Error(`Attempted to subscribe to same primary selector twice, in same request: ${primaryFeed}`);
|
|
758
|
+
}
|
|
759
|
+
groupStreams[stream].push(feed);
|
|
760
|
+
payloads.push(subscribePayload);
|
|
761
|
+
pairs.push({
|
|
762
|
+
pair: this._getPair({ stream, feed }),
|
|
763
|
+
onData: onMessage,
|
|
764
|
+
onError
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Subscribe in parallel and listen for responses
|
|
769
|
+
*/
|
|
770
|
+
setTimeout(() => __awaiter(this, void 0, void 0, function* () {
|
|
771
|
+
var _b;
|
|
772
|
+
yield this.ready();
|
|
773
|
+
for (const { pair, onError } of pairs) {
|
|
774
|
+
let _resolve;
|
|
775
|
+
const onPaired = (e) => {
|
|
776
|
+
var _a, _b, _c;
|
|
777
|
+
const message = utils_1.JsonUtils.parse(e.data);
|
|
778
|
+
if (!(message === null || message === void 0 ? void 0 : message.s) || !((_a = message === null || message === void 0 ? void 0 : message.s1) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
const responseStream = (_c = (_b = message.s) === null || _b === void 0 ? void 0 : _b.replace) === null || _c === void 0 ? void 0 : _c.call(_b, `${this._version}.`, '');
|
|
782
|
+
const { stream, feed } = this._parsePair(pair);
|
|
783
|
+
const asset = feed.split('@')[0];
|
|
784
|
+
const subs = message.s1;
|
|
785
|
+
const isResolved = stream === responseStream && (subs.includes(asset) ||
|
|
786
|
+
subs.includes(asset.toLowerCase()) ||
|
|
787
|
+
subs.includes(feed) ||
|
|
788
|
+
subs.includes(feed.toLowerCase()));
|
|
789
|
+
if (isResolved) {
|
|
790
|
+
_resolve();
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
const promise = new Promise((resolve) => {
|
|
794
|
+
_resolve = resolve;
|
|
795
|
+
this._ws.addEventListener('message', onPaired);
|
|
796
|
+
});
|
|
797
|
+
utils_1.Utils.timeout(promise, (_b = this._options.timeout) !== null && _b !== void 0 ? _b : 30000, new Error('Subscribe Timeout: ' + pair))
|
|
798
|
+
.catch((error) => onError === null || onError === void 0 ? void 0 : onError(error))
|
|
799
|
+
.finally(() => {
|
|
800
|
+
this._ws.removeEventListener('message', onPaired);
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
const streams = Object.keys(groupStreams);
|
|
804
|
+
for (const stream of streams) {
|
|
805
|
+
this._sendMessage({
|
|
806
|
+
method: 'subscribe',
|
|
807
|
+
stream,
|
|
808
|
+
feed: groupStreams[stream]
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
}));
|
|
812
|
+
return pairs.map(({ pair, onData }) => {
|
|
813
|
+
return this._addConsumer(pair, onData);
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
unsubscribe(...pairedConsumerKeys) {
|
|
817
|
+
for (const pairedConsumerKey of pairedConsumerKeys) {
|
|
818
|
+
this._removeConsumer(pairedConsumerKey);
|
|
819
|
+
}
|
|
701
820
|
return this;
|
|
702
821
|
}
|
|
703
822
|
connect() {
|