@camstack/system 1.1.35 → 1.1.37

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.
Files changed (53) hide show
  1. package/dist/addon-runner.js +87 -35
  2. package/dist/addon-runner.mjs +87 -35
  3. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.d.ts +8 -4
  4. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +22 -10
  5. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +23 -11
  6. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.d.ts +4 -0
  7. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +23 -9
  8. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +24 -10
  9. package/dist/builtins/alerts/alerts.addon.js +1 -1
  10. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  11. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  12. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  13. package/dist/builtins/console-logging/index.js +1 -1
  14. package/dist/builtins/console-logging/index.mjs +1 -1
  15. package/dist/builtins/device-manager/device-manager.addon.js +1 -1
  16. package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
  17. package/dist/builtins/hub-forwarder/index.js +1 -1
  18. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  19. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  20. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  21. package/dist/builtins/local-network/local-network.addon.js +1 -1
  22. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  23. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  24. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  25. package/dist/builtins/platform-probe/index.js +1 -1
  26. package/dist/builtins/platform-probe/index.mjs +1 -1
  27. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  28. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  29. package/dist/builtins/snapshot/index.js +1 -1
  30. package/dist/builtins/snapshot/index.mjs +1 -1
  31. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  32. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  33. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +1 -1
  34. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +1 -1
  35. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  36. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  37. package/dist/builtins/system-config/system-config.addon.js +1 -1
  38. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  39. package/dist/builtins/winston-logging/index.js +1 -1
  40. package/dist/builtins/winston-logging/index.mjs +1 -1
  41. package/dist/{dist-DlGZpWo8.mjs → dist-CU3lb_Ys.mjs} +401 -125
  42. package/dist/{dist-DriXJoVg.js → dist-fRVWwrkF.js} +401 -125
  43. package/dist/index.js +26 -7
  44. package/dist/index.mjs +26 -7
  45. package/dist/kernel/index.d.ts +1 -1
  46. package/dist/kernel/moleculer/child-cap-descriptors.d.ts +34 -0
  47. package/dist/kernel/moleculer/child-cap-dispatch.d.ts +10 -2
  48. package/dist/kernel/moleculer/node-registry.d.ts +22 -1
  49. package/dist/kernel/moleculer/register-node-client.d.ts +8 -5
  50. package/dist/kernel/transport/child-cap-protocol.d.ts +20 -0
  51. package/dist/{manifest-python-deps-MUu1e33G.mjs → manifest-python-deps-4QvOLiBn.mjs} +5 -3
  52. package/dist/{manifest-python-deps-jZA_Qorz.js → manifest-python-deps-B6ahe90k.js} +5 -3
  53. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("./chunk-Cek0wNdY.js");
3
- const require_dist = require("./dist-DriXJoVg.js");
3
+ const require_dist = require("./dist-fRVWwrkF.js");
4
4
  const require_model_download_service = require("./model-download-service-D-Umz4-L.js");
5
5
  const require_resource_monitor = require("./resource-monitor-DNNomR-i.js");
6
6
  const require_builtins_sqlite_storage_filesystem_storage_addon = require("./builtins/sqlite-storage/filesystem-storage.addon.js");
@@ -21,7 +21,7 @@ const require_builtins_local_auth_local_auth_addon = require("./builtins/local-a
21
21
  require("./builtins/local-auth/index.js");
22
22
  const require_builtins_device_manager_device_manager_addon = require("./builtins/device-manager/device-manager.addon.js");
23
23
  require("./builtins/device-manager/index.js");
24
- const require_manifest_python_deps = require("./manifest-python-deps-jZA_Qorz.js");
24
+ const require_manifest_python_deps = require("./manifest-python-deps-B6ahe90k.js");
25
25
  const require_custom_action_registry = require("./custom-action-registry-vLYEFTtv.js");
26
26
  let _camstack_types_node = require("@camstack/types/node");
27
27
  let zod = require("zod");
@@ -91751,6 +91751,8 @@ var HubNodeRegistry = class {
91751
91751
  nodes = /* @__PURE__ */ new Map();
91752
91752
  /** nodeId → its device-scoped native caps (last `registerNode` wins). */
91753
91753
  nativeCaps = /* @__PURE__ */ new Map();
91754
+ /** nodeId → its root-package identity (last `registerNode` wins). */
91755
+ rootPackages = /* @__PURE__ */ new Map();
91754
91756
  /**
91755
91757
  * deviceId → flat native-cap entries for THAT device, across all nodes.
91756
91758
  * Maintained incrementally on every `registerNode`/`removeNode` so a
@@ -91798,6 +91800,11 @@ var HubNodeRegistry = class {
91798
91800
  deviceIds: [...n.deviceIds]
91799
91801
  }));
91800
91802
  this.nativeCaps.set(params.nodeId, caps);
91803
+ if (params.rootPackage !== void 0) this.rootPackages.set(params.nodeId, {
91804
+ name: params.rootPackage.name,
91805
+ version: params.rootPackage.version
91806
+ });
91807
+ else this.rootPackages.delete(params.nodeId);
91801
91808
  for (const cap of caps) for (const deviceId of cap.deviceIds) {
91802
91809
  const entry = {
91803
91810
  nodeId: params.nodeId,
@@ -91815,6 +91822,11 @@ var HubNodeRegistry = class {
91815
91822
  this.dropNodeFromDeviceIndex(nodeId);
91816
91823
  this.nodes.delete(nodeId);
91817
91824
  this.nativeCaps.delete(nodeId);
91825
+ this.rootPackages.delete(nodeId);
91826
+ }
91827
+ /** The node's root-package identity, or null when it never reported one. */
91828
+ getNodeRootPackage(nodeId) {
91829
+ return this.rootPackages.get(nodeId) ?? null;
91818
91830
  }
91819
91831
  /** The node's manifest, or undefined when the node never registered. */
91820
91832
  getNodeManifest(nodeId) {
@@ -91868,11 +91880,14 @@ var HubNodeRegistry = class {
91868
91880
  //#region src/kernel/moleculer/register-node-client.ts
91869
91881
  /**
91870
91882
  * Build a `RegisterNodeParams` from a node id, its per-addon manifests,
91871
- * optionally its device-scoped native caps, and optionally the SHA-256 hash
91872
- * of the cluster secret. `nativeCaps` is omitted entirely on the first
91873
- * handshake; `clusterSecretHash` is omitted when no secret is configured.
91883
+ * optionally its device-scoped native caps, optionally the SHA-256 hash
91884
+ * of the cluster secret, and optionally the node's root-package identity
91885
+ * (runtime-updatable node packages: version visibility). `nativeCaps` is
91886
+ * omitted entirely on the first handshake; `clusterSecretHash` is omitted
91887
+ * when no secret is configured; `rootPackage` is omitted by nodes that do
91888
+ * not run the root-package model (UDS children).
91874
91889
  */
91875
- function buildNodeManifest(nodeId, addons, nativeCaps, clusterSecretHash) {
91890
+ function buildNodeManifest(nodeId, addons, nativeCaps, clusterSecretHash, rootPackage) {
91876
91891
  return {
91877
91892
  nodeId,
91878
91893
  addons: addons.map((a) => ({
@@ -91884,7 +91899,11 @@ function buildNodeManifest(nodeId, addons, nativeCaps, clusterSecretHash) {
91884
91899
  addonId: n.addonId,
91885
91900
  deviceIds: [...n.deviceIds]
91886
91901
  })) },
91887
- ...clusterSecretHash === void 0 ? {} : { clusterSecretHash }
91902
+ ...clusterSecretHash === void 0 ? {} : { clusterSecretHash },
91903
+ ...rootPackage === void 0 ? {} : { rootPackage: {
91904
+ name: rootPackage.name,
91905
+ version: rootPackage.version
91906
+ } }
91888
91907
  };
91889
91908
  }
91890
91909
  function delay(ms, signal) {
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as errMsg$1, A as isVoidInput, Ct as resolveCapMount, F as looseSchema, M as lifecycleJobSchema, O as isArrayOutputSchema, St as readinessKey, V as procedureAuthKey, _t as expandCapMethods, bt as parseJsonObject, ct as ReadinessRegistry, dt as asJsonObject$1, ft as asNumber, ht as emitDownForOwnedCaps, j as kebabToCamel, k as isObjectInput, lt as ReadinessTimeoutError, mt as createEvent, nt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, o as METHOD_ACCESS_MAP, p as addonSettingsCapability, pt as asString$1, rt as DEVICE_STATUS_METHOD, s as RUNTIME_DEFAULTS, st as EventCategory$1, t as ALL_CAPABILITY_DEFINITIONS, tt as DATAPLANE_SECRET_HEADER$1, wt as scopeKey, xt as parseJsonUnknown$1 } from "./dist-DlGZpWo8.mjs";
1
+ import { $ as errMsg$1, A as isVoidInput, Ct as resolveCapMount, F as looseSchema, M as lifecycleJobSchema, O as isArrayOutputSchema, St as readinessKey, V as procedureAuthKey, _t as expandCapMethods, bt as parseJsonObject, ct as ReadinessRegistry, dt as asJsonObject$1, ft as asNumber, ht as emitDownForOwnedCaps, j as kebabToCamel, k as isObjectInput, lt as ReadinessTimeoutError, mt as createEvent, nt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, o as METHOD_ACCESS_MAP, p as addonSettingsCapability, pt as asString$1, rt as DEVICE_STATUS_METHOD, s as RUNTIME_DEFAULTS, st as EventCategory$1, t as ALL_CAPABILITY_DEFINITIONS, tt as DATAPLANE_SECRET_HEADER$1, wt as scopeKey, xt as parseJsonUnknown$1 } from "./dist-CU3lb_Ys.mjs";
2
2
  import { a as downloadModel, c as getModelFilePath, d as contentTypeFor, f as createAuthenticatedFileServer, h as resolveFilePath, i as downloadFile, l as isModelDownloaded, m as parseTokenizedUrl, n as collectModelFiles, o as ensureModel, p as parseRangeHeader, r as deleteModelFromDisk, s as fetchJson, t as ModelDownloadService, u as createFileDataPlaneHandler } from "./model-download-service-C-IHWnXx.mjs";
3
3
  import { n as getSinglePidStats, t as getPidStats } from "./resource-monitor-Le3l0qS2.mjs";
4
4
  import { FilesystemStorageAddon, t as FilesystemStorageProvider } from "./builtins/sqlite-storage/filesystem-storage.addon.mjs";
@@ -19,7 +19,7 @@ import { LocalAuthAddon, a as require_ms, c as __esmMin, d as __toCommonJS, f as
19
19
  import "./builtins/local-auth/index.mjs";
20
20
  import { DeviceManagerAddon } from "./builtins/device-manager/device-manager.addon.mjs";
21
21
  import "./builtins/device-manager/index.mjs";
22
- import { $ as buildUdsNativeCapProxy, A as createParentUnownedCallHandler, B as AGENT_CAP_FWD_SERVICE, C as buildLinkChain, D as HUB_CAP_FWD_ACTION, E as localProviderLink, F as createUdsLoggerWithControl, G as createLocalTransport, H as CapRouteError, I as LocalChildClient, J as SocketChannel, K as UdsLocalTransportClient, L as LocalChildRegistry, M as createUdsEventBus, N as udsChildLogToWorkerEntry, O as HUB_CAP_FWD_SERVICE, P as createUdsLogger, Q as buildNativeCapProxy, R as UDS_NO_ROUTE_PREFIX, S as brokerTransportLink, T as ipcParentLink, U as classifyCapRoute, V as CapRouteResolver, W as callWithServiceDiscovery, X as FrameDecoder, Y as localEndpointPath, Z as encodeFrame, _ as resolveHwAccel, _t as CapabilityUnavailableError, a as getWorkerDeviceRegistry, at as createAddonService, b as getCapUsageRegistry, c as setHubConnected, ct as capActionName, d as getMoleculerEventStats, dt as capServiceName, et as createBrokerDeviceManagerApi, f as registerEventBusService, ft as parseCapAction, g as createKernelHwAccel, gt as CapabilityHandle, h as AddonDepsManager, ht as DeviceRegistry, i as createUdsAddonContext, j as createUdsEventBridge, k as createHubCapForwardService, l as EVENT_TOPIC_PREFIX, lt as capActionSuffix, m as subscribePassthrough, mt as serializeTypedArrays, n as adaptBrokerToCluster, o as getOrInitReadinessRegistry, ot as validateProviderRegistrations, p as setNodeEventInterest, pt as deserializeTypedArrays, q as UdsLocalTransportServer, r as createAddonContext, rt as mountNativeCapService, s as getOrInitReadinessRegistryForClient, st as NATIVE_PROVIDER_SERVICE_INFIX, t as installManifestPythonDeps, u as getBrokerEventBus, ut as capBareAction, v as CapUsageRegistry, vt as installManifestNativeDeps, w as ipcChildLink, x as brokerCallForCap, y as __resetCapUsageRegistryForTests, yt as resolveAddonClass, z as AGENT_CAP_FWD_ACTION } from "./manifest-python-deps-MUu1e33G.mjs";
22
+ import { $ as buildUdsNativeCapProxy, A as createParentUnownedCallHandler, B as AGENT_CAP_FWD_SERVICE, C as buildLinkChain, D as HUB_CAP_FWD_ACTION, E as localProviderLink, F as createUdsLoggerWithControl, G as createLocalTransport, H as CapRouteError, I as LocalChildClient, J as SocketChannel, K as UdsLocalTransportClient, L as LocalChildRegistry, M as createUdsEventBus, N as udsChildLogToWorkerEntry, O as HUB_CAP_FWD_SERVICE, P as createUdsLogger, Q as buildNativeCapProxy, R as UDS_NO_ROUTE_PREFIX, S as brokerTransportLink, T as ipcParentLink, U as classifyCapRoute, V as CapRouteResolver, W as callWithServiceDiscovery, X as FrameDecoder, Y as localEndpointPath, Z as encodeFrame, _ as resolveHwAccel, _t as CapabilityUnavailableError, a as getWorkerDeviceRegistry, at as createAddonService, b as getCapUsageRegistry, c as setHubConnected, ct as capActionName, d as getMoleculerEventStats, dt as capServiceName, et as createBrokerDeviceManagerApi, f as registerEventBusService, ft as parseCapAction, g as createKernelHwAccel, gt as CapabilityHandle, h as AddonDepsManager, ht as DeviceRegistry, i as createUdsAddonContext, j as createUdsEventBridge, k as createHubCapForwardService, l as EVENT_TOPIC_PREFIX, lt as capActionSuffix, m as subscribePassthrough, mt as serializeTypedArrays, n as adaptBrokerToCluster, o as getOrInitReadinessRegistry, ot as validateProviderRegistrations, p as setNodeEventInterest, pt as deserializeTypedArrays, q as UdsLocalTransportServer, r as createAddonContext, rt as mountNativeCapService, s as getOrInitReadinessRegistryForClient, st as NATIVE_PROVIDER_SERVICE_INFIX, t as installManifestPythonDeps, u as getBrokerEventBus, ut as capBareAction, v as CapUsageRegistry, vt as installManifestNativeDeps, w as ipcChildLink, x as brokerCallForCap, y as __resetCapUsageRegistryForTests, yt as resolveAddonClass, z as AGENT_CAP_FWD_ACTION } from "./manifest-python-deps-4QvOLiBn.mjs";
23
23
  import { t as CustomActionRegistry } from "./custom-action-registry-BEXwC-oo.mjs";
24
24
  import { PYTHON_VERSION, buildBinaryPath, downloadBinary, ensureBinary, ensureFfmpeg, ensurePython, findInPath, getFfmpegDownloadUrl, getPlatformInfo, getPythonDownloadUrl, installPythonPackages, installPythonRequirements } from "@camstack/types/node";
25
25
  import { z } from "zod";
@@ -91743,6 +91743,8 @@ var HubNodeRegistry = class {
91743
91743
  nodes = /* @__PURE__ */ new Map();
91744
91744
  /** nodeId → its device-scoped native caps (last `registerNode` wins). */
91745
91745
  nativeCaps = /* @__PURE__ */ new Map();
91746
+ /** nodeId → its root-package identity (last `registerNode` wins). */
91747
+ rootPackages = /* @__PURE__ */ new Map();
91746
91748
  /**
91747
91749
  * deviceId → flat native-cap entries for THAT device, across all nodes.
91748
91750
  * Maintained incrementally on every `registerNode`/`removeNode` so a
@@ -91790,6 +91792,11 @@ var HubNodeRegistry = class {
91790
91792
  deviceIds: [...n.deviceIds]
91791
91793
  }));
91792
91794
  this.nativeCaps.set(params.nodeId, caps);
91795
+ if (params.rootPackage !== void 0) this.rootPackages.set(params.nodeId, {
91796
+ name: params.rootPackage.name,
91797
+ version: params.rootPackage.version
91798
+ });
91799
+ else this.rootPackages.delete(params.nodeId);
91793
91800
  for (const cap of caps) for (const deviceId of cap.deviceIds) {
91794
91801
  const entry = {
91795
91802
  nodeId: params.nodeId,
@@ -91807,6 +91814,11 @@ var HubNodeRegistry = class {
91807
91814
  this.dropNodeFromDeviceIndex(nodeId);
91808
91815
  this.nodes.delete(nodeId);
91809
91816
  this.nativeCaps.delete(nodeId);
91817
+ this.rootPackages.delete(nodeId);
91818
+ }
91819
+ /** The node's root-package identity, or null when it never reported one. */
91820
+ getNodeRootPackage(nodeId) {
91821
+ return this.rootPackages.get(nodeId) ?? null;
91810
91822
  }
91811
91823
  /** The node's manifest, or undefined when the node never registered. */
91812
91824
  getNodeManifest(nodeId) {
@@ -91860,11 +91872,14 @@ var HubNodeRegistry = class {
91860
91872
  //#region src/kernel/moleculer/register-node-client.ts
91861
91873
  /**
91862
91874
  * Build a `RegisterNodeParams` from a node id, its per-addon manifests,
91863
- * optionally its device-scoped native caps, and optionally the SHA-256 hash
91864
- * of the cluster secret. `nativeCaps` is omitted entirely on the first
91865
- * handshake; `clusterSecretHash` is omitted when no secret is configured.
91875
+ * optionally its device-scoped native caps, optionally the SHA-256 hash
91876
+ * of the cluster secret, and optionally the node's root-package identity
91877
+ * (runtime-updatable node packages: version visibility). `nativeCaps` is
91878
+ * omitted entirely on the first handshake; `clusterSecretHash` is omitted
91879
+ * when no secret is configured; `rootPackage` is omitted by nodes that do
91880
+ * not run the root-package model (UDS children).
91866
91881
  */
91867
- function buildNodeManifest(nodeId, addons, nativeCaps, clusterSecretHash) {
91882
+ function buildNodeManifest(nodeId, addons, nativeCaps, clusterSecretHash, rootPackage) {
91868
91883
  return {
91869
91884
  nodeId,
91870
91885
  addons: addons.map((a) => ({
@@ -91876,7 +91891,11 @@ function buildNodeManifest(nodeId, addons, nativeCaps, clusterSecretHash) {
91876
91891
  addonId: n.addonId,
91877
91892
  deviceIds: [...n.deviceIds]
91878
91893
  })) },
91879
- ...clusterSecretHash === void 0 ? {} : { clusterSecretHash }
91894
+ ...clusterSecretHash === void 0 ? {} : { clusterSecretHash },
91895
+ ...rootPackage === void 0 ? {} : { rootPackage: {
91896
+ name: rootPackage.name,
91897
+ version: rootPackage.version
91898
+ } }
91880
91899
  };
91881
91900
  }
91882
91901
  function delay(ms, signal) {
@@ -39,7 +39,7 @@ export { HubLogForwarder } from './moleculer/hub-log-forwarder.js';
39
39
  export type { AddonContextOptions } from './moleculer/addon-context-factory.js';
40
40
  export { createHubService } from './moleculer/hub-service.js';
41
41
  export { HubNodeRegistry } from './moleculer/node-registry.js';
42
- export type { CallFn, RegisteredAddonManifest, RegisteredNativeCap, RegisterNodeParams, RegisterNodeResult, NodeCapEntry, NodeNativeCapEntry, } from './moleculer/node-registry.js';
42
+ export type { CallFn, NodeRootPackageInfo, RegisteredAddonManifest, RegisteredNativeCap, RegisterNodeParams, RegisterNodeResult, NodeCapEntry, NodeNativeCapEntry, } from './moleculer/node-registry.js';
43
43
  export { callRegisterNodeWithRetry, buildNodeManifest } from './moleculer/register-node-client.js';
44
44
  export type { RegisterNodeBroker, CallRegisterNodeOptions, } from './moleculer/register-node-client.js';
45
45
  export { hashClusterSecret, clusterSecretMatches, isClusterSecretMismatchError, CLUSTER_SECRET_MISMATCH_TYPE, CLUSTER_SECRET_REJECTED_EXIT_CODE, } from './moleculer/cluster-secret.js';
@@ -0,0 +1,34 @@
1
+ import { ChildCapDescriptor } from '../transport/child-cap-protocol.js';
2
+ /** One hosted addon's contribution to the runner UNION manifest. */
3
+ export interface RunnerManifestEntry {
4
+ readonly addonId: string;
5
+ readonly capabilities: readonly string[];
6
+ }
7
+ /** One native-cap snapshot row — a device-scoped cap and the devices it covers. */
8
+ export interface NativeCapSnapshotEntry {
9
+ readonly capName: string;
10
+ readonly addonId: string;
11
+ readonly deviceIds: readonly number[];
12
+ }
13
+ /**
14
+ * Builds the {@link ChildCapDescriptor} array that the UDS child transport
15
+ * sends to the parent on registration.
16
+ *
17
+ * - Singleton caps come from the runner UNION manifest (all caps registered by
18
+ * every addon in this runner). One descriptor per unique (addonId, capName)
19
+ * pair, mode `'singleton'` and no `deviceId`. The `addonId` stamp lets the
20
+ * parent's manifest builder register each hosted addon's caps under the
21
+ * REAL addon id — a GROUPED runner (`execution.group`) hosts several addons,
22
+ * and deduplicating by capName alone would collapse two co-located providers
23
+ * of the same collection cap (e.g. `network-access` from cloudflare-tunnel
24
+ * AND tailscale-ingress) into one descriptor registered under a synthetic
25
+ * `addonId = childId` (the group name) — the "@camstack/addon-net-access"
26
+ * admin-UI bug.
27
+ * - Device-scoped caps come from the native-cap snapshot — one descriptor per
28
+ * (capName, deviceId) pair, mode `'collection'`, stamped with the owning
29
+ * addon's id.
30
+ *
31
+ * Pure module — extracted from `addon-runner.ts` (whose `main()` runs at
32
+ * import time) so it is unit-testable.
33
+ */
34
+ export declare function buildChildCapDescriptors(manifest: readonly RunnerManifestEntry[], nativeCapSnapshot: readonly NativeCapSnapshotEntry[]): ChildCapDescriptor[];
@@ -6,8 +6,16 @@ import { CapCallInput } from '../transport/child-cap-protocol.js';
6
6
  * registered".
7
7
  */
8
8
  export interface ChildCapDispatchDeps {
9
- /** Resolve a singleton/system-scoped provider by cap name. */
10
- getSingletonProvider(capName: string): object | null | undefined;
9
+ /**
10
+ * Resolve a singleton/system-scoped provider by cap name. `addonId` is a
11
+ * PROVIDER-SELECTION hint for grouped runners where multiple co-located
12
+ * addons register the SAME cap (e.g. two `network-access` providers in the
13
+ * `net-access` group): when it matches a hosted addon's provider, return
14
+ * that one; otherwise fall back to the cap's sole/first provider (an
15
+ * `addonId` that names no hosted provider is method DATA, not routing —
16
+ * e.g. `addons.restartAddon({ addonId })`).
17
+ */
18
+ getSingletonProvider(capName: string, addonId?: string): object | null | undefined;
11
19
  /** Resolve a device-scoped provider by cap name and device id. */
12
20
  getDeviceProvider(capName: string, deviceId: number): object | null | undefined;
13
21
  }
@@ -32,6 +32,17 @@ interface RegisteredNativeCap {
32
32
  readonly addonId: string;
33
33
  readonly deviceIds: readonly number[];
34
34
  }
35
+ /**
36
+ * A node's runtime-updatable ROOT package identity (`@camstack/server` on
37
+ * the hub, `@camstack/agent` on agents) — carried in the `registerNode`
38
+ * manifest so the hub knows every node's exact software version (design:
39
+ * runtime-updatable node packages, "visibility"). Version skew is SEEN in
40
+ * the UI instead of discovered via a black-hole.
41
+ */
42
+ interface NodeRootPackageInfo {
43
+ readonly name: string;
44
+ readonly version: string;
45
+ }
35
46
  /** Payload of the `$hub.registerNode` RPC — a node's COMPLETE manifest. */
36
47
  interface RegisterNodeParams {
37
48
  readonly nodeId: string;
@@ -50,6 +61,12 @@ interface RegisterNodeParams {
50
61
  * receiver; never carries the raw secret. (Cluster-secret registration gate.)
51
62
  */
52
63
  readonly clusterSecretHash?: string;
64
+ /**
65
+ * The node's root-package identity. Optional — absent from UDS child
66
+ * manifests and pre-phase-2 agents; present on agents running the
67
+ * runtime-updatable root model.
68
+ */
69
+ readonly rootPackage?: NodeRootPackageInfo;
53
70
  }
54
71
  /** Ack returned by `$hub.registerNode` — presence of `ok` is the signal. */
55
72
  interface RegisterNodeResult {
@@ -73,6 +90,8 @@ declare class HubNodeRegistry {
73
90
  private readonly nodes;
74
91
  /** nodeId → its device-scoped native caps (last `registerNode` wins). */
75
92
  private readonly nativeCaps;
93
+ /** nodeId → its root-package identity (last `registerNode` wins). */
94
+ private readonly rootPackages;
76
95
  /**
77
96
  * deviceId → flat native-cap entries for THAT device, across all nodes.
78
97
  * Maintained incrementally on every `registerNode`/`removeNode` so a
@@ -99,6 +118,8 @@ declare class HubNodeRegistry {
99
118
  registerNode(params: RegisterNodeParams): void;
100
119
  /** Drop a node entirely — caps AND native caps — on `$node.disconnected`. */
101
120
  removeNode(nodeId: string): void;
121
+ /** The node's root-package identity, or null when it never reported one. */
122
+ getNodeRootPackage(nodeId: string): NodeRootPackageInfo | null;
102
123
  /** The node's manifest, or undefined when the node never registered. */
103
124
  getNodeManifest(nodeId: string): readonly RegisteredAddonManifest[] | undefined;
104
125
  /**
@@ -123,4 +144,4 @@ declare class HubNodeRegistry {
123
144
  listNodeIds(): readonly string[];
124
145
  }
125
146
  export { HubNodeRegistry };
126
- export type { CallFn, RegisteredAddonManifest, RegisteredNativeCap, RegisterNodeParams, RegisterNodeResult, NodeCapEntry, NodeNativeCapEntry, };
147
+ export type { CallFn, NodeRootPackageInfo, RegisteredAddonManifest, RegisteredNativeCap, RegisterNodeParams, RegisterNodeResult, NodeCapEntry, NodeNativeCapEntry, };
@@ -1,4 +1,4 @@
1
- import { RegisteredAddonManifest, RegisteredNativeCap, RegisterNodeParams } from './node-registry.js';
1
+ import { NodeRootPackageInfo, RegisteredAddonManifest, RegisteredNativeCap, RegisterNodeParams } from './node-registry.js';
2
2
  /** Minimal broker surface this client needs. */
3
3
  interface RegisterNodeBroker {
4
4
  call(action: string, params: unknown, opts?: {
@@ -19,11 +19,14 @@ interface CallRegisterNodeOptions {
19
19
  }
20
20
  /**
21
21
  * Build a `RegisterNodeParams` from a node id, its per-addon manifests,
22
- * optionally its device-scoped native caps, and optionally the SHA-256 hash
23
- * of the cluster secret. `nativeCaps` is omitted entirely on the first
24
- * handshake; `clusterSecretHash` is omitted when no secret is configured.
22
+ * optionally its device-scoped native caps, optionally the SHA-256 hash
23
+ * of the cluster secret, and optionally the node's root-package identity
24
+ * (runtime-updatable node packages: version visibility). `nativeCaps` is
25
+ * omitted entirely on the first handshake; `clusterSecretHash` is omitted
26
+ * when no secret is configured; `rootPackage` is omitted by nodes that do
27
+ * not run the root-package model (UDS children).
25
28
  */
26
- declare function buildNodeManifest(nodeId: string, addons: readonly RegisteredAddonManifest[], nativeCaps?: readonly RegisteredNativeCap[], clusterSecretHash?: string): RegisterNodeParams;
29
+ declare function buildNodeManifest(nodeId: string, addons: readonly RegisteredAddonManifest[], nativeCaps?: readonly RegisteredNativeCap[], clusterSecretHash?: string, rootPackage?: NodeRootPackageInfo): RegisterNodeParams;
27
30
  /**
28
31
  * Call `<target>.registerNode` and retry until the parent acks. The loop
29
32
  * terminates ONLY on a successful ack or an abort — there is no fixed
@@ -9,6 +9,16 @@ export interface ChildCapDescriptor {
9
9
  readonly mode: 'singleton' | 'collection';
10
10
  /** Present for device-scoped caps; absent for singleton/system caps. */
11
11
  readonly deviceId?: number;
12
+ /**
13
+ * The addon that registered this cap. A GROUPED runner (`execution.group`)
14
+ * hosts multiple addons in one child, so the parent can no longer assume
15
+ * `addonId === childId` — this field lets the parent's manifest builder
16
+ * split the descriptor set into one `RegisteredAddonManifest` entry per
17
+ * hosted addon (real provider registryKeys, per-addon settings/logs/UI).
18
+ * OPTIONAL for wire compat: a legacy child omits it and the parent falls
19
+ * back to the childId (identical to the historical single-addon behaviour).
20
+ */
21
+ readonly addonId?: string;
12
22
  }
13
23
  /** First message a child sends after connecting — its complete cap manifest. */
14
24
  export interface RegisterMessage {
@@ -90,6 +100,16 @@ export interface CapCallMessage {
90
100
  readonly deviceId?: number;
91
101
  /** Optional per-call node pin (out-of-band routing hint; see {@link CapCallOutMessage.nodeId}). */
92
102
  readonly nodeId?: string;
103
+ /**
104
+ * Out-of-band PROVIDER-selection hint: the addonId of the provider the hub
105
+ * resolved for this call. Needed for GROUPED runners where two co-located
106
+ * addons register the SAME collection cap (e.g. `network-access` from both
107
+ * cloudflare-tunnel and tailscale-ingress) — the hub's collection mount
108
+ * strips `addonId` from the method args after resolving the provider, so
109
+ * without this hint the child could only pick one-per-capName. Absent →
110
+ * the child dispatch falls back to its sole provider for the cap.
111
+ */
112
+ readonly addonId?: string;
93
113
  }
94
114
  /** Parent → child: a system event delivered by the hub for the child to handle locally. */
95
115
  export interface ParentEventMessage {
@@ -1,4 +1,4 @@
1
- import { H as readNodePin } from "./dist-DlGZpWo8.mjs";
1
+ import { H as readNodePin } from "./dist-CU3lb_Ys.mjs";
2
2
  import { ensureBinary, ensureFfmpeg, ensurePython, installPythonPackages, installPythonRequirements } from "@camstack/types/node";
3
3
  import { createServer } from "node:http";
4
4
  import * as fs from "node:fs";
@@ -4192,7 +4192,8 @@ var LocalChildRegistry = class {
4192
4192
  capName: input.capName,
4193
4193
  method: input.method,
4194
4194
  args: input.args,
4195
- ...input.deviceId !== void 0 ? { deviceId: input.deviceId } : {}
4195
+ ...input.deviceId !== void 0 ? { deviceId: input.deviceId } : {},
4196
+ ...input.addonId !== void 0 ? { addonId: input.addonId } : {}
4196
4197
  };
4197
4198
  }
4198
4199
  listChildren() {
@@ -4890,6 +4891,7 @@ function createParentUnownedCallHandler(deps) {
4890
4891
  return async (input) => {
4891
4892
  const deviceId = input.deviceId ?? extractDeviceId(input.args);
4892
4893
  const nodeId = deps.isDataNodeIdCap?.(input.capName) === true ? void 0 : input.nodeId ?? extractNodeId(input.args);
4894
+ const pinnedToOtherNode = nodeId !== void 0 && nodeId !== deps.broker.nodeID;
4893
4895
  if (nodeId === void 0) {
4894
4896
  const empty = deps.resolveEmptyCollection?.(input.capName, input.method);
4895
4897
  if (empty != null) return empty;
@@ -4906,7 +4908,7 @@ function createParentUnownedCallHandler(deps) {
4906
4908
  }
4907
4909
  else deps.logger?.debug?.(`onUnownedCall: resolver not ready, routing ${input.capName}.${input.method} via broker fallback`);
4908
4910
  try {
4909
- if (deviceId !== void 0) {
4911
+ if (deviceId !== void 0 && !pinnedToOtherNode) {
4910
4912
  const localDispatcher = deps.getLocalDispatcher?.() ?? null;
4911
4913
  if (localDispatcher !== null) {
4912
4914
  let childId = localDispatcher.resolveChildId(input.capName, deviceId);
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require("./chunk-Cek0wNdY.js");
2
- const require_dist = require("./dist-DriXJoVg.js");
2
+ const require_dist = require("./dist-fRVWwrkF.js");
3
3
  let _camstack_types_node = require("@camstack/types/node");
4
4
  let node_http = require("node:http");
5
5
  let node_fs = require("node:fs");
@@ -4194,7 +4194,8 @@ var LocalChildRegistry = class {
4194
4194
  capName: input.capName,
4195
4195
  method: input.method,
4196
4196
  args: input.args,
4197
- ...input.deviceId !== void 0 ? { deviceId: input.deviceId } : {}
4197
+ ...input.deviceId !== void 0 ? { deviceId: input.deviceId } : {},
4198
+ ...input.addonId !== void 0 ? { addonId: input.addonId } : {}
4198
4199
  };
4199
4200
  }
4200
4201
  listChildren() {
@@ -4892,6 +4893,7 @@ function createParentUnownedCallHandler(deps) {
4892
4893
  return async (input) => {
4893
4894
  const deviceId = input.deviceId ?? extractDeviceId(input.args);
4894
4895
  const nodeId = deps.isDataNodeIdCap?.(input.capName) === true ? void 0 : input.nodeId ?? extractNodeId(input.args);
4896
+ const pinnedToOtherNode = nodeId !== void 0 && nodeId !== deps.broker.nodeID;
4895
4897
  if (nodeId === void 0) {
4896
4898
  const empty = deps.resolveEmptyCollection?.(input.capName, input.method);
4897
4899
  if (empty != null) return empty;
@@ -4908,7 +4910,7 @@ function createParentUnownedCallHandler(deps) {
4908
4910
  }
4909
4911
  else deps.logger?.debug?.(`onUnownedCall: resolver not ready, routing ${input.capName}.${input.method} via broker fallback`);
4910
4912
  try {
4911
- if (deviceId !== void 0) {
4913
+ if (deviceId !== void 0 && !pinnedToOtherNode) {
4912
4914
  const localDispatcher = deps.getLocalDispatcher?.() ?? null;
4913
4915
  if (localDispatcher !== null) {
4914
4916
  let childId = localDispatcher.resolveChildId(input.capName, deviceId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.1.35",
3
+ "version": "1.1.37",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",