@nktkas/hyperliquid 0.17.4 → 0.18.1
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 +48 -36
- package/esm/deps/jsr.io/@std/async/1.0.12/delay.d.ts +43 -0
- package/esm/deps/jsr.io/@std/async/1.0.12/delay.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/async/1.0.12/delay.js +63 -0
- package/esm/deps/jsr.io/@std/encoding/{1.0.9 → 1.0.10}/_common16.d.ts +1 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common16.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/encoding/{1.0.9 → 1.0.10}/_common16.js +1 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_common_detach.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.10/_types.d.ts.map +1 -0
- package/esm/deps/jsr.io/@std/encoding/1.0.10/hex.d.ts.map +1 -0
- package/esm/src/base.d.ts +2 -2
- package/esm/src/base.d.ts.map +1 -1
- package/esm/src/clients/event.d.ts +2 -1
- package/esm/src/clients/event.d.ts.map +1 -1
- package/esm/src/clients/event.js +3 -0
- package/esm/src/clients/public.d.ts +2 -1
- package/esm/src/clients/public.d.ts.map +1 -1
- package/esm/src/clients/public.js +3 -0
- package/esm/src/clients/wallet.d.ts +24 -13
- package/esm/src/clients/wallet.d.ts.map +1 -1
- package/esm/src/clients/wallet.js +88 -62
- package/esm/src/signing.d.ts +4 -1
- package/esm/src/signing.d.ts.map +1 -1
- package/esm/src/signing.js +46 -23
- package/esm/src/transports/http/http_transport.d.ts +9 -60
- package/esm/src/transports/http/http_transport.d.ts.map +1 -1
- package/esm/src/transports/http/http_transport.js +9 -57
- package/esm/src/transports/websocket/_hyperliquid_event_target.d.ts +3 -12
- package/esm/src/transports/websocket/_hyperliquid_event_target.d.ts.map +1 -1
- package/esm/src/transports/websocket/_reconnecting_websocket.d.ts +22 -44
- package/esm/src/transports/websocket/_reconnecting_websocket.d.ts.map +1 -1
- package/esm/src/transports/websocket/_reconnecting_websocket.js +127 -193
- package/esm/src/transports/websocket/websocket_transport.d.ts +8 -1
- package/esm/src/transports/websocket/websocket_transport.d.ts.map +1 -1
- package/esm/src/transports/websocket/websocket_transport.js +26 -21
- package/esm/src/types/exchange/requests.d.ts +26 -2
- package/esm/src/types/exchange/requests.d.ts.map +1 -1
- package/esm/src/types/exchange/responses.d.ts +6 -6
- package/esm/src/types/exchange/responses.d.ts.map +1 -1
- package/esm/src/types/info/accounts.d.ts +14 -0
- package/esm/src/types/info/accounts.d.ts.map +1 -1
- package/esm/src/types/info/assets.d.ts +18 -0
- package/esm/src/types/info/assets.d.ts.map +1 -1
- package/package.json +2 -1
- package/script/deps/jsr.io/@std/async/1.0.12/delay.d.ts +43 -0
- package/script/deps/jsr.io/@std/async/1.0.12/delay.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/async/1.0.12/delay.js +76 -0
- package/script/deps/jsr.io/@std/encoding/{1.0.9 → 1.0.10}/_common16.d.ts +1 -1
- package/script/deps/jsr.io/@std/encoding/1.0.10/_common16.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/encoding/{1.0.9 → 1.0.10}/_common16.js +1 -1
- package/script/deps/jsr.io/@std/encoding/1.0.10/_common_detach.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/encoding/1.0.10/_types.d.ts.map +1 -0
- package/script/deps/jsr.io/@std/encoding/1.0.10/hex.d.ts.map +1 -0
- package/script/src/base.d.ts +2 -2
- package/script/src/base.d.ts.map +1 -1
- package/script/src/clients/event.d.ts +2 -1
- package/script/src/clients/event.d.ts.map +1 -1
- package/script/src/clients/event.js +3 -0
- package/script/src/clients/public.d.ts +2 -1
- package/script/src/clients/public.d.ts.map +1 -1
- package/script/src/clients/public.js +3 -0
- package/script/src/clients/wallet.d.ts +24 -13
- package/script/src/clients/wallet.d.ts.map +1 -1
- package/script/src/clients/wallet.js +88 -62
- package/script/src/signing.d.ts +4 -1
- package/script/src/signing.d.ts.map +1 -1
- package/script/src/signing.js +46 -23
- package/script/src/transports/http/http_transport.d.ts +9 -60
- package/script/src/transports/http/http_transport.d.ts.map +1 -1
- package/script/src/transports/http/http_transport.js +9 -57
- package/script/src/transports/websocket/_hyperliquid_event_target.d.ts +3 -12
- package/script/src/transports/websocket/_hyperliquid_event_target.d.ts.map +1 -1
- package/script/src/transports/websocket/_reconnecting_websocket.d.ts +22 -44
- package/script/src/transports/websocket/_reconnecting_websocket.d.ts.map +1 -1
- package/script/src/transports/websocket/_reconnecting_websocket.js +129 -195
- package/script/src/transports/websocket/websocket_transport.d.ts +8 -1
- package/script/src/transports/websocket/websocket_transport.d.ts.map +1 -1
- package/script/src/transports/websocket/websocket_transport.js +26 -21
- package/script/src/types/exchange/requests.d.ts +26 -2
- package/script/src/types/exchange/requests.d.ts.map +1 -1
- package/script/src/types/exchange/responses.d.ts +6 -6
- package/script/src/types/exchange/responses.d.ts.map +1 -1
- package/script/src/types/info/accounts.d.ts +14 -0
- package/script/src/types/info/accounts.d.ts.map +1 -1
- package/script/src/types/info/assets.d.ts +18 -0
- package/script/src/types/info/assets.d.ts.map +1 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.9/_common16.d.ts.map +0 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.9/_common_detach.d.ts.map +0 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.9/_types.d.ts.map +0 -1
- package/esm/deps/jsr.io/@std/encoding/1.0.9/hex.d.ts.map +0 -1
- package/script/deps/jsr.io/@std/encoding/1.0.9/_common16.d.ts.map +0 -1
- package/script/deps/jsr.io/@std/encoding/1.0.9/_common_detach.d.ts.map +0 -1
- package/script/deps/jsr.io/@std/encoding/1.0.9/_types.d.ts.map +0 -1
- package/script/deps/jsr.io/@std/encoding/1.0.9/hex.d.ts.map +0 -1
- /package/esm/deps/jsr.io/@std/encoding/{1.0.9 → 1.0.10}/_common_detach.d.ts +0 -0
- /package/esm/deps/jsr.io/@std/encoding/{1.0.9 → 1.0.10}/_common_detach.js +0 -0
- /package/esm/deps/jsr.io/@std/encoding/{1.0.9 → 1.0.10}/_types.d.ts +0 -0
- /package/esm/deps/jsr.io/@std/encoding/{1.0.9 → 1.0.10}/_types.js +0 -0
- /package/esm/deps/jsr.io/@std/encoding/{1.0.9 → 1.0.10}/hex.d.ts +0 -0
- /package/esm/deps/jsr.io/@std/encoding/{1.0.9 → 1.0.10}/hex.js +0 -0
- /package/script/deps/jsr.io/@std/encoding/{1.0.9 → 1.0.10}/_common_detach.d.ts +0 -0
- /package/script/deps/jsr.io/@std/encoding/{1.0.9 → 1.0.10}/_common_detach.js +0 -0
- /package/script/deps/jsr.io/@std/encoding/{1.0.9 → 1.0.10}/_types.d.ts +0 -0
- /package/script/deps/jsr.io/@std/encoding/{1.0.9 → 1.0.10}/_types.js +0 -0
- /package/script/deps/jsr.io/@std/encoding/{1.0.9 → 1.0.10}/hex.d.ts +0 -0
- /package/script/deps/jsr.io/@std/encoding/{1.0.9 → 1.0.10}/hex.js +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// deno-lint-ignore-file no-explicit-any
|
|
2
|
+
import { delay } from "../../../deps/jsr.io/@std/async/1.0.12/delay.js";
|
|
2
3
|
import { TransportError } from "../../base.js";
|
|
3
4
|
/** Simple FIFO (First In, First Out) buffer implementation. */
|
|
4
5
|
class FIFOMessageBuffer {
|
|
@@ -44,192 +45,174 @@ export class ReconnectingWebSocketError extends TransportError {
|
|
|
44
45
|
* Fully compatible with standard WebSocket API.
|
|
45
46
|
*/
|
|
46
47
|
export class ReconnectingWebSocket {
|
|
47
|
-
/**
|
|
48
|
-
* Creates a new reconnecting WebSocket.
|
|
49
|
-
* @param url - The WebSocket URL to connect to.
|
|
50
|
-
* @param protocols - The WebSocket protocols to use.
|
|
51
|
-
* @param options - The configuration options.
|
|
52
|
-
*/
|
|
53
48
|
constructor(url, protocols, options) {
|
|
54
|
-
/** Controller for handling connection termination. */
|
|
55
|
-
Object.defineProperty(this, "_terminationController", {
|
|
56
|
-
enumerable: true,
|
|
57
|
-
configurable: true,
|
|
58
|
-
writable: true,
|
|
59
|
-
value: new AbortController()
|
|
60
|
-
});
|
|
61
|
-
/** WebSocket protocols defined in constructor. */
|
|
62
|
-
Object.defineProperty(this, "_protocols", {
|
|
63
|
-
enumerable: true,
|
|
64
|
-
configurable: true,
|
|
65
|
-
writable: true,
|
|
66
|
-
value: void 0
|
|
67
|
-
});
|
|
68
|
-
/** Non-permanent original instance of WebSocket. */
|
|
69
49
|
Object.defineProperty(this, "_socket", {
|
|
70
50
|
enumerable: true,
|
|
71
51
|
configurable: true,
|
|
72
52
|
writable: true,
|
|
73
53
|
value: void 0
|
|
74
54
|
});
|
|
75
|
-
|
|
76
|
-
Object.defineProperty(this, "_reconnectCount", {
|
|
55
|
+
Object.defineProperty(this, "_protocols", {
|
|
77
56
|
enumerable: true,
|
|
78
57
|
configurable: true,
|
|
79
58
|
writable: true,
|
|
80
|
-
value: 0
|
|
59
|
+
value: void 0
|
|
81
60
|
});
|
|
82
|
-
|
|
83
|
-
Object.defineProperty(this, "_eventListeners", {
|
|
61
|
+
Object.defineProperty(this, "_listeners", {
|
|
84
62
|
enumerable: true,
|
|
85
63
|
configurable: true,
|
|
86
64
|
writable: true,
|
|
87
65
|
value: []
|
|
88
66
|
});
|
|
89
|
-
|
|
90
|
-
Object.defineProperty(this, "_onclose", {
|
|
67
|
+
Object.defineProperty(this, "_attempt", {
|
|
91
68
|
enumerable: true,
|
|
92
69
|
configurable: true,
|
|
93
70
|
writable: true,
|
|
94
|
-
value:
|
|
71
|
+
value: 0
|
|
95
72
|
});
|
|
96
|
-
|
|
97
|
-
Object.defineProperty(this, "_onerror", {
|
|
73
|
+
Object.defineProperty(this, "reconnectOptions", {
|
|
98
74
|
enumerable: true,
|
|
99
75
|
configurable: true,
|
|
100
76
|
writable: true,
|
|
101
77
|
value: void 0
|
|
102
78
|
});
|
|
103
|
-
|
|
104
|
-
Object.defineProperty(this, "_onmessage", {
|
|
79
|
+
Object.defineProperty(this, "reconnectAbortController", {
|
|
105
80
|
enumerable: true,
|
|
106
81
|
configurable: true,
|
|
107
82
|
writable: true,
|
|
108
|
-
value:
|
|
83
|
+
value: new AbortController()
|
|
109
84
|
});
|
|
110
|
-
|
|
111
|
-
Object.defineProperty(this, "_onopen", {
|
|
85
|
+
Object.defineProperty(this, "_open", {
|
|
112
86
|
enumerable: true,
|
|
113
87
|
configurable: true,
|
|
114
88
|
writable: true,
|
|
115
|
-
value:
|
|
89
|
+
value: () => {
|
|
90
|
+
// Reset the attempt counter
|
|
91
|
+
this._attempt = 0;
|
|
92
|
+
// Send all buffered messages
|
|
93
|
+
let message;
|
|
94
|
+
while ((message = this.reconnectOptions.messageBuffer.shift()) !== undefined) {
|
|
95
|
+
this._socket.send(message);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
116
98
|
});
|
|
117
|
-
|
|
118
|
-
Object.defineProperty(this, "reconnectOptions", {
|
|
99
|
+
Object.defineProperty(this, "_close", {
|
|
119
100
|
enumerable: true,
|
|
120
101
|
configurable: true,
|
|
121
102
|
writable: true,
|
|
122
|
-
value:
|
|
103
|
+
value: async (event) => {
|
|
104
|
+
try {
|
|
105
|
+
// If the event was triggered but the socket is not closing, ignore it
|
|
106
|
+
if (this._socket.readyState !== ReconnectingWebSocket.CLOSING &&
|
|
107
|
+
this._socket.readyState !== ReconnectingWebSocket.CLOSED)
|
|
108
|
+
return;
|
|
109
|
+
// If the instance is terminated, do not attempt to reconnect
|
|
110
|
+
if (this.reconnectAbortController.signal.aborted)
|
|
111
|
+
return;
|
|
112
|
+
// Check if reconnection should be attempted
|
|
113
|
+
if (++this._attempt > this.reconnectOptions.maxRetries) {
|
|
114
|
+
this._cleanup("RECONNECTION_LIMIT_REACHED");
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const userDecision = await this.reconnectOptions.shouldReconnect(event, this.reconnectAbortController.signal);
|
|
118
|
+
if (this.reconnectAbortController.signal.aborted)
|
|
119
|
+
return;
|
|
120
|
+
if (!userDecision) {
|
|
121
|
+
this._cleanup("RECONNECTION_STOPPED_BY_USER");
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
// Delay before reconnecting
|
|
125
|
+
const reconnectDelay = typeof this.reconnectOptions.connectionDelay === "number"
|
|
126
|
+
? this.reconnectOptions.connectionDelay
|
|
127
|
+
: await this.reconnectOptions.connectionDelay(this._attempt, this.reconnectAbortController.signal);
|
|
128
|
+
if (this.reconnectAbortController.signal.aborted)
|
|
129
|
+
return;
|
|
130
|
+
await delay(reconnectDelay, { signal: this.reconnectAbortController.signal });
|
|
131
|
+
// Create a new WebSocket instance
|
|
132
|
+
const { onclose, onerror, onmessage, onopen } = this._socket;
|
|
133
|
+
this._socket = this._createSocket(this._socket.url, this._protocols);
|
|
134
|
+
// Reconnect all listeners
|
|
135
|
+
this._setupEventListeners();
|
|
136
|
+
this._listeners.forEach(({ type, listenerProxy, options }) => {
|
|
137
|
+
this._socket.addEventListener(type, listenerProxy, options);
|
|
138
|
+
});
|
|
139
|
+
this._socket.onclose = onclose;
|
|
140
|
+
this._socket.onerror = onerror;
|
|
141
|
+
this._socket.onmessage = onmessage;
|
|
142
|
+
this._socket.onopen = onopen;
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
this._cleanup("UNKNOWN_ERROR", error);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
123
148
|
});
|
|
124
|
-
|
|
125
|
-
Object.defineProperty(this, "terminationSignal", {
|
|
149
|
+
Object.defineProperty(this, "CONNECTING", {
|
|
126
150
|
enumerable: true,
|
|
127
151
|
configurable: true,
|
|
128
152
|
writable: true,
|
|
129
|
-
value:
|
|
153
|
+
value: 0
|
|
130
154
|
});
|
|
131
|
-
Object.defineProperty(this, "
|
|
155
|
+
Object.defineProperty(this, "OPEN", {
|
|
132
156
|
enumerable: true,
|
|
133
157
|
configurable: true,
|
|
134
158
|
writable: true,
|
|
135
|
-
value:
|
|
159
|
+
value: 1
|
|
136
160
|
});
|
|
137
161
|
Object.defineProperty(this, "CLOSING", {
|
|
138
162
|
enumerable: true,
|
|
139
163
|
configurable: true,
|
|
140
164
|
writable: true,
|
|
141
|
-
value:
|
|
165
|
+
value: 2
|
|
142
166
|
});
|
|
143
|
-
Object.defineProperty(this, "
|
|
144
|
-
enumerable: true,
|
|
145
|
-
configurable: true,
|
|
146
|
-
writable: true,
|
|
147
|
-
value: WebSocket.CONNECTING
|
|
148
|
-
});
|
|
149
|
-
Object.defineProperty(this, "OPEN", {
|
|
167
|
+
Object.defineProperty(this, "CLOSED", {
|
|
150
168
|
enumerable: true,
|
|
151
169
|
configurable: true,
|
|
152
170
|
writable: true,
|
|
153
|
-
value:
|
|
171
|
+
value: 3
|
|
154
172
|
});
|
|
155
|
-
// Set the default options
|
|
156
173
|
this.reconnectOptions = {
|
|
157
174
|
maxRetries: options?.maxRetries ?? 3,
|
|
158
175
|
connectionTimeout: options?.connectionTimeout === undefined ? 10_000 : options.connectionTimeout,
|
|
159
|
-
connectionDelay: options?.connectionDelay ?? ((
|
|
176
|
+
connectionDelay: options?.connectionDelay ?? ((n) => Math.min(~~(1 << n) * 150, 10_000)),
|
|
160
177
|
shouldReconnect: options?.shouldReconnect ?? (() => true),
|
|
161
178
|
messageBuffer: options?.messageBuffer ?? new FIFOMessageBuffer(),
|
|
162
179
|
};
|
|
180
|
+
this._socket = this._createSocket(url, protocols);
|
|
163
181
|
this._protocols = protocols;
|
|
164
|
-
|
|
165
|
-
this._socket = createWebSocketWithTimeout(url, this._protocols, this.reconnectOptions.connectionTimeout);
|
|
166
|
-
// Initialize the reconnection event listeners
|
|
167
|
-
this._initEventListeners();
|
|
168
|
-
// Store the original event listeners for reconnection
|
|
169
|
-
this._onclose = this._socket.onclose;
|
|
170
|
-
this._onerror = this._socket.onerror;
|
|
171
|
-
this._onmessage = this._socket.onmessage;
|
|
172
|
-
this._onopen = this._socket.onopen;
|
|
182
|
+
this._setupEventListeners();
|
|
173
183
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
this.
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
},
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
if (this._terminationController.signal.aborted)
|
|
195
|
-
return; // Check again after the await
|
|
196
|
-
if (!userDecision) {
|
|
197
|
-
this._cleanup(new ReconnectingWebSocketError("RECONNECTION_STOPPED_BY_USER"));
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
// Delay before reconnecting
|
|
201
|
-
const delay = typeof this.reconnectOptions.connectionDelay === "number"
|
|
202
|
-
? this.reconnectOptions.connectionDelay
|
|
203
|
-
: await this.reconnectOptions.connectionDelay(this._reconnectCount);
|
|
204
|
-
if (this._terminationController.signal.aborted)
|
|
205
|
-
return; // Check again after the await
|
|
206
|
-
await sleep(delay, this._terminationController.signal);
|
|
207
|
-
// Create a new WebSocket instance
|
|
208
|
-
this._socket = createWebSocketWithTimeout(this.url, this._protocols, this.reconnectOptions.connectionTimeout);
|
|
209
|
-
// Reconnect all listeners
|
|
210
|
-
this._initEventListeners();
|
|
211
|
-
this._eventListeners.forEach(({ type, listenerProxy, options }) => {
|
|
212
|
-
this._socket.addEventListener(type, listenerProxy, options);
|
|
213
|
-
});
|
|
214
|
-
this._socket.onclose = this._onclose;
|
|
215
|
-
this._socket.onerror = this._onerror;
|
|
216
|
-
this._socket.onmessage = this._onmessage;
|
|
217
|
-
this._socket.onopen = this._onopen;
|
|
218
|
-
}
|
|
219
|
-
catch (error) {
|
|
220
|
-
this._cleanup(new ReconnectingWebSocketError("UNKNOWN_ERROR", error));
|
|
221
|
-
}
|
|
222
|
-
}, { once: true });
|
|
184
|
+
_createSocket(url, protocols) {
|
|
185
|
+
const socket = new WebSocket(url, protocols);
|
|
186
|
+
if (this.reconnectOptions.connectionTimeout === null)
|
|
187
|
+
return socket;
|
|
188
|
+
const timeoutId = setTimeout(() => {
|
|
189
|
+
socket.removeEventListener("open", openHandler);
|
|
190
|
+
socket.removeEventListener("close", closeHandler);
|
|
191
|
+
socket.close(3008, "Timeout"); // https://www.iana.org/assignments/websocket/websocket.xml#close-code-number
|
|
192
|
+
}, this.reconnectOptions.connectionTimeout);
|
|
193
|
+
const openHandler = () => {
|
|
194
|
+
socket.removeEventListener("close", closeHandler);
|
|
195
|
+
clearTimeout(timeoutId);
|
|
196
|
+
};
|
|
197
|
+
const closeHandler = () => {
|
|
198
|
+
socket.removeEventListener("open", openHandler);
|
|
199
|
+
clearTimeout(timeoutId);
|
|
200
|
+
};
|
|
201
|
+
socket.addEventListener("open", openHandler, { once: true });
|
|
202
|
+
socket.addEventListener("close", closeHandler, { once: true });
|
|
203
|
+
return socket;
|
|
223
204
|
}
|
|
224
|
-
/**
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
205
|
+
/** Initializes the internal event listeners for the socket. */
|
|
206
|
+
_setupEventListeners() {
|
|
207
|
+
this._socket.addEventListener("open", this._open, { once: true });
|
|
208
|
+
this._socket.addEventListener("close", this._close, { once: true });
|
|
209
|
+
}
|
|
210
|
+
/** Clean up internal resources. */
|
|
211
|
+
_cleanup(code, error) {
|
|
212
|
+
this.reconnectAbortController.abort(new ReconnectingWebSocketError(code, error));
|
|
230
213
|
this.reconnectOptions.messageBuffer.clear();
|
|
231
|
-
this.
|
|
232
|
-
this._socket.
|
|
214
|
+
this._listeners = [];
|
|
215
|
+
this._socket.close();
|
|
233
216
|
}
|
|
234
217
|
// WebSocket property implementations
|
|
235
218
|
get url() {
|
|
@@ -258,43 +241,38 @@ export class ReconnectingWebSocket {
|
|
|
258
241
|
}
|
|
259
242
|
set onclose(value) {
|
|
260
243
|
this._socket.onclose = value;
|
|
261
|
-
this._onclose = value; // Store the listener for reconnection
|
|
262
244
|
}
|
|
263
245
|
get onerror() {
|
|
264
246
|
return this._socket.onerror;
|
|
265
247
|
}
|
|
266
248
|
set onerror(value) {
|
|
267
249
|
this._socket.onerror = value;
|
|
268
|
-
this._onerror = value; // Store the listener for reconnection
|
|
269
250
|
}
|
|
270
251
|
get onmessage() {
|
|
271
252
|
return this._socket.onmessage;
|
|
272
253
|
}
|
|
273
254
|
set onmessage(value) {
|
|
274
255
|
this._socket.onmessage = value;
|
|
275
|
-
this._onmessage = value; // Store the listener for reconnection
|
|
276
256
|
}
|
|
277
257
|
get onopen() {
|
|
278
258
|
return this._socket.onopen;
|
|
279
259
|
}
|
|
280
260
|
set onopen(value) {
|
|
281
261
|
this._socket.onopen = value;
|
|
282
|
-
this._onopen = value; // Store the listener for reconnection
|
|
283
262
|
}
|
|
284
263
|
/**
|
|
285
264
|
* @param permanently - If `true`, the connection will be permanently closed. Default is `true`.
|
|
286
265
|
*/
|
|
287
266
|
close(code, reason, permanently = true) {
|
|
288
267
|
this._socket.close(code, reason);
|
|
289
|
-
if (permanently)
|
|
290
|
-
this._cleanup(
|
|
291
|
-
}
|
|
268
|
+
if (permanently)
|
|
269
|
+
this._cleanup("USER_INITIATED_CLOSE");
|
|
292
270
|
}
|
|
293
271
|
/**
|
|
294
272
|
* @note If the connection is not open, the data will be buffered and sent when the connection is established.
|
|
295
273
|
*/
|
|
296
274
|
send(data) {
|
|
297
|
-
if (this._socket.readyState !==
|
|
275
|
+
if (this._socket.readyState !== ReconnectingWebSocket.OPEN && !this.reconnectAbortController.signal.aborted) {
|
|
298
276
|
this.reconnectOptions.messageBuffer.push(data);
|
|
299
277
|
}
|
|
300
278
|
else {
|
|
@@ -304,16 +282,16 @@ export class ReconnectingWebSocket {
|
|
|
304
282
|
addEventListener(type, listener, options) {
|
|
305
283
|
// Wrap the listener to handle reconnection
|
|
306
284
|
let listenerProxy;
|
|
307
|
-
if (this.
|
|
308
|
-
// If the
|
|
285
|
+
if (this.reconnectAbortController.signal.aborted) {
|
|
286
|
+
// If the instance is terminated, use the original listener
|
|
309
287
|
listenerProxy = listener;
|
|
310
288
|
}
|
|
311
289
|
else {
|
|
312
290
|
// Check if the listener is already registered
|
|
313
|
-
const index = this.
|
|
291
|
+
const index = this._listeners.findIndex((e) => listenersMatch(e, { type, listener, options }));
|
|
314
292
|
if (index !== -1) {
|
|
315
293
|
// Use the existing listener proxy
|
|
316
|
-
listenerProxy = this.
|
|
294
|
+
listenerProxy = this._listeners[index].listenerProxy;
|
|
317
295
|
}
|
|
318
296
|
else {
|
|
319
297
|
// Wrap the original listener to follow the once option when reconnecting
|
|
@@ -327,15 +305,16 @@ export class ReconnectingWebSocket {
|
|
|
327
305
|
}
|
|
328
306
|
}
|
|
329
307
|
finally {
|
|
308
|
+
// If the listener is marked as once, remove it after the first invocation
|
|
330
309
|
if (typeof options === "object" && options.once === true) {
|
|
331
|
-
const index = this.
|
|
310
|
+
const index = this._listeners.findIndex((e) => listenersMatch(e, { type, listener, options }));
|
|
332
311
|
if (index !== -1) {
|
|
333
|
-
this.
|
|
312
|
+
this._listeners.splice(index, 1);
|
|
334
313
|
}
|
|
335
314
|
}
|
|
336
315
|
}
|
|
337
316
|
};
|
|
338
|
-
this.
|
|
317
|
+
this._listeners.push({ type, listener, options, listenerProxy });
|
|
339
318
|
}
|
|
340
319
|
}
|
|
341
320
|
// Add the wrapped (or original) listener
|
|
@@ -343,11 +322,11 @@ export class ReconnectingWebSocket {
|
|
|
343
322
|
}
|
|
344
323
|
removeEventListener(type, listener, options) {
|
|
345
324
|
// Remove a wrapped listener, not an original listener
|
|
346
|
-
const index = this.
|
|
325
|
+
const index = this._listeners.findIndex((e) => listenersMatch(e, { type, listener, options }));
|
|
347
326
|
if (index !== -1) {
|
|
348
|
-
const { listenerProxy } = this.
|
|
327
|
+
const { listenerProxy } = this._listeners[index];
|
|
349
328
|
this._socket.removeEventListener(type, listenerProxy, options);
|
|
350
|
-
this.
|
|
329
|
+
this._listeners.splice(index, 1);
|
|
351
330
|
}
|
|
352
331
|
else {
|
|
353
332
|
// If the wrapped listener is not found, remove the original listener
|
|
@@ -358,52 +337,30 @@ export class ReconnectingWebSocket {
|
|
|
358
337
|
return this._socket.dispatchEvent(event);
|
|
359
338
|
}
|
|
360
339
|
}
|
|
361
|
-
Object.defineProperty(ReconnectingWebSocket, "
|
|
340
|
+
Object.defineProperty(ReconnectingWebSocket, "CONNECTING", {
|
|
362
341
|
enumerable: true,
|
|
363
342
|
configurable: true,
|
|
364
343
|
writable: true,
|
|
365
|
-
value:
|
|
344
|
+
value: 0
|
|
366
345
|
});
|
|
367
|
-
Object.defineProperty(ReconnectingWebSocket, "
|
|
346
|
+
Object.defineProperty(ReconnectingWebSocket, "OPEN", {
|
|
368
347
|
enumerable: true,
|
|
369
348
|
configurable: true,
|
|
370
349
|
writable: true,
|
|
371
|
-
value:
|
|
350
|
+
value: 1
|
|
372
351
|
});
|
|
373
|
-
Object.defineProperty(ReconnectingWebSocket, "
|
|
352
|
+
Object.defineProperty(ReconnectingWebSocket, "CLOSING", {
|
|
374
353
|
enumerable: true,
|
|
375
354
|
configurable: true,
|
|
376
355
|
writable: true,
|
|
377
|
-
value:
|
|
356
|
+
value: 2
|
|
378
357
|
});
|
|
379
|
-
Object.defineProperty(ReconnectingWebSocket, "
|
|
358
|
+
Object.defineProperty(ReconnectingWebSocket, "CLOSED", {
|
|
380
359
|
enumerable: true,
|
|
381
360
|
configurable: true,
|
|
382
361
|
writable: true,
|
|
383
|
-
value:
|
|
362
|
+
value: 3
|
|
384
363
|
});
|
|
385
|
-
/** Creates a WebSocket with connection timeout. */
|
|
386
|
-
function createWebSocketWithTimeout(url, protocols, timeout) {
|
|
387
|
-
const socket = new WebSocket(url, protocols);
|
|
388
|
-
if (timeout === null || timeout === undefined)
|
|
389
|
-
return socket;
|
|
390
|
-
const timeoutId = setTimeout(() => {
|
|
391
|
-
socket.removeEventListener("open", openHandler);
|
|
392
|
-
socket.removeEventListener("close", closeHandler);
|
|
393
|
-
socket.close(3008, "Timeout"); // https://www.iana.org/assignments/websocket/websocket.xml#close-code-number
|
|
394
|
-
}, timeout);
|
|
395
|
-
const openHandler = () => {
|
|
396
|
-
socket.removeEventListener("close", closeHandler);
|
|
397
|
-
clearTimeout(timeoutId);
|
|
398
|
-
};
|
|
399
|
-
const closeHandler = () => {
|
|
400
|
-
socket.removeEventListener("open", openHandler);
|
|
401
|
-
clearTimeout(timeoutId);
|
|
402
|
-
};
|
|
403
|
-
socket.addEventListener("open", openHandler, { once: true });
|
|
404
|
-
socket.addEventListener("close", closeHandler, { once: true });
|
|
405
|
-
return socket;
|
|
406
|
-
}
|
|
407
364
|
/** Check if two event listeners are the same (just like EventTarget). */
|
|
408
365
|
function listenersMatch(a, b) {
|
|
409
366
|
// EventTarget only compares capture in options, even if one is an object and the other is boolean
|
|
@@ -411,26 +368,3 @@ function listenersMatch(a, b) {
|
|
|
411
368
|
const bCapture = Boolean(typeof b.options === "object" ? b.options.capture : b.options);
|
|
412
369
|
return a.type === b.type && a.listener === b.listener && aCapture === bCapture;
|
|
413
370
|
}
|
|
414
|
-
/**
|
|
415
|
-
* Returns a promise that resolves after the specified number of ms,
|
|
416
|
-
* or rejects as soon as the given signal is aborted.
|
|
417
|
-
* @param ms - The number of ms to sleep.
|
|
418
|
-
* @param signal - An optional abort signal.
|
|
419
|
-
* @returns A promise that resolves after the specified delay.
|
|
420
|
-
*/
|
|
421
|
-
function sleep(ms, signal) {
|
|
422
|
-
if (signal?.aborted)
|
|
423
|
-
return Promise.reject(signal.reason);
|
|
424
|
-
return new Promise((resolve, reject) => {
|
|
425
|
-
const onAbort = () => {
|
|
426
|
-
clearTimeout(timer);
|
|
427
|
-
reject(signal?.reason);
|
|
428
|
-
};
|
|
429
|
-
const onTimeout = () => {
|
|
430
|
-
signal?.removeEventListener("abort", onAbort);
|
|
431
|
-
resolve();
|
|
432
|
-
};
|
|
433
|
-
const timer = setTimeout(onTimeout, ms);
|
|
434
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
435
|
-
});
|
|
436
|
-
}
|
|
@@ -41,7 +41,7 @@ export interface WebSocketTransportOptions {
|
|
|
41
41
|
reconnect?: ReconnectingWebSocketOptions;
|
|
42
42
|
}
|
|
43
43
|
/** WebSocket implementation of the REST and Subscription transport interfaces. */
|
|
44
|
-
export declare class WebSocketTransport implements IRequestTransport, ISubscriptionTransport {
|
|
44
|
+
export declare class WebSocketTransport implements IRequestTransport, ISubscriptionTransport, AsyncDisposable {
|
|
45
45
|
/** The interval timer ID for keep-alive messages. */
|
|
46
46
|
protected _keepAliveTimer: number | null;
|
|
47
47
|
/** The WebSocket request dispatcher instance. */
|
|
@@ -109,5 +109,12 @@ export declare class WebSocketTransport implements IRequestTransport, ISubscript
|
|
|
109
109
|
* @returns A promise that resolves when the connection is fully closed.
|
|
110
110
|
*/
|
|
111
111
|
close(signal?: AbortSignal): Promise<void>;
|
|
112
|
+
/**
|
|
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.
|
|
116
|
+
*/
|
|
117
|
+
protected _getCombinedTimeoutSignal(signal?: AbortSignal): AbortSignal | undefined;
|
|
118
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
112
119
|
}
|
|
113
120
|
//# 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;
|
|
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"}
|
|
@@ -107,15 +107,11 @@ export class WebSocketTransport {
|
|
|
107
107
|
* @note Explorer requests are not supported in the Hyperliquid WebSocket API.
|
|
108
108
|
*/
|
|
109
109
|
request(type, payload, signal) {
|
|
110
|
-
|
|
111
|
-
const timeoutSignal = this.timeout ? AbortSignal.timeout(this.timeout) : undefined;
|
|
112
|
-
const combinedSignal = signal && timeoutSignal
|
|
113
|
-
? AbortSignal.any([signal, timeoutSignal])
|
|
114
|
-
: signal ?? timeoutSignal;
|
|
110
|
+
const combinedTimeoutSignal = this._getCombinedTimeoutSignal(signal);
|
|
115
111
|
return this._wsRequester.request("post", {
|
|
116
112
|
type: type === "exchange" ? "action" : type,
|
|
117
113
|
payload,
|
|
118
|
-
},
|
|
114
|
+
}, combinedTimeoutSignal);
|
|
119
115
|
}
|
|
120
116
|
/**
|
|
121
117
|
* Subscribes to a Hyperliquid event channel.
|
|
@@ -132,11 +128,8 @@ export class WebSocketTransport {
|
|
|
132
128
|
let subscription = this._subscriptions.get(id);
|
|
133
129
|
if (!subscription) {
|
|
134
130
|
// Send subscription request
|
|
135
|
-
const
|
|
136
|
-
const
|
|
137
|
-
? AbortSignal.any([signal, timeoutSignal])
|
|
138
|
-
: signal ?? timeoutSignal;
|
|
139
|
-
const requestPromise = this._wsRequester.request("subscribe", payload, combinedSignal);
|
|
131
|
+
const combinedTimeoutSignal = this._getCombinedTimeoutSignal(signal);
|
|
132
|
+
const requestPromise = this._wsRequester.request("subscribe", payload, combinedTimeoutSignal);
|
|
140
133
|
// Cache subscription info
|
|
141
134
|
subscription = { listeners: new Map(), requestPromise };
|
|
142
135
|
this._subscriptions.set(id, subscription);
|
|
@@ -155,12 +148,9 @@ export class WebSocketTransport {
|
|
|
155
148
|
// Cleanup subscription
|
|
156
149
|
this._subscriptions.delete(id);
|
|
157
150
|
// If the socket is open, send unsubscription request
|
|
158
|
-
if (this.socket.readyState ===
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
? AbortSignal.any([signal, timeoutSignal])
|
|
162
|
-
: signal ?? timeoutSignal;
|
|
163
|
-
await this._wsRequester.request("unsubscribe", payload, combinedSignal);
|
|
151
|
+
if (this.socket.readyState === ReconnectingWebSocket.OPEN) {
|
|
152
|
+
const combinedTimeoutSignal = this._getCombinedTimeoutSignal(signal);
|
|
153
|
+
await this._wsRequester.request("unsubscribe", payload, combinedTimeoutSignal);
|
|
164
154
|
}
|
|
165
155
|
}
|
|
166
156
|
};
|
|
@@ -192,11 +182,11 @@ export class WebSocketTransport {
|
|
|
192
182
|
ready(signal) {
|
|
193
183
|
return new Promise((resolve, reject) => {
|
|
194
184
|
const combinedSignal = signal
|
|
195
|
-
? AbortSignal.any([this.socket.
|
|
196
|
-
: this.socket.
|
|
185
|
+
? AbortSignal.any([this.socket.reconnectAbortController.signal, signal])
|
|
186
|
+
: this.socket.reconnectAbortController.signal;
|
|
197
187
|
if (combinedSignal.aborted)
|
|
198
188
|
return reject(combinedSignal.reason);
|
|
199
|
-
if (this.socket.readyState ===
|
|
189
|
+
if (this.socket.readyState === ReconnectingWebSocket.OPEN)
|
|
200
190
|
return resolve();
|
|
201
191
|
const handleOpen = () => {
|
|
202
192
|
combinedSignal.removeEventListener("abort", handleAbort);
|
|
@@ -219,7 +209,7 @@ export class WebSocketTransport {
|
|
|
219
209
|
return new Promise((resolve, reject) => {
|
|
220
210
|
if (signal?.aborted)
|
|
221
211
|
return reject(signal.reason);
|
|
222
|
-
if (this.socket.readyState ===
|
|
212
|
+
if (this.socket.readyState === ReconnectingWebSocket.CLOSED)
|
|
223
213
|
return resolve();
|
|
224
214
|
const handleClose = () => {
|
|
225
215
|
signal?.removeEventListener("abort", handleAbort);
|
|
@@ -234,4 +224,19 @@ export class WebSocketTransport {
|
|
|
234
224
|
this.socket.close();
|
|
235
225
|
});
|
|
236
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* Combines the provided abort signal with the timeout signal.
|
|
229
|
+
* @param signal An optional abort signal.
|
|
230
|
+
* @returns A combined abort signal or undefined.
|
|
231
|
+
*/
|
|
232
|
+
_getCombinedTimeoutSignal(signal) {
|
|
233
|
+
const timeoutSignal = this.timeout ? AbortSignal.timeout(this.timeout) : undefined;
|
|
234
|
+
const combinedSignal = signal && timeoutSignal
|
|
235
|
+
? AbortSignal.any([signal, timeoutSignal])
|
|
236
|
+
: signal ?? timeoutSignal;
|
|
237
|
+
return combinedSignal;
|
|
238
|
+
}
|
|
239
|
+
async [Symbol.asyncDispose]() {
|
|
240
|
+
await this.close();
|
|
241
|
+
}
|
|
237
242
|
}
|