@camstack/server 1.2.675 → 1.2.676

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/CHANGELOG.md CHANGED
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.2.676] - 2026-10-28
11
+
12
+ ### Fixed
13
+
14
+ - An agent advertises itself on the network again, so the hub lists a new agent for pairing without typing its address
15
+ - An unpaired agent no longer crash-loops: it stays up to be paired and starts its addons once pairing completes
16
+
10
17
  ## [1.2.675] - 2026-10-28
11
18
 
12
19
  ### Changed
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.decideAgentBootMode = decideAgentBootMode;
4
+ function decideAgentBootMode(input) {
5
+ return input.paired ? 'full' : 'pairing-only';
6
+ }
@@ -56,6 +56,7 @@ const agent_http_js_1 = require("./agent-http.js");
56
56
  const agent_node_certificates_js_1 = require("./agent-node-certificates.js");
57
57
  const agent_reconnect_js_1 = require("./agent-reconnect.js");
58
58
  const serial_queue_js_1 = require("./serial-queue.js");
59
+ const agent_boot_mode_js_1 = require("./agent-boot-mode.js");
59
60
  const agent_infra_capabilities_js_1 = require("./agent-infra-capabilities.js");
60
61
  const agent_service_js_1 = require("./agent-service.js");
61
62
  const agent_hub_addon_update_js_1 = require("./agent-hub-addon-update.js");
@@ -900,6 +901,7 @@ async function startAgent(configPath) {
900
901
  leafFingerprint: (0, agent_pairing_store_js_1.pairedLeafFingerprint)(config.configPath),
901
902
  });
902
903
  };
904
+ const addonsBooted = (0, agent_boot_mode_js_1.decideAgentBootMode)({ paired: (0, agent_pairing_store_js_1.isAgentPaired)(config.configPath) }) === 'full';
903
905
  const localPairing = (0, agent_pairing_local_js_1.createLocalPairingAnnouncer)(config.dataDir, consoleLogger);
904
906
  const pairing = new system_1.AgentPairing({
905
907
  nodeId: config.nodeId,
@@ -912,7 +914,16 @@ async function startAgent(configPath) {
912
914
  meta: { hubUrl: installed.hubUrl, hubAddress: installed.hubAddress },
913
915
  });
914
916
  // The completion is answered first; the wire is replaced right after.
915
- const timer = setTimeout(() => void reconnect().then(advertise, advertise), 400);
917
+ const timer = setTimeout(() => {
918
+ if (addonsBooted) {
919
+ void reconnect().then(advertise, advertise);
920
+ }
921
+ else {
922
+ // Booted unpaired: no addon was started (agent-boot-mode.ts). Relaunch (D5) so
923
+ // the core addons boot with the hub reachable.
924
+ (0, agent_update_service_js_1.scheduleAgentRestart)(consoleLogger, 'paired with the hub', config.dataDir);
925
+ }
926
+ }, 400);
916
927
  timer.unref?.();
917
928
  },
918
929
  log: (message, meta) => consoleLogger.info(`pairing: ${message}`, meta ? { meta } : undefined),
@@ -951,6 +962,40 @@ async function startAgent(configPath) {
951
962
  }).then((listener) => {
952
963
  agentHttpListener = listener;
953
964
  });
965
+ // Graceful shutdown
966
+ const shutdown = async () => {
967
+ console.log('[Agent] Shutting down...');
968
+ // Abort any in-flight upward hub registration retry loop.
969
+ registerAbortController.abort();
970
+ // Dispose the UDS event bridge to remove the parent-bus subscriber and
971
+ // clear the child-event handler, preventing subscriber leaks on shutdown.
972
+ udsEventBridgeDispose?.();
973
+ udsEventBridgeDispose = null;
974
+ for (const [, entry] of loadedAddons) {
975
+ if (entry.addon?.shutdown) {
976
+ try {
977
+ await entry.addon.shutdown();
978
+ }
979
+ catch {
980
+ /* */
981
+ }
982
+ }
983
+ }
984
+ // Withdraw the mDNS advertisement, then stop accepting new HTTP/HTTPS connections before
985
+ // the broker goes away.
986
+ await agentMdns.stop().catch(() => undefined);
987
+ await agentHttpListener?.close().catch(() => undefined);
988
+ await broker.stop();
989
+ process.exit(0);
990
+ };
991
+ process.on('SIGTERM', shutdown);
992
+ process.on('SIGINT', shutdown);
993
+ // An unpaired agent has no hub to read settings from (D857): serve pairing only and
994
+ // relaunch after the certificate is installed (D5). See agent-boot-mode.ts.
995
+ if (!addonsBooted) {
996
+ console.log(`[Agent] Node "${config.nodeId}" is unpaired - serving pairing only; addons boot after pairing`);
997
+ return;
998
+ }
954
999
  // ── Phase 1: Load core infrastructure addons (in-process) ──
955
1000
  // storage + settings + metrics + hub-forwarder (log destination)
956
1001
  await bootCoreAddons(broker, config, capabilityRegistry, loadedAddons, loggerFactory);
@@ -1003,34 +1048,6 @@ async function startAgent(configPath) {
1003
1048
  }
1004
1049
  });
1005
1050
  console.log(`[Agent] Node "${config.nodeId}" (name="${config.name}") ready — ${loadedAddons.size} addon(s) loaded`);
1006
- // Graceful shutdown
1007
- const shutdown = async () => {
1008
- console.log('[Agent] Shutting down...');
1009
- // Abort any in-flight upward hub registration retry loop.
1010
- registerAbortController.abort();
1011
- // Dispose the UDS event bridge to remove the parent-bus subscriber and
1012
- // clear the child-event handler, preventing subscriber leaks on shutdown.
1013
- udsEventBridgeDispose?.();
1014
- udsEventBridgeDispose = null;
1015
- for (const [, entry] of loadedAddons) {
1016
- if (entry.addon?.shutdown) {
1017
- try {
1018
- await entry.addon.shutdown();
1019
- }
1020
- catch {
1021
- /* */
1022
- }
1023
- }
1024
- }
1025
- // Withdraw the mDNS advertisement, then stop accepting new HTTP/HTTPS connections before
1026
- // the broker goes away.
1027
- await agentMdns.stop().catch(() => undefined);
1028
- await agentHttpListener?.close().catch(() => undefined);
1029
- await broker.stop();
1030
- process.exit(0);
1031
- };
1032
- process.on('SIGTERM', shutdown);
1033
- process.on('SIGINT', shutdown);
1034
1051
  }
1035
1052
  // ---------------------------------------------------------------------------
1036
1053
  // Phase 1: Boot core addons (storage, settings, metrics — NO winston)
@@ -1217,7 +1234,10 @@ async function loadClusterCapableAddons(broker, config, capabilityRegistry, load
1217
1234
  try {
1218
1235
  await broker.call('$process.spawnRunner', {
1219
1236
  runnerId: groupId,
1220
- addons: addons.map((a) => ({ addonId: a.addonId, addonDir: a.addonDir })),
1237
+ addons: addons.map((a) => ({
1238
+ addonId: a.addonId,
1239
+ addonDir: a.addonDir,
1240
+ })),
1221
1241
  });
1222
1242
  // Shared with the reload path (`ensureGroupRunner`) so the boot and
1223
1243
  // reload registrations can never drift — the drift was the in-process
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/server",
3
- "version": "1.2.675",
3
+ "version": "1.2.676",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -60,7 +60,7 @@
60
60
  "@camstack/addon-post-analysis": "1.2.649",
61
61
  "@camstack/develop": "0.1.38",
62
62
  "@camstack/sdk": "1.2.154",
63
- "@camstack/system": "1.2.506",
63
+ "@camstack/system": "1.2.507",
64
64
  "@camstack/types": "1.2.436",
65
65
  "@camstack/ui-library": "1.2.345",
66
66
  "@fastify/compress": "^9.0.0",