@rabby-wallet/hyperliquid-sdk 1.0.1 → 1.0.3

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.
@@ -18,8 +18,10 @@ export declare class WebSocketClient {
18
18
  private readonly url;
19
19
  private readonly config;
20
20
  private subscriptions;
21
+ private activeSubscriptions;
21
22
  private reconnectAttempts;
22
23
  private isConnecting;
24
+ private isManualDisconnect;
23
25
  private pendingSubscriptions;
24
26
  private heartbeatInterval;
25
27
  private readonly HEARTBEAT_INTERVAL;
@@ -90,4 +92,12 @@ export declare class WebSocketClient {
90
92
  * Get current connection state
91
93
  */
92
94
  get readyState(): number;
95
+ /**
96
+ * Get list of active subscription types
97
+ */
98
+ getActiveSubscriptions(): string[];
99
+ /**
100
+ * Reset reconnection attempts and enable auto-reconnect
101
+ */
102
+ resetReconnectState(): void;
93
103
  }
@@ -18,8 +18,10 @@ class WebSocketClient {
18
18
  constructor(config) {
19
19
  this.ws = null;
20
20
  this.subscriptions = new Map();
21
+ this.activeSubscriptions = new Map();
21
22
  this.reconnectAttempts = 0;
22
23
  this.isConnecting = false;
24
+ this.isManualDisconnect = false; // 标记是否为主动断开连接
23
25
  this.pendingSubscriptions = [];
24
26
  this.heartbeatInterval = null;
25
27
  this.HEARTBEAT_INTERVAL = 50000; // 50秒发送一次心跳,小于60秒超时
@@ -67,6 +69,7 @@ class WebSocketClient {
67
69
  this.ws.onopen = () => {
68
70
  this.isConnecting = false;
69
71
  this.reconnectAttempts = 0;
72
+ this.isManualDisconnect = false; // 重置手动断开标志
70
73
  console.log('hyperliquid sdk WebSocket connected');
71
74
  // Start heartbeat
72
75
  this.startHeartbeat();
@@ -75,10 +78,12 @@ class WebSocketClient {
75
78
  var _a;
76
79
  if (((_a = this.ws) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN) {
77
80
  this.subscriptions.set(message.subscription.type, callback);
81
+ this.activeSubscriptions.set(message.subscription.type, { message, callback });
78
82
  this.ws.send(JSON.stringify(Object.assign(Object.assign({}, message), { method: 'subscribe' })));
79
83
  }
80
84
  });
81
85
  this.pendingSubscriptions = [];
86
+ console.log(`Resubscribed to ${this.activeSubscriptions.size} channels after reconnection`);
82
87
  resolve();
83
88
  };
84
89
  this.ws.onmessage = (event) => {
@@ -104,10 +109,28 @@ class WebSocketClient {
104
109
  console.log('WebSocket disconnected');
105
110
  // Stop heartbeat
106
111
  this.stopHeartbeat();
107
- if (this.config.autoReconnect && this.reconnectAttempts < this.config.maxReconnectAttempts) {
108
- this.reconnectAttempts++;
109
- console.log(`Reconnecting... (${this.reconnectAttempts}/${this.config.maxReconnectAttempts})`);
110
- setTimeout(() => this.connect(), this.config.reconnectDelay);
112
+ // Only attempt reconnection if it's not a manual disconnect
113
+ if (!this.isManualDisconnect && this.config.autoReconnect) {
114
+ // Save current active subscriptions to pending for reconnection
115
+ if (this.activeSubscriptions.size > 0) {
116
+ this.activeSubscriptions.forEach((subscription, type) => {
117
+ const existingPending = this.pendingSubscriptions.find(sub => sub.message.subscription.type === type);
118
+ if (!existingPending) {
119
+ this.pendingSubscriptions.push(subscription);
120
+ }
121
+ });
122
+ }
123
+ if (this.reconnectAttempts < this.config.maxReconnectAttempts) {
124
+ this.reconnectAttempts++;
125
+ console.log(`Reconnecting... (${this.reconnectAttempts}/${this.config.maxReconnectAttempts})`);
126
+ setTimeout(() => this.connect(), this.config.reconnectDelay);
127
+ }
128
+ else {
129
+ console.error('Max reconnection attempts reached. Connection failed.');
130
+ }
131
+ }
132
+ else if (this.isManualDisconnect) {
133
+ this.isManualDisconnect = false; // Reset flag
111
134
  }
112
135
  };
113
136
  this.ws.onerror = (error) => {
@@ -144,26 +167,31 @@ class WebSocketClient {
144
167
  * Disconnect from the WebSocket
145
168
  */
146
169
  disconnect() {
170
+ this.isManualDisconnect = true; // 标记为主动断开
147
171
  this.stopHeartbeat();
148
172
  if (this.ws) {
149
173
  this.ws.close();
150
174
  this.ws = null;
151
175
  }
152
176
  this.subscriptions.clear();
177
+ this.activeSubscriptions.clear();
153
178
  this.pendingSubscriptions = [];
179
+ this.reconnectAttempts = 0; // 重置重连计数
154
180
  }
155
181
  /**
156
182
  * Subscribe to a channel
157
183
  */
158
184
  subscribe(message, callback) {
159
185
  var _a;
186
+ const subscriptionData = { message, callback };
160
187
  if (((_a = this.ws) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN) {
161
188
  this.subscriptions.set(message.subscription.type, callback);
189
+ this.activeSubscriptions.set(message.subscription.type, subscriptionData);
162
190
  this.ws.send(JSON.stringify(Object.assign(Object.assign({}, message), { method: 'subscribe' })));
163
191
  }
164
192
  else {
165
193
  // Store pending subscription for when connection is established
166
- this.pendingSubscriptions.push({ message, callback });
194
+ this.pendingSubscriptions.push(subscriptionData);
167
195
  // Auto-connect if not connected
168
196
  if (!this.isConnecting && (!this.ws || this.ws.readyState === WebSocket.CLOSED)) {
169
197
  this.connect().catch(console.error);
@@ -172,12 +200,14 @@ class WebSocketClient {
172
200
  return {
173
201
  unsubscribe: () => {
174
202
  var _a;
175
- this.subscriptions.delete(message.subscription.type);
203
+ const type = message.subscription.type;
204
+ this.subscriptions.delete(type);
205
+ this.activeSubscriptions.delete(type);
176
206
  if (((_a = this.ws) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN) {
177
207
  this.ws.send(JSON.stringify(Object.assign(Object.assign({}, message), { method: 'unsubscribe' })));
178
208
  }
179
209
  // Remove from pending subscriptions
180
- this.pendingSubscriptions = this.pendingSubscriptions.filter(sub => sub.message.subscription.type !== message.subscription.type);
210
+ this.pendingSubscriptions = this.pendingSubscriptions.filter(sub => sub.message.subscription.type !== type);
181
211
  },
182
212
  };
183
213
  }
@@ -280,5 +310,18 @@ class WebSocketClient {
280
310
  var _a, _b;
281
311
  return (_b = (_a = this.ws) === null || _a === void 0 ? void 0 : _a.readyState) !== null && _b !== void 0 ? _b : WebSocket.CLOSED;
282
312
  }
313
+ /**
314
+ * Get list of active subscription types
315
+ */
316
+ getActiveSubscriptions() {
317
+ return Array.from(this.activeSubscriptions.keys());
318
+ }
319
+ /**
320
+ * Reset reconnection attempts and enable auto-reconnect
321
+ */
322
+ resetReconnectState() {
323
+ this.reconnectAttempts = 0;
324
+ this.isManualDisconnect = false;
325
+ }
283
326
  }
284
327
  exports.WebSocketClient = WebSocketClient;
@@ -322,13 +322,12 @@ export interface ActiveAssetData {
322
322
  markPx: string;
323
323
  }
324
324
  export interface WebData2 {
325
- assetPositions: AssetPosition[];
326
- marginSummary: MarginSummary;
327
- crossMarginSummary: MarginSummary;
328
- crossMaintenanceMarginUsed: string;
325
+ clearinghouseState: ClearinghouseState;
326
+ assetCtxs: AssetCtx[];
327
+ meta: Meta;
329
328
  openOrders: WsOrder[];
330
- totalNtlPos: string;
331
- time: number;
329
+ serverTime: number;
330
+ user: string;
332
331
  }
333
332
  export interface FeeResponse {
334
333
  userCrossRate: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rabby-wallet/hyperliquid-sdk",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Simplified Hyperliquid Perpetuals Trading SDK for Frontend Applications",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",