@nktkas/hyperliquid 0.19.1 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/CONTRIBUTING.md +4 -2
  2. package/README.md +36 -35
  3. package/esm/_dnt.polyfills.d.ts +20 -0
  4. package/esm/_dnt.polyfills.d.ts.map +1 -0
  5. package/esm/_dnt.polyfills.js +12 -0
  6. package/esm/mod.d.ts +3 -0
  7. package/esm/mod.d.ts.map +1 -1
  8. package/esm/mod.js +2 -0
  9. package/esm/src/base.d.ts +1 -47
  10. package/esm/src/base.d.ts.map +1 -1
  11. package/esm/src/base.js +1 -8
  12. package/esm/src/clients/event.d.ts +6 -4
  13. package/esm/src/clients/event.d.ts.map +1 -1
  14. package/esm/src/clients/event.js +58 -77
  15. package/esm/src/clients/public.d.ts +26 -5
  16. package/esm/src/clients/public.d.ts.map +1 -1
  17. package/esm/src/clients/public.js +29 -41
  18. package/esm/src/clients/wallet.d.ts +200 -26
  19. package/esm/src/clients/wallet.d.ts.map +1 -1
  20. package/esm/src/clients/wallet.js +306 -284
  21. package/esm/src/signing.d.ts +80 -5
  22. package/esm/src/signing.d.ts.map +1 -1
  23. package/esm/src/signing.js +96 -7
  24. package/esm/src/transports/base.d.ts +49 -0
  25. package/esm/src/transports/base.d.ts.map +1 -0
  26. package/esm/src/transports/base.js +8 -0
  27. package/esm/src/transports/http/http_transport.d.ts +8 -5
  28. package/esm/src/transports/http/http_transport.d.ts.map +1 -1
  29. package/esm/src/transports/http/http_transport.js +15 -62
  30. package/esm/src/transports/websocket/_hyperliquid_event_target.d.ts +36 -39
  31. package/esm/src/transports/websocket/_hyperliquid_event_target.d.ts.map +1 -1
  32. package/esm/src/transports/websocket/_reconnecting_websocket.d.ts +18 -25
  33. package/esm/src/transports/websocket/_reconnecting_websocket.d.ts.map +1 -1
  34. package/esm/src/transports/websocket/_reconnecting_websocket.js +80 -179
  35. package/{script/src/transports/websocket/_websocket_request_dispatcher.d.ts → esm/src/transports/websocket/_websocket_async_request.d.ts} +14 -18
  36. package/esm/src/transports/websocket/_websocket_async_request.d.ts.map +1 -0
  37. package/esm/src/transports/websocket/{_websocket_request_dispatcher.js → _websocket_async_request.js} +42 -75
  38. package/esm/src/transports/websocket/websocket_transport.d.ts +38 -28
  39. package/esm/src/transports/websocket/websocket_transport.d.ts.map +1 -1
  40. package/esm/src/transports/websocket/websocket_transport.js +61 -76
  41. package/esm/src/types/exchange/requests.d.ts +278 -66
  42. package/esm/src/types/exchange/requests.d.ts.map +1 -1
  43. package/esm/src/types/info/assets.d.ts +0 -48
  44. package/esm/src/types/info/assets.d.ts.map +1 -1
  45. package/esm/src/types/info/markets.d.ts +52 -0
  46. package/esm/src/types/info/markets.d.ts.map +1 -0
  47. package/esm/src/types/info/markets.js +1 -0
  48. package/esm/src/types/info/orders.d.ts +1 -1
  49. package/esm/src/types/info/orders.d.ts.map +1 -1
  50. package/esm/src/types/info/requests.d.ts +14 -5
  51. package/esm/src/types/info/requests.d.ts.map +1 -1
  52. package/esm/src/types/mod.d.ts +4 -0
  53. package/esm/src/types/mod.d.ts.map +1 -1
  54. package/esm/src/types/mod.js +3 -1
  55. package/esm/src/types/subscriptions/requests.d.ts +2 -0
  56. package/esm/src/types/subscriptions/requests.d.ts.map +1 -1
  57. package/package.json +12 -9
  58. package/script/_dnt.polyfills.d.ts +20 -0
  59. package/script/_dnt.polyfills.d.ts.map +1 -0
  60. package/script/_dnt.polyfills.js +23 -0
  61. package/script/mod.d.ts +3 -0
  62. package/script/mod.d.ts.map +1 -1
  63. package/script/mod.js +3 -1
  64. package/script/src/base.d.ts +1 -47
  65. package/script/src/base.d.ts.map +1 -1
  66. package/script/src/base.js +2 -10
  67. package/script/src/clients/event.d.ts +6 -4
  68. package/script/src/clients/event.d.ts.map +1 -1
  69. package/script/src/clients/event.js +58 -77
  70. package/script/src/clients/public.d.ts +26 -5
  71. package/script/src/clients/public.d.ts.map +1 -1
  72. package/script/src/clients/public.js +29 -41
  73. package/script/src/clients/wallet.d.ts +200 -26
  74. package/script/src/clients/wallet.d.ts.map +1 -1
  75. package/script/src/clients/wallet.js +305 -283
  76. package/script/src/signing.d.ts +80 -5
  77. package/script/src/signing.d.ts.map +1 -1
  78. package/script/src/signing.js +148 -58
  79. package/script/src/transports/base.d.ts +49 -0
  80. package/script/src/transports/base.d.ts.map +1 -0
  81. package/script/src/transports/base.js +22 -0
  82. package/script/src/transports/http/http_transport.d.ts +8 -5
  83. package/script/src/transports/http/http_transport.d.ts.map +1 -1
  84. package/script/src/transports/http/http_transport.js +16 -63
  85. package/script/src/transports/websocket/_hyperliquid_event_target.d.ts +36 -39
  86. package/script/src/transports/websocket/_hyperliquid_event_target.d.ts.map +1 -1
  87. package/script/src/transports/websocket/_reconnecting_websocket.d.ts +18 -25
  88. package/script/src/transports/websocket/_reconnecting_websocket.d.ts.map +1 -1
  89. package/script/src/transports/websocket/_reconnecting_websocket.js +81 -180
  90. package/{esm/src/transports/websocket/_websocket_request_dispatcher.d.ts → script/src/transports/websocket/_websocket_async_request.d.ts} +14 -18
  91. package/script/src/transports/websocket/_websocket_async_request.d.ts.map +1 -0
  92. package/script/src/transports/websocket/{_websocket_request_dispatcher.js → _websocket_async_request.js} +45 -78
  93. package/script/src/transports/websocket/websocket_transport.d.ts +38 -28
  94. package/script/src/transports/websocket/websocket_transport.d.ts.map +1 -1
  95. package/script/src/transports/websocket/websocket_transport.js +63 -78
  96. package/script/src/types/exchange/requests.d.ts +278 -66
  97. package/script/src/types/exchange/requests.d.ts.map +1 -1
  98. package/script/src/types/info/assets.d.ts +0 -48
  99. package/script/src/types/info/assets.d.ts.map +1 -1
  100. package/script/src/types/info/markets.d.ts +52 -0
  101. package/script/src/types/info/markets.d.ts.map +1 -0
  102. package/script/{deps/jsr.io/@noble/hashes/1.8.0/src/crypto.js → src/types/info/markets.js} +0 -2
  103. package/script/src/types/info/orders.d.ts +1 -1
  104. package/script/src/types/info/orders.d.ts.map +1 -1
  105. package/script/src/types/info/requests.d.ts +14 -5
  106. package/script/src/types/info/requests.d.ts.map +1 -1
  107. package/script/src/types/mod.d.ts +4 -0
  108. package/script/src/types/mod.d.ts.map +1 -1
  109. package/script/src/types/mod.js +25 -22
  110. package/script/src/types/subscriptions/requests.d.ts +2 -0
  111. package/script/src/types/subscriptions/requests.d.ts.map +1 -1
  112. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/_u64.d.ts +0 -55
  113. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/_u64.d.ts.map +0 -1
  114. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/_u64.js +0 -66
  115. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/crypto.d.ts +0 -2
  116. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/crypto.d.ts.map +0 -1
  117. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/crypto.js +0 -1
  118. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/sha3.d.ts +0 -53
  119. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/sha3.d.ts.map +0 -1
  120. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/sha3.js +0 -294
  121. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/utils.d.ts +0 -161
  122. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/utils.d.ts.map +0 -1
  123. package/esm/deps/jsr.io/@noble/hashes/1.8.0/src/utils.js +0 -280
  124. package/esm/src/transports/websocket/_websocket_request_dispatcher.d.ts.map +0 -1
  125. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/_u64.d.ts +0 -55
  126. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/_u64.d.ts.map +0 -1
  127. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/_u64.js +0 -99
  128. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/crypto.d.ts +0 -2
  129. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/crypto.d.ts.map +0 -1
  130. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/sha3.d.ts +0 -53
  131. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/sha3.d.ts.map +0 -1
  132. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/sha3.js +0 -309
  133. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/utils.d.ts +0 -161
  134. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/utils.d.ts.map +0 -1
  135. package/script/deps/jsr.io/@noble/hashes/1.8.0/src/utils.js +0 -322
  136. package/script/src/transports/websocket/_websocket_request_dispatcher.d.ts.map +0 -1
@@ -1,4 +1,4 @@
1
- import { TransportError } from "../../base.js";
1
+ import { TransportError } from "../base.js";
2
2
  import type { HyperliquidEventTarget } from "./_hyperliquid_event_target.js";
3
3
  /**
4
4
  * Error thrown when a WebSocket request fails:
@@ -12,31 +12,27 @@ export declare class WebSocketRequestError extends TransportError {
12
12
  * Manages WebSocket requests to the Hyperliquid API.
13
13
  * Handles request creation, sending, and mapping responses to their corresponding requests.
14
14
  */
15
- export declare class WebSocketRequestDispatcher {
16
- private socket;
17
- /** Last used post request ID */
18
- private lastId;
19
- /** Map of pending requests waiting for responses */
20
- private pending;
15
+ export declare class WebSocketAsyncRequest {
16
+ protected socket: WebSocket;
17
+ protected lastId: number;
18
+ protected queue: Map<number | string, {
19
+ resolve: (value?: any) => void;
20
+ reject: (reason?: any) => void;
21
+ }>;
22
+ lastRequestTime: number;
21
23
  /**
22
- * Creates a new WebSocket request dispatcher.
24
+ * Creates a new WebSocket async request handler.
23
25
  * @param socket - WebSocket connection instance for sending requests to the Hyperliquid WebSocket API
24
26
  * @param hlEvents - Used to recognize Hyperliquid responses and match them with sent requests
25
27
  */
26
28
  constructor(socket: WebSocket, hlEvents: HyperliquidEventTarget);
27
29
  /**
28
30
  * Sends a request to the Hyperliquid API.
29
- * @param method - The method of websocket request.
30
- * @param payload - The payload to send with the request.
31
- * @param signal - An optional abort signal.
32
31
  * @returns A promise that resolves with the parsed JSON response body.
33
32
  */
34
- request(method: "post" | "subscribe" | "unsubscribe", payload: unknown, signal?: AbortSignal): Promise<unknown>;
35
- /**
36
- * Normalizes a request object to an ID.
37
- * @param value - A request object.
38
- * @returns A stringified request.
39
- */
33
+ request(method: "ping", signal?: AbortSignal): Promise<void>;
34
+ request<T>(method: "post" | "subscribe" | "unsubscribe", payload: unknown, signal?: AbortSignal): Promise<T>;
35
+ /** Normalizes an object and then converts it to a string. */
40
36
  static requestToId(value: unknown): string;
41
37
  }
42
- //# sourceMappingURL=_websocket_request_dispatcher.d.ts.map
38
+ //# sourceMappingURL=_websocket_async_request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_websocket_async_request.d.ts","sourceRoot":"","sources":["../../../../src/src/transports/websocket/_websocket_async_request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAiB7E;;;;GAIG;AACH,qBAAa,qBAAsB,SAAQ,cAAc;gBACzC,OAAO,EAAE,MAAM;CAI9B;AAED;;;GAGG;AACH,qBAAa,qBAAqB;IAkBlB,SAAS,CAAC,MAAM,EAAE,SAAS;IAjBvC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAK;IAC7B,SAAS,CAAC,KAAK,EAAE,GAAG,CAChB,MAAM,GAAG,MAAM,EACf;QAEI,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;QAE/B,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;KAClC,CACJ,CAAa;IACd,eAAe,EAAE,MAAM,CAAK;IAE5B;;;;OAIG;gBACmB,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,sBAAsB;IA2DzE;;;OAGG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAC5D,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC;IA2ClH,6DAA6D;IAC7D,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM;CAK7C"}
@@ -4,13 +4,13 @@
4
4
  if (v !== undefined) module.exports = v;
5
5
  }
6
6
  else if (typeof define === "function" && define.amd) {
7
- define(["require", "exports", "../../base.js"], factory);
7
+ define(["require", "exports", "../base.js"], factory);
8
8
  }
9
9
  })(function (require, exports) {
10
10
  "use strict";
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.WebSocketRequestDispatcher = exports.WebSocketRequestError = void 0;
13
- const base_js_1 = require("../../base.js");
12
+ exports.WebSocketAsyncRequest = exports.WebSocketRequestError = void 0;
13
+ const base_js_1 = require("../base.js");
14
14
  /**
15
15
  * Error thrown when a WebSocket request fails:
16
16
  * - When the WebSocket connection is closed
@@ -27,44 +27,32 @@
27
27
  * Manages WebSocket requests to the Hyperliquid API.
28
28
  * Handles request creation, sending, and mapping responses to their corresponding requests.
29
29
  */
30
- class WebSocketRequestDispatcher {
30
+ class WebSocketAsyncRequest {
31
+ socket;
32
+ lastId = 0;
33
+ queue = new Map();
34
+ lastRequestTime = 0;
31
35
  /**
32
- * Creates a new WebSocket request dispatcher.
36
+ * Creates a new WebSocket async request handler.
33
37
  * @param socket - WebSocket connection instance for sending requests to the Hyperliquid WebSocket API
34
38
  * @param hlEvents - Used to recognize Hyperliquid responses and match them with sent requests
35
39
  */
36
40
  constructor(socket, hlEvents) {
37
- Object.defineProperty(this, "socket", {
38
- enumerable: true,
39
- configurable: true,
40
- writable: true,
41
- value: socket
42
- });
43
- /** Last used post request ID */
44
- Object.defineProperty(this, "lastId", {
45
- enumerable: true,
46
- configurable: true,
47
- writable: true,
48
- value: 0
49
- });
50
- /** Map of pending requests waiting for responses */
51
- Object.defineProperty(this, "pending", {
52
- enumerable: true,
53
- configurable: true,
54
- writable: true,
55
- value: new Map()
56
- });
41
+ this.socket = socket;
57
42
  // Monitor responses and match the pending request
58
43
  hlEvents.addEventListener("subscriptionResponse", (event) => {
59
44
  // Use a stringified request as an id
60
- const id = WebSocketRequestDispatcher.requestToId(event.detail.subscription);
61
- this.pending.get(id)?.resolve(event.detail);
45
+ const id = WebSocketAsyncRequest.requestToId(event.detail.subscription);
46
+ this.queue.get(id)?.resolve(event.detail);
62
47
  });
63
48
  hlEvents.addEventListener("post", (event) => {
64
49
  const data = event.detail.response.type === "info"
65
50
  ? event.detail.response.payload.data
66
51
  : event.detail.response.payload;
67
- this.pending.get(event.detail.id)?.resolve(data);
52
+ this.queue.get(event.detail.id)?.resolve(data);
53
+ });
54
+ hlEvents.addEventListener("pong", () => {
55
+ this.queue.get("ping")?.resolve();
68
56
  });
69
57
  hlEvents.addEventListener("error", (event) => {
70
58
  try {
@@ -74,19 +62,19 @@
74
62
  const parsedRequest = JSON.parse(request);
75
63
  if ("id" in parsedRequest && typeof parsedRequest.id === "number") {
76
64
  // If a post request was sent, it is possible to get the id from the request
77
- this.pending.get(parsedRequest.id)?.reject(new WebSocketRequestError(`Cannot complete WebSocket request: ${event.detail}`));
65
+ this.queue.get(parsedRequest.id)?.reject(new WebSocketRequestError(`Cannot complete WebSocket request: ${event.detail}`));
78
66
  }
79
67
  else if ("subscription" in parsedRequest &&
80
68
  typeof parsedRequest.subscription === "object" &&
81
69
  parsedRequest.subscription !== null) {
82
70
  // If a subscription/unsubscribe request was sent, use the request as an id
83
- const id = WebSocketRequestDispatcher.requestToId(parsedRequest.subscription);
84
- this.pending.get(id)?.reject(new WebSocketRequestError(`Cannot complete WebSocket request: ${event.detail}`));
71
+ const id = WebSocketAsyncRequest.requestToId(parsedRequest.subscription);
72
+ this.queue.get(id)?.reject(new WebSocketRequestError(`Cannot complete WebSocket request: ${event.detail}`));
85
73
  }
86
74
  else {
87
75
  // If the request is not recognized, use the parsed request as an id
88
- const id = WebSocketRequestDispatcher.requestToId(parsedRequest);
89
- this.pending.get(id)?.reject(new WebSocketRequestError(`Cannot complete WebSocket request: ${event.detail}`));
76
+ const id = WebSocketAsyncRequest.requestToId(parsedRequest);
77
+ this.queue.get(id)?.reject(new WebSocketRequestError(`Cannot complete WebSocket request: ${event.detail}`));
90
78
  }
91
79
  }
92
80
  }
@@ -96,68 +84,55 @@
96
84
  });
97
85
  // Throws all pending requests if the connection is dropped
98
86
  socket.addEventListener("close", () => {
99
- this.pending.forEach(({ reject }) => {
87
+ this.queue.forEach(({ reject }) => {
100
88
  reject(new WebSocketRequestError("Cannot complete WebSocket request: connection is closed"));
101
89
  });
102
- this.pending.clear();
90
+ this.queue.clear();
103
91
  });
104
92
  }
105
- /**
106
- * Sends a request to the Hyperliquid API.
107
- * @param method - The method of websocket request.
108
- * @param payload - The payload to send with the request.
109
- * @param signal - An optional abort signal.
110
- * @returns A promise that resolves with the parsed JSON response body.
111
- */
112
- async request(method, payload, signal) {
93
+ async request(method, payload_or_signal, maybeSignal) {
94
+ const payload = payload_or_signal instanceof AbortSignal ? undefined : payload_or_signal;
95
+ const signal = payload_or_signal instanceof AbortSignal ? payload_or_signal : maybeSignal;
113
96
  // Reject the request if the signal is aborted
114
97
  if (signal?.aborted)
115
98
  return Promise.reject(signal.reason);
116
- // Create a request object
99
+ // Create a request
117
100
  let id;
118
101
  let request;
119
102
  if (method === "post") {
120
103
  id = ++this.lastId;
121
104
  request = { method, id, request: payload };
122
105
  }
106
+ else if (method === "ping") {
107
+ id = "ping";
108
+ request = { method };
109
+ }
123
110
  else {
124
- id = WebSocketRequestDispatcher.requestToId(payload);
111
+ id = WebSocketAsyncRequest.requestToId(payload);
125
112
  request = { method, subscription: payload };
126
113
  }
127
114
  // Send the request
128
115
  this.socket.send(JSON.stringify(request));
116
+ this.lastRequestTime = Date.now();
129
117
  // Wait for a response
130
- let onAbort;
131
- return await new Promise((resolve, reject) => {
132
- // Add an abort listener
133
- onAbort = () => reject(signal?.reason);
134
- signal?.addEventListener("abort", onAbort, { once: true });
135
- // Add the promise to the pending list
136
- this.pending.set(id, { resolve, reject });
137
- }).finally(() => {
138
- // Remove the abort listener when the promise is settled
118
+ const { promise, resolve, reject } = Promise.withResolvers();
119
+ this.queue.set(id, { resolve, reject });
120
+ const onAbort = () => reject(signal?.reason);
121
+ signal?.addEventListener("abort", onAbort, { once: true });
122
+ return await promise.finally(() => {
123
+ this.queue.delete(id);
139
124
  signal?.removeEventListener("abort", onAbort);
140
- // Clean up the pending list
141
- this.pending.delete(id);
142
125
  });
143
126
  }
144
- /**
145
- * Normalizes a request object to an ID.
146
- * @param value - A request object.
147
- * @returns A stringified request.
148
- */
127
+ /** Normalizes an object and then converts it to a string. */
149
128
  static requestToId(value) {
150
129
  const lowerHex = containsUppercaseHex(value) ? deepLowerHex(value) : value;
151
130
  const sorted = deepSortKeys(lowerHex);
152
- return JSON.stringify(sorted);
131
+ return JSON.stringify(sorted); // Also removes undefined
153
132
  }
154
133
  }
155
- exports.WebSocketRequestDispatcher = WebSocketRequestDispatcher;
156
- /**
157
- * Deeply converts hexadecimal strings in an object/array to lowercase.
158
- * @param obj - The object/array to convert hexadecimal strings to lowercase.
159
- * @returns A new object/array with hexadecimal strings converted to lowercase.
160
- */
134
+ exports.WebSocketAsyncRequest = WebSocketAsyncRequest;
135
+ /** Deeply converts hexadecimal strings in an object/array to lowercase. */
161
136
  function deepLowerHex(obj) {
162
137
  if (typeof obj === "string") {
163
138
  return /^(0X[0-9a-fA-F]*|0x[0-9a-fA-F]*[A-F][0-9a-fA-F]*)$/.test(obj) ? obj.toLowerCase() : obj;
@@ -175,20 +150,12 @@
175
150
  }
176
151
  return obj;
177
152
  }
178
- /**
179
- * Check if an object contains uppercase hexadecimal strings.
180
- * @param obj - The object to check.
181
- * @returns True if the object contains uppercase hexadecimal strings, false otherwise.
182
- */
153
+ /** Check if an object contains uppercase hexadecimal strings. */
183
154
  function containsUppercaseHex(obj) {
184
155
  const str = JSON.stringify(obj);
185
156
  return /0X[0-9a-fA-F]*|0x[0-9a-fA-F]*[A-F][0-9a-fA-F]*/.test(str);
186
157
  }
187
- /**
188
- * Deeply sort the keys of an object.
189
- * @param obj - An object to sort the keys of.
190
- * @returns A new object with sorted keys.
191
- */
158
+ /** Deeply sort the keys of an object. */
192
159
  function deepSortKeys(obj) {
193
160
  if (typeof obj !== "object" || obj === null) {
194
161
  return obj;
@@ -1,7 +1,7 @@
1
1
  import { type MessageBufferStrategy, ReconnectingWebSocket, ReconnectingWebSocketError, type ReconnectingWebSocketOptions } from "./_reconnecting_websocket.js";
2
2
  import { HyperliquidEventTarget } from "./_hyperliquid_event_target.js";
3
- import { WebSocketRequestDispatcher, WebSocketRequestError } from "./_websocket_request_dispatcher.js";
4
- import type { IRequestTransport, ISubscriptionTransport, Subscription } from "../../base.js";
3
+ import { WebSocketAsyncRequest, WebSocketRequestError } from "./_websocket_async_request.js";
4
+ import type { IRequestTransport, ISubscriptionTransport, Subscription } from "../base.js";
5
5
  export { WebSocketRequestError };
6
6
  export { type MessageBufferStrategy, ReconnectingWebSocketError, type ReconnectingWebSocketOptions };
7
7
  /** Configuration options for the WebSocket transport layer. */
@@ -10,44 +10,42 @@ export interface WebSocketTransportOptions {
10
10
  * The WebSocket URL.
11
11
  * - Mainnet:
12
12
  * - API: `wss://api.hyperliquid.xyz/ws`
13
- * - RPC: `wss://rpc.hyperliquid.xyz/ws`
13
+ * - Explorer: `wss://rpc.hyperliquid.xyz/ws`
14
14
  * - Testnet:
15
15
  * - API: `wss://api.hyperliquid-testnet.xyz/ws`
16
- * - RPC: `wss://rpc.hyperliquid-testnet.xyz/ws`
16
+ * - Explorer: `wss://rpc.hyperliquid-testnet.xyz/ws`
17
17
  * @defaultValue `wss://api.hyperliquid.xyz/ws`
18
18
  */
19
19
  url?: string | URL;
20
20
  /**
21
- * Request timeout in ms.
21
+ * Timeout for requests in ms.
22
22
  * Set to `null` to disable.
23
23
  * @defaultValue `10_000`
24
24
  */
25
25
  timeout?: number | null;
26
- /**
27
- * Keep-alive configuration.
28
- * @defaultValue `{ interval: 20_000 }`
29
- */
26
+ /** Keep-alive configuration. */
30
27
  keepAlive?: {
31
28
  /**
32
- * The interval in ms to send keep-alive messages.
29
+ * Interval between sending ping messages in ms.
33
30
  * Set to `null` to disable.
34
- * @defaultValue `20_000`
31
+ * @defaultValue `30_000`
35
32
  */
36
33
  interval?: number | null;
34
+ /**
35
+ * Timeout for the ping request in ms.
36
+ * Set to `null` to disable.
37
+ * same as {@link timeout} for requests.
38
+ */
39
+ timeout?: number | null;
37
40
  };
38
- /**
39
- * Reconnection policy configuration for closed connections.
40
- */
41
+ /** Reconnection policy configuration for closed connections. */
41
42
  reconnect?: ReconnectingWebSocketOptions;
42
43
  }
43
44
  /** WebSocket implementation of the REST and Subscription transport interfaces. */
44
45
  export declare class WebSocketTransport implements IRequestTransport, ISubscriptionTransport, AsyncDisposable {
45
- /** The interval timer ID for keep-alive messages. */
46
- protected _keepAliveTimer: number | null;
47
- /** The WebSocket request dispatcher instance. */
48
- protected _wsRequester: WebSocketRequestDispatcher;
49
- /** The Hyperliquid event target instance. */
46
+ protected _wsRequester: WebSocketAsyncRequest;
50
47
  protected _hlEvents: HyperliquidEventTarget;
48
+ protected _keepAliveTimeout: ReturnType<typeof setTimeout> | null;
51
49
  /**
52
50
  * Map of active subscriptions.
53
51
  * - Key: Unique subscription identifier based on payload
@@ -63,13 +61,18 @@ export declare class WebSocketTransport implements IRequestTransport, ISubscript
63
61
  * Set to `null` to disable.
64
62
  */
65
63
  timeout: number | null;
66
- /** Keep-alive configuration settings. */
64
+ /** Keep-alive configuration. */
67
65
  readonly keepAlive: {
68
66
  /**
69
- * The interval in ms to send keep-alive messages.
67
+ * Interval between sending ping messages in ms.
70
68
  * Set to `null` to disable.
71
69
  */
72
70
  readonly interval: number | null;
71
+ /**
72
+ * Timeout for the ping request in ms.
73
+ * Set to `null` to disable.
74
+ */
75
+ timeout?: number | null;
73
76
  };
74
77
  /** The WebSocket that is used for communication. */
75
78
  readonly socket: ReconnectingWebSocket;
@@ -80,23 +83,29 @@ export declare class WebSocketTransport implements IRequestTransport, ISubscript
80
83
  constructor(options?: WebSocketTransportOptions);
81
84
  /**
82
85
  * Sends a request to the Hyperliquid API via WebSocket.
86
+ *
87
+ * Note: Explorer requests are not supported in the Hyperliquid WebSocket API.
88
+ *
83
89
  * @param endpoint - The API endpoint to send the request to (`explorer` requests are not supported).
84
90
  * @param payload - The payload to send with the request.
85
91
  * @param signal - An optional abort signal.
86
92
  * @returns A promise that resolves with parsed JSON response body.
87
93
  * @throws {WebSocketRequestError} - An error that occurs when a WebSocket request fails.
88
- * @note Explorer requests are not supported in the Hyperliquid WebSocket API.
89
94
  */
90
- request(type: "info" | "exchange" | "explorer", payload: unknown, signal?: AbortSignal): Promise<unknown>;
95
+ request<T>(type: "info" | "exchange" | "explorer", payload: unknown, signal?: AbortSignal): Promise<T>;
91
96
  /**
92
97
  * Subscribes to a Hyperliquid event channel.
98
+ *
99
+ * Sends a subscription request to the server and listens for events.
100
+ *
93
101
  * @param channel - The event channel to listen to.
94
102
  * @param payload - A payload to send with the subscription request.
95
103
  * @param listener - A function to call when the event is dispatched.
96
104
  * @param signal - An optional abort signal for canceling the subscription request.
97
105
  * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
106
+ * @throws {WebSocketRequestError} - An error that occurs when a WebSocket request fails.
98
107
  */
99
- subscribe(channel: string, payload: unknown, listener: (data: CustomEvent) => void, signal?: AbortSignal): Promise<Subscription>;
108
+ subscribe<T>(channel: string, payload: unknown, listener: (data: CustomEvent<T>) => void, signal?: AbortSignal): Promise<Subscription>;
100
109
  /**
101
110
  * Waits until the WebSocket connection is ready.
102
111
  * @param signal - An optional abort signal.
@@ -109,12 +118,13 @@ export declare class WebSocketTransport implements IRequestTransport, ISubscript
109
118
  * @returns A promise that resolves when the connection is fully closed.
110
119
  */
111
120
  close(signal?: AbortSignal): Promise<void>;
121
+ /** Combines the provided abort signal with the timeout signal. */
122
+ protected _getCombinedTimeoutSignal(signal?: AbortSignal): AbortSignal | undefined;
112
123
  /**
113
- * Combines the provided abort signal with the timeout signal.
114
- * @param signal An optional abort signal.
115
- * @returns A combined abort signal or undefined.
124
+ * Initiate background keep the connection alive.
125
+ * Sends ping only when needed.
116
126
  */
117
- protected _getCombinedTimeoutSignal(signal?: AbortSignal): AbortSignal | undefined;
127
+ protected _keepAlive(): void;
118
128
  [Symbol.asyncDispose](): Promise<void>;
119
129
  }
120
130
  //# sourceMappingURL=websocket_transport.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"websocket_transport.d.ts","sourceRoot":"","sources":["../../../../src/src/transports/websocket/websocket_transport.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,KAAK,qBAAqB,EAC1B,qBAAqB,EACrB,0BAA0B,EAC1B,KAAK,4BAA4B,EACpC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AACvG,OAAO,KAAK,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7F,OAAO,EAAE,qBAAqB,EAAE,CAAC;AACjC,OAAO,EAAE,KAAK,qBAAqB,EAAE,0BAA0B,EAAE,KAAK,4BAA4B,EAAE,CAAC;AAErG,+DAA+D;AAC/D,MAAM,WAAW,yBAAyB;IACtC;;;;;;;;;OASG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IAEnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAExB;;;OAGG;IACH,SAAS,CAAC,EAAE;QACR;;;;WAIG;QACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,CAAC;IAEF;;OAEG;IACH,SAAS,CAAC,EAAE,4BAA4B,CAAC;CAC5C;AAED,kFAAkF;AAClF,qBAAa,kBAAmB,YAAW,iBAAiB,EAAE,sBAAsB,EAAE,eAAe;IACjG,qDAAqD;IACrD,SAAS,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEhD,iDAAiD;IACjD,SAAS,CAAC,YAAY,EAAE,0BAA0B,CAAC;IAEnD,6CAA6C;IAC7C,SAAS,CAAC,SAAS,EAAE,sBAAsB,CAAC;IAE5C;;;;;OAKG;IACH,SAAS,CAAC,cAAc,EAAE,GAAG,CACzB,MAAM,EACN;QACI,SAAS,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACrF,cAAc,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;KACpC,CACJ,CAAa;IAEd;;;OAGG;IACH,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAEvB,yCAAyC;IACzC,QAAQ,CAAC,SAAS,EAAE;QAChB;;;WAGG;QACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;KACpC,CAAC;IAEF,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IAEvC;;;OAGG;gBACS,OAAO,CAAC,EAAE,yBAAyB;IAuC/C;;;;;;;;OAQG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAQzG;;;;;;;OAOG;IACG,SAAS,CACX,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,EACrC,MAAM,CAAC,EAAE,WAAW,GACrB,OAAO,CAAC,YAAY,CAAC;IAgExB;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB1C;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB1C;;;;OAIG;IACH,SAAS,CAAC,yBAAyB,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,WAAW,GAAG,SAAS;IAQ5E,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/C"}
1
+ {"version":3,"file":"websocket_transport.d.ts","sourceRoot":"","sources":["../../../../src/src/transports/websocket/websocket_transport.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,KAAK,qBAAqB,EAC1B,qBAAqB,EACrB,0BAA0B,EAC1B,KAAK,4BAA4B,EACpC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAC7F,OAAO,KAAK,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1F,OAAO,EAAE,qBAAqB,EAAE,CAAC;AACjC,OAAO,EAAE,KAAK,qBAAqB,EAAE,0BAA0B,EAAE,KAAK,4BAA4B,EAAE,CAAC;AAErG,+DAA+D;AAC/D,MAAM,WAAW,yBAAyB;IACtC;;;;;;;;;OASG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IAEnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAExB,gCAAgC;IAChC,SAAS,CAAC,EAAE;QACR;;;;WAIG;QACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAEzB;;;;WAIG;QACH,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC3B,CAAC;IAEF,gEAAgE;IAChE,SAAS,CAAC,EAAE,4BAA4B,CAAC;CAC5C;AAED,kFAAkF;AAClF,qBAAa,kBAAmB,YAAW,iBAAiB,EAAE,sBAAsB,EAAE,eAAe;IACjG,SAAS,CAAC,YAAY,EAAE,qBAAqB,CAAC;IAC9C,SAAS,CAAC,SAAS,EAAE,sBAAsB,CAAC;IAC5C,SAAS,CAAC,iBAAiB,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,IAAI,CAAQ;IAEzE;;;;;OAKG;IACH,SAAS,CAAC,cAAc,EAAE,GAAG,CACzB,MAAM,EACN;QACI,SAAS,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QACrF,cAAc,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;KACpC,CACJ,CAAa;IAEd;;;OAGG;IACH,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAEvB,gCAAgC;IAChC,QAAQ,CAAC,SAAS,EAAE;QAChB;;;WAGG;QACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAEjC;;;WAGG;QACH,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC3B,CAAC;IAEF,oDAAoD;IACpD,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IAEvC;;;OAGG;gBACS,OAAO,CAAC,EAAE,yBAAyB;IAoC/C;;;;;;;;;;OAUG;IACH,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC;IAQtG;;;;;;;;;;;OAWG;IACG,SAAS,CAAC,CAAC,EACb,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,IAAI,EACxC,MAAM,CAAC,EAAE,WAAW,GACrB,OAAO,CAAC,YAAY,CAAC;IAgExB;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB1C;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB1C,kEAAkE;IAClE,SAAS,CAAC,yBAAyB,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,WAAW,GAAG,SAAS;IAQlF;;;OAGG;IACH,SAAS,CAAC,UAAU,IAAI,IAAI;IAuBtB,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/C"}
@@ -4,7 +4,7 @@
4
4
  if (v !== undefined) module.exports = v;
5
5
  }
6
6
  else if (typeof define === "function" && define.amd) {
7
- define(["require", "exports", "./_reconnecting_websocket.js", "./_hyperliquid_event_target.js", "./_websocket_request_dispatcher.js"], factory);
7
+ define(["require", "exports", "./_reconnecting_websocket.js", "./_hyperliquid_event_target.js", "./_websocket_async_request.js"], factory);
8
8
  }
9
9
  })(function (require, exports) {
10
10
  "use strict";
@@ -13,93 +13,52 @@
13
13
  const _reconnecting_websocket_js_1 = require("./_reconnecting_websocket.js");
14
14
  Object.defineProperty(exports, "ReconnectingWebSocketError", { enumerable: true, get: function () { return _reconnecting_websocket_js_1.ReconnectingWebSocketError; } });
15
15
  const _hyperliquid_event_target_js_1 = require("./_hyperliquid_event_target.js");
16
- const _websocket_request_dispatcher_js_1 = require("./_websocket_request_dispatcher.js");
17
- Object.defineProperty(exports, "WebSocketRequestError", { enumerable: true, get: function () { return _websocket_request_dispatcher_js_1.WebSocketRequestError; } });
16
+ const _websocket_async_request_js_1 = require("./_websocket_async_request.js");
17
+ Object.defineProperty(exports, "WebSocketRequestError", { enumerable: true, get: function () { return _websocket_async_request_js_1.WebSocketRequestError; } });
18
18
  /** WebSocket implementation of the REST and Subscription transport interfaces. */
19
19
  class WebSocketTransport {
20
+ _wsRequester;
21
+ _hlEvents;
22
+ _keepAliveTimeout = null;
23
+ /**
24
+ * Map of active subscriptions.
25
+ * - Key: Unique subscription identifier based on payload
26
+ * - Value: Subscription info containing the subscription request promise
27
+ * and a map of listeners to their metadata (channel + unsubscribe function).
28
+ */
29
+ _subscriptions = new Map();
30
+ /**
31
+ * Request timeout in ms.
32
+ * Set to `null` to disable.
33
+ */
34
+ timeout;
35
+ /** Keep-alive configuration. */
36
+ keepAlive;
37
+ /** The WebSocket that is used for communication. */
38
+ socket;
20
39
  /**
21
40
  * Creates a new WebSocket transport instance.
22
41
  * @param options - Configuration options for the WebSocket transport layer.
23
42
  */
24
43
  constructor(options) {
25
- /** The interval timer ID for keep-alive messages. */
26
- Object.defineProperty(this, "_keepAliveTimer", {
27
- enumerable: true,
28
- configurable: true,
29
- writable: true,
30
- value: null
31
- });
32
- /** The WebSocket request dispatcher instance. */
33
- Object.defineProperty(this, "_wsRequester", {
34
- enumerable: true,
35
- configurable: true,
36
- writable: true,
37
- value: void 0
38
- });
39
- /** The Hyperliquid event target instance. */
40
- Object.defineProperty(this, "_hlEvents", {
41
- enumerable: true,
42
- configurable: true,
43
- writable: true,
44
- value: void 0
45
- });
46
- /**
47
- * Map of active subscriptions.
48
- * - Key: Unique subscription identifier based on payload
49
- * - Value: Subscription info containing the subscription request promise
50
- * and a map of listeners to their metadata (channel + unsubscribe function).
51
- */
52
- Object.defineProperty(this, "_subscriptions", {
53
- enumerable: true,
54
- configurable: true,
55
- writable: true,
56
- value: new Map()
57
- });
58
- /**
59
- * Request timeout in ms.
60
- * Set to `null` to disable.
61
- */
62
- Object.defineProperty(this, "timeout", {
63
- enumerable: true,
64
- configurable: true,
65
- writable: true,
66
- value: void 0
67
- });
68
- /** Keep-alive configuration settings. */
69
- Object.defineProperty(this, "keepAlive", {
70
- enumerable: true,
71
- configurable: true,
72
- writable: true,
73
- value: void 0
74
- });
75
- /** The WebSocket that is used for communication. */
76
- Object.defineProperty(this, "socket", {
77
- enumerable: true,
78
- configurable: true,
79
- writable: true,
80
- value: void 0
81
- });
82
44
  this.socket = new _reconnecting_websocket_js_1.ReconnectingWebSocket(options?.url ?? "wss://api.hyperliquid.xyz/ws", undefined, options?.reconnect);
83
45
  this._hlEvents = new _hyperliquid_event_target_js_1.HyperliquidEventTarget(this.socket);
84
- this._wsRequester = new _websocket_request_dispatcher_js_1.WebSocketRequestDispatcher(this.socket, this._hlEvents);
46
+ this._wsRequester = new _websocket_async_request_js_1.WebSocketAsyncRequest(this.socket, this._hlEvents);
85
47
  this.timeout = options?.timeout === undefined ? 10_000 : options.timeout;
86
48
  this.keepAlive = {
87
- interval: options?.keepAlive?.interval === undefined ? 20_000 : options.keepAlive.interval,
49
+ interval: options?.keepAlive?.interval === undefined ? 30_000 : options.keepAlive?.interval,
50
+ timeout: options?.keepAlive?.timeout === undefined ? this.timeout : options.keepAlive?.timeout,
88
51
  };
89
52
  // Initialize listeners
90
53
  this.socket.addEventListener("open", () => {
91
- // Start keep-alive timer
92
- if (this.keepAlive.interval && this._keepAliveTimer === null) {
93
- this._keepAliveTimer = setInterval(() => {
94
- this.socket.send(JSON.stringify({ method: "ping" }));
95
- }, this.keepAlive.interval);
96
- }
54
+ // Start keep-alive handler
55
+ this._keepAlive();
97
56
  });
98
57
  this.socket.addEventListener("close", () => {
99
58
  // Clear keep-alive timer
100
- if (this._keepAliveTimer !== null) {
101
- clearInterval(this._keepAliveTimer);
102
- this._keepAliveTimer = null;
59
+ if (this._keepAliveTimeout !== null) {
60
+ clearTimeout(this._keepAliveTimeout);
61
+ this._keepAliveTimeout = null;
103
62
  }
104
63
  // Clear all subscriptions
105
64
  for (const subscriptionInfo of this._subscriptions.values()) {
@@ -111,12 +70,14 @@
111
70
  }
112
71
  /**
113
72
  * Sends a request to the Hyperliquid API via WebSocket.
73
+ *
74
+ * Note: Explorer requests are not supported in the Hyperliquid WebSocket API.
75
+ *
114
76
  * @param endpoint - The API endpoint to send the request to (`explorer` requests are not supported).
115
77
  * @param payload - The payload to send with the request.
116
78
  * @param signal - An optional abort signal.
117
79
  * @returns A promise that resolves with parsed JSON response body.
118
80
  * @throws {WebSocketRequestError} - An error that occurs when a WebSocket request fails.
119
- * @note Explorer requests are not supported in the Hyperliquid WebSocket API.
120
81
  */
121
82
  request(type, payload, signal) {
122
83
  const combinedTimeoutSignal = this._getCombinedTimeoutSignal(signal);
@@ -127,15 +88,19 @@
127
88
  }
128
89
  /**
129
90
  * Subscribes to a Hyperliquid event channel.
91
+ *
92
+ * Sends a subscription request to the server and listens for events.
93
+ *
130
94
  * @param channel - The event channel to listen to.
131
95
  * @param payload - A payload to send with the subscription request.
132
96
  * @param listener - A function to call when the event is dispatched.
133
97
  * @param signal - An optional abort signal for canceling the subscription request.
134
98
  * @returns A promise that resolves with a {@link Subscription} object to manage the subscription lifecycle.
99
+ * @throws {WebSocketRequestError} - An error that occurs when a WebSocket request fails.
135
100
  */
136
101
  async subscribe(channel, payload, listener, signal) {
137
102
  // Create a unique identifier for the subscription
138
- const id = _websocket_request_dispatcher_js_1.WebSocketRequestDispatcher.requestToId(payload);
103
+ const id = _websocket_async_request_js_1.WebSocketAsyncRequest.requestToId(payload);
139
104
  // Initialize new subscription, if it doesn't exist
140
105
  let subscription = this._subscriptions.get(id);
141
106
  if (!subscription) {
@@ -236,11 +201,7 @@
236
201
  this.socket.close();
237
202
  });
238
203
  }
239
- /**
240
- * Combines the provided abort signal with the timeout signal.
241
- * @param signal An optional abort signal.
242
- * @returns A combined abort signal or undefined.
243
- */
204
+ /** Combines the provided abort signal with the timeout signal. */
244
205
  _getCombinedTimeoutSignal(signal) {
245
206
  const timeoutSignal = this.timeout ? AbortSignal.timeout(this.timeout) : undefined;
246
207
  const combinedSignal = signal && timeoutSignal
@@ -248,6 +209,30 @@
248
209
  : signal ?? timeoutSignal;
249
210
  return combinedSignal;
250
211
  }
212
+ /**
213
+ * Initiate background keep the connection alive.
214
+ * Sends ping only when needed.
215
+ */
216
+ _keepAlive() {
217
+ if (this.keepAlive.interval === null || this._keepAliveTimeout)
218
+ return;
219
+ const tick = async () => {
220
+ if (this.socket.readyState !== _reconnecting_websocket_js_1.ReconnectingWebSocket.OPEN || !this._keepAliveTimeout)
221
+ return;
222
+ // Check if the last request was sent more than the keep-alive interval ago
223
+ if (Date.now() - this._wsRequester.lastRequestTime >= this.keepAlive.interval) {
224
+ const timeoutSignal = this.keepAlive.timeout ? AbortSignal.timeout(this.keepAlive.timeout) : undefined;
225
+ await this._wsRequester.request("ping", timeoutSignal)
226
+ .catch(() => undefined); // Ignore errors
227
+ }
228
+ // Schedule the next ping
229
+ if (this.socket.readyState === _reconnecting_websocket_js_1.ReconnectingWebSocket.OPEN && this._keepAliveTimeout) {
230
+ const nextDelay = this.keepAlive.interval - (Date.now() - this._wsRequester.lastRequestTime);
231
+ this._keepAliveTimeout = setTimeout(tick, nextDelay);
232
+ }
233
+ };
234
+ this._keepAliveTimeout = setTimeout(tick, this.keepAlive.interval);
235
+ }
251
236
  async [Symbol.asyncDispose]() {
252
237
  await this.close();
253
238
  }