@camstack/server 1.2.431 → 1.2.433

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.
@@ -406,7 +406,7 @@ async function startAgent(configPath) {
406
406
  }
407
407
  // ONE COPY PER NODE — the same sweep the hub runs, at this role's own
408
408
  // healthy-boot moment (D45, task 32). Operator, 2026-08-13: "l'agente deve
409
- // essere identico all'hub". An agent is where the redundant copies actually
409
+ // essere identico all'hub" [the agent must be identical to the hub]. An agent is where the redundant copies actually
410
410
  // are: `little-unraid` still holds `<dataDir>/addons/@camstack/system@1.2.78`
411
411
  // — a copy nothing loads (both roles pass `['@camstack/system']` as the
412
412
  // loader's skip list) and that WINS over the closure for anything resolving
@@ -484,6 +484,8 @@ async function startAgent(configPath) {
484
484
  // back to broker-only (no parentUdsPath propagated). See moleculer.service.ts.
485
485
  let agentParentUdsPath;
486
486
  let agentUdsRegistry;
487
+ /** The agent's cluster bus, set once the broker is started (see `lifecycleEvents` below). */
488
+ let agentLifecycleBus = null;
487
489
  try {
488
490
  const agentNodeId = broker.nodeID;
489
491
  // F0 (slice-5 outbound): route a forked child's unowned `ctx.api.<cap>`
@@ -534,6 +536,21 @@ async function startAgent(configPath) {
534
536
  });
535
537
  agentUdsRegistry = new system_1.LocalChildRegistry({
536
538
  server: (0, system_1.createLocalTransport)().createServer(agentNodeId),
539
+ // `WorkerOnline` / `WorkerOffline` `<agent>/<childId>` for a forked runner
540
+ // (no broker of its own, so no `$node.connected`), on the agent's
541
+ // cluster-broadcasting bus. The bus exists only after `broker.start()`;
542
+ // runners are spawned after it (`loadClusterCapableAddons`), and an
543
+ // event before it is said, never silent.
544
+ lifecycleEvents: {
545
+ parentNodeId: () => agentNodeId,
546
+ emit: (event) => {
547
+ if (agentLifecycleBus === null) {
548
+ consoleLogger.info(`runner lifecycle event before the agent bus exists — dropped: ${event.category}`);
549
+ return;
550
+ }
551
+ agentLifecycleBus.emit(event);
552
+ },
553
+ },
537
554
  // The agent's own id — a cap call pinned to THIS agent (e.g. the
538
555
  // benchmark running `pipeline-executor.runPipeline` on the very node it
539
556
  // is on) is served by the co-resident sibling instead of being forwarded
@@ -686,6 +703,7 @@ async function startAgent(configPath) {
686
703
  // was not started (no UDS children). Wired after broker.start() so
687
704
  // getBrokerEventBus returns the fully operational shared bus.
688
705
  const agentBrokerEventBus = (0, system_1.getBrokerEventBus)(broker);
706
+ agentLifecycleBus = agentBrokerEventBus;
689
707
  agentUpdateService.bindAvailability(agentBrokerEventBus, broker.nodeID);
690
708
  let udsEventBridgeDispose = null;
691
709
  if (agentUdsRegistry !== undefined) {
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * ## Why one document and not one method per knob
8
8
  *
9
- * The audit in `docs/design/plans/2026-08-26-logging-per-componente.md` found
9
+ * The audit in `docs/design/plans/2026-08-26-per-component-logging.md` found
10
10
  * the level spread over five knobs in three settings panels, two kernel config
11
11
  * keys and an env var that never reached an addon. Adding a cap method per
12
12
  * knob would have reproduced that on the API. So: adding a logging setting
@@ -81,7 +81,7 @@ const SOURCE_ADDON_FIELD = 'addonId';
81
81
  /**
82
82
  * The input field naming WHICH of a device's providers to ask. One at a time,
83
83
  * by `addonId`, never a list of source ids: the operator settled the surface
84
- * on 2026-09-20 (*"l'utilizzatore è uno solo"*).
84
+ * on 2026-09-20 (*"l'utilizzatore è uno solo"* [there is only one user]).
85
85
  *
86
86
  * An absent pin narrows NOTHING — the method fans out, which is right for
87
87
  * `listSources` and was never right for `listClips`. Whether absence is
@@ -408,6 +408,12 @@ class MoleculerService {
408
408
  // onUnownedCall (a pin to ANOTHER node still bypasses the sibling).
409
409
  ownNodeId: nodeId,
410
410
  onUnownedCall,
411
+ // A forked runner has no Moleculer broker, so `$node.connected` never
412
+ // fires for it: the registry says `WorkerOnline` / `WorkerOffline`
413
+ // `<hub>/<childId>` itself, on the hub's bus — WorkerOnline at the
414
+ // pre-init register, before the child initializes (the D696 provider
415
+ // gate forgets a provider there, before it can restore and seed).
416
+ lifecycleEvents: { parentNodeId: () => nodeId, emit: (event) => this.eventBus.emit(event) },
411
417
  // `getStatus` of a CLAIMED cap is answered by the hub mirror BEFORE the
412
418
  // sibling short-circuit can dispatch it to the owning child (D663, S3)
413
419
  // — the same resolver the handler above and `callCapabilityOnNode` use.
@@ -10,7 +10,7 @@
10
10
  * the first-boot fallback source; every other addon is single-copy, always,
11
11
  * installed during the initial boot;
12
12
  * - **no pinning at all** — *"il sistema è designato per essere
13
- * addons-agnostic, latest va sempre bene al primo boot"*. There is no version
13
+ * addons-agnostic, latest va sempre bene al primo boot"* [the system is designed to be addons-agnostic, latest is always fine at first boot]. There is no version
14
14
  * contract between the closure and an addon, so first boot asks for `latest`
15
15
  * and the copy that lands is the one the node keeps.
16
16
  *
package/dist/launcher.js CHANGED
@@ -341,8 +341,8 @@ async function launch() {
341
341
  //
342
342
  // The image no longer bakes a NON-system addon tree, so this roster comes
343
343
  // from the registry on a fresh node: "tutti gli altri addons devono rimanere
344
- // copia unica, sempre, installati durante l'avvio iniziale" (2026-08-12), at
345
- // `latest`, because "il sistema e' designato per essere addons-agnostic"
344
+ // copia unica, sempre, installati durante l'avvio iniziale" [all the other addons must remain a single copy, always, installed during the initial boot] (2026-08-12), at
345
+ // `latest`, because "il sistema e' designato per essere addons-agnostic" [the system is designed to be addons-agnostic]
346
346
  // (2026-08-13). The plan below is what `ensureRequiredPackages` is about to
347
347
  // do, said out loud BEFORE it happens: how many packages this node must fetch
348
348
  // (i.e. whether this boot needs the registry at all), and where an installed
@@ -565,7 +565,7 @@ async function launch() {
565
565
  // that could both run still scream.
566
566
  //
567
567
  // NEVER fatal — operator directive, 2026-08-12: "non dovremmo mai prevenire
568
- // il boot". There is no flag that turns this into a refusal. A node that
568
+ // il boot" [we should never prevent the boot]. There is no flag that turns this into a refusal. A node that
569
569
  // cannot start is a camera system that is not recording, and the inventory is
570
570
  // the thing that was supposed to EXPLAIN a bad layout, not enact a verdict on
571
571
  // it. Removing a copy stays an operator decision.
@@ -37,7 +37,7 @@ exports.runSingleCopyCleanup = runSingleCopyCleanup;
37
37
  /**
38
38
  * The one adapter that runs the post-boot single-copy sweep on BOTH roles.
39
39
  *
40
- * Operator, 2026-08-13: *"l'agente deve essere identico all'hub"*. Two code
40
+ * Operator, 2026-08-13: *"l'agente deve essere identico all'hub"* [the agent must be identical to the hub]. Two code
41
41
  * paths that must agree get one implementation — the hub calls this after its
42
42
  * boot-health confirmation, the agent after its first acked `registerNode`, and
43
43
  * neither owns a private idea of what may be deleted.
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * - the SYSTEM seed stays in the image, as the first-boot and fallback source
9
9
  * (*"teniamo gli addons di sistema nell'immagine per il primo boot, da usare
10
- * in caso di fallback"*);
10
+ * in caso di fallback"* [we keep the system addons in the image for the first boot, to be used in case of fallback]);
11
11
  * - once a node **has booted correctly**, the redundant DATA-side copies are
12
12
  * removed — the legacy `<dataDir>/framework` tree and any host-provided
13
13
  * package sitting under the addon root;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/server",
3
- "version": "1.2.431",
3
+ "version": "1.2.433",
4
4
  "license": "MIT",
5
5
  "private": false,
6
6
  "files": [
@@ -37,18 +37,18 @@
37
37
  ]
38
38
  },
39
39
  "dependencies": {
40
- "@camstack/addon-admin-ui": "1.2.300",
41
- "@camstack/addon-agent-ui": "1.2.162",
40
+ "@camstack/addon-admin-ui": "1.2.302",
41
+ "@camstack/addon-agent-ui": "1.2.163",
42
42
  "@camstack/addon-auth": "1.2.124",
43
43
  "@camstack/addon-decoder-nodeav": "1.2.116",
44
44
  "@camstack/addon-notifiers": "1.2.122",
45
- "@camstack/addon-pipeline": "1.2.315",
46
- "@camstack/addon-pipeline-orchestrator": "1.2.272",
47
- "@camstack/addon-post-analysis": "1.2.311",
45
+ "@camstack/addon-pipeline": "1.2.316",
46
+ "@camstack/addon-pipeline-orchestrator": "1.2.273",
47
+ "@camstack/addon-post-analysis": "1.2.313",
48
48
  "@camstack/sdk": "1.2.119",
49
- "@camstack/system": "1.2.332",
50
- "@camstack/types": "1.2.285",
51
- "@camstack/ui-library": "1.2.220",
49
+ "@camstack/system": "1.2.334",
50
+ "@camstack/types": "1.2.287",
51
+ "@camstack/ui-library": "1.2.221",
52
52
  "@fastify/compress": "^9.0.0",
53
53
  "@fastify/cookie": "^11.0.2",
54
54
  "@fastify/cors": "^11.2.0",