@thingd/cli 0.49.5 → 0.49.7

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.
@@ -51,6 +51,7 @@ export type ThingdClusterStatus = {
51
51
  peers: string[];
52
52
  leaderElection: boolean;
53
53
  electionMaxFailures: number;
54
+ consecutiveFailures: number;
54
55
  replication: {
55
56
  lastReplicatedSequence: number;
56
57
  status: string;
@@ -59,7 +60,7 @@ export type ThingdClusterStatus = {
59
60
  };
60
61
  export declare function readClusterOptionsFromEnv(env: Record<string, string | undefined>): ThingdClusterOptions;
61
62
  export declare function resolveClusterOptions(options: ThingdClusterOptions | undefined): ResolvedThingdClusterOptions;
62
- export declare function getClusterStatus(cluster: ResolvedThingdClusterOptions, db: ThingD): Promise<ThingdClusterStatus>;
63
+ export declare function getClusterStatus(cluster: ResolvedThingdClusterOptions, db: ThingD, consecutiveFailures?: number): Promise<ThingdClusterStatus>;
63
64
  export declare function forwardMcpRequestToLeader(cluster: ResolvedThingdClusterOptions, mcpPath: string, request: IncomingMessage, response: ServerResponse): Promise<void>;
64
65
  export declare function findNextLeaderCandidate(cluster: ResolvedThingdClusterOptions): {
65
66
  url: string;
@@ -1 +1 @@
1
- {"version":3,"file":"cluster.d.ts","sourceRoot":"","sources":["../../src/mcp/cluster.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAG1C,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;AACjE,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG,QAAQ,GAAG,YAAY,CAAC;AAEtE,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,+EAA+E;IAC/E,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IACzC,IAAI,EAAE,iBAAiB,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,sBAAsB,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,wFAAwF;IACxF,oBAAoB,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,sBAAsB,CAAC;IAClC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,cAAc,EAAE,OAAO,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,WAAW,EACP;QACE,sBAAsB,EAAE,MAAM,CAAC;QAC/B,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,GACD,iBAAiB,CAAC;CACvB,CAAC;AAIF,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACtC,oBAAoB,CAkBtB;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,oBAAoB,GAAG,SAAS,GACxC,4BAA4B,CA0C9B;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,4BAA4B,EACrC,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,mBAAmB,CAAC,CAiD9B;AAED,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,4BAA4B,EACrC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC,CAsCf;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,4BAA4B,GACpC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,CA+B9C"}
1
+ {"version":3,"file":"cluster.d.ts","sourceRoot":"","sources":["../../src/mcp/cluster.ts"],"names":[],"mappings":"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"}
@@ -55,7 +55,7 @@ export function resolveClusterOptions(options) {
55
55
  cachedReplicationLag: 0,
56
56
  };
57
57
  }
58
- export async function getClusterStatus(cluster, db) {
58
+ export async function getClusterStatus(cluster, db, consecutiveFailures = 0) {
59
59
  let replication = "not-implemented";
60
60
  if (cluster.mode === "follower") {
61
61
  try {
@@ -101,6 +101,7 @@ export async function getClusterStatus(cluster, db) {
101
101
  peers: cluster.peers,
102
102
  leaderElection: cluster.leaderElection,
103
103
  electionMaxFailures: cluster.electionMaxFailures,
104
+ consecutiveFailures,
104
105
  replication,
105
106
  };
106
107
  }
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/mcp/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,MAAM,EAAuB,MAAM,WAAW,CAAC;AAGjG,OAAO,EAKL,KAAK,qBAAqB,EAC1B,KAAK,yBAAyB,EAC/B,MAAM,aAAa,CAAC;AACrB,OAAO,EAML,KAAK,oBAAoB,EAC1B,MAAM,cAAc,CAAC;AACtB,OAAO,EAA2B,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEhF,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,KAAK,CAAC,EAAE,qBAAqB,GAAG,KAAK,CAAC;IACtC,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,yBAAyB,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB,CAAC;AAkBF,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,uBAAuB,CAAC,CAqDlC"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/mcp/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,MAAM,EAAuB,MAAM,WAAW,CAAC;AAGjG,OAAO,EAKL,KAAK,qBAAqB,EAC1B,KAAK,yBAAyB,EAC/B,MAAM,aAAa,CAAC;AACrB,OAAO,EAML,KAAK,oBAAoB,EAC1B,MAAM,cAAc,CAAC;AACtB,OAAO,EAA2B,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEhF,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,KAAK,CAAC,EAAE,qBAAqB,GAAG,KAAK,CAAC;IACtC,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,yBAAyB,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB,CAAC;AAmBF,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,uBAAuB,CAAC,CAqDlC"}
package/dist/mcp/http.js CHANGED
@@ -150,7 +150,7 @@ async function handleHealth(state, request, response) {
150
150
  });
151
151
  return;
152
152
  }
153
- const status = await getClusterStatus(state.cluster, state.db);
153
+ const status = await getClusterStatus(state.cluster, state.db, state.consecutiveReplicationFailures);
154
154
  writeJson(response, 200, {
155
155
  ok: true,
156
156
  service: "thingd-mcp",
@@ -167,7 +167,7 @@ async function handleClusterStatus(state, request, response) {
167
167
  });
168
168
  return;
169
169
  }
170
- const status = await getClusterStatus(state.cluster, state.db);
170
+ const status = await getClusterStatus(state.cluster, state.db, state.consecutiveReplicationFailures);
171
171
  writeJson(response, 200, status, request.method === "HEAD");
172
172
  }
173
173
  function handleClusterPeers(state, request, response) {
@@ -384,9 +384,12 @@ function startReplicationRunner(state) {
384
384
  if (!leaderUrl) {
385
385
  return;
386
386
  }
387
- const pullInterval = 500;
387
+ const pullInterval = parseInt(process.env.THINGD_CLUSTER_REPLICATION_INTERVAL_MS ?? "500", 10);
388
+ const abort = new AbortController();
389
+ state.replicationAbort = abort;
390
+ const signal = abort.signal;
388
391
  async function runSync() {
389
- if (state.replicationStopped) {
392
+ if (signal.aborted || state.replicationStopped) {
390
393
  return;
391
394
  }
392
395
  const status = await state.db.get("__thingd_meta", "replication_status");
@@ -395,7 +398,7 @@ function startReplicationRunner(state) {
395
398
  : 0;
396
399
  let fetched = false;
397
400
  for (const url of resolveLeaderUrls(state.cluster)) {
398
- if (state.replicationStopped) {
401
+ if (signal.aborted || state.replicationStopped) {
399
402
  return;
400
403
  }
401
404
  try {
@@ -418,7 +421,7 @@ function startReplicationRunner(state) {
418
421
  const resData = (await response.json());
419
422
  if (resData.success && Array.isArray(resData.events) && resData.events.length > 0) {
420
423
  for (const ev of resData.events) {
421
- if (state.replicationStopped) {
424
+ if (signal.aborted || state.replicationStopped) {
422
425
  return;
423
426
  }
424
427
  const type = ev.type;
@@ -458,14 +461,22 @@ function startReplicationRunner(state) {
458
461
  break;
459
462
  }
460
463
  catch (error) {
461
- console.error(`Replication from ${url} failed:`, error instanceof Error ? error.message : String(error));
464
+ // Log replication failures periodically (once per electionMaxFailures)
465
+ // to avoid flooding logs when the leader is unreachable.
466
+ if (state.consecutiveReplicationFailures % state.cluster.electionMaxFailures === 0) {
467
+ console.error(`Replication from ${url} failed:`, error instanceof Error ? error.message : String(error));
468
+ }
462
469
  }
463
470
  }
464
- if (state.replicationStopped) {
471
+ if (signal.aborted || state.replicationStopped) {
465
472
  return;
466
473
  }
467
474
  if (!fetched) {
468
475
  state.consecutiveReplicationFailures++;
476
+ // Print "All leader URLs exhausted" only once per failure threshold
477
+ if (state.consecutiveReplicationFailures === state.cluster.electionMaxFailures) {
478
+ console.error("All leader URLs exhausted for replication");
479
+ }
469
480
  if (state.cluster.leaderElection &&
470
481
  state.consecutiveReplicationFailures >= state.cluster.electionMaxFailures) {
471
482
  state.consecutiveReplicationFailures = 0;
@@ -476,14 +487,11 @@ function startReplicationRunner(state) {
476
487
  }
477
488
  // leaderUrl was updated by failover; retry immediately.
478
489
  }
479
- else {
480
- console.error("All leader URLs exhausted for replication");
481
- }
482
490
  }
483
491
  else {
484
492
  state.consecutiveReplicationFailures = 0;
485
493
  }
486
- if (!state.replicationStopped) {
494
+ if (!signal.aborted && !state.replicationStopped) {
487
495
  state.replicationTimer = setTimeout(() => {
488
496
  void runSync();
489
497
  }, pullInterval);
@@ -494,6 +502,7 @@ function startReplicationRunner(state) {
494
502
  }, pullInterval);
495
503
  }
496
504
  function stopReplicationRunner(state) {
505
+ state.replicationAbort?.abort();
497
506
  state.replicationStopped = true;
498
507
  if (state.replicationTimer) {
499
508
  clearTimeout(state.replicationTimer);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thingd/cli",
3
- "version": "0.49.5",
3
+ "version": "0.49.7",
4
4
  "description": "CLI, Interactive TUI Dashboard, and MCP server for thingd — a fast object-first data engine for applications and AI agents.",
5
5
  "type": "module",
6
6
  "homepage": "https://engine.thingd.cloud",
@@ -45,7 +45,7 @@
45
45
  "cli-table3": "^0.6.5",
46
46
  "picocolors": "^1.1.1",
47
47
  "zod": "^4.4.3",
48
- "@thingd/sdk": "0.49.5"
48
+ "@thingd/sdk": "0.49.7"
49
49
  },
50
50
  "engines": {
51
51
  "node": ">=24.0.0"