@camstack/server 1.1.64 → 1.1.65

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.
@@ -78,9 +78,12 @@ const AGENT_BOOTSTRAP_PACKAGES = new Set([
78
78
  * nodes — excluded, same rule as `listNodes()` / `classifyNode`.
79
79
  */
80
80
  function toNodeLiveness(nodes) {
81
- return nodes
82
- .filter((node) => !node.id.includes('/'))
83
- .map((node) => ({ id: node.id, isHub: node.id === 'hub', isOnline: node.available }));
81
+ return (nodes
82
+ // A Moleculer registry can transiently hold a malformed entry with no id
83
+ // (seen live 2026-07-16 after agent churn): guard it or every consumer of
84
+ // this projection 500s on `undefined.includes`.
85
+ .filter((node) => typeof node.id === 'string' && !node.id.includes('/'))
86
+ .map((node) => ({ id: node.id, isHub: node.id === 'hub', isOnline: node.available })));
84
87
  }
85
88
  /**
86
89
  * Project a live `AgentListItem` into the durable history descriptor. Field
@@ -269,7 +272,9 @@ class AgentRegistryService {
269
272
  async reconcileConnectedAgents() {
270
273
  const registry = this.moleculer.broker.registry;
271
274
  const nodes = registry?.getNodeList?.({ onlyAvailable: true }) ?? [];
272
- const agentIds = nodes.map((n) => n.id).filter((id) => id !== 'hub' && !id.includes('/'));
275
+ const agentIds = nodes
276
+ .map((n) => n.id)
277
+ .filter((id) => typeof id === 'string' && id !== 'hub' && !id.includes('/'));
273
278
  if (agentIds.length === 0)
274
279
  return;
275
280
  console.log(`[agent-registry] Boot reconcile: ${agentIds.length} connected agent(s)`);
@@ -468,8 +473,10 @@ class AgentRegistryService {
468
473
  const nodes = registry?.getNodeList?.({ onlyAvailable: false }) ?? [];
469
474
  for (const node of nodes) {
470
475
  const nodeId = node.id;
471
- // Skip hub (already included) and child processes (contain '/')
472
- if (nodeId === 'hub' || nodeId.includes('/'))
476
+ // Skip hub (already included), child processes (contain '/'), and
477
+ // malformed registry entries with no id (live 2026-07-16: one such
478
+ // ghost 500'd nodes.topology — the whole Cluster page — until restart).
479
+ if (typeof nodeId !== 'string' || nodeId === 'hub' || nodeId.includes('/'))
473
480
  continue;
474
481
  if (!node.available) {
475
482
  // Offline: skip the `$agent.status`/`$process.list` RPC fan-out
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/server",
3
- "version": "1.1.64",
3
+ "version": "1.1.65",
4
4
  "private": false,
5
5
  "files": [
6
6
  "dist",