@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.
Files changed (223) hide show
  1. package/README.md +108 -116
  2. package/esm/bin/_utils.d.ts +80 -0
  3. package/esm/bin/_utils.d.ts.map +1 -0
  4. package/esm/bin/_utils.js +112 -0
  5. package/esm/bin/_utils.js.map +1 -0
  6. package/esm/bin/cli.js +43 -161
  7. package/esm/bin/cli.js.map +1 -1
  8. package/esm/src/clients/exchange.d.ts +93 -93
  9. package/esm/src/clients/exchange.d.ts.map +1 -1
  10. package/esm/src/clients/exchange.js +63 -58
  11. package/esm/src/clients/exchange.js.map +1 -1
  12. package/esm/src/clients/info.d.ts +113 -113
  13. package/esm/src/clients/info.d.ts.map +1 -1
  14. package/esm/src/clients/info.js +70 -73
  15. package/esm/src/clients/info.js.map +1 -1
  16. package/esm/src/clients/multiSign.d.ts +3 -3
  17. package/esm/src/clients/multiSign.d.ts.map +1 -1
  18. package/esm/src/clients/multiSign.js +4 -2
  19. package/esm/src/clients/multiSign.js.map +1 -1
  20. package/esm/src/clients/subscription.d.ts +23 -23
  21. package/esm/src/clients/subscription.d.ts.map +1 -1
  22. package/esm/src/clients/subscription.js +8 -11
  23. package/esm/src/clients/subscription.js.map +1 -1
  24. package/esm/src/schemas/_base.d.ts +6 -8
  25. package/esm/src/schemas/_base.d.ts.map +1 -1
  26. package/esm/src/schemas/_base.js +5 -28
  27. package/esm/src/schemas/_base.js.map +1 -1
  28. package/esm/src/schemas/exchange/requests.d.ts +1676 -1657
  29. package/esm/src/schemas/exchange/requests.d.ts.map +1 -1
  30. package/esm/src/schemas/exchange/requests.js +195 -199
  31. package/esm/src/schemas/exchange/requests.js.map +1 -1
  32. package/esm/src/schemas/exchange/responses.d.ts +10 -10
  33. package/esm/src/schemas/exchange/responses.js +3 -3
  34. package/esm/src/schemas/exchange/responses.js.map +1 -1
  35. package/esm/src/schemas/explorer/requests.d.ts +2 -2
  36. package/esm/src/schemas/explorer/requests.js +3 -3
  37. package/esm/src/schemas/explorer/requests.js.map +1 -1
  38. package/esm/src/schemas/explorer/responses.d.ts +16 -16
  39. package/esm/src/schemas/explorer/responses.js +3 -3
  40. package/esm/src/schemas/explorer/responses.js.map +1 -1
  41. package/esm/src/schemas/info/accounts.d.ts +298 -298
  42. package/esm/src/schemas/info/accounts.js +24 -24
  43. package/esm/src/schemas/info/accounts.js.map +1 -1
  44. package/esm/src/schemas/info/assets.d.ts +110 -110
  45. package/esm/src/schemas/info/assets.js +9 -9
  46. package/esm/src/schemas/info/assets.js.map +1 -1
  47. package/esm/src/schemas/info/markets.d.ts +25 -25
  48. package/esm/src/schemas/info/markets.js +3 -3
  49. package/esm/src/schemas/info/markets.js.map +1 -1
  50. package/esm/src/schemas/info/orders.d.ts +104 -104
  51. package/esm/src/schemas/info/orders.js +3 -3
  52. package/esm/src/schemas/info/orders.js.map +1 -1
  53. package/esm/src/schemas/info/requests.d.ts +32 -32
  54. package/esm/src/schemas/info/requests.js +55 -55
  55. package/esm/src/schemas/info/requests.js.map +1 -1
  56. package/esm/src/schemas/info/validators.d.ts +27 -27
  57. package/esm/src/schemas/info/validators.js +6 -6
  58. package/esm/src/schemas/info/validators.js.map +1 -1
  59. package/esm/src/schemas/info/vaults.d.ts +46 -46
  60. package/esm/src/schemas/info/vaults.js +10 -10
  61. package/esm/src/schemas/info/vaults.js.map +1 -1
  62. package/esm/src/schemas/subscriptions/requests.d.ts +4 -4
  63. package/esm/src/schemas/subscriptions/requests.js +17 -17
  64. package/esm/src/schemas/subscriptions/requests.js.map +1 -1
  65. package/esm/src/schemas/subscriptions/responses.d.ts +401 -401
  66. package/esm/src/schemas/subscriptions/responses.js +14 -14
  67. package/esm/src/schemas/subscriptions/responses.js.map +1 -1
  68. package/esm/src/signing/mod.js +4 -4
  69. package/esm/src/signing/mod.js.map +1 -1
  70. package/esm/src/signing/signTypedData/private_key.js +16 -16
  71. package/esm/src/signing/signTypedData/private_key.js.map +1 -1
  72. package/esm/src/transports/_polyfills.d.ts +12 -0
  73. package/esm/src/transports/_polyfills.d.ts.map +1 -0
  74. package/esm/src/transports/_polyfills.js +40 -0
  75. package/esm/src/transports/_polyfills.js.map +1 -0
  76. package/esm/src/transports/base.d.ts +6 -6
  77. package/esm/src/transports/base.d.ts.map +1 -1
  78. package/esm/src/transports/http/http_transport.d.ts +11 -4
  79. package/esm/src/transports/http/http_transport.d.ts.map +1 -1
  80. package/esm/src/transports/http/http_transport.js +17 -6
  81. package/esm/src/transports/http/http_transport.js.map +1 -1
  82. package/esm/src/transports/websocket/_hyperliquid_event_target.d.ts +8 -7
  83. package/esm/src/transports/websocket/_hyperliquid_event_target.d.ts.map +1 -1
  84. package/esm/src/transports/websocket/_hyperliquid_event_target.js +14 -33
  85. package/esm/src/transports/websocket/_hyperliquid_event_target.js.map +1 -1
  86. package/esm/src/transports/websocket/_reconnecting_websocket.d.ts +26 -29
  87. package/esm/src/transports/websocket/_reconnecting_websocket.d.ts.map +1 -1
  88. package/esm/src/transports/websocket/_reconnecting_websocket.js +82 -76
  89. package/esm/src/transports/websocket/_reconnecting_websocket.js.map +1 -1
  90. package/esm/src/transports/websocket/_websocket_async_request.d.ts +6 -0
  91. package/esm/src/transports/websocket/_websocket_async_request.d.ts.map +1 -1
  92. package/esm/src/transports/websocket/_websocket_async_request.js +49 -41
  93. package/esm/src/transports/websocket/_websocket_async_request.js.map +1 -1
  94. package/esm/src/transports/websocket/websocket_transport.d.ts +48 -70
  95. package/esm/src/transports/websocket/websocket_transport.d.ts.map +1 -1
  96. package/esm/src/transports/websocket/websocket_transport.js +90 -103
  97. package/esm/src/transports/websocket/websocket_transport.js.map +1 -1
  98. package/package.json +3 -7
  99. package/script/bin/_utils.d.ts +80 -0
  100. package/script/bin/_utils.d.ts.map +1 -0
  101. package/script/bin/_utils.js +116 -0
  102. package/script/bin/_utils.js.map +1 -0
  103. package/script/bin/cli.js +43 -164
  104. package/script/bin/cli.js.map +1 -1
  105. package/script/src/clients/exchange.d.ts +93 -93
  106. package/script/src/clients/exchange.d.ts.map +1 -1
  107. package/script/src/clients/exchange.js +62 -57
  108. package/script/src/clients/exchange.js.map +1 -1
  109. package/script/src/clients/info.d.ts +113 -113
  110. package/script/src/clients/info.d.ts.map +1 -1
  111. package/script/src/clients/info.js +70 -73
  112. package/script/src/clients/info.js.map +1 -1
  113. package/script/src/clients/multiSign.d.ts +3 -3
  114. package/script/src/clients/multiSign.d.ts.map +1 -1
  115. package/script/src/clients/multiSign.js +10 -8
  116. package/script/src/clients/multiSign.js.map +1 -1
  117. package/script/src/clients/subscription.d.ts +23 -23
  118. package/script/src/clients/subscription.d.ts.map +1 -1
  119. package/script/src/clients/subscription.js +8 -11
  120. package/script/src/clients/subscription.js.map +1 -1
  121. package/script/src/schemas/_base.d.ts +6 -8
  122. package/script/src/schemas/_base.d.ts.map +1 -1
  123. package/script/src/schemas/_base.js +6 -29
  124. package/script/src/schemas/_base.js.map +1 -1
  125. package/script/src/schemas/exchange/requests.d.ts +1676 -1657
  126. package/script/src/schemas/exchange/requests.d.ts.map +1 -1
  127. package/script/src/schemas/exchange/requests.js +194 -198
  128. package/script/src/schemas/exchange/requests.js.map +1 -1
  129. package/script/src/schemas/exchange/responses.d.ts +10 -10
  130. package/script/src/schemas/exchange/responses.js +2 -2
  131. package/script/src/schemas/exchange/responses.js.map +1 -1
  132. package/script/src/schemas/explorer/requests.d.ts +2 -2
  133. package/script/src/schemas/explorer/requests.js +2 -2
  134. package/script/src/schemas/explorer/requests.js.map +1 -1
  135. package/script/src/schemas/explorer/responses.d.ts +16 -16
  136. package/script/src/schemas/explorer/responses.js +2 -2
  137. package/script/src/schemas/explorer/responses.js.map +1 -1
  138. package/script/src/schemas/info/accounts.d.ts +298 -298
  139. package/script/src/schemas/info/accounts.js +23 -23
  140. package/script/src/schemas/info/accounts.js.map +1 -1
  141. package/script/src/schemas/info/assets.d.ts +110 -110
  142. package/script/src/schemas/info/assets.js +8 -8
  143. package/script/src/schemas/info/assets.js.map +1 -1
  144. package/script/src/schemas/info/markets.d.ts +25 -25
  145. package/script/src/schemas/info/markets.js +2 -2
  146. package/script/src/schemas/info/markets.js.map +1 -1
  147. package/script/src/schemas/info/orders.d.ts +104 -104
  148. package/script/src/schemas/info/orders.js +2 -2
  149. package/script/src/schemas/info/orders.js.map +1 -1
  150. package/script/src/schemas/info/requests.d.ts +32 -32
  151. package/script/src/schemas/info/requests.js +54 -54
  152. package/script/src/schemas/info/requests.js.map +1 -1
  153. package/script/src/schemas/info/validators.d.ts +27 -27
  154. package/script/src/schemas/info/validators.js +5 -5
  155. package/script/src/schemas/info/validators.js.map +1 -1
  156. package/script/src/schemas/info/vaults.d.ts +46 -46
  157. package/script/src/schemas/info/vaults.js +9 -9
  158. package/script/src/schemas/info/vaults.js.map +1 -1
  159. package/script/src/schemas/subscriptions/requests.d.ts +4 -4
  160. package/script/src/schemas/subscriptions/requests.js +16 -16
  161. package/script/src/schemas/subscriptions/requests.js.map +1 -1
  162. package/script/src/schemas/subscriptions/responses.d.ts +401 -401
  163. package/script/src/schemas/subscriptions/responses.js +13 -13
  164. package/script/src/schemas/subscriptions/responses.js.map +1 -1
  165. package/script/src/signing/mod.js +37 -4
  166. package/script/src/signing/mod.js.map +1 -1
  167. package/script/src/signing/signTypedData/private_key.js +49 -16
  168. package/script/src/signing/signTypedData/private_key.js.map +1 -1
  169. package/script/src/transports/_polyfills.d.ts +12 -0
  170. package/script/src/transports/_polyfills.d.ts.map +1 -0
  171. package/script/src/transports/_polyfills.js +43 -0
  172. package/script/src/transports/_polyfills.js.map +1 -0
  173. package/script/src/transports/base.d.ts +6 -6
  174. package/script/src/transports/base.d.ts.map +1 -1
  175. package/script/src/transports/http/http_transport.d.ts +11 -4
  176. package/script/src/transports/http/http_transport.d.ts.map +1 -1
  177. package/script/src/transports/http/http_transport.js +17 -6
  178. package/script/src/transports/http/http_transport.js.map +1 -1
  179. package/script/src/transports/websocket/_hyperliquid_event_target.d.ts +8 -7
  180. package/script/src/transports/websocket/_hyperliquid_event_target.d.ts.map +1 -1
  181. package/script/src/transports/websocket/_hyperliquid_event_target.js +47 -33
  182. package/script/src/transports/websocket/_hyperliquid_event_target.js.map +1 -1
  183. package/script/src/transports/websocket/_reconnecting_websocket.d.ts +26 -29
  184. package/script/src/transports/websocket/_reconnecting_websocket.d.ts.map +1 -1
  185. package/script/src/transports/websocket/_reconnecting_websocket.js +82 -76
  186. package/script/src/transports/websocket/_reconnecting_websocket.js.map +1 -1
  187. package/script/src/transports/websocket/_websocket_async_request.d.ts +6 -0
  188. package/script/src/transports/websocket/_websocket_async_request.d.ts.map +1 -1
  189. package/script/src/transports/websocket/_websocket_async_request.js +52 -43
  190. package/script/src/transports/websocket/_websocket_async_request.js.map +1 -1
  191. package/script/src/transports/websocket/websocket_transport.d.ts +48 -70
  192. package/script/src/transports/websocket/websocket_transport.d.ts.map +1 -1
  193. package/script/src/transports/websocket/websocket_transport.js +92 -105
  194. package/script/src/transports/websocket/websocket_transport.js.map +1 -1
  195. package/src/bin/_utils.ts +185 -0
  196. package/src/bin/cli.ts +49 -171
  197. package/src/src/clients/exchange.ts +160 -149
  198. package/src/src/clients/info.ts +128 -128
  199. package/src/src/clients/multiSign.ts +15 -13
  200. package/src/src/clients/subscription.ts +32 -32
  201. package/src/src/schemas/_base.ts +18 -40
  202. package/src/src/schemas/exchange/requests.ts +202 -199
  203. package/src/src/schemas/exchange/responses.ts +3 -3
  204. package/src/src/schemas/explorer/requests.ts +3 -3
  205. package/src/src/schemas/explorer/responses.ts +3 -3
  206. package/src/src/schemas/info/accounts.ts +24 -24
  207. package/src/src/schemas/info/assets.ts +9 -9
  208. package/src/src/schemas/info/markets.ts +3 -3
  209. package/src/src/schemas/info/orders.ts +3 -3
  210. package/src/src/schemas/info/requests.ts +55 -55
  211. package/src/src/schemas/info/validators.ts +6 -6
  212. package/src/src/schemas/info/vaults.ts +10 -10
  213. package/src/src/schemas/subscriptions/requests.ts +17 -17
  214. package/src/src/schemas/subscriptions/responses.ts +14 -14
  215. package/src/src/signing/mod.ts +4 -4
  216. package/src/src/signing/signTypedData/private_key.ts +17 -17
  217. package/src/src/transports/_polyfills.ts +41 -0
  218. package/src/src/transports/base.ts +6 -6
  219. package/src/src/transports/http/http_transport.ts +25 -14
  220. package/src/src/transports/websocket/_hyperliquid_event_target.ts +24 -51
  221. package/src/src/transports/websocket/_reconnecting_websocket.ts +107 -119
  222. package/src/src/transports/websocket/_websocket_async_request.ts +57 -59
  223. package/src/src/transports/websocket/websocket_transport.ts +126 -167
@@ -1,83 +1,64 @@
1
- import { TransportError } from "../base.js";
2
- import type { IRequestTransport, ISubscriptionTransport, Subscription } from "../base.js";
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 { type MessageBufferStrategy, ReconnectingWebSocketError, type ReconnectingWebSocketOptions };
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
- * The WebSocket URL.
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
- /** Keep-alive configuration. */
42
- keepAlive?: {
43
- /**
44
- * Interval between sending ping messages in ms.
45
- * Set to `null` to disable.
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 event resubscription after reconnection.
48
+ * Enable automatic re-subscription to Hyperliquid subscription after reconnection.
63
49
  * @defaultValue `true`
64
50
  */
65
- autoResubscribe?: boolean;
66
- }
67
-
68
- /** Error thrown when a WebSocket request fails. */
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, AsyncDisposable {
58
+ export class WebSocketTransport implements IRequestTransport, ISubscriptionTransport {
78
59
  protected _wsRequester: WebSocketAsyncRequest;
79
60
  protected _hlEvents: HyperliquidEventTarget;
80
- protected _keepAliveTimeout: ReturnType<typeof setTimeout> | null = null;
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
- resubscribeAbortController?: AbortController; // To monitor reconnection errors
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
- * Request timeout in ms.
78
+ * Timeout for requests in ms.
99
79
  * Set to `null` to disable.
100
80
  */
101
81
  timeout: number | null;
102
-
103
- /** Keep-alive configuration. */
104
- keepAlive: {
105
- /**
106
- * Interval between sending ping messages in ms.
107
- * Set to `null` to disable.
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._keepAliveStart();
148
- this._resubscribeStart();
113
+ this._keepAliveRun();
114
+ this._resubscribeRun();
149
115
  });
150
- this.socket.addEventListener("close", () => {
116
+ const handleClose = () => {
151
117
  this._keepAliveStop();
152
118
  this._resubscribeStop();
153
- this._isReconnecting = true;
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 {@linkcode https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal | AbortSignal}. If this option is set, the request can be canceled by calling {@linkcode https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort | abort()} on the corresponding {@linkcode https://developer.mozilla.org/en-US/docs/Web/API/AbortController | AbortController}.
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 ? AbortSignal.timeout(this.timeout) : undefined;
194
+ const timeoutSignal = this.timeout ? AbortSignal_.timeout(this.timeout) : undefined;
172
195
  const combinedSignal = signal && timeoutSignal
173
- ? AbortSignal.any([signal, timeoutSignal])
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 as EventListener);
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 as EventListener);
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?.signal,
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 {@linkcode https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal | AbortSignal}. If this option is set, the promise can be canceled by calling {@linkcode https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort | abort()} on the corresponding {@linkcode https://developer.mozilla.org/en-US/docs/Web/API/AbortController | AbortController}.
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
- ? AbortSignal.any([this.socket.reconnectAbortController.signal, signal])
289
- : this.socket.reconnectAbortController.signal;
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 {@linkcode https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal | AbortSignal}. If this option is set, the promise can be canceled by calling {@linkcode https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort | abort()} on the corresponding {@linkcode https://developer.mozilla.org/en-US/docs/Web/API/AbortController | AbortController}.
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
  }