solana-traderclaw 1.0.124 → 1.0.126

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.
@@ -1,7 +1,10 @@
1
1
  // src/alpha-ws.ts
2
- var RECONNECT_DELAYS = [1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
2
+ var RECONNECT_DELAYS_MS = [1e3, 2e3, 4e3, 8e3, 16e3, 3e4];
3
3
  var PING_INTERVAL_MS = 3e4;
4
4
  var PONG_TIMEOUT_MS = 1e4;
5
+ var CIRCUIT_UNHEALTHY_THRESHOLD = 12;
6
+ var CIRCUIT_BACKOFF_MS = 3e5;
7
+ var ERROR_LOG_THROTTLE_MS = 6e4;
5
8
  var ALPHA_INGESTION_STALE_MS = 20 * 60 * 1e3;
6
9
  var ALPHA_STALE_GRACE_AFTER_CONNECT_MS = 3 * 60 * 1e3;
7
10
  var AlphaStreamManager = class {
@@ -10,6 +13,8 @@ var AlphaStreamManager = class {
10
13
  subscribed = false;
11
14
  authenticated = false;
12
15
  reconnectAttempt = 0;
16
+ /** Closes where we were not in subscribed state (e.g. handshake failures) — drives circuit backoff. */
17
+ unhealthyStreak = 0;
13
18
  reconnectTimer = null;
14
19
  intentionalClose = false;
15
20
  messageCount = 0;
@@ -18,6 +23,7 @@ var AlphaStreamManager = class {
18
23
  tier = "";
19
24
  premiumAccess = false;
20
25
  currentAccessToken = "";
26
+ lastErrorLogAt = /* @__PURE__ */ new Map();
21
27
  constructor(config) {
22
28
  this.config = config;
23
29
  }
@@ -104,6 +110,8 @@ var AlphaStreamManager = class {
104
110
  async unsubscribe() {
105
111
  this.intentionalClose = true;
106
112
  this.subscribed = false;
113
+ this.unhealthyStreak = 0;
114
+ this.reconnectAttempt = 0;
107
115
  if (this.reconnectTimer) {
108
116
  clearTimeout(this.reconnectTimer);
109
117
  this.reconnectTimer = null;
@@ -138,7 +146,10 @@ var AlphaStreamManager = class {
138
146
  messageCount: this.messageCount,
139
147
  lastEventTs: this.lastEventTs,
140
148
  connectedAt: this.connectedAt,
141
- uptimeSeconds: this.connectedAt ? Math.floor((Date.now() - this.connectedAt) / 1e3) : 0
149
+ uptimeSeconds: this.connectedAt ? Math.floor((Date.now() - this.connectedAt) / 1e3) : 0,
150
+ reconnectAttempt: this.reconnectAttempt,
151
+ unhealthyStreak: this.unhealthyStreak,
152
+ circuitBackoff: this.unhealthyStreak >= CIRCUIT_UNHEALTHY_THRESHOLD
142
153
  };
143
154
  }
144
155
  sendAlphaSubscribe() {
@@ -221,16 +232,22 @@ var AlphaStreamManager = class {
221
232
  this.ws.on("close", () => {
222
233
  clearTimeout(connectTimeout);
223
234
  clearKeepalive();
235
+ const wasHealthy = this.subscribed;
224
236
  this.subscribed = false;
225
237
  this.authenticated = false;
226
238
  this.log("info", "WebSocket closed");
227
239
  if (!this.intentionalClose) {
240
+ if (wasHealthy) {
241
+ this.unhealthyStreak = 0;
242
+ } else {
243
+ this.unhealthyStreak++;
244
+ }
228
245
  this.scheduleReconnect();
229
246
  }
230
247
  });
231
248
  this.ws.on("error", (err) => {
232
249
  clearTimeout(connectTimeout);
233
- this.log("error", `WebSocket error: ${err.message}`);
250
+ this.logThrottledError(`ws:${err.message}`, `WebSocket error: ${err.message}`);
234
251
  if (this.ws && this.ws.readyState !== 1) {
235
252
  reject(err);
236
253
  }
@@ -257,6 +274,7 @@ var AlphaStreamManager = class {
257
274
  break;
258
275
  case "alpha_stream_subscribed":
259
276
  this.subscribed = true;
277
+ this.unhealthyStreak = 0;
260
278
  this.tier = msg.tier || this.tier;
261
279
  this.premiumAccess = msg.premiumAccess || false;
262
280
  this.log("info", `Subscribed to alpha stream: tier=${this.tier}, premium=${this.premiumAccess}`);
@@ -308,18 +326,46 @@ var AlphaStreamManager = class {
308
326
  }
309
327
  scheduleReconnect() {
310
328
  if (this.intentionalClose) return;
311
- const delay = RECONNECT_DELAYS[Math.min(this.reconnectAttempt, RECONNECT_DELAYS.length - 1)];
329
+ if (this.reconnectTimer) {
330
+ clearTimeout(this.reconnectTimer);
331
+ this.reconnectTimer = null;
332
+ }
333
+ const idx = Math.min(this.reconnectAttempt, RECONNECT_DELAYS_MS.length - 1);
334
+ let delay = RECONNECT_DELAYS_MS[idx];
335
+ if (this.unhealthyStreak >= CIRCUIT_UNHEALTHY_THRESHOLD) {
336
+ delay = Math.max(delay, CIRCUIT_BACKOFF_MS);
337
+ }
312
338
  this.reconnectAttempt++;
313
- this.log("info", `Reconnecting in ${delay}ms (attempt ${this.reconnectAttempt})`);
339
+ if (this.shouldLogReconnectPlan()) {
340
+ const circuitNote = this.unhealthyStreak >= CIRCUIT_UNHEALTHY_THRESHOLD ? ` (circuit: ${Math.round(CIRCUIT_BACKOFF_MS / 1e3)}s backoff \u2014 orchestrator path unhealthy)` : "";
341
+ this.log("info", `Reconnecting in ${delay}ms (attempt ${this.reconnectAttempt}, unhealthyStreak=${this.unhealthyStreak})${circuitNote}`);
342
+ }
314
343
  this.reconnectTimer = setTimeout(async () => {
344
+ this.reconnectTimer = null;
315
345
  try {
316
346
  await this.connect();
317
347
  } catch (err) {
318
- this.log("error", `Reconnect failed: ${err instanceof Error ? err.message : String(err)}`);
319
- this.scheduleReconnect();
348
+ this.logThrottledError(
349
+ "reconnect-failed",
350
+ `Reconnect failed: ${err instanceof Error ? err.message : String(err)}`
351
+ );
320
352
  }
321
353
  }, delay);
322
354
  }
355
+ /** Reduce log spam when wedged (CPU + disk heavy with JSON file logging). */
356
+ shouldLogReconnectPlan() {
357
+ const n = this.reconnectAttempt;
358
+ if (n <= 3) return true;
359
+ if (n <= 30 && n % 5 === 0) return true;
360
+ return n % 25 === 0;
361
+ }
362
+ logThrottledError(key, msg) {
363
+ const now = Date.now();
364
+ const last = this.lastErrorLogAt.get(key) ?? 0;
365
+ if (now - last < ERROR_LOG_THROTTLE_MS) return;
366
+ this.lastErrorLogAt.set(key, now);
367
+ this.log("error", msg);
368
+ }
323
369
  log(level, msg) {
324
370
  if (this.config.logger) {
325
371
  this.config.logger[level](`[alpha-stream] ${msg}`);
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  } from "./chunk-3UQIQJPQ.js";
19
19
  import {
20
20
  AlphaStreamManager
21
- } from "./chunk-KNJVODJC.js";
21
+ } from "./chunk-ZUY36F4Q.js";
22
22
  import {
23
23
  BitqueryStreamManager
24
24
  } from "./chunk-S2DLZKMQ.js";
@@ -2,7 +2,7 @@ import {
2
2
  ALPHA_INGESTION_STALE_MS,
3
3
  ALPHA_STALE_GRACE_AFTER_CONNECT_MS,
4
4
  AlphaStreamManager
5
- } from "../chunk-KNJVODJC.js";
5
+ } from "../chunk-ZUY36F4Q.js";
6
6
  export {
7
7
  ALPHA_INGESTION_STALE_MS,
8
8
  ALPHA_STALE_GRACE_AFTER_CONNECT_MS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "solana-traderclaw",
3
- "version": "1.0.124",
3
+ "version": "1.0.126",
4
4
  "description": "TraderClaw V1-Upgraded — Solana trading for OpenClaw with intelligence lab, tool envelopes, prompt scrubbing, read-only X social intel, and split skill docs",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",