@lifi/perps-sdk 1.5.2 → 1.5.4
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/cjs/services/resolveSubscribeQuote.d.ts.map +1 -1
- package/dist/cjs/services/resolveSubscribeQuote.js +33 -19
- package/dist/cjs/services/resolveSubscribeQuote.js.map +1 -1
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/websocket/PerpsWsClient.d.ts +2 -0
- package/dist/cjs/websocket/PerpsWsClient.d.ts.map +1 -1
- package/dist/cjs/websocket/PerpsWsClient.js +9 -0
- package/dist/cjs/websocket/PerpsWsClient.js.map +1 -1
- package/dist/esm/services/resolveSubscribeQuote.d.ts +9 -8
- package/dist/esm/services/resolveSubscribeQuote.d.ts.map +1 -1
- package/dist/esm/services/resolveSubscribeQuote.js +44 -27
- package/dist/esm/services/resolveSubscribeQuote.js.map +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/websocket/PerpsWsClient.d.ts +5 -0
- package/dist/esm/websocket/PerpsWsClient.d.ts.map +1 -1
- package/dist/esm/websocket/PerpsWsClient.js +12 -0
- package/dist/esm/websocket/PerpsWsClient.js.map +1 -1
- package/dist/types/services/resolveSubscribeQuote.d.ts +9 -8
- package/dist/types/services/resolveSubscribeQuote.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/websocket/PerpsWsClient.d.ts +5 -0
- package/dist/types/websocket/PerpsWsClient.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/services/resolveSubscribeQuote.ts +56 -28
- package/src/version.ts +1 -1
- package/src/websocket/PerpsWsClient.ts +17 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveSubscribeQuote.d.ts","sourceRoot":"","sources":["../../../src/services/resolveSubscribeQuote.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"resolveSubscribeQuote.d.ts","sourceRoot":"","sources":["../../../src/services/resolveSubscribeQuote.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAGR,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EACV,cAAc,EACd,sBAAsB,EACtB,aAAa,EACd,MAAM,sBAAsB,CAAA;AAE7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAUvD,eAAO,MAAM,iBAAiB,MAAM,CAAA;AAqBpC,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,EACjC,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,IAAI,CAAC,CAuFrB"}
|
|
@@ -7,7 +7,7 @@ const resolveQuote_js_1 = require("./resolveQuote.js");
|
|
|
7
7
|
exports.QUOTE_THROTTLE_MS = 100;
|
|
8
8
|
async function resolveSubscribeQuote(client, provider, ws, params, feeTier, onQuote) {
|
|
9
9
|
const market = await (0, resolveQuote_js_1.resolveQuoteMarket)(client, provider, params);
|
|
10
|
-
|
|
10
|
+
let latestContext = await (0, resolveQuote_js_1.resolveQuotePrice)(client, provider, market.id);
|
|
11
11
|
let latestBook;
|
|
12
12
|
let lastEmitAt = Number.NEGATIVE_INFINITY;
|
|
13
13
|
let trailing;
|
|
@@ -23,32 +23,45 @@ async function resolveSubscribeQuote(client, provider, ws, params, feeTier, onQu
|
|
|
23
23
|
side: params.side,
|
|
24
24
|
sizeUsd: params.size,
|
|
25
25
|
market,
|
|
26
|
-
price,
|
|
26
|
+
price: latestContext,
|
|
27
27
|
bids: latestBook.bids,
|
|
28
28
|
asks: latestBook.asks,
|
|
29
29
|
feeTier,
|
|
30
30
|
timestamp: Date.now(),
|
|
31
31
|
}));
|
|
32
32
|
};
|
|
33
|
-
const
|
|
34
|
-
if (event.channel !== '
|
|
33
|
+
const unsubscribeContext = await ws.subscribe({ channel: 'marketContext', dex: provider, marketId: market.id }, (event) => {
|
|
34
|
+
if (event.channel !== 'marketContext') {
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
|
-
|
|
38
|
-
if (trailing !== undefined) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
const wait = exports.QUOTE_THROTTLE_MS - (Date.now() - lastEmitAt);
|
|
42
|
-
if (wait <= 0) {
|
|
43
|
-
emit();
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
trailing = setTimeout(() => {
|
|
47
|
-
trailing = undefined;
|
|
48
|
-
emit();
|
|
49
|
-
}, wait);
|
|
50
|
-
}
|
|
37
|
+
latestContext = event.data;
|
|
51
38
|
});
|
|
39
|
+
let unsubscribeBook;
|
|
40
|
+
try {
|
|
41
|
+
unsubscribeBook = await ws.subscribe({ channel: 'orderbook', dex: provider, marketId: market.id }, (event) => {
|
|
42
|
+
if (event.channel !== 'orderbook') {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
latestBook = event.data;
|
|
46
|
+
if (trailing !== undefined) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const wait = exports.QUOTE_THROTTLE_MS - (Date.now() - lastEmitAt);
|
|
50
|
+
if (wait <= 0) {
|
|
51
|
+
emit();
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
trailing = setTimeout(() => {
|
|
55
|
+
trailing = undefined;
|
|
56
|
+
emit();
|
|
57
|
+
}, wait);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
unsubscribeContext();
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
52
65
|
let released = false;
|
|
53
66
|
return () => {
|
|
54
67
|
if (released) {
|
|
@@ -59,7 +72,8 @@ async function resolveSubscribeQuote(client, provider, ws, params, feeTier, onQu
|
|
|
59
72
|
clearTimeout(trailing);
|
|
60
73
|
trailing = undefined;
|
|
61
74
|
}
|
|
62
|
-
|
|
75
|
+
unsubscribeContext();
|
|
76
|
+
unsubscribeBook();
|
|
63
77
|
};
|
|
64
78
|
}
|
|
65
79
|
//# sourceMappingURL=resolveSubscribeQuote.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveSubscribeQuote.js","sourceRoot":"","sources":["../../../src/services/resolveSubscribeQuote.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"resolveSubscribeQuote.js","sourceRoot":"","sources":["../../../src/services/resolveSubscribeQuote.ts"],"names":[],"mappings":"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"}
|
package/dist/cjs/version.d.ts
CHANGED
package/dist/cjs/version.js
CHANGED
|
@@ -16,11 +16,13 @@ export declare class PerpsWsClient {
|
|
|
16
16
|
private readonly options;
|
|
17
17
|
private providers;
|
|
18
18
|
private initPromises;
|
|
19
|
+
private closed;
|
|
19
20
|
constructor(client: PerpsSDKClient, options?: PerpsWsClientOptions);
|
|
20
21
|
subscribe<S extends Subscription>(sub: S, listener: (event: EventForSubscription<S>) => void, onStatus?: WsStatusListener): Promise<() => void>;
|
|
21
22
|
subscribeQuote(params: GetQuoteParams, onQuote: QuoteListener): Promise<() => void>;
|
|
22
23
|
close(): void;
|
|
23
24
|
reconnect(provider: string): void;
|
|
25
|
+
private assertOpen;
|
|
24
26
|
private getOrCreateProvider;
|
|
25
27
|
private initProvider;
|
|
26
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PerpsWsClient.d.ts","sourceRoot":"","sources":["../../../src/websocket/PerpsWsClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEzE,OAAO,KAAK,EACV,oBAAoB,EAEpB,UAAU,EACV,gBAAgB,EACjB,MAAM,YAAY,CAAA;AAQnB,MAAM,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE;IAEvC,QAAQ,EAAE,MAAM,CAAA;IAEhB,KAAK,EAAE,MAAM,CAAA;IAOb,OAAO,EAAE,MAAM,EAAE,CAAA;IAMjB,MAAM,EAAE,cAAc,CAAA;CACvB,KAAK,UAAU,CAAA;AAOhB,MAAM,WAAW,oBAAoB;IASnC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;CAChD;AAQD,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,YAAY,CAAyC;
|
|
1
|
+
{"version":3,"file":"PerpsWsClient.d.ts","sourceRoot":"","sources":["../../../src/websocket/PerpsWsClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEzE,OAAO,KAAK,EACV,oBAAoB,EAEpB,UAAU,EACV,gBAAgB,EACjB,MAAM,YAAY,CAAA;AAQnB,MAAM,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE;IAEvC,QAAQ,EAAE,MAAM,CAAA;IAEhB,KAAK,EAAE,MAAM,CAAA;IAOb,OAAO,EAAE,MAAM,EAAE,CAAA;IAMjB,MAAM,EAAE,cAAc,CAAA;CACvB,KAAK,UAAU,CAAA;AAOhB,MAAM,WAAW,oBAAoB;IASnC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;CAChD;AAQD,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,YAAY,CAAyC;IAC7D,OAAO,CAAC,MAAM,CAAQ;gBAEV,MAAM,EAAE,cAAc,EAAE,OAAO,GAAE,oBAAyB;IAkBhE,SAAS,CAAC,CAAC,SAAS,YAAY,EACpC,GAAG,EAAE,CAAC,EACN,QAAQ,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,KAAK,IAAI,EAClD,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,OAAO,CAAC,MAAM,IAAI,CAAC;IAkBhB,cAAc,CAClB,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,IAAI,CAAC;IAqBtB,KAAK;IAeL,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIjC,OAAO,CAAC,UAAU;YASJ,mBAAmB;YAqBnB,YAAY;CAsC3B"}
|
|
@@ -10,6 +10,7 @@ class PerpsWsClient {
|
|
|
10
10
|
options;
|
|
11
11
|
providers = new Map();
|
|
12
12
|
initPromises = new Map();
|
|
13
|
+
closed = false;
|
|
13
14
|
constructor(client, options = {}) {
|
|
14
15
|
this.client = client;
|
|
15
16
|
this.options = options;
|
|
@@ -30,6 +31,7 @@ class PerpsWsClient {
|
|
|
30
31
|
}, onQuote);
|
|
31
32
|
}
|
|
32
33
|
close() {
|
|
34
|
+
this.closed = true;
|
|
33
35
|
for (const p of this.providers.values()) {
|
|
34
36
|
p.close();
|
|
35
37
|
}
|
|
@@ -39,7 +41,13 @@ class PerpsWsClient {
|
|
|
39
41
|
reconnect(provider) {
|
|
40
42
|
this.providers.get(provider)?.reconnect();
|
|
41
43
|
}
|
|
44
|
+
assertOpen() {
|
|
45
|
+
if (this.closed) {
|
|
46
|
+
throw new PerpsError_js_1.PerpsError(perps_types_1.PerpsErrorCode.SDKError, 'PerpsWsClient is closed. Create a new instance to subscribe again.');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
42
49
|
async getOrCreateProvider(provider) {
|
|
50
|
+
this.assertOpen();
|
|
43
51
|
const existing = this.providers.get(provider);
|
|
44
52
|
if (existing) {
|
|
45
53
|
return existing;
|
|
@@ -60,6 +68,7 @@ class PerpsWsClient {
|
|
|
60
68
|
'new PerpsWsClient(client, { wsProviders: { [key]: factory } }).');
|
|
61
69
|
}
|
|
62
70
|
const { providers } = await (0, getProviders_js_1.getProviders)(this.client);
|
|
71
|
+
this.assertOpen();
|
|
63
72
|
const providerInfo = providers.find((d) => d.key === provider);
|
|
64
73
|
if (!providerInfo?.wsUrl) {
|
|
65
74
|
throw new Error(`No WebSocket URL found for provider: ${provider}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PerpsWsClient.js","sourceRoot":"","sources":["../../../src/websocket/PerpsWsClient.ts"],"names":[],"mappings":";;;AAAA,mDAAqE;AACrE,2DAAoD;AACpD,iEAA0D;AAG1D,uDAAgD;AAyDhD,MAAa,aAAa;IACP,MAAM,CAAgB;IACtB,OAAO,CAAsB;IACtC,SAAS,GAAG,IAAI,GAAG,EAAsB,CAAA;IACzC,YAAY,GAAG,IAAI,GAAG,EAA+B,CAAA;
|
|
1
|
+
{"version":3,"file":"PerpsWsClient.js","sourceRoot":"","sources":["../../../src/websocket/PerpsWsClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,17 +12,18 @@ export declare const QUOTE_THROTTLE_MS = 100;
|
|
|
12
12
|
/**
|
|
13
13
|
* Shared provider-side `subscribeQuote` implementation: resolve
|
|
14
14
|
* `params.symbol` to a market on `provider` (via {@link resolveQuoteMarket}),
|
|
15
|
-
* subscribe to that market's orderbook
|
|
16
|
-
* update rebuild the {@link Quote}
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
15
|
+
* subscribe to that market's orderbook and marketContext channels on `ws`,
|
|
16
|
+
* and on each book update rebuild the {@link Quote} against the latest
|
|
17
|
+
* {@link MarketContext} with the provider's public base `feeTier` — the same
|
|
18
|
+
* transform the one-shot `resolveQuote` applies to a REST snapshot. Emissions
|
|
19
|
+
* are throttled to {@link QUOTE_THROTTLE_MS}: the first book update emits
|
|
20
|
+
* immediately, then at most one (trailing, latest-book) emission per
|
|
20
21
|
* interval. Both venue WS plugins delegate here; each only supplies its own
|
|
21
22
|
* base tier.
|
|
22
23
|
*
|
|
23
|
-
* The returned unsubscribe is idempotent — it releases
|
|
24
|
-
*
|
|
25
|
-
*
|
|
24
|
+
* The returned unsubscribe is idempotent — it releases both underlying
|
|
25
|
+
* listeners once and cancels any pending trailing emission, so the wire
|
|
26
|
+
* subscriptions' ref counts cannot be double-decremented.
|
|
26
27
|
*
|
|
27
28
|
* @throws {PerpsError} `MarketNotFound` when no market matches symbol+type.
|
|
28
29
|
* @internal
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveSubscribeQuote.d.ts","sourceRoot":"","sources":["../../../src/services/resolveSubscribeQuote.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"resolveSubscribeQuote.d.ts","sourceRoot":"","sources":["../../../src/services/resolveSubscribeQuote.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAGR,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EACV,cAAc,EACd,sBAAsB,EACtB,aAAa,EACd,MAAM,sBAAsB,CAAA;AAE7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAGvD;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,MAAM,CAAA;AAEpC;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,EACjC,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,IAAI,CAAC,CAuFrB"}
|
|
@@ -11,24 +11,27 @@ export const QUOTE_THROTTLE_MS = 100;
|
|
|
11
11
|
/**
|
|
12
12
|
* Shared provider-side `subscribeQuote` implementation: resolve
|
|
13
13
|
* `params.symbol` to a market on `provider` (via {@link resolveQuoteMarket}),
|
|
14
|
-
* subscribe to that market's orderbook
|
|
15
|
-
* update rebuild the {@link Quote}
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
14
|
+
* subscribe to that market's orderbook and marketContext channels on `ws`,
|
|
15
|
+
* and on each book update rebuild the {@link Quote} against the latest
|
|
16
|
+
* {@link MarketContext} with the provider's public base `feeTier` — the same
|
|
17
|
+
* transform the one-shot `resolveQuote` applies to a REST snapshot. Emissions
|
|
18
|
+
* are throttled to {@link QUOTE_THROTTLE_MS}: the first book update emits
|
|
19
|
+
* immediately, then at most one (trailing, latest-book) emission per
|
|
19
20
|
* interval. Both venue WS plugins delegate here; each only supplies its own
|
|
20
21
|
* base tier.
|
|
21
22
|
*
|
|
22
|
-
* The returned unsubscribe is idempotent — it releases
|
|
23
|
-
*
|
|
24
|
-
*
|
|
23
|
+
* The returned unsubscribe is idempotent — it releases both underlying
|
|
24
|
+
* listeners once and cancels any pending trailing emission, so the wire
|
|
25
|
+
* subscriptions' ref counts cannot be double-decremented.
|
|
25
26
|
*
|
|
26
27
|
* @throws {PerpsError} `MarketNotFound` when no market matches symbol+type.
|
|
27
28
|
* @internal
|
|
28
29
|
*/
|
|
29
30
|
export async function resolveSubscribeQuote(client, provider, ws, params, feeTier, onQuote) {
|
|
30
31
|
const market = await resolveQuoteMarket(client, provider, params);
|
|
31
|
-
|
|
32
|
+
// REST snapshot seeds the context; the marketContext subscription below
|
|
33
|
+
// keeps it live so streamed impact/funding track the moving market.
|
|
34
|
+
let latestContext = await resolveQuotePrice(client, provider, market.id);
|
|
32
35
|
let latestBook;
|
|
33
36
|
let lastEmitAt = Number.NEGATIVE_INFINITY;
|
|
34
37
|
let trailing;
|
|
@@ -44,32 +47,45 @@ export async function resolveSubscribeQuote(client, provider, ws, params, feeTie
|
|
|
44
47
|
side: params.side,
|
|
45
48
|
sizeUsd: params.size,
|
|
46
49
|
market,
|
|
47
|
-
price,
|
|
50
|
+
price: latestContext,
|
|
48
51
|
bids: latestBook.bids,
|
|
49
52
|
asks: latestBook.asks,
|
|
50
53
|
feeTier,
|
|
51
54
|
timestamp: Date.now(),
|
|
52
55
|
}));
|
|
53
56
|
};
|
|
54
|
-
const
|
|
55
|
-
if (event.channel !== '
|
|
57
|
+
const unsubscribeContext = await ws.subscribe({ channel: 'marketContext', dex: provider, marketId: market.id }, (event) => {
|
|
58
|
+
if (event.channel !== 'marketContext') {
|
|
56
59
|
return;
|
|
57
60
|
}
|
|
58
|
-
|
|
59
|
-
if (trailing !== undefined) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
const wait = QUOTE_THROTTLE_MS - (Date.now() - lastEmitAt);
|
|
63
|
-
if (wait <= 0) {
|
|
64
|
-
emit();
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
trailing = setTimeout(() => {
|
|
68
|
-
trailing = undefined;
|
|
69
|
-
emit();
|
|
70
|
-
}, wait);
|
|
71
|
-
}
|
|
61
|
+
latestContext = event.data;
|
|
72
62
|
});
|
|
63
|
+
let unsubscribeBook;
|
|
64
|
+
try {
|
|
65
|
+
unsubscribeBook = await ws.subscribe({ channel: 'orderbook', dex: provider, marketId: market.id }, (event) => {
|
|
66
|
+
if (event.channel !== 'orderbook') {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
latestBook = event.data;
|
|
70
|
+
if (trailing !== undefined) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const wait = QUOTE_THROTTLE_MS - (Date.now() - lastEmitAt);
|
|
74
|
+
if (wait <= 0) {
|
|
75
|
+
emit();
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
trailing = setTimeout(() => {
|
|
79
|
+
trailing = undefined;
|
|
80
|
+
emit();
|
|
81
|
+
}, wait);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
unsubscribeContext();
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
73
89
|
let released = false;
|
|
74
90
|
return () => {
|
|
75
91
|
if (released) {
|
|
@@ -80,7 +96,8 @@ export async function resolveSubscribeQuote(client, provider, ws, params, feeTie
|
|
|
80
96
|
clearTimeout(trailing);
|
|
81
97
|
trailing = undefined;
|
|
82
98
|
}
|
|
83
|
-
|
|
99
|
+
unsubscribeContext();
|
|
100
|
+
unsubscribeBook();
|
|
84
101
|
};
|
|
85
102
|
}
|
|
86
103
|
//# sourceMappingURL=resolveSubscribeQuote.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveSubscribeQuote.js","sourceRoot":"","sources":["../../../src/services/resolveSubscribeQuote.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"resolveSubscribeQuote.js","sourceRoot":"","sources":["../../../src/services/resolveSubscribeQuote.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/version.d.ts
CHANGED
package/dist/esm/version.js
CHANGED
|
@@ -54,6 +54,7 @@ export declare class PerpsWsClient {
|
|
|
54
54
|
private readonly options;
|
|
55
55
|
private providers;
|
|
56
56
|
private initPromises;
|
|
57
|
+
private closed;
|
|
57
58
|
constructor(client: PerpsSDKClient, options?: PerpsWsClientOptions);
|
|
58
59
|
/**
|
|
59
60
|
* Subscribe to a realtime channel, lazily creating the provider's WS
|
|
@@ -83,6 +84,9 @@ export declare class PerpsWsClient {
|
|
|
83
84
|
subscribeQuote(params: GetQuoteParams, onQuote: QuoteListener): Promise<() => void>;
|
|
84
85
|
/**
|
|
85
86
|
* Close every open provider WS connection and drop all cached providers.
|
|
87
|
+
* Terminal: after `close()` the client is dead — `subscribe` and
|
|
88
|
+
* `subscribeQuote` reject, and any provider init still suspended mid-flight
|
|
89
|
+
* aborts without opening a socket. Create a new instance to subscribe again.
|
|
86
90
|
*
|
|
87
91
|
* @public
|
|
88
92
|
*/
|
|
@@ -94,6 +98,7 @@ export declare class PerpsWsClient {
|
|
|
94
98
|
* @public
|
|
95
99
|
*/
|
|
96
100
|
reconnect(provider: string): void;
|
|
101
|
+
private assertOpen;
|
|
97
102
|
private getOrCreateProvider;
|
|
98
103
|
private initProvider;
|
|
99
104
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PerpsWsClient.d.ts","sourceRoot":"","sources":["../../../src/websocket/PerpsWsClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEzE,OAAO,KAAK,EACV,oBAAoB,EAEpB,UAAU,EACV,gBAAgB,EACjB,MAAM,YAAY,CAAA;AAEnB;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE;IACvC,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAA;IAChB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB;;;;OAIG;IACH,MAAM,EAAE,cAAc,CAAA;CACvB,KAAK,UAAU,CAAA;AAEhB;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;CAChD;AAED;;;;;GAKG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,YAAY,CAAyC;
|
|
1
|
+
{"version":3,"file":"PerpsWsClient.d.ts","sourceRoot":"","sources":["../../../src/websocket/PerpsWsClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEzE,OAAO,KAAK,EACV,oBAAoB,EAEpB,UAAU,EACV,gBAAgB,EACjB,MAAM,YAAY,CAAA;AAEnB;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE;IACvC,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAA;IAChB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB;;;;OAIG;IACH,MAAM,EAAE,cAAc,CAAA;CACvB,KAAK,UAAU,CAAA;AAEhB;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;CAChD;AAED;;;;;GAKG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,YAAY,CAAyC;IAC7D,OAAO,CAAC,MAAM,CAAQ;gBAEV,MAAM,EAAE,cAAc,EAAE,OAAO,GAAE,oBAAyB;IAKtE;;;;;;;;;;;;OAYG;IACG,SAAS,CAAC,CAAC,SAAS,YAAY,EACpC,GAAG,EAAE,CAAC,EACN,QAAQ,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,KAAK,IAAI,EAClD,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,OAAO,CAAC,MAAM,IAAI,CAAC;IAOtB;;;;;;;;;;OAUG;IACG,cAAc,CAClB,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,IAAI,CAAC;IAatB;;;;;;;OAOG;IACH,KAAK;IASL;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIjC,OAAO,CAAC,UAAU;YASJ,mBAAmB;YAqBnB,YAAY;CAsC3B"}
|
|
@@ -13,6 +13,7 @@ export class PerpsWsClient {
|
|
|
13
13
|
options;
|
|
14
14
|
providers = new Map();
|
|
15
15
|
initPromises = new Map();
|
|
16
|
+
closed = false;
|
|
16
17
|
constructor(client, options = {}) {
|
|
17
18
|
this.client = client;
|
|
18
19
|
this.options = options;
|
|
@@ -58,10 +59,14 @@ export class PerpsWsClient {
|
|
|
58
59
|
}
|
|
59
60
|
/**
|
|
60
61
|
* Close every open provider WS connection and drop all cached providers.
|
|
62
|
+
* Terminal: after `close()` the client is dead — `subscribe` and
|
|
63
|
+
* `subscribeQuote` reject, and any provider init still suspended mid-flight
|
|
64
|
+
* aborts without opening a socket. Create a new instance to subscribe again.
|
|
61
65
|
*
|
|
62
66
|
* @public
|
|
63
67
|
*/
|
|
64
68
|
close() {
|
|
69
|
+
this.closed = true;
|
|
65
70
|
for (const p of this.providers.values()) {
|
|
66
71
|
p.close();
|
|
67
72
|
}
|
|
@@ -77,7 +82,13 @@ export class PerpsWsClient {
|
|
|
77
82
|
reconnect(provider) {
|
|
78
83
|
this.providers.get(provider)?.reconnect();
|
|
79
84
|
}
|
|
85
|
+
assertOpen() {
|
|
86
|
+
if (this.closed) {
|
|
87
|
+
throw new PerpsError(PerpsErrorCode.SDKError, 'PerpsWsClient is closed. Create a new instance to subscribe again.');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
80
90
|
async getOrCreateProvider(provider) {
|
|
91
|
+
this.assertOpen();
|
|
81
92
|
const existing = this.providers.get(provider);
|
|
82
93
|
if (existing) {
|
|
83
94
|
return existing;
|
|
@@ -98,6 +109,7 @@ export class PerpsWsClient {
|
|
|
98
109
|
'new PerpsWsClient(client, { wsProviders: { [key]: factory } }).');
|
|
99
110
|
}
|
|
100
111
|
const { providers } = await getProviders(this.client);
|
|
112
|
+
this.assertOpen();
|
|
101
113
|
const providerInfo = providers.find((d) => d.key === provider);
|
|
102
114
|
if (!providerInfo?.wsUrl) {
|
|
103
115
|
throw new Error(`No WebSocket URL found for provider: ${provider}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PerpsWsClient.js","sourceRoot":"","sources":["../../../src/websocket/PerpsWsClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAqB,MAAM,mBAAmB,CAAA;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAA;AAG1D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAmDhD;;;;;GAKG;AACH,MAAM,OAAO,aAAa;IACP,MAAM,CAAgB;IACtB,OAAO,CAAsB;IACtC,SAAS,GAAG,IAAI,GAAG,EAAsB,CAAA;IACzC,YAAY,GAAG,IAAI,GAAG,EAA+B,CAAA;
|
|
1
|
+
{"version":3,"file":"PerpsWsClient.js","sourceRoot":"","sources":["../../../src/websocket/PerpsWsClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,17 +12,18 @@ export declare const QUOTE_THROTTLE_MS = 100;
|
|
|
12
12
|
/**
|
|
13
13
|
* Shared provider-side `subscribeQuote` implementation: resolve
|
|
14
14
|
* `params.symbol` to a market on `provider` (via {@link resolveQuoteMarket}),
|
|
15
|
-
* subscribe to that market's orderbook
|
|
16
|
-
* update rebuild the {@link Quote}
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
15
|
+
* subscribe to that market's orderbook and marketContext channels on `ws`,
|
|
16
|
+
* and on each book update rebuild the {@link Quote} against the latest
|
|
17
|
+
* {@link MarketContext} with the provider's public base `feeTier` — the same
|
|
18
|
+
* transform the one-shot `resolveQuote` applies to a REST snapshot. Emissions
|
|
19
|
+
* are throttled to {@link QUOTE_THROTTLE_MS}: the first book update emits
|
|
20
|
+
* immediately, then at most one (trailing, latest-book) emission per
|
|
20
21
|
* interval. Both venue WS plugins delegate here; each only supplies its own
|
|
21
22
|
* base tier.
|
|
22
23
|
*
|
|
23
|
-
* The returned unsubscribe is idempotent — it releases
|
|
24
|
-
*
|
|
25
|
-
*
|
|
24
|
+
* The returned unsubscribe is idempotent — it releases both underlying
|
|
25
|
+
* listeners once and cancels any pending trailing emission, so the wire
|
|
26
|
+
* subscriptions' ref counts cannot be double-decremented.
|
|
26
27
|
*
|
|
27
28
|
* @throws {PerpsError} `MarketNotFound` when no market matches symbol+type.
|
|
28
29
|
* @internal
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveSubscribeQuote.d.ts","sourceRoot":"","sources":["../../../src/services/resolveSubscribeQuote.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"resolveSubscribeQuote.d.ts","sourceRoot":"","sources":["../../../src/services/resolveSubscribeQuote.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAGR,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EACV,cAAc,EACd,sBAAsB,EACtB,aAAa,EACd,MAAM,sBAAsB,CAAA;AAE7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAGvD;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,MAAM,CAAA;AAEpC;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,EACjC,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,IAAI,CAAC,CAuFrB"}
|
package/dist/types/version.d.ts
CHANGED
|
@@ -54,6 +54,7 @@ export declare class PerpsWsClient {
|
|
|
54
54
|
private readonly options;
|
|
55
55
|
private providers;
|
|
56
56
|
private initPromises;
|
|
57
|
+
private closed;
|
|
57
58
|
constructor(client: PerpsSDKClient, options?: PerpsWsClientOptions);
|
|
58
59
|
/**
|
|
59
60
|
* Subscribe to a realtime channel, lazily creating the provider's WS
|
|
@@ -83,6 +84,9 @@ export declare class PerpsWsClient {
|
|
|
83
84
|
subscribeQuote(params: GetQuoteParams, onQuote: QuoteListener): Promise<() => void>;
|
|
84
85
|
/**
|
|
85
86
|
* Close every open provider WS connection and drop all cached providers.
|
|
87
|
+
* Terminal: after `close()` the client is dead — `subscribe` and
|
|
88
|
+
* `subscribeQuote` reject, and any provider init still suspended mid-flight
|
|
89
|
+
* aborts without opening a socket. Create a new instance to subscribe again.
|
|
86
90
|
*
|
|
87
91
|
* @public
|
|
88
92
|
*/
|
|
@@ -94,6 +98,7 @@ export declare class PerpsWsClient {
|
|
|
94
98
|
* @public
|
|
95
99
|
*/
|
|
96
100
|
reconnect(provider: string): void;
|
|
101
|
+
private assertOpen;
|
|
97
102
|
private getOrCreateProvider;
|
|
98
103
|
private initProvider;
|
|
99
104
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PerpsWsClient.d.ts","sourceRoot":"","sources":["../../../src/websocket/PerpsWsClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEzE,OAAO,KAAK,EACV,oBAAoB,EAEpB,UAAU,EACV,gBAAgB,EACjB,MAAM,YAAY,CAAA;AAEnB;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE;IACvC,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAA;IAChB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB;;;;OAIG;IACH,MAAM,EAAE,cAAc,CAAA;CACvB,KAAK,UAAU,CAAA;AAEhB;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;CAChD;AAED;;;;;GAKG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,YAAY,CAAyC;
|
|
1
|
+
{"version":3,"file":"PerpsWsClient.d.ts","sourceRoot":"","sources":["../../../src/websocket/PerpsWsClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEzE,OAAO,KAAK,EACV,oBAAoB,EAEpB,UAAU,EACV,gBAAgB,EACjB,MAAM,YAAY,CAAA;AAEnB;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE;IACvC,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAA;IAChB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB;;;;OAIG;IACH,MAAM,EAAE,cAAc,CAAA;CACvB,KAAK,UAAU,CAAA;AAEhB;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;CAChD;AAED;;;;;GAKG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,YAAY,CAAyC;IAC7D,OAAO,CAAC,MAAM,CAAQ;gBAEV,MAAM,EAAE,cAAc,EAAE,OAAO,GAAE,oBAAyB;IAKtE;;;;;;;;;;;;OAYG;IACG,SAAS,CAAC,CAAC,SAAS,YAAY,EACpC,GAAG,EAAE,CAAC,EACN,QAAQ,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,KAAK,IAAI,EAClD,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,OAAO,CAAC,MAAM,IAAI,CAAC;IAOtB;;;;;;;;;;OAUG;IACG,cAAc,CAClB,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,IAAI,CAAC;IAatB;;;;;;;OAOG;IACH,KAAK;IASL;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIjC,OAAO,CAAC,UAAU;YASJ,mBAAmB;YAqBnB,YAAY;CAsC3B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lifi/perps-sdk",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.4",
|
|
4
4
|
"description": "LI.FI Perps SDK for perpetuals trading",
|
|
5
5
|
"homepage": "https://github.com/lifinance/perps-sdk",
|
|
6
6
|
"bugs": {
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@lifi/types": "17.82.1",
|
|
45
45
|
"partysocket": "^1.1.19",
|
|
46
46
|
"viem": "^2.48.8",
|
|
47
|
-
"@lifi/perps-types": "^1.
|
|
47
|
+
"@lifi/perps-types": "^1.6.0"
|
|
48
48
|
},
|
|
49
49
|
"publishConfig": {
|
|
50
50
|
"access": "public"
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
FeeTier,
|
|
3
|
+
MarketContext,
|
|
4
|
+
OrderbookResponse,
|
|
5
|
+
} from '@lifi/perps-types'
|
|
2
6
|
import type {
|
|
3
7
|
PerpsSDKClient,
|
|
4
8
|
ProviderGetQuoteParams,
|
|
@@ -20,17 +24,18 @@ export const QUOTE_THROTTLE_MS = 100
|
|
|
20
24
|
/**
|
|
21
25
|
* Shared provider-side `subscribeQuote` implementation: resolve
|
|
22
26
|
* `params.symbol` to a market on `provider` (via {@link resolveQuoteMarket}),
|
|
23
|
-
* subscribe to that market's orderbook
|
|
24
|
-
* update rebuild the {@link Quote}
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
27
|
+
* subscribe to that market's orderbook and marketContext channels on `ws`,
|
|
28
|
+
* and on each book update rebuild the {@link Quote} against the latest
|
|
29
|
+
* {@link MarketContext} with the provider's public base `feeTier` — the same
|
|
30
|
+
* transform the one-shot `resolveQuote` applies to a REST snapshot. Emissions
|
|
31
|
+
* are throttled to {@link QUOTE_THROTTLE_MS}: the first book update emits
|
|
32
|
+
* immediately, then at most one (trailing, latest-book) emission per
|
|
28
33
|
* interval. Both venue WS plugins delegate here; each only supplies its own
|
|
29
34
|
* base tier.
|
|
30
35
|
*
|
|
31
|
-
* The returned unsubscribe is idempotent — it releases
|
|
32
|
-
*
|
|
33
|
-
*
|
|
36
|
+
* The returned unsubscribe is idempotent — it releases both underlying
|
|
37
|
+
* listeners once and cancels any pending trailing emission, so the wire
|
|
38
|
+
* subscriptions' ref counts cannot be double-decremented.
|
|
34
39
|
*
|
|
35
40
|
* @throws {PerpsError} `MarketNotFound` when no market matches symbol+type.
|
|
36
41
|
* @internal
|
|
@@ -44,7 +49,13 @@ export async function resolveSubscribeQuote(
|
|
|
44
49
|
onQuote: QuoteListener
|
|
45
50
|
): Promise<() => void> {
|
|
46
51
|
const market = await resolveQuoteMarket(client, provider, params)
|
|
47
|
-
|
|
52
|
+
// REST snapshot seeds the context; the marketContext subscription below
|
|
53
|
+
// keeps it live so streamed impact/funding track the moving market.
|
|
54
|
+
let latestContext: MarketContext = await resolveQuotePrice(
|
|
55
|
+
client,
|
|
56
|
+
provider,
|
|
57
|
+
market.id
|
|
58
|
+
)
|
|
48
59
|
|
|
49
60
|
let latestBook: OrderbookResponse | undefined
|
|
50
61
|
let lastEmitAt = Number.NEGATIVE_INFINITY
|
|
@@ -63,7 +74,7 @@ export async function resolveSubscribeQuote(
|
|
|
63
74
|
side: params.side,
|
|
64
75
|
sizeUsd: params.size,
|
|
65
76
|
market,
|
|
66
|
-
price,
|
|
77
|
+
price: latestContext,
|
|
67
78
|
bids: latestBook.bids,
|
|
68
79
|
asks: latestBook.asks,
|
|
69
80
|
feeTier,
|
|
@@ -72,28 +83,44 @@ export async function resolveSubscribeQuote(
|
|
|
72
83
|
)
|
|
73
84
|
}
|
|
74
85
|
|
|
75
|
-
const
|
|
76
|
-
{ channel: '
|
|
86
|
+
const unsubscribeContext = await ws.subscribe(
|
|
87
|
+
{ channel: 'marketContext', dex: provider, marketId: market.id },
|
|
77
88
|
(event) => {
|
|
78
|
-
if (event.channel !== '
|
|
79
|
-
return
|
|
80
|
-
}
|
|
81
|
-
latestBook = event.data
|
|
82
|
-
if (trailing !== undefined) {
|
|
89
|
+
if (event.channel !== 'marketContext') {
|
|
83
90
|
return
|
|
84
91
|
}
|
|
85
|
-
|
|
86
|
-
if (wait <= 0) {
|
|
87
|
-
emit()
|
|
88
|
-
} else {
|
|
89
|
-
trailing = setTimeout(() => {
|
|
90
|
-
trailing = undefined
|
|
91
|
-
emit()
|
|
92
|
-
}, wait)
|
|
93
|
-
}
|
|
92
|
+
latestContext = event.data
|
|
94
93
|
}
|
|
95
94
|
)
|
|
96
95
|
|
|
96
|
+
let unsubscribeBook: () => void
|
|
97
|
+
try {
|
|
98
|
+
unsubscribeBook = await ws.subscribe(
|
|
99
|
+
{ channel: 'orderbook', dex: provider, marketId: market.id },
|
|
100
|
+
(event) => {
|
|
101
|
+
if (event.channel !== 'orderbook') {
|
|
102
|
+
return
|
|
103
|
+
}
|
|
104
|
+
latestBook = event.data
|
|
105
|
+
if (trailing !== undefined) {
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
const wait = QUOTE_THROTTLE_MS - (Date.now() - lastEmitAt)
|
|
109
|
+
if (wait <= 0) {
|
|
110
|
+
emit()
|
|
111
|
+
} else {
|
|
112
|
+
trailing = setTimeout(() => {
|
|
113
|
+
trailing = undefined
|
|
114
|
+
emit()
|
|
115
|
+
}, wait)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
)
|
|
119
|
+
} catch (error) {
|
|
120
|
+
unsubscribeContext()
|
|
121
|
+
throw error
|
|
122
|
+
}
|
|
123
|
+
|
|
97
124
|
let released = false
|
|
98
125
|
return () => {
|
|
99
126
|
if (released) {
|
|
@@ -104,6 +131,7 @@ export async function resolveSubscribeQuote(
|
|
|
104
131
|
clearTimeout(trailing)
|
|
105
132
|
trailing = undefined
|
|
106
133
|
}
|
|
107
|
-
|
|
134
|
+
unsubscribeContext()
|
|
135
|
+
unsubscribeBook()
|
|
108
136
|
}
|
|
109
137
|
}
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export const name = '@lifi/perps-sdk'
|
|
2
|
-
export const version = '1.5.
|
|
2
|
+
export const version = '1.5.4'
|
|
@@ -65,6 +65,7 @@ export class PerpsWsClient {
|
|
|
65
65
|
private readonly options: PerpsWsClientOptions
|
|
66
66
|
private providers = new Map<string, WsProvider>()
|
|
67
67
|
private initPromises = new Map<string, Promise<WsProvider>>()
|
|
68
|
+
private closed = false
|
|
68
69
|
|
|
69
70
|
constructor(client: PerpsSDKClient, options: PerpsWsClientOptions = {}) {
|
|
70
71
|
this.client = client
|
|
@@ -124,10 +125,14 @@ export class PerpsWsClient {
|
|
|
124
125
|
|
|
125
126
|
/**
|
|
126
127
|
* Close every open provider WS connection and drop all cached providers.
|
|
128
|
+
* Terminal: after `close()` the client is dead — `subscribe` and
|
|
129
|
+
* `subscribeQuote` reject, and any provider init still suspended mid-flight
|
|
130
|
+
* aborts without opening a socket. Create a new instance to subscribe again.
|
|
127
131
|
*
|
|
128
132
|
* @public
|
|
129
133
|
*/
|
|
130
134
|
close() {
|
|
135
|
+
this.closed = true
|
|
131
136
|
for (const p of this.providers.values()) {
|
|
132
137
|
p.close()
|
|
133
138
|
}
|
|
@@ -145,7 +150,18 @@ export class PerpsWsClient {
|
|
|
145
150
|
this.providers.get(provider)?.reconnect()
|
|
146
151
|
}
|
|
147
152
|
|
|
153
|
+
private assertOpen(): void {
|
|
154
|
+
if (this.closed) {
|
|
155
|
+
throw new PerpsError(
|
|
156
|
+
PerpsErrorCode.SDKError,
|
|
157
|
+
'PerpsWsClient is closed. Create a new instance to subscribe again.'
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
148
162
|
private async getOrCreateProvider(provider: string): Promise<WsProvider> {
|
|
163
|
+
this.assertOpen()
|
|
164
|
+
|
|
149
165
|
const existing = this.providers.get(provider)
|
|
150
166
|
if (existing) {
|
|
151
167
|
return existing
|
|
@@ -175,6 +191,7 @@ export class PerpsWsClient {
|
|
|
175
191
|
}
|
|
176
192
|
|
|
177
193
|
const { providers } = await getProviders(this.client)
|
|
194
|
+
this.assertOpen()
|
|
178
195
|
|
|
179
196
|
const providerInfo = providers.find((d) => d.key === provider)
|
|
180
197
|
if (!providerInfo?.wsUrl) {
|