@nktkas/hyperliquid 0.25.0-beta.3 → 0.25.0-beta.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/README.md +108 -116
- package/esm/bin/_utils.d.ts +80 -0
- package/esm/bin/_utils.d.ts.map +1 -0
- package/esm/bin/_utils.js +112 -0
- package/esm/bin/_utils.js.map +1 -0
- package/esm/bin/cli.js +43 -161
- package/esm/bin/cli.js.map +1 -1
- package/esm/src/clients/exchange.d.ts +93 -93
- package/esm/src/clients/exchange.d.ts.map +1 -1
- package/esm/src/clients/exchange.js +63 -58
- package/esm/src/clients/exchange.js.map +1 -1
- package/esm/src/clients/info.d.ts +113 -113
- package/esm/src/clients/info.d.ts.map +1 -1
- package/esm/src/clients/info.js +70 -73
- package/esm/src/clients/info.js.map +1 -1
- package/esm/src/clients/multiSign.d.ts +3 -3
- package/esm/src/clients/multiSign.d.ts.map +1 -1
- package/esm/src/clients/multiSign.js +4 -2
- package/esm/src/clients/multiSign.js.map +1 -1
- package/esm/src/clients/subscription.d.ts +23 -23
- package/esm/src/clients/subscription.d.ts.map +1 -1
- package/esm/src/clients/subscription.js +8 -11
- package/esm/src/clients/subscription.js.map +1 -1
- package/esm/src/schemas/_base.d.ts +6 -8
- package/esm/src/schemas/_base.d.ts.map +1 -1
- package/esm/src/schemas/_base.js +5 -28
- package/esm/src/schemas/_base.js.map +1 -1
- package/esm/src/schemas/exchange/requests.d.ts +1676 -1657
- package/esm/src/schemas/exchange/requests.d.ts.map +1 -1
- package/esm/src/schemas/exchange/requests.js +195 -199
- package/esm/src/schemas/exchange/requests.js.map +1 -1
- package/esm/src/schemas/exchange/responses.d.ts +10 -10
- package/esm/src/schemas/exchange/responses.js +3 -3
- package/esm/src/schemas/exchange/responses.js.map +1 -1
- package/esm/src/schemas/explorer/requests.d.ts +2 -2
- package/esm/src/schemas/explorer/requests.js +3 -3
- package/esm/src/schemas/explorer/requests.js.map +1 -1
- package/esm/src/schemas/explorer/responses.d.ts +16 -16
- package/esm/src/schemas/explorer/responses.js +3 -3
- package/esm/src/schemas/explorer/responses.js.map +1 -1
- package/esm/src/schemas/info/accounts.d.ts +298 -298
- package/esm/src/schemas/info/accounts.js +24 -24
- package/esm/src/schemas/info/accounts.js.map +1 -1
- package/esm/src/schemas/info/assets.d.ts +110 -110
- package/esm/src/schemas/info/assets.js +9 -9
- package/esm/src/schemas/info/assets.js.map +1 -1
- package/esm/src/schemas/info/markets.d.ts +25 -25
- package/esm/src/schemas/info/markets.js +3 -3
- package/esm/src/schemas/info/markets.js.map +1 -1
- package/esm/src/schemas/info/orders.d.ts +104 -104
- package/esm/src/schemas/info/orders.js +3 -3
- package/esm/src/schemas/info/orders.js.map +1 -1
- package/esm/src/schemas/info/requests.d.ts +32 -32
- package/esm/src/schemas/info/requests.js +55 -55
- package/esm/src/schemas/info/requests.js.map +1 -1
- package/esm/src/schemas/info/validators.d.ts +27 -27
- package/esm/src/schemas/info/validators.js +6 -6
- package/esm/src/schemas/info/validators.js.map +1 -1
- package/esm/src/schemas/info/vaults.d.ts +46 -46
- package/esm/src/schemas/info/vaults.js +10 -10
- package/esm/src/schemas/info/vaults.js.map +1 -1
- package/esm/src/schemas/subscriptions/requests.d.ts +4 -4
- package/esm/src/schemas/subscriptions/requests.js +17 -17
- package/esm/src/schemas/subscriptions/requests.js.map +1 -1
- package/esm/src/schemas/subscriptions/responses.d.ts +401 -401
- package/esm/src/schemas/subscriptions/responses.js +14 -14
- package/esm/src/schemas/subscriptions/responses.js.map +1 -1
- package/esm/src/signing/mod.js +4 -4
- package/esm/src/signing/mod.js.map +1 -1
- package/esm/src/signing/signTypedData/private_key.js +16 -16
- package/esm/src/signing/signTypedData/private_key.js.map +1 -1
- package/esm/src/transports/_polyfills.d.ts +12 -0
- package/esm/src/transports/_polyfills.d.ts.map +1 -0
- package/esm/src/transports/_polyfills.js +40 -0
- package/esm/src/transports/_polyfills.js.map +1 -0
- package/esm/src/transports/base.d.ts +6 -6
- package/esm/src/transports/base.d.ts.map +1 -1
- package/esm/src/transports/http/http_transport.d.ts +11 -4
- package/esm/src/transports/http/http_transport.d.ts.map +1 -1
- package/esm/src/transports/http/http_transport.js +17 -6
- package/esm/src/transports/http/http_transport.js.map +1 -1
- package/esm/src/transports/websocket/_hyperliquid_event_target.d.ts +8 -7
- package/esm/src/transports/websocket/_hyperliquid_event_target.d.ts.map +1 -1
- package/esm/src/transports/websocket/_hyperliquid_event_target.js +14 -33
- package/esm/src/transports/websocket/_hyperliquid_event_target.js.map +1 -1
- package/esm/src/transports/websocket/_reconnecting_websocket.d.ts +26 -29
- package/esm/src/transports/websocket/_reconnecting_websocket.d.ts.map +1 -1
- package/esm/src/transports/websocket/_reconnecting_websocket.js +82 -76
- package/esm/src/transports/websocket/_reconnecting_websocket.js.map +1 -1
- package/esm/src/transports/websocket/_websocket_async_request.d.ts +6 -0
- package/esm/src/transports/websocket/_websocket_async_request.d.ts.map +1 -1
- package/esm/src/transports/websocket/_websocket_async_request.js +49 -41
- package/esm/src/transports/websocket/_websocket_async_request.js.map +1 -1
- package/esm/src/transports/websocket/websocket_transport.d.ts +48 -70
- package/esm/src/transports/websocket/websocket_transport.d.ts.map +1 -1
- package/esm/src/transports/websocket/websocket_transport.js +90 -103
- package/esm/src/transports/websocket/websocket_transport.js.map +1 -1
- package/package.json +3 -7
- package/script/bin/_utils.d.ts +80 -0
- package/script/bin/_utils.d.ts.map +1 -0
- package/script/bin/_utils.js +116 -0
- package/script/bin/_utils.js.map +1 -0
- package/script/bin/cli.js +43 -164
- package/script/bin/cli.js.map +1 -1
- package/script/src/clients/exchange.d.ts +93 -93
- package/script/src/clients/exchange.d.ts.map +1 -1
- package/script/src/clients/exchange.js +62 -57
- package/script/src/clients/exchange.js.map +1 -1
- package/script/src/clients/info.d.ts +113 -113
- package/script/src/clients/info.d.ts.map +1 -1
- package/script/src/clients/info.js +70 -73
- package/script/src/clients/info.js.map +1 -1
- package/script/src/clients/multiSign.d.ts +3 -3
- package/script/src/clients/multiSign.d.ts.map +1 -1
- package/script/src/clients/multiSign.js +10 -8
- package/script/src/clients/multiSign.js.map +1 -1
- package/script/src/clients/subscription.d.ts +23 -23
- package/script/src/clients/subscription.d.ts.map +1 -1
- package/script/src/clients/subscription.js +8 -11
- package/script/src/clients/subscription.js.map +1 -1
- package/script/src/schemas/_base.d.ts +6 -8
- package/script/src/schemas/_base.d.ts.map +1 -1
- package/script/src/schemas/_base.js +6 -29
- package/script/src/schemas/_base.js.map +1 -1
- package/script/src/schemas/exchange/requests.d.ts +1676 -1657
- package/script/src/schemas/exchange/requests.d.ts.map +1 -1
- package/script/src/schemas/exchange/requests.js +194 -198
- package/script/src/schemas/exchange/requests.js.map +1 -1
- package/script/src/schemas/exchange/responses.d.ts +10 -10
- package/script/src/schemas/exchange/responses.js +2 -2
- package/script/src/schemas/exchange/responses.js.map +1 -1
- package/script/src/schemas/explorer/requests.d.ts +2 -2
- package/script/src/schemas/explorer/requests.js +2 -2
- package/script/src/schemas/explorer/requests.js.map +1 -1
- package/script/src/schemas/explorer/responses.d.ts +16 -16
- package/script/src/schemas/explorer/responses.js +2 -2
- package/script/src/schemas/explorer/responses.js.map +1 -1
- package/script/src/schemas/info/accounts.d.ts +298 -298
- package/script/src/schemas/info/accounts.js +23 -23
- package/script/src/schemas/info/accounts.js.map +1 -1
- package/script/src/schemas/info/assets.d.ts +110 -110
- package/script/src/schemas/info/assets.js +8 -8
- package/script/src/schemas/info/assets.js.map +1 -1
- package/script/src/schemas/info/markets.d.ts +25 -25
- package/script/src/schemas/info/markets.js +2 -2
- package/script/src/schemas/info/markets.js.map +1 -1
- package/script/src/schemas/info/orders.d.ts +104 -104
- package/script/src/schemas/info/orders.js +2 -2
- package/script/src/schemas/info/orders.js.map +1 -1
- package/script/src/schemas/info/requests.d.ts +32 -32
- package/script/src/schemas/info/requests.js +54 -54
- package/script/src/schemas/info/requests.js.map +1 -1
- package/script/src/schemas/info/validators.d.ts +27 -27
- package/script/src/schemas/info/validators.js +5 -5
- package/script/src/schemas/info/validators.js.map +1 -1
- package/script/src/schemas/info/vaults.d.ts +46 -46
- package/script/src/schemas/info/vaults.js +9 -9
- package/script/src/schemas/info/vaults.js.map +1 -1
- package/script/src/schemas/subscriptions/requests.d.ts +4 -4
- package/script/src/schemas/subscriptions/requests.js +16 -16
- package/script/src/schemas/subscriptions/requests.js.map +1 -1
- package/script/src/schemas/subscriptions/responses.d.ts +401 -401
- package/script/src/schemas/subscriptions/responses.js +13 -13
- package/script/src/schemas/subscriptions/responses.js.map +1 -1
- package/script/src/signing/mod.js +37 -4
- package/script/src/signing/mod.js.map +1 -1
- package/script/src/signing/signTypedData/private_key.js +49 -16
- package/script/src/signing/signTypedData/private_key.js.map +1 -1
- package/script/src/transports/_polyfills.d.ts +12 -0
- package/script/src/transports/_polyfills.d.ts.map +1 -0
- package/script/src/transports/_polyfills.js +43 -0
- package/script/src/transports/_polyfills.js.map +1 -0
- package/script/src/transports/base.d.ts +6 -6
- package/script/src/transports/base.d.ts.map +1 -1
- package/script/src/transports/http/http_transport.d.ts +11 -4
- package/script/src/transports/http/http_transport.d.ts.map +1 -1
- package/script/src/transports/http/http_transport.js +17 -6
- package/script/src/transports/http/http_transport.js.map +1 -1
- package/script/src/transports/websocket/_hyperliquid_event_target.d.ts +8 -7
- package/script/src/transports/websocket/_hyperliquid_event_target.d.ts.map +1 -1
- package/script/src/transports/websocket/_hyperliquid_event_target.js +47 -33
- package/script/src/transports/websocket/_hyperliquid_event_target.js.map +1 -1
- package/script/src/transports/websocket/_reconnecting_websocket.d.ts +26 -29
- package/script/src/transports/websocket/_reconnecting_websocket.d.ts.map +1 -1
- package/script/src/transports/websocket/_reconnecting_websocket.js +82 -76
- package/script/src/transports/websocket/_reconnecting_websocket.js.map +1 -1
- package/script/src/transports/websocket/_websocket_async_request.d.ts +6 -0
- package/script/src/transports/websocket/_websocket_async_request.d.ts.map +1 -1
- package/script/src/transports/websocket/_websocket_async_request.js +52 -43
- package/script/src/transports/websocket/_websocket_async_request.js.map +1 -1
- package/script/src/transports/websocket/websocket_transport.d.ts +48 -70
- package/script/src/transports/websocket/websocket_transport.d.ts.map +1 -1
- package/script/src/transports/websocket/websocket_transport.js +92 -105
- package/script/src/transports/websocket/websocket_transport.js.map +1 -1
- package/src/bin/_utils.ts +185 -0
- package/src/bin/cli.ts +49 -171
- package/src/src/clients/exchange.ts +160 -149
- package/src/src/clients/info.ts +128 -128
- package/src/src/clients/multiSign.ts +15 -13
- package/src/src/clients/subscription.ts +32 -32
- package/src/src/schemas/_base.ts +18 -40
- package/src/src/schemas/exchange/requests.ts +202 -199
- package/src/src/schemas/exchange/responses.ts +3 -3
- package/src/src/schemas/explorer/requests.ts +3 -3
- package/src/src/schemas/explorer/responses.ts +3 -3
- package/src/src/schemas/info/accounts.ts +24 -24
- package/src/src/schemas/info/assets.ts +9 -9
- package/src/src/schemas/info/markets.ts +3 -3
- package/src/src/schemas/info/orders.ts +3 -3
- package/src/src/schemas/info/requests.ts +55 -55
- package/src/src/schemas/info/validators.ts +6 -6
- package/src/src/schemas/info/vaults.ts +10 -10
- package/src/src/schemas/subscriptions/requests.ts +17 -17
- package/src/src/schemas/subscriptions/responses.ts +14 -14
- package/src/src/signing/mod.ts +4 -4
- package/src/src/signing/signTypedData/private_key.ts +17 -17
- package/src/src/transports/_polyfills.ts +41 -0
- package/src/src/transports/base.ts +6 -6
- package/src/src/transports/http/http_transport.ts +25 -14
- package/src/src/transports/websocket/_hyperliquid_event_target.ts +24 -51
- package/src/src/transports/websocket/_reconnecting_websocket.ts +107 -119
- package/src/src/transports/websocket/_websocket_async_request.ts +57 -59
- package/src/src/transports/websocket/websocket_transport.ts +126 -167
|
@@ -1,83 +1,64 @@
|
|
|
1
|
-
import { TransportError } from "../base.js";
|
|
2
|
-
import
|
|
1
|
+
import { type IRequestTransport, type ISubscriptionTransport, type Subscription, TransportError } from "../base.js";
|
|
2
|
+
import { AbortSignal_ } from "../_polyfills.js";
|
|
3
3
|
import {
|
|
4
|
-
type MessageBufferStrategy,
|
|
5
4
|
ReconnectingWebSocket,
|
|
6
5
|
ReconnectingWebSocketError,
|
|
7
6
|
type ReconnectingWebSocketOptions,
|
|
8
7
|
} from "./_reconnecting_websocket.js";
|
|
9
8
|
import { HyperliquidEventTarget } from "./_hyperliquid_event_target.js";
|
|
10
|
-
import { WebSocketAsyncRequest } from "./_websocket_async_request.js";
|
|
9
|
+
import { WebSocketAsyncRequest, WebSocketRequestError } from "./_websocket_async_request.js";
|
|
11
10
|
|
|
12
|
-
export {
|
|
11
|
+
export { ReconnectingWebSocketError, WebSocketRequestError };
|
|
12
|
+
|
|
13
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
13
14
|
|
|
14
15
|
/** Configuration options for the WebSocket transport layer. */
|
|
15
16
|
export interface WebSocketTransportOptions {
|
|
16
17
|
/**
|
|
17
|
-
*
|
|
18
|
+
* Indicates this transport uses testnet endpoint.
|
|
19
|
+
* @defaultValue `false`
|
|
20
|
+
*/
|
|
21
|
+
isTestnet?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Custom WebSocket endpoint for API and Subscription requests.
|
|
18
24
|
* - Mainnet:
|
|
19
25
|
* - API: `wss://api.hyperliquid.xyz/ws`
|
|
20
26
|
* - Explorer: `wss://rpc.hyperliquid.xyz/ws`
|
|
21
27
|
* - Testnet:
|
|
22
28
|
* - API: `wss://api.hyperliquid-testnet.xyz/ws`
|
|
23
29
|
* - Explorer: `wss://rpc.hyperliquid-testnet.xyz/ws`
|
|
24
|
-
* @defaultValue `wss://api.hyperliquid.xyz/ws`
|
|
30
|
+
* @defaultValue `wss://api.hyperliquid.xyz/ws` for mainnet, `wss://api.hyperliquid-testnet.xyz/ws` for testnet
|
|
25
31
|
*/
|
|
26
32
|
url?: string | URL;
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Indicates this transport uses testnet endpoint.
|
|
30
|
-
* @defaultValue `false`
|
|
31
|
-
*/
|
|
32
|
-
isTestnet?: boolean;
|
|
33
|
-
|
|
34
33
|
/**
|
|
35
34
|
* Timeout for requests in ms.
|
|
36
35
|
* Set to `null` to disable.
|
|
37
36
|
* @defaultValue `10_000`
|
|
38
37
|
*/
|
|
39
38
|
timeout?: number | null;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
* @defaultValue `30_000`
|
|
47
|
-
*/
|
|
48
|
-
interval?: number | null;
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Timeout for the ping request in ms.
|
|
52
|
-
* Set to `null` to disable.
|
|
53
|
-
* @defaultValue same as {@link timeout} for requests.
|
|
54
|
-
*/
|
|
55
|
-
timeout?: number | null;
|
|
56
|
-
};
|
|
57
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Interval between sending ping messages in ms.
|
|
41
|
+
* Set to `null` to disable.
|
|
42
|
+
* @defaultValue `30_000`
|
|
43
|
+
*/
|
|
44
|
+
keepAliveInterval?: number | null;
|
|
58
45
|
/** Reconnection policy configuration for closed connections. */
|
|
59
46
|
reconnect?: ReconnectingWebSocketOptions;
|
|
60
|
-
|
|
61
47
|
/**
|
|
62
|
-
* Enable automatic
|
|
48
|
+
* Enable automatic re-subscription to Hyperliquid subscription after reconnection.
|
|
63
49
|
* @defaultValue `true`
|
|
64
50
|
*/
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
export class WebSocketRequestError extends TransportError {
|
|
70
|
-
constructor(message?: string, options?: ErrorOptions) {
|
|
71
|
-
super(message, options);
|
|
72
|
-
this.name = "WebSocketRequestError";
|
|
73
|
-
}
|
|
51
|
+
resubscribe?: boolean;
|
|
52
|
+
onRequest?: (type: string, payload: unknown) => MaybePromise<unknown | void | null | undefined>;
|
|
53
|
+
onResponse?: (response: unknown) => MaybePromise<unknown | void | null | undefined>;
|
|
54
|
+
onError?: (error: unknown) => MaybePromise<Error | void | null | undefined>;
|
|
74
55
|
}
|
|
75
56
|
|
|
76
57
|
/** WebSocket implementation of the REST and Subscription transport interfaces. */
|
|
77
|
-
export class WebSocketTransport implements IRequestTransport, ISubscriptionTransport
|
|
58
|
+
export class WebSocketTransport implements IRequestTransport, ISubscriptionTransport {
|
|
78
59
|
protected _wsRequester: WebSocketAsyncRequest;
|
|
79
60
|
protected _hlEvents: HyperliquidEventTarget;
|
|
80
|
-
protected _keepAliveTimeout: ReturnType<typeof setTimeout> |
|
|
61
|
+
protected _keepAliveTimeout: ReturnType<typeof setTimeout> | undefined;
|
|
81
62
|
protected _subscriptions: Map<
|
|
82
63
|
string, // Unique identifier based on the payload
|
|
83
64
|
{
|
|
@@ -86,37 +67,25 @@ export class WebSocketTransport implements IRequestTransport, ISubscriptionTrans
|
|
|
86
67
|
() => Promise<void> // Unsubscribe function
|
|
87
68
|
>;
|
|
88
69
|
promise: Promise<unknown>; // Subscription request promise
|
|
89
|
-
|
|
70
|
+
promiseFinished: boolean;
|
|
71
|
+
resubscribeAbortController: AbortController; // To monitor reconnection errors
|
|
90
72
|
}
|
|
91
73
|
> = new Map();
|
|
92
|
-
protected _isReconnecting = false;
|
|
93
74
|
|
|
94
75
|
/** Indicates this transport uses testnet endpoint. */
|
|
95
76
|
isTestnet: boolean;
|
|
96
|
-
|
|
97
77
|
/**
|
|
98
|
-
*
|
|
78
|
+
* Timeout for requests in ms.
|
|
99
79
|
* Set to `null` to disable.
|
|
100
80
|
*/
|
|
101
81
|
timeout: number | null;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
interval: number | null;
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Timeout for the ping request in ms.
|
|
113
|
-
* Set to `null` to disable.
|
|
114
|
-
*/
|
|
115
|
-
timeout?: number | null;
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
/** Enable automatic resubscription after reconnection. */
|
|
119
|
-
autoResubscribe: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Interval between sending ping messages in ms.
|
|
84
|
+
* Set to `null` to disable.
|
|
85
|
+
*/
|
|
86
|
+
keepAliveInterval: number | null;
|
|
87
|
+
/** Enable automatic re-subscription to Hyperliquid subscription after reconnection. */
|
|
88
|
+
resubscribe: boolean;
|
|
120
89
|
|
|
121
90
|
/** The WebSocket that is used for communication. */
|
|
122
91
|
readonly socket: ReconnectingWebSocket;
|
|
@@ -126,59 +95,110 @@ export class WebSocketTransport implements IRequestTransport, ISubscriptionTrans
|
|
|
126
95
|
* @param options - Configuration options for the WebSocket transport layer.
|
|
127
96
|
*/
|
|
128
97
|
constructor(options?: WebSocketTransportOptions) {
|
|
98
|
+
this.isTestnet = options?.isTestnet ?? false;
|
|
99
|
+
this.timeout = options?.timeout === undefined ? 10_000 : options.timeout;
|
|
100
|
+
this.keepAliveInterval = options?.keepAliveInterval ?? 30_000;
|
|
101
|
+
this.resubscribe = options?.resubscribe ?? true;
|
|
102
|
+
|
|
129
103
|
this.socket = new ReconnectingWebSocket(
|
|
130
|
-
options?.url ?? "wss://api.hyperliquid.xyz/ws",
|
|
131
|
-
undefined,
|
|
104
|
+
options?.url ?? (this.isTestnet ? "wss://api.hyperliquid-testnet.xyz/ws" : "wss://api.hyperliquid.xyz/ws"),
|
|
132
105
|
options?.reconnect,
|
|
133
106
|
);
|
|
107
|
+
|
|
134
108
|
this._hlEvents = new HyperliquidEventTarget(this.socket);
|
|
135
109
|
this._wsRequester = new WebSocketAsyncRequest(this.socket, this._hlEvents);
|
|
136
110
|
|
|
137
|
-
this.isTestnet = options?.isTestnet ?? false;
|
|
138
|
-
this.timeout = options?.timeout === undefined ? 10_000 : options.timeout;
|
|
139
|
-
this.keepAlive = {
|
|
140
|
-
interval: options?.keepAlive?.interval === undefined ? 30_000 : options.keepAlive?.interval,
|
|
141
|
-
timeout: options?.keepAlive?.timeout === undefined ? this.timeout : options.keepAlive?.timeout,
|
|
142
|
-
};
|
|
143
|
-
this.autoResubscribe = options?.autoResubscribe ?? true;
|
|
144
|
-
|
|
145
111
|
// Initialize listeners
|
|
146
112
|
this.socket.addEventListener("open", () => {
|
|
147
|
-
this.
|
|
148
|
-
this.
|
|
113
|
+
this._keepAliveRun();
|
|
114
|
+
this._resubscribeRun();
|
|
149
115
|
});
|
|
150
|
-
|
|
116
|
+
const handleClose = () => {
|
|
151
117
|
this._keepAliveStop();
|
|
152
118
|
this._resubscribeStop();
|
|
153
|
-
|
|
154
|
-
|
|
119
|
+
};
|
|
120
|
+
this.socket.addEventListener("close", handleClose);
|
|
121
|
+
this.socket.addEventListener("error", handleClose);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Keep the connection alive.
|
|
126
|
+
* Sends ping only when no other requests were sent within the keep-alive interval.
|
|
127
|
+
*/
|
|
128
|
+
protected _keepAliveRun(): void {
|
|
129
|
+
if (this.keepAliveInterval === null || this._keepAliveTimeout) return;
|
|
130
|
+
|
|
131
|
+
const tick = async () => {
|
|
132
|
+
if (
|
|
133
|
+
this.socket.readyState !== ReconnectingWebSocket.OPEN || !this._keepAliveTimeout ||
|
|
134
|
+
this.keepAliveInterval === null
|
|
135
|
+
) return;
|
|
136
|
+
|
|
137
|
+
// Check if the last request was sent more than the keep-alive interval ago
|
|
138
|
+
if (Date.now() - this._wsRequester.lastRequestTime >= this.keepAliveInterval) {
|
|
139
|
+
const timeoutSignal = this.timeout ? AbortSignal_.timeout(this.keepAliveInterval) : undefined;
|
|
140
|
+
await this._wsRequester.request("ping", timeoutSignal)
|
|
141
|
+
.catch(() => undefined); // Ignore errors
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Schedule the next ping
|
|
145
|
+
if (
|
|
146
|
+
this.socket.readyState === ReconnectingWebSocket.OPEN && this._keepAliveTimeout &&
|
|
147
|
+
this.keepAliveInterval !== null
|
|
148
|
+
) {
|
|
149
|
+
const nextDelay = this.keepAliveInterval - (Date.now() - this._wsRequester.lastRequestTime);
|
|
150
|
+
this._keepAliveTimeout = setTimeout(tick, nextDelay);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
this._keepAliveTimeout = setTimeout(tick, this.keepAliveInterval);
|
|
155
|
+
}
|
|
156
|
+
protected _keepAliveStop(): void {
|
|
157
|
+
clearTimeout(this._keepAliveTimeout);
|
|
158
|
+
this._keepAliveTimeout = undefined;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Resubscribe to all existing subscriptions if auto-resubscribe is enabled. */
|
|
162
|
+
protected _resubscribeRun(): void {
|
|
163
|
+
if (this.resubscribe) {
|
|
164
|
+
for (const [id, subscription] of this._subscriptions.entries()) {
|
|
165
|
+
if (subscription.promiseFinished) { // reconnect only previously connected subscriptions to avoid double subscriptions due to message buffering.
|
|
166
|
+
subscription.promise = this._wsRequester.request("subscribe", JSON.parse(id))
|
|
167
|
+
.catch((error) => subscription.resubscribeAbortController.abort(error))
|
|
168
|
+
.finally(() => subscription.promiseFinished = true);
|
|
169
|
+
subscription.promiseFinished = false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
protected _resubscribeStop(): void {
|
|
175
|
+
if (!this.resubscribe || this.socket.terminateSignal.aborted) {
|
|
176
|
+
for (const subscriptionInfo of this._subscriptions.values()) {
|
|
177
|
+
for (const [_, unsubscribe] of subscriptionInfo.listeners) {
|
|
178
|
+
unsubscribe(); // does not cause an error if used when the connection is closed
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
155
182
|
}
|
|
156
183
|
|
|
157
184
|
/**
|
|
158
185
|
* Sends a request to the Hyperliquid API via WebSocket.
|
|
159
|
-
*
|
|
160
|
-
* Note: Explorer requests are not supported in the Hyperliquid WebSocket API.
|
|
161
|
-
*
|
|
162
|
-
* @param endpoint - The API endpoint to send the request to (`explorer` requests are not supported).
|
|
186
|
+
* @param endpoint - The API endpoint to send the request to.
|
|
163
187
|
* @param payload - The payload to send with the request.
|
|
164
|
-
* @param signal - An
|
|
188
|
+
* @param signal - An [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) can be used to cancel the request by calling [`abort()`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort) on the corresponding [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
|
|
165
189
|
* @returns A promise that resolves with parsed JSON response body.
|
|
166
|
-
*
|
|
167
190
|
* @throws {WebSocketRequestError} - An error that occurs when a WebSocket request fails.
|
|
168
191
|
*/
|
|
169
192
|
async request<T>(type: "info" | "exchange", payload: unknown, signal?: AbortSignal): Promise<T> {
|
|
170
193
|
try {
|
|
171
|
-
const timeoutSignal = this.timeout ?
|
|
194
|
+
const timeoutSignal = this.timeout ? AbortSignal_.timeout(this.timeout) : undefined;
|
|
172
195
|
const combinedSignal = signal && timeoutSignal
|
|
173
|
-
?
|
|
196
|
+
? AbortSignal_.any([signal, timeoutSignal])
|
|
174
197
|
: signal ?? timeoutSignal;
|
|
175
198
|
|
|
176
199
|
return await this._wsRequester.request(
|
|
177
200
|
"post",
|
|
178
|
-
{
|
|
179
|
-
type: type === "exchange" ? "action" : type,
|
|
180
|
-
payload,
|
|
181
|
-
},
|
|
201
|
+
{ type: type === "exchange" ? "action" : type, payload },
|
|
182
202
|
combinedSignal,
|
|
183
203
|
);
|
|
184
204
|
} catch (error) {
|
|
@@ -193,12 +213,10 @@ export class WebSocketTransport implements IRequestTransport, ISubscriptionTrans
|
|
|
193
213
|
/**
|
|
194
214
|
* Subscribes to a Hyperliquid event channel.
|
|
195
215
|
* Sends a subscription request to the server and listens for events.
|
|
196
|
-
*
|
|
197
216
|
* @param channel - The event channel to listen to.
|
|
198
217
|
* @param payload - A payload to send with the subscription request.
|
|
199
218
|
* @param listener - A function to call when the event is dispatched.
|
|
200
219
|
* @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
|
|
201
|
-
*
|
|
202
220
|
* @throws {WebSocketRequestError} - An error that occurs when a WebSocket request fails.
|
|
203
221
|
*/
|
|
204
222
|
async subscribe<T>(
|
|
@@ -214,12 +232,14 @@ export class WebSocketTransport implements IRequestTransport, ISubscriptionTrans
|
|
|
214
232
|
let subscription = this._subscriptions.get(id);
|
|
215
233
|
if (!subscription) {
|
|
216
234
|
// Send subscription request
|
|
217
|
-
const promise = this._wsRequester.request("subscribe", payload)
|
|
235
|
+
const promise = this._wsRequester.request("subscribe", payload)
|
|
236
|
+
.finally(() => subscription!.promiseFinished = true);
|
|
218
237
|
|
|
219
238
|
// Cache subscription info
|
|
220
239
|
subscription = {
|
|
221
240
|
listeners: new Map(),
|
|
222
241
|
promise,
|
|
242
|
+
promiseFinished: false,
|
|
223
243
|
resubscribeAbortController: new AbortController(),
|
|
224
244
|
};
|
|
225
245
|
this._subscriptions.set(id, subscription);
|
|
@@ -232,7 +252,7 @@ export class WebSocketTransport implements IRequestTransport, ISubscriptionTrans
|
|
|
232
252
|
unsubscribe = async () => {
|
|
233
253
|
try {
|
|
234
254
|
// Remove listener and cleanup
|
|
235
|
-
this._hlEvents.removeEventListener(channel, listener
|
|
255
|
+
this._hlEvents.removeEventListener(channel, listener);
|
|
236
256
|
const subscription = this._subscriptions.get(id);
|
|
237
257
|
subscription?.listeners.delete(listener);
|
|
238
258
|
|
|
@@ -256,7 +276,7 @@ export class WebSocketTransport implements IRequestTransport, ISubscriptionTrans
|
|
|
256
276
|
};
|
|
257
277
|
|
|
258
278
|
// Add listener and cache unsubscribe function
|
|
259
|
-
this._hlEvents.addEventListener(channel, listener
|
|
279
|
+
this._hlEvents.addEventListener(channel, listener);
|
|
260
280
|
subscription.listeners.set(listener, unsubscribe);
|
|
261
281
|
}
|
|
262
282
|
|
|
@@ -266,7 +286,7 @@ export class WebSocketTransport implements IRequestTransport, ISubscriptionTrans
|
|
|
266
286
|
// Return subscription control object
|
|
267
287
|
return {
|
|
268
288
|
unsubscribe,
|
|
269
|
-
resubscribeSignal: subscription.resubscribeAbortController
|
|
289
|
+
resubscribeSignal: subscription.resubscribeAbortController.signal,
|
|
270
290
|
};
|
|
271
291
|
} catch (error) {
|
|
272
292
|
if (error instanceof TransportError) throw error; // Re-throw known errors
|
|
@@ -279,14 +299,14 @@ export class WebSocketTransport implements IRequestTransport, ISubscriptionTrans
|
|
|
279
299
|
|
|
280
300
|
/**
|
|
281
301
|
* Waits until the WebSocket connection is ready.
|
|
282
|
-
* @param signal - An
|
|
302
|
+
* @param signal - An [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) can be used to cancel the promise by calling [`abort()`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort) on the corresponding [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
|
|
283
303
|
* @returns A promise that resolves when the connection is ready.
|
|
284
304
|
*/
|
|
285
305
|
ready(signal?: AbortSignal): Promise<void> {
|
|
286
306
|
return new Promise((resolve, reject) => {
|
|
287
307
|
const combinedSignal = signal
|
|
288
|
-
?
|
|
289
|
-
: this.socket.
|
|
308
|
+
? AbortSignal_.any([this.socket.terminateSignal, signal])
|
|
309
|
+
: this.socket.terminateSignal;
|
|
290
310
|
|
|
291
311
|
if (combinedSignal.aborted) return reject(combinedSignal.reason);
|
|
292
312
|
if (this.socket.readyState === ReconnectingWebSocket.OPEN) return resolve();
|
|
@@ -307,7 +327,7 @@ export class WebSocketTransport implements IRequestTransport, ISubscriptionTrans
|
|
|
307
327
|
|
|
308
328
|
/**
|
|
309
329
|
* Closes the WebSocket connection and waits until it is fully closed.
|
|
310
|
-
* @param signal - An
|
|
330
|
+
* @param signal - An [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) can be used to cancel the promise by calling [`abort()`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort) on the corresponding [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
|
|
311
331
|
* @returns A promise that resolves when the connection is fully closed.
|
|
312
332
|
*/
|
|
313
333
|
close(signal?: AbortSignal): Promise<void> {
|
|
@@ -320,75 +340,14 @@ export class WebSocketTransport implements IRequestTransport, ISubscriptionTrans
|
|
|
320
340
|
resolve();
|
|
321
341
|
};
|
|
322
342
|
const handleAbort = () => {
|
|
323
|
-
this.socket.removeEventListener("close", handleClose);
|
|
324
343
|
reject(signal?.reason);
|
|
325
344
|
};
|
|
326
345
|
|
|
327
|
-
this.socket.addEventListener("close", handleClose, { once: true });
|
|
346
|
+
this.socket.addEventListener("close", handleClose, { once: true, signal });
|
|
347
|
+
this.socket.addEventListener("error", handleClose, { once: true, signal });
|
|
328
348
|
signal?.addEventListener("abort", handleAbort, { once: true });
|
|
329
349
|
|
|
330
350
|
this.socket.close();
|
|
331
351
|
});
|
|
332
352
|
}
|
|
333
|
-
|
|
334
|
-
/** Keep the connection alive. Sends ping only when necessary. */
|
|
335
|
-
protected _keepAliveStart(): void {
|
|
336
|
-
if (this.keepAlive.interval === null || this._keepAliveTimeout) return;
|
|
337
|
-
|
|
338
|
-
const tick = async () => {
|
|
339
|
-
if (
|
|
340
|
-
this.socket.readyState !== ReconnectingWebSocket.OPEN || !this._keepAliveTimeout ||
|
|
341
|
-
this.keepAlive.interval === null
|
|
342
|
-
) return;
|
|
343
|
-
|
|
344
|
-
// Check if the last request was sent more than the keep-alive interval ago
|
|
345
|
-
if (Date.now() - this._wsRequester.lastRequestTime >= this.keepAlive.interval) {
|
|
346
|
-
const timeoutSignal = this.keepAlive.timeout ? AbortSignal.timeout(this.keepAlive.timeout) : undefined;
|
|
347
|
-
await this._wsRequester.request("ping", timeoutSignal)
|
|
348
|
-
.catch(() => undefined); // Ignore errors
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// Schedule the next ping
|
|
352
|
-
if (
|
|
353
|
-
this.socket.readyState === ReconnectingWebSocket.OPEN && this._keepAliveTimeout &&
|
|
354
|
-
this.keepAlive.interval !== null
|
|
355
|
-
) {
|
|
356
|
-
const nextDelay = this.keepAlive.interval - (Date.now() - this._wsRequester.lastRequestTime);
|
|
357
|
-
this._keepAliveTimeout = setTimeout(tick, nextDelay);
|
|
358
|
-
}
|
|
359
|
-
};
|
|
360
|
-
|
|
361
|
-
this._keepAliveTimeout = setTimeout(tick, this.keepAlive.interval);
|
|
362
|
-
}
|
|
363
|
-
protected _keepAliveStop(): void {
|
|
364
|
-
if (this._keepAliveTimeout !== null) {
|
|
365
|
-
clearTimeout(this._keepAliveTimeout);
|
|
366
|
-
this._keepAliveTimeout = null;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
/** Resubscribe to all existing subscriptions if auto-resubscribe is enabled. */
|
|
371
|
-
protected _resubscribeStart(): void {
|
|
372
|
-
if (this.autoResubscribe && this._isReconnecting) {
|
|
373
|
-
for (const [id, subscriptionInfo] of this._subscriptions.entries()) {
|
|
374
|
-
subscriptionInfo.promise = this._wsRequester.request("subscribe", JSON.parse(id))
|
|
375
|
-
.catch((error) => {
|
|
376
|
-
subscriptionInfo.resubscribeAbortController?.abort(error);
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
protected _resubscribeStop(): void {
|
|
382
|
-
if (!this.autoResubscribe || this.socket.reconnectAbortController.signal.aborted) {
|
|
383
|
-
for (const subscriptionInfo of this._subscriptions.values()) {
|
|
384
|
-
for (const [_, unsubscribe] of subscriptionInfo.listeners) {
|
|
385
|
-
unsubscribe(); // does not cause an error if used when the connection is closed
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
async [Symbol.asyncDispose](): Promise<void> {
|
|
392
|
-
await this.close();
|
|
393
|
-
}
|
|
394
353
|
}
|