@camstack/agent 1.0.7 → 1.0.8

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/dist/cli.mjs CHANGED
@@ -2,7 +2,7 @@
2
2
  import { createRequire as __cr } from 'node:module'; const require = globalThis.require ?? __cr(import.meta.url);
3
3
  import {
4
4
  startAgent
5
- } from "./chunk-GM2IV7NO.mjs";
5
+ } from "./chunk-U6SD2QE6.mjs";
6
6
 
7
7
  // src/cli.ts
8
8
  import * as os from "os";
package/dist/index.d.ts CHANGED
@@ -80,6 +80,20 @@ declare function createAgentService(deps: AgentServiceDeps): ServiceSchema;
80
80
 
81
81
  declare function startAgent(configPath?: string): Promise<void>;
82
82
 
83
+ /**
84
+ * Discriminated hub connection state surfaced by the agent status API.
85
+ *
86
+ * - `connected` — hub node is in the Moleculer registry (available).
87
+ * - `searching` — discovery mode active, no hub found yet.
88
+ * - `disconnected` — direct address configured but hub not in registry.
89
+ * - `secret-mismatch`— `$hub.registerNode` was rejected with a cluster-secret error.
90
+ *
91
+ * `registering` (transport up but registerNode not yet acked) is not
92
+ * currently deterministic from the broker registry alone — it would require
93
+ * a tighter integration with the retry loop. Omitted until a clean signal
94
+ * exists; the brief gap is invisible at 3 s poll rate.
95
+ */
96
+ type HubConnectionState = 'connected' | 'searching' | 'disconnected' | 'secret-mismatch';
83
97
  interface AgentHttpConfig {
84
98
  readonly port: number;
85
99
  readonly nodeId: string;
@@ -87,6 +101,14 @@ interface AgentHttpConfig {
87
101
  readonly configPath: string;
88
102
  /** Called when the UI requests a reconnect (hub/secret changed). */
89
103
  readonly onReconnect?: () => Promise<void>;
104
+ /**
105
+ * Optional getter for the current hub connection state. When provided,
106
+ * the status endpoint uses this to surface a richer discriminated state
107
+ * instead of the legacy boolean `hubConnected`. The bootstrap wires this
108
+ * to expose `secret-mismatch` which is not derivable from the broker
109
+ * registry alone.
110
+ */
111
+ readonly getHubConnectionState?: () => HubConnectionState;
90
112
  }
91
113
  declare function createAgentHttpServer(getBroker: () => ServiceBroker, config: AgentHttpConfig): Promise<FastifyInstance>;
92
114
  declare function startAgentHttpServer(getBroker: () => ServiceBroker, config: AgentHttpConfig): Promise<void>;
package/dist/index.js CHANGED
@@ -554,6 +554,12 @@ function getRegistryNodes(broker) {
554
554
  return [];
555
555
  }
556
556
  }
557
+ function deriveHubConnectionState(nodes, discoveryMode) {
558
+ const hubInRegistry = nodes.some((n) => n.id === "hub");
559
+ if (hubInRegistry) return "connected";
560
+ if (discoveryMode) return "searching";
561
+ return "disconnected";
562
+ }
557
563
  function getEffectiveConfig(configPath, nodeId) {
558
564
  const raw = readConfigFile(configPath);
559
565
  return {
@@ -585,6 +591,7 @@ async function createAgentHttpServer(getBroker, config) {
585
591
  const nodes = getRegistryNodes(broker);
586
592
  const hubConnected = nodes.some((n) => n.id === "hub");
587
593
  const discoveryMode = !eff.hubAddress;
594
+ const hubConnectionState = config.getHubConnectionState ? config.getHubConnectionState() : deriveHubConnectionState(nodes, discoveryMode);
588
595
  try {
589
596
  const status = await broker.call("$agent.status");
590
597
  return {
@@ -592,6 +599,7 @@ async function createAgentHttpServer(getBroker, config) {
592
599
  name: eff.name,
593
600
  hubAddress: eff.hubAddress,
594
601
  hubConnected,
602
+ hubConnectionState,
595
603
  discoveryMode,
596
604
  hasSecret: eff.hasSecret,
597
605
  discoveredNodes: nodes.filter((n) => n.id !== broker.nodeID).map((n) => n.id)
@@ -602,6 +610,7 @@ async function createAgentHttpServer(getBroker, config) {
602
610
  name: eff.name,
603
611
  hubAddress: eff.hubAddress,
604
612
  hubConnected,
613
+ hubConnectionState,
605
614
  discoveryMode,
606
615
  hasSecret: eff.hasSecret,
607
616
  discoveredNodes: [],
@@ -814,7 +823,7 @@ function narrowParams(raw) {
814
823
  deviceId: typeof deviceId === "number" ? deviceId : void 0
815
824
  };
816
825
  }
817
- function createAgentCapDispatchService(agentNodeId, agentUdsRegistry, logger) {
826
+ function createAgentCapDispatchService(agentNodeId, agentUdsRegistry, inProcessLookup, logger) {
818
827
  return {
819
828
  name: import_system2.AGENT_CAP_FWD_SERVICE,
820
829
  actions: {
@@ -824,11 +833,15 @@ function createAgentCapDispatchService(agentNodeId, agentUdsRegistry, logger) {
824
833
  const { capName, method, args, deviceId } = params;
825
834
  const childId = params.childId !== void 0 ? params.childId : agentUdsRegistry.resolveChildId(capName, deviceId);
826
835
  if (childId == null) {
836
+ const ref = inProcessLookup?.(capName) ?? null;
837
+ if (ref !== null) {
838
+ return ref.invoke(method, args);
839
+ }
827
840
  logger?.info(
828
- `agent ${agentNodeId}: no UDS child for cap "${capName}"${deviceId !== void 0 ? ` (deviceId ${deviceId})` : ""}`
841
+ `agent ${agentNodeId}: no provider for cap "${capName}"${deviceId !== void 0 ? ` (deviceId ${deviceId})` : ""}`
829
842
  );
830
843
  throw new Error(
831
- `agent ${agentNodeId} has no UDS child for cap "${capName}"${deviceId !== void 0 ? ` (deviceId ${deviceId})` : ""}`
844
+ `agent ${agentNodeId} has no provider for cap "${capName}"${deviceId !== void 0 ? ` (deviceId ${deviceId})` : ""}`
832
845
  );
833
846
  }
834
847
  const input = {
@@ -845,9 +858,11 @@ function createAgentCapDispatchService(agentNodeId, agentUdsRegistry, logger) {
845
858
  }
846
859
 
847
860
  // src/register-agent-cap-dispatch.ts
848
- function registerAgentCapDispatch(registrar, agentUdsRegistry, logger) {
861
+ function registerAgentCapDispatch(registrar, agentUdsRegistry, inProcessLookup, logger) {
849
862
  if (agentUdsRegistry === void 0) return;
850
- registrar.createService(createAgentCapDispatchService(registrar.nodeID, agentUdsRegistry, logger));
863
+ registrar.createService(
864
+ createAgentCapDispatchService(registrar.nodeID, agentUdsRegistry, inProcessLookup, logger)
865
+ );
851
866
  }
852
867
 
853
868
  // src/agent-bootstrap.ts
@@ -913,6 +928,27 @@ async function startAgent(configPath) {
913
928
  };
914
929
  const loadedAddons = /* @__PURE__ */ new Map();
915
930
  const subtree = new import_system3.HubNodeRegistry();
931
+ let hubConnectionStateOverride = null;
932
+ function getHubConnectionState() {
933
+ if (hubConnectionStateOverride !== null) return hubConnectionStateOverride;
934
+ try {
935
+ const registry = broker.registry;
936
+ const nodes = registry?.getNodeList?.({ onlyAvailable: true }) ?? [];
937
+ if (nodes.some((n) => n.id === "hub")) return "connected";
938
+ } catch {
939
+ }
940
+ const configNow = readConfigFile2(config.configPath);
941
+ const discoveryMode = typeof configNow.hubAddress !== "string" || configNow.hubAddress.length === 0;
942
+ return discoveryMode ? "searching" : "disconnected";
943
+ }
944
+ function readConfigFile2(p) {
945
+ if (!fs6.existsSync(p)) return {};
946
+ try {
947
+ return JSON.parse(fs6.readFileSync(p, "utf-8"));
948
+ } catch {
949
+ return {};
950
+ }
951
+ }
916
952
  const registerAbortController = new AbortController();
917
953
  function buildAgentOwnManifest() {
918
954
  const addonCapMap = /* @__PURE__ */ new Map();
@@ -975,6 +1011,7 @@ async function startAgent(configPath) {
975
1011
  consoleLogger.error(
976
1012
  "hub registration rejected: cluster secret mismatch \u2014 correct CAMSTACK_CLUSTER_SECRET and restart the agent"
977
1013
  );
1014
+ hubConnectionStateOverride = "secret-mismatch";
978
1015
  return;
979
1016
  }
980
1017
  });
@@ -1104,7 +1141,21 @@ async function startAgent(configPath) {
1104
1141
  agentParentUdsPath
1105
1142
  );
1106
1143
  broker.createService(processServiceSchema);
1107
- registerAgentCapDispatch(broker, agentUdsRegistry, consoleLogger);
1144
+ const agentInProcessLookup = (capName) => {
1145
+ const provider = capabilityRegistry.getSingleton(capName);
1146
+ if (provider === null || provider === void 0) return null;
1147
+ return {
1148
+ invoke: (method, args) => {
1149
+ const fn = provider[method];
1150
+ if (typeof fn !== "function") {
1151
+ return Promise.reject(new Error(`method "${method}" not found on cap "${capName}"`));
1152
+ }
1153
+ const result = fn.call(provider, args);
1154
+ return Promise.resolve(result);
1155
+ }
1156
+ };
1157
+ };
1158
+ registerAgentCapDispatch(broker, agentUdsRegistry, agentInProcessLookup, consoleLogger);
1108
1159
  (0, import_system3.registerEventBusService)(broker);
1109
1160
  broker.createService((0, import_system3.createHwAccelService)((0, import_system3.createKernelHwAccel)()));
1110
1161
  await broker.start();
@@ -1131,7 +1182,8 @@ async function startAgent(configPath) {
1131
1182
  nodeId: config.nodeId,
1132
1183
  dataDir: config.dataDir,
1133
1184
  configPath: config.configPath,
1134
- onReconnect: reconnect
1185
+ onReconnect: reconnect,
1186
+ getHubConnectionState
1135
1187
  });
1136
1188
  await bootCoreAddons(broker, config, capabilityRegistry, loadedAddons, loggerFactory);
1137
1189
  for (const dest of capabilityRegistry.getCollection("log-destination")) {
@@ -1153,6 +1205,9 @@ async function startAgent(configPath) {
1153
1205
  broker.localBus.on("$node.connected", (data) => {
1154
1206
  const node = data.node;
1155
1207
  if (node?.id !== "hub") return;
1208
+ if (hubConnectionStateOverride === "secret-mismatch") {
1209
+ hubConnectionStateOverride = null;
1210
+ }
1156
1211
  triggerUpwardRegistration();
1157
1212
  if (hubReachableFired) return;
1158
1213
  hubReachableFired = true;