@camstack/system 1.2.170 → 1.2.171

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/index.js CHANGED
@@ -5316,7 +5316,6 @@ var CapabilityRegistry = class CapabilityRegistry {
5316
5316
  routerFactory = null;
5317
5317
  configReader = null;
5318
5318
  collectionConfigReader = null;
5319
- configManager = null;
5320
5319
  _ready = false;
5321
5320
  /** Boot-time dependency graph: capability → dependsOn names (from CapabilityDeclaration) */
5322
5321
  capabilityDeps = /* @__PURE__ */ new Map();
@@ -5401,10 +5400,6 @@ var CapabilityRegistry = class CapabilityRegistry {
5401
5400
  setCollectionConfigReader(reader) {
5402
5401
  this.collectionConfigReader = reader;
5403
5402
  }
5404
- /** Set the config manager for persisted device activation state. */
5405
- setConfigManager(manager) {
5406
- this.configManager = manager;
5407
- }
5408
5403
  /** Register boot-time dependency edges (from CapabilityDeclaration.dependsOn). */
5409
5404
  setDependencies(capabilityName, dependsOn) {
5410
5405
  this.capabilityDeps.set(capabilityName, dependsOn);
@@ -6140,88 +6135,18 @@ var CapabilityRegistry = class CapabilityRegistry {
6140
6135
  });
6141
6136
  }
6142
6137
  /**
6143
- * Check if a specific addon's capability is active system-wide.
6138
+ * Check if a specific addon's capability is active.
6144
6139
  *
6145
- * Resolution: 1. explicit system override → 2. autoActivate flag 3. default true
6140
+ * Resolution: the manifest's `autoActivate` flag, else active. There is no
6141
+ * persisted override layer — see D334: an activation map keyed by
6142
+ * `{capability}/{addonId}` is a second authority over a function some addon
6143
+ * already owns, which is what D62 forbids.
6146
6144
  */
6147
6145
  isActiveForSystem(capability, addonId) {
6148
- if (this.configManager) {
6149
- const explicit = this.configManager.getSystemActivation()[`${capability}/${addonId}`];
6150
- if (explicit !== void 0) return explicit;
6151
- }
6152
6146
  const autoActivate = this.autoActivateFlags.get(`${capability}/${addonId}`);
6153
6147
  if (autoActivate !== void 0) return autoActivate;
6154
6148
  return true;
6155
6149
  }
6156
- /** Set system-wide activation for a capability/addon pair. */
6157
- setSystemActivation(capability, addonId, active) {
6158
- if (!this.configManager) {
6159
- this.logger.warn("Cannot set system activation: ConfigManager not wired");
6160
- return;
6161
- }
6162
- this.configManager.setSystemActivation(capability, addonId, active);
6163
- this.logger.info("System activation set", {
6164
- tags: { addonId },
6165
- meta: {
6166
- capability,
6167
- active
6168
- }
6169
- });
6170
- this.emitEvent("capability:system-activation-changed", {
6171
- capability,
6172
- addonId,
6173
- active
6174
- });
6175
- }
6176
- /**
6177
- * Check if a specific addon's capability is active for a device.
6178
- *
6179
- * Resolution: 1. explicit device override → 2. system activation → 3. autoActivate → 4. default true
6180
- */
6181
- isActiveForDevice(capability, addonId, deviceId) {
6182
- if (this.configManager) {
6183
- const explicit = this.configManager.getDeviceActivation(deviceId)[`${capability}/${addonId}`];
6184
- if (explicit !== void 0) return explicit;
6185
- }
6186
- return this.isActiveForSystem(capability, addonId);
6187
- }
6188
- /** Set device activation for a capability/addon pair. */
6189
- setDeviceActivation(deviceId, capability, addonId, active) {
6190
- if (!this.configManager) {
6191
- this.logger.warn("Cannot set device activation: ConfigManager not wired");
6192
- return;
6193
- }
6194
- this.configManager.setDeviceActivation(deviceId, capability, addonId, active);
6195
- this.logger.info("Device activation set", {
6196
- tags: {
6197
- deviceId: Number(deviceId),
6198
- addonId
6199
- },
6200
- meta: {
6201
- capability,
6202
- active
6203
- }
6204
- });
6205
- this.emitEvent("capability:device-activation-changed", {
6206
- deviceId,
6207
- capability,
6208
- addonId,
6209
- active
6210
- });
6211
- }
6212
- /**
6213
- * Get all addon/capability activations for a device.
6214
- * Returns every registered provider with its resolved active status.
6215
- */
6216
- getDeviceActivations(deviceId) {
6217
- const result = [];
6218
- for (const [capName, state] of this.capabilities) for (const addonId of state.providers.keys()) result.push({
6219
- capability: capName,
6220
- addonId,
6221
- active: this.isActiveForDevice(capName, addonId, deviceId)
6222
- });
6223
- return result;
6224
- }
6225
6150
  /**
6226
6151
  * Get all addon/capability activations at system level.
6227
6152
  * Returns every registered provider with its resolved active status.
@@ -6280,7 +6205,8 @@ var CapabilityRegistry = class CapabilityRegistry {
6280
6205
  }
6281
6206
  /**
6282
6207
  * Resolve a singleton provider for a specific device.
6283
- * Checks activation (autoActivate + explicit overrides) then per-device override.
6208
+ * Checks activation (the manifest's autoActivate) then the per-device
6209
+ * singleton override — the in-memory provider pin, not a persisted flag.
6284
6210
  */
6285
6211
  resolveForDevice(capability, deviceId) {
6286
6212
  const state = this.capabilities.get(capability);
@@ -6289,7 +6215,7 @@ var CapabilityRegistry = class CapabilityRegistry {
6289
6215
  if (deviceMap) {
6290
6216
  const overrideAddonId = deviceMap.get(capability);
6291
6217
  if (overrideAddonId) {
6292
- if (this.isActiveForDevice(capability, overrideAddonId, deviceId)) {
6218
+ if (this.isActiveForSystem(capability, overrideAddonId)) {
6293
6219
  const provider = state.providers.get(overrideAddonId);
6294
6220
  if (provider) return asProvider(provider);
6295
6221
  }
@@ -6302,11 +6228,11 @@ var CapabilityRegistry = class CapabilityRegistry {
6302
6228
  });
6303
6229
  }
6304
6230
  }
6305
- if (state.activeAddonId && this.isActiveForDevice(capability, state.activeAddonId, deviceId)) {
6231
+ if (state.activeAddonId && this.isActiveForSystem(capability, state.activeAddonId)) {
6306
6232
  const active = state.providers.get(state.activeAddonId);
6307
6233
  return active !== void 0 ? asProvider(active) : null;
6308
6234
  }
6309
- for (const [addonId, provider] of state.providers) if (this.isActiveForDevice(capability, addonId, deviceId)) return asProvider(provider);
6235
+ for (const [addonId, provider] of state.providers) if (this.isActiveForSystem(capability, addonId)) return asProvider(provider);
6310
6236
  return null;
6311
6237
  }
6312
6238
  /** Set a per-device collection filter. */
@@ -6342,12 +6268,12 @@ var CapabilityRegistry = class CapabilityRegistry {
6342
6268
  }
6343
6269
  /**
6344
6270
  * Resolve collection providers for a specific device.
6345
- * Filters by activation (autoActivate + explicit overrides) and optional collection filter.
6271
+ * Filters by activation (the manifest's autoActivate) and optional collection filter.
6346
6272
  */
6347
6273
  resolveCollectionForDevice(capability, deviceId) {
6348
6274
  const state = this.capabilities.get(capability);
6349
6275
  if (!state || state.definition.mode !== "collection") return [];
6350
- let entries = [...state.providers.entries()].filter(([addonId]) => !state.disabledProviders.has(addonId)).filter(([addonId]) => this.isActiveForDevice(capability, addonId, deviceId));
6276
+ let entries = [...state.providers.entries()].filter(([addonId]) => !state.disabledProviders.has(addonId)).filter(([addonId]) => this.isActiveForSystem(capability, addonId));
6351
6277
  const deviceMap = this.deviceCollectionFilters.get(deviceId);
6352
6278
  if (deviceMap) {
6353
6279
  const filterAddonIds = deviceMap.get(capability);
@@ -9485,26 +9411,17 @@ var ENV_VAR_MAP = {
9485
9411
  CAMSTACK_ADMIN_USER: "auth.adminUsername",
9486
9412
  CAMSTACK_ADMIN_PASS: "auth.adminPassword"
9487
9413
  };
9488
- var EMPTY_RUNTIME_STATE = {
9489
- systemActivation: {},
9490
- deviceActivation: {}
9491
- };
9492
9414
  var ConfigManager = class ConfigManager {
9493
9415
  configPath;
9494
9416
  bootstrapConfig;
9495
9417
  settingsStore = null;
9496
9418
  settingsDoor = null;
9497
- runtimeState;
9498
- runtimeStatePath;
9499
9419
  constructor(configPath) {
9500
9420
  this.configPath = configPath;
9501
9421
  const rawYaml = this.loadYaml();
9502
9422
  const merged = this.applyEnvOverrides((0, _camstack_types_addon.asJsonObject)(rawYaml) ?? {});
9503
9423
  this.bootstrapConfig = bootstrapSchema.parse(merged);
9504
9424
  this.warnDefaultCredentials();
9505
- const dataPath = this.bootstrapConfig.server.dataPath ?? "camstack-data";
9506
- this.runtimeStatePath = node_path.resolve(dataPath, "runtime-state.json");
9507
- this.runtimeState = this.loadRuntimeState();
9508
9425
  }
9509
9426
  /**
9510
9427
  * Wire the settings-store backend. Called once, after the `settings-store`
@@ -9789,72 +9706,6 @@ var ConfigManager = class ConfigManager {
9789
9706
  }
9790
9707
  };
9791
9708
  }
9792
- /** Get all system-wide activation overrides. */
9793
- getSystemActivation() {
9794
- return this.runtimeState.systemActivation;
9795
- }
9796
- /** Set system-wide activation for a capability/addon pair. */
9797
- setSystemActivation(capability, addonId, active) {
9798
- const key = `${capability}/${addonId}`;
9799
- this.runtimeState = {
9800
- ...this.runtimeState,
9801
- systemActivation: {
9802
- ...this.runtimeState.systemActivation,
9803
- [key]: active
9804
- }
9805
- };
9806
- this.saveRuntimeState();
9807
- }
9808
- /**
9809
- * Get activation overrides for a device.
9810
- * Returns a map of `{capability}/{addonId}` → active boolean.
9811
- * Missing entries mean "use system activation or autoActivate default".
9812
- */
9813
- getDeviceActivation(deviceId) {
9814
- return this.runtimeState.deviceActivation[deviceId] ?? {};
9815
- }
9816
- /**
9817
- * Get all device activation overrides.
9818
- * Returns deviceId → (`{capability}/{addonId}` → active).
9819
- */
9820
- getAllDeviceActivation() {
9821
- return this.runtimeState.deviceActivation;
9822
- }
9823
- /**
9824
- * Set activation for a specific capability/addon on a device.
9825
- * Persists immediately to runtime-state.json.
9826
- *
9827
- * @param deviceId - The device to configure
9828
- * @param capability - Capability name (e.g., 'motion-detection')
9829
- * @param addonId - Addon providing the capability (e.g., 'wasm-motion')
9830
- * @param active - Whether the capability is active on this device
9831
- */
9832
- setDeviceActivation(deviceId, capability, addonId, active) {
9833
- const key = `${capability}/${addonId}`;
9834
- const updated = {
9835
- ...this.runtimeState.deviceActivation[deviceId] ?? {},
9836
- [key]: active
9837
- };
9838
- this.runtimeState = {
9839
- ...this.runtimeState,
9840
- deviceActivation: {
9841
- ...this.runtimeState.deviceActivation,
9842
- [deviceId]: updated
9843
- }
9844
- };
9845
- this.saveRuntimeState();
9846
- }
9847
- /**
9848
- * Clear all activation overrides for a device (resets to autoActivate defaults).
9849
- */
9850
- clearDeviceActivation(deviceId) {
9851
- const { [deviceId]: _removed, ...rest } = this.runtimeState.deviceActivation;
9852
- this.runtimeState = {
9853
- ...this.runtimeState,
9854
- deviceActivation: rest
9855
- };
9856
- this.saveRuntimeState();
9857
- }
9858
9709
  getBootstrap(configPath) {
9859
9710
  return this.getFromBootstrap(configPath);
9860
9711
  }
@@ -10024,39 +9875,6 @@ var ConfigManager = class ConfigManager {
10024
9875
  }
10025
9876
  return found ? result : null;
10026
9877
  }
10027
- loadRuntimeState() {
10028
- if (!node_fs.existsSync(this.runtimeStatePath)) return EMPTY_RUNTIME_STATE;
10029
- try {
10030
- const parsed = (0, _camstack_types_addon.asJsonObject)((0, _camstack_types_addon.parseJsonUnknown)(node_fs.readFileSync(this.runtimeStatePath, "utf-8")));
10031
- if (parsed === null) return EMPTY_RUNTIME_STATE;
10032
- const systemActivation = (0, _camstack_types_addon.asJsonObject)(parsed.systemActivation) ?? {};
10033
- const deviceActivationRaw = (0, _camstack_types_addon.asJsonObject)(parsed.deviceActivation) ?? {};
10034
- const deviceActivation = {};
10035
- for (const [deviceId, entry] of Object.entries(deviceActivationRaw)) {
10036
- const nested = (0, _camstack_types_addon.asJsonObject)(entry);
10037
- if (nested === null) continue;
10038
- const bools = {};
10039
- for (const [k, v] of Object.entries(nested)) if (typeof v === "boolean") bools[k] = v;
10040
- deviceActivation[deviceId] = bools;
10041
- }
10042
- const systemBools = {};
10043
- for (const [k, v] of Object.entries(systemActivation)) if (typeof v === "boolean") systemBools[k] = v;
10044
- return {
10045
- systemActivation: systemBools,
10046
- deviceActivation
10047
- };
10048
- } catch {
10049
- console.warn(`[ConfigManager] Failed to parse runtime state at ${this.runtimeStatePath}, using defaults`);
10050
- return EMPTY_RUNTIME_STATE;
10051
- }
10052
- }
10053
- saveRuntimeState() {
10054
- const dir = node_path.dirname(this.runtimeStatePath);
10055
- if (!node_fs.existsSync(dir)) node_fs.mkdirSync(dir, { recursive: true });
10056
- const tmpPath = `${this.runtimeStatePath}.tmp`;
10057
- node_fs.writeFileSync(tmpPath, JSON.stringify(this.runtimeState, null, 2), "utf-8");
10058
- node_fs.renameSync(tmpPath, this.runtimeStatePath);
10059
- }
10060
9878
  };
10061
9879
  //#endregion
10062
9880
  //#region ../../node_modules/moleculer/src/constants.js
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM$1, r as __exportAll, t as __commonJSMin$1 } from "./chunk-CNf5ZN-e.mjs";
2
- import { $ as isCollectionArrayMethod, $t as parseJsonObject, Bt as ReadinessRegistry, E as addonSettingsCapability, Ft as DEVICE_SETTINGS_CONTRIBUTION_METHODS, Gt as asString$1, It as DEVICE_STATUS_METHOD, Kt as createEvent, Mt as errMsg$1, Pt as DATAPLANE_SECRET_HEADER$1, Q as isArrayOutputSchema, Ut as asJsonObject$1, Vt as ReadinessTimeoutError, Wt as asNumber, Y as extractNestedAddonId, Yt as expandCapMethods, an as EventCategory$1, at as lifecycleJobSchema, bt as scopesAllowAddon, ct as logLevelAtMost, en as parseJsonUnknown$1, et as isObjectInput, f as LOG_LEVEL_RANK, ft as objectInputDeclaresAddonId, h as RUNTIME_DEFAULTS, ht as procedureAuthKey, it as kebabToCamel, lt as looseSchema, nn as resolveCapMount, p as METHOD_ACCESS_MAP, qt as emitDownForOwnedCaps, rn as scopeKey, rt as isVoidInput, t as ALL_CAPABILITY_DEFINITIONS, tn as readinessKey, vt as resolveMethodAuth, xt as scopesAllowDeviceCap } from "./dist-1DEQFmTq.mjs";
2
+ import { $ as isCollectionArrayMethod, $t as parseJsonObject, Bt as ReadinessRegistry, E as addonSettingsCapability, Ft as DEVICE_SETTINGS_CONTRIBUTION_METHODS, Gt as asString$1, It as DEVICE_STATUS_METHOD, Kt as createEvent, Mt as errMsg$1, Pt as DATAPLANE_SECRET_HEADER$1, Q as isArrayOutputSchema, Ut as asJsonObject$1, Vt as ReadinessTimeoutError, Wt as asNumber, Y as extractNestedAddonId, Yt as expandCapMethods, an as EventCategory$1, at as lifecycleJobSchema, bt as scopesAllowAddon, ct as logLevelAtMost, en as parseJsonUnknown, et as isObjectInput, f as LOG_LEVEL_RANK, ft as objectInputDeclaresAddonId, h as RUNTIME_DEFAULTS, ht as procedureAuthKey, it as kebabToCamel, lt as looseSchema, nn as resolveCapMount, p as METHOD_ACCESS_MAP, qt as emitDownForOwnedCaps, rn as scopeKey, rt as isVoidInput, t as ALL_CAPABILITY_DEFINITIONS, tn as readinessKey, vt as resolveMethodAuth, xt as scopesAllowDeviceCap } from "./dist-1DEQFmTq.mjs";
3
3
  import { AlertCenterAddon } from "./builtins/alerts/alerts.addon.mjs";
4
4
  import "./builtins/alerts/index.mjs";
5
5
  import { t as formatLogLine } from "./formatter-B7qW8bPJ.mjs";
@@ -43,7 +43,7 @@ import { accessSync, constants, existsSync } from "node:fs";
43
43
  import * as os$18 from "node:os";
44
44
  import { request } from "node:http";
45
45
  import * as vm from "node:vm";
46
- import { asJsonObject, errMsg, parseJsonUnknown } from "@camstack/types/addon";
46
+ import { asJsonObject, errMsg } from "@camstack/types/addon";
47
47
  import { fileURLToPath, pathToFileURL } from "node:url";
48
48
  import { EventEmitter } from "node:events";
49
49
  import As from "node:stream";
@@ -2757,7 +2757,7 @@ function readOwningPackageVersion(entryPath) {
2757
2757
  let dir = path$39.dirname(entryPath);
2758
2758
  for (let hop = 0; hop < PACKAGE_JSON_LOOKUP_DEPTH; hop++) {
2759
2759
  try {
2760
- const version = asJsonObject$1(parseJsonUnknown$1(fs$17.readFileSync(path$39.join(dir, "package.json"), "utf-8")))?.["version"];
2760
+ const version = asJsonObject$1(parseJsonUnknown(fs$17.readFileSync(path$39.join(dir, "package.json"), "utf-8")))?.["version"];
2761
2761
  if (typeof version === "string" && version.length > 0) return version;
2762
2762
  } catch {}
2763
2763
  const parent = path$39.dirname(dir);
@@ -2947,7 +2947,7 @@ var AddonLoader = class {
2947
2947
  /** Load addon from a specific directory (package.json + dist/) */
2948
2948
  async loadFromAddonDir(addonDir) {
2949
2949
  const pkgJsonPath = path$39.join(addonDir, "package.json");
2950
- const pkgJson = asJsonObject$1(parseJsonUnknown$1(fs$17.readFileSync(pkgJsonPath, "utf-8"))) ?? {};
2950
+ const pkgJson = asJsonObject$1(parseJsonUnknown(fs$17.readFileSync(pkgJsonPath, "utf-8"))) ?? {};
2951
2951
  const packageNameRaw = pkgJson["name"];
2952
2952
  const packageName = typeof packageNameRaw === "string" ? packageNameRaw : "";
2953
2953
  const packageVersionRaw = pkgJson["version"];
@@ -3384,7 +3384,7 @@ async function installPackageFromNpm(packageName, targetDir) {
3384
3384
  const distSrc = path$39.join(srcPkgJsonDir, "dist");
3385
3385
  if (fs$17.existsSync(distSrc)) await copyDirRecursive(distSrc, path$39.join(targetDir, "dist"));
3386
3386
  try {
3387
- const npmPkg = asJsonObject$1(parseJsonUnknown$1(await fs$17.promises.readFile(path$39.join(srcPkgJsonDir, "package.json"), "utf-8")));
3387
+ const npmPkg = asJsonObject$1(parseJsonUnknown(await fs$17.promises.readFile(path$39.join(srcPkgJsonDir, "package.json"), "utf-8")));
3388
3388
  if (npmPkg) await copyExtraFileDirs(npmPkg, srcPkgJsonDir, targetDir);
3389
3389
  } catch {}
3390
3390
  } finally {
@@ -3685,7 +3685,7 @@ function parseInstallSource(value) {
3685
3685
  function readPackageJson(pkgJsonPath) {
3686
3686
  let raw;
3687
3687
  try {
3688
- raw = asJsonObject$1(parseJsonUnknown$1(fs$17.readFileSync(pkgJsonPath, "utf-8")));
3688
+ raw = asJsonObject$1(parseJsonUnknown(fs$17.readFileSync(pkgJsonPath, "utf-8")));
3689
3689
  } catch {
3690
3690
  return null;
3691
3691
  }
@@ -4904,7 +4904,7 @@ var AddonInstaller = class AddonInstaller {
4904
4904
  ]) {
4905
4905
  const candidate = path$39.join(this.workspaceDir, dirName);
4906
4906
  try {
4907
- const pkg = asJsonObject$1(parseJsonUnknown$1(fs$17.readFileSync(path$39.join(candidate, "package.json"), "utf-8")));
4907
+ const pkg = asJsonObject$1(parseJsonUnknown(fs$17.readFileSync(path$39.join(candidate, "package.json"), "utf-8")));
4908
4908
  if (pkg && asString$1(pkg["name"]) === packageName) return candidate;
4909
4909
  } catch {}
4910
4910
  }
@@ -5231,7 +5231,7 @@ function readPendingRestart(dataDir) {
5231
5231
  }
5232
5232
  let parsed;
5233
5233
  try {
5234
- parsed = asJsonObject$1(parseJsonUnknown$1(raw));
5234
+ parsed = asJsonObject$1(parseJsonUnknown(raw));
5235
5235
  } catch (err) {
5236
5236
  console.error("[restart-coordinator] Marker JSON invalid — clearing:", err);
5237
5237
  clearPendingRestart(dataDir);
@@ -5309,7 +5309,6 @@ var CapabilityRegistry = class CapabilityRegistry {
5309
5309
  routerFactory = null;
5310
5310
  configReader = null;
5311
5311
  collectionConfigReader = null;
5312
- configManager = null;
5313
5312
  _ready = false;
5314
5313
  /** Boot-time dependency graph: capability → dependsOn names (from CapabilityDeclaration) */
5315
5314
  capabilityDeps = /* @__PURE__ */ new Map();
@@ -5394,10 +5393,6 @@ var CapabilityRegistry = class CapabilityRegistry {
5394
5393
  setCollectionConfigReader(reader) {
5395
5394
  this.collectionConfigReader = reader;
5396
5395
  }
5397
- /** Set the config manager for persisted device activation state. */
5398
- setConfigManager(manager) {
5399
- this.configManager = manager;
5400
- }
5401
5396
  /** Register boot-time dependency edges (from CapabilityDeclaration.dependsOn). */
5402
5397
  setDependencies(capabilityName, dependsOn) {
5403
5398
  this.capabilityDeps.set(capabilityName, dependsOn);
@@ -6133,88 +6128,18 @@ var CapabilityRegistry = class CapabilityRegistry {
6133
6128
  });
6134
6129
  }
6135
6130
  /**
6136
- * Check if a specific addon's capability is active system-wide.
6131
+ * Check if a specific addon's capability is active.
6137
6132
  *
6138
- * Resolution: 1. explicit system override → 2. autoActivate flag 3. default true
6133
+ * Resolution: the manifest's `autoActivate` flag, else active. There is no
6134
+ * persisted override layer — see D334: an activation map keyed by
6135
+ * `{capability}/{addonId}` is a second authority over a function some addon
6136
+ * already owns, which is what D62 forbids.
6139
6137
  */
6140
6138
  isActiveForSystem(capability, addonId) {
6141
- if (this.configManager) {
6142
- const explicit = this.configManager.getSystemActivation()[`${capability}/${addonId}`];
6143
- if (explicit !== void 0) return explicit;
6144
- }
6145
6139
  const autoActivate = this.autoActivateFlags.get(`${capability}/${addonId}`);
6146
6140
  if (autoActivate !== void 0) return autoActivate;
6147
6141
  return true;
6148
6142
  }
6149
- /** Set system-wide activation for a capability/addon pair. */
6150
- setSystemActivation(capability, addonId, active) {
6151
- if (!this.configManager) {
6152
- this.logger.warn("Cannot set system activation: ConfigManager not wired");
6153
- return;
6154
- }
6155
- this.configManager.setSystemActivation(capability, addonId, active);
6156
- this.logger.info("System activation set", {
6157
- tags: { addonId },
6158
- meta: {
6159
- capability,
6160
- active
6161
- }
6162
- });
6163
- this.emitEvent("capability:system-activation-changed", {
6164
- capability,
6165
- addonId,
6166
- active
6167
- });
6168
- }
6169
- /**
6170
- * Check if a specific addon's capability is active for a device.
6171
- *
6172
- * Resolution: 1. explicit device override → 2. system activation → 3. autoActivate → 4. default true
6173
- */
6174
- isActiveForDevice(capability, addonId, deviceId) {
6175
- if (this.configManager) {
6176
- const explicit = this.configManager.getDeviceActivation(deviceId)[`${capability}/${addonId}`];
6177
- if (explicit !== void 0) return explicit;
6178
- }
6179
- return this.isActiveForSystem(capability, addonId);
6180
- }
6181
- /** Set device activation for a capability/addon pair. */
6182
- setDeviceActivation(deviceId, capability, addonId, active) {
6183
- if (!this.configManager) {
6184
- this.logger.warn("Cannot set device activation: ConfigManager not wired");
6185
- return;
6186
- }
6187
- this.configManager.setDeviceActivation(deviceId, capability, addonId, active);
6188
- this.logger.info("Device activation set", {
6189
- tags: {
6190
- deviceId: Number(deviceId),
6191
- addonId
6192
- },
6193
- meta: {
6194
- capability,
6195
- active
6196
- }
6197
- });
6198
- this.emitEvent("capability:device-activation-changed", {
6199
- deviceId,
6200
- capability,
6201
- addonId,
6202
- active
6203
- });
6204
- }
6205
- /**
6206
- * Get all addon/capability activations for a device.
6207
- * Returns every registered provider with its resolved active status.
6208
- */
6209
- getDeviceActivations(deviceId) {
6210
- const result = [];
6211
- for (const [capName, state] of this.capabilities) for (const addonId of state.providers.keys()) result.push({
6212
- capability: capName,
6213
- addonId,
6214
- active: this.isActiveForDevice(capName, addonId, deviceId)
6215
- });
6216
- return result;
6217
- }
6218
6143
  /**
6219
6144
  * Get all addon/capability activations at system level.
6220
6145
  * Returns every registered provider with its resolved active status.
@@ -6273,7 +6198,8 @@ var CapabilityRegistry = class CapabilityRegistry {
6273
6198
  }
6274
6199
  /**
6275
6200
  * Resolve a singleton provider for a specific device.
6276
- * Checks activation (autoActivate + explicit overrides) then per-device override.
6201
+ * Checks activation (the manifest's autoActivate) then the per-device
6202
+ * singleton override — the in-memory provider pin, not a persisted flag.
6277
6203
  */
6278
6204
  resolveForDevice(capability, deviceId) {
6279
6205
  const state = this.capabilities.get(capability);
@@ -6282,7 +6208,7 @@ var CapabilityRegistry = class CapabilityRegistry {
6282
6208
  if (deviceMap) {
6283
6209
  const overrideAddonId = deviceMap.get(capability);
6284
6210
  if (overrideAddonId) {
6285
- if (this.isActiveForDevice(capability, overrideAddonId, deviceId)) {
6211
+ if (this.isActiveForSystem(capability, overrideAddonId)) {
6286
6212
  const provider = state.providers.get(overrideAddonId);
6287
6213
  if (provider) return asProvider(provider);
6288
6214
  }
@@ -6295,11 +6221,11 @@ var CapabilityRegistry = class CapabilityRegistry {
6295
6221
  });
6296
6222
  }
6297
6223
  }
6298
- if (state.activeAddonId && this.isActiveForDevice(capability, state.activeAddonId, deviceId)) {
6224
+ if (state.activeAddonId && this.isActiveForSystem(capability, state.activeAddonId)) {
6299
6225
  const active = state.providers.get(state.activeAddonId);
6300
6226
  return active !== void 0 ? asProvider(active) : null;
6301
6227
  }
6302
- for (const [addonId, provider] of state.providers) if (this.isActiveForDevice(capability, addonId, deviceId)) return asProvider(provider);
6228
+ for (const [addonId, provider] of state.providers) if (this.isActiveForSystem(capability, addonId)) return asProvider(provider);
6303
6229
  return null;
6304
6230
  }
6305
6231
  /** Set a per-device collection filter. */
@@ -6335,12 +6261,12 @@ var CapabilityRegistry = class CapabilityRegistry {
6335
6261
  }
6336
6262
  /**
6337
6263
  * Resolve collection providers for a specific device.
6338
- * Filters by activation (autoActivate + explicit overrides) and optional collection filter.
6264
+ * Filters by activation (the manifest's autoActivate) and optional collection filter.
6339
6265
  */
6340
6266
  resolveCollectionForDevice(capability, deviceId) {
6341
6267
  const state = this.capabilities.get(capability);
6342
6268
  if (!state || state.definition.mode !== "collection") return [];
6343
- let entries = [...state.providers.entries()].filter(([addonId]) => !state.disabledProviders.has(addonId)).filter(([addonId]) => this.isActiveForDevice(capability, addonId, deviceId));
6269
+ let entries = [...state.providers.entries()].filter(([addonId]) => !state.disabledProviders.has(addonId)).filter(([addonId]) => this.isActiveForSystem(capability, addonId));
6344
6270
  const deviceMap = this.deviceCollectionFilters.get(deviceId);
6345
6271
  if (deviceMap) {
6346
6272
  const filterAddonIds = deviceMap.get(capability);
@@ -9478,26 +9404,17 @@ var ENV_VAR_MAP = {
9478
9404
  CAMSTACK_ADMIN_USER: "auth.adminUsername",
9479
9405
  CAMSTACK_ADMIN_PASS: "auth.adminPassword"
9480
9406
  };
9481
- var EMPTY_RUNTIME_STATE = {
9482
- systemActivation: {},
9483
- deviceActivation: {}
9484
- };
9485
9407
  var ConfigManager = class ConfigManager {
9486
9408
  configPath;
9487
9409
  bootstrapConfig;
9488
9410
  settingsStore = null;
9489
9411
  settingsDoor = null;
9490
- runtimeState;
9491
- runtimeStatePath;
9492
9412
  constructor(configPath) {
9493
9413
  this.configPath = configPath;
9494
9414
  const rawYaml = this.loadYaml();
9495
9415
  const merged = this.applyEnvOverrides(asJsonObject(rawYaml) ?? {});
9496
9416
  this.bootstrapConfig = bootstrapSchema.parse(merged);
9497
9417
  this.warnDefaultCredentials();
9498
- const dataPath = this.bootstrapConfig.server.dataPath ?? "camstack-data";
9499
- this.runtimeStatePath = path$39.resolve(dataPath, "runtime-state.json");
9500
- this.runtimeState = this.loadRuntimeState();
9501
9418
  }
9502
9419
  /**
9503
9420
  * Wire the settings-store backend. Called once, after the `settings-store`
@@ -9782,72 +9699,6 @@ var ConfigManager = class ConfigManager {
9782
9699
  }
9783
9700
  };
9784
9701
  }
9785
- /** Get all system-wide activation overrides. */
9786
- getSystemActivation() {
9787
- return this.runtimeState.systemActivation;
9788
- }
9789
- /** Set system-wide activation for a capability/addon pair. */
9790
- setSystemActivation(capability, addonId, active) {
9791
- const key = `${capability}/${addonId}`;
9792
- this.runtimeState = {
9793
- ...this.runtimeState,
9794
- systemActivation: {
9795
- ...this.runtimeState.systemActivation,
9796
- [key]: active
9797
- }
9798
- };
9799
- this.saveRuntimeState();
9800
- }
9801
- /**
9802
- * Get activation overrides for a device.
9803
- * Returns a map of `{capability}/{addonId}` → active boolean.
9804
- * Missing entries mean "use system activation or autoActivate default".
9805
- */
9806
- getDeviceActivation(deviceId) {
9807
- return this.runtimeState.deviceActivation[deviceId] ?? {};
9808
- }
9809
- /**
9810
- * Get all device activation overrides.
9811
- * Returns deviceId → (`{capability}/{addonId}` → active).
9812
- */
9813
- getAllDeviceActivation() {
9814
- return this.runtimeState.deviceActivation;
9815
- }
9816
- /**
9817
- * Set activation for a specific capability/addon on a device.
9818
- * Persists immediately to runtime-state.json.
9819
- *
9820
- * @param deviceId - The device to configure
9821
- * @param capability - Capability name (e.g., 'motion-detection')
9822
- * @param addonId - Addon providing the capability (e.g., 'wasm-motion')
9823
- * @param active - Whether the capability is active on this device
9824
- */
9825
- setDeviceActivation(deviceId, capability, addonId, active) {
9826
- const key = `${capability}/${addonId}`;
9827
- const updated = {
9828
- ...this.runtimeState.deviceActivation[deviceId] ?? {},
9829
- [key]: active
9830
- };
9831
- this.runtimeState = {
9832
- ...this.runtimeState,
9833
- deviceActivation: {
9834
- ...this.runtimeState.deviceActivation,
9835
- [deviceId]: updated
9836
- }
9837
- };
9838
- this.saveRuntimeState();
9839
- }
9840
- /**
9841
- * Clear all activation overrides for a device (resets to autoActivate defaults).
9842
- */
9843
- clearDeviceActivation(deviceId) {
9844
- const { [deviceId]: _removed, ...rest } = this.runtimeState.deviceActivation;
9845
- this.runtimeState = {
9846
- ...this.runtimeState,
9847
- deviceActivation: rest
9848
- };
9849
- this.saveRuntimeState();
9850
- }
9851
9702
  getBootstrap(configPath) {
9852
9703
  return this.getFromBootstrap(configPath);
9853
9704
  }
@@ -10017,39 +9868,6 @@ var ConfigManager = class ConfigManager {
10017
9868
  }
10018
9869
  return found ? result : null;
10019
9870
  }
10020
- loadRuntimeState() {
10021
- if (!fs$17.existsSync(this.runtimeStatePath)) return EMPTY_RUNTIME_STATE;
10022
- try {
10023
- const parsed = asJsonObject(parseJsonUnknown(fs$17.readFileSync(this.runtimeStatePath, "utf-8")));
10024
- if (parsed === null) return EMPTY_RUNTIME_STATE;
10025
- const systemActivation = asJsonObject(parsed.systemActivation) ?? {};
10026
- const deviceActivationRaw = asJsonObject(parsed.deviceActivation) ?? {};
10027
- const deviceActivation = {};
10028
- for (const [deviceId, entry] of Object.entries(deviceActivationRaw)) {
10029
- const nested = asJsonObject(entry);
10030
- if (nested === null) continue;
10031
- const bools = {};
10032
- for (const [k, v] of Object.entries(nested)) if (typeof v === "boolean") bools[k] = v;
10033
- deviceActivation[deviceId] = bools;
10034
- }
10035
- const systemBools = {};
10036
- for (const [k, v] of Object.entries(systemActivation)) if (typeof v === "boolean") systemBools[k] = v;
10037
- return {
10038
- systemActivation: systemBools,
10039
- deviceActivation
10040
- };
10041
- } catch {
10042
- console.warn(`[ConfigManager] Failed to parse runtime state at ${this.runtimeStatePath}, using defaults`);
10043
- return EMPTY_RUNTIME_STATE;
10044
- }
10045
- }
10046
- saveRuntimeState() {
10047
- const dir = path$39.dirname(this.runtimeStatePath);
10048
- if (!fs$17.existsSync(dir)) fs$17.mkdirSync(dir, { recursive: true });
10049
- const tmpPath = `${this.runtimeStatePath}.tmp`;
10050
- fs$17.writeFileSync(tmpPath, JSON.stringify(this.runtimeState, null, 2), "utf-8");
10051
- fs$17.renameSync(tmpPath, this.runtimeStatePath);
10052
- }
10053
9871
  };
10054
9872
  //#endregion
10055
9873
  //#region ../../node_modules/moleculer/src/constants.js
@@ -1,5 +1,4 @@
1
1
  import { CapabilityDeclaration, CapabilityDefinition, CapabilityInfo, CapabilityMode, CapabilityProviderMap, CollectionCapabilityMap, IEventBus, IScopedLogger, SingletonCapabilityMap } from '@camstack/types';
2
- import { ConfigManager } from './config-manager.js';
3
2
  /** Result of creating a capability router (opaque to the kernel). */
4
3
  export type CapabilityRouter = unknown;
5
4
  /** Factory that creates a tRPC router from a capability definition + provider getter. */
@@ -38,7 +37,6 @@ export declare class CapabilityRegistry {
38
37
  private routerFactory;
39
38
  private configReader;
40
39
  private collectionConfigReader;
41
- private configManager;
42
40
  private _ready;
43
41
  /** Boot-time dependency graph: capability → dependsOn names (from CapabilityDeclaration) */
44
42
  private readonly capabilityDeps;
@@ -116,8 +114,6 @@ export declare class CapabilityRegistry {
116
114
  * in a previous session comes back disabled after a hub reboot.
117
115
  */
118
116
  setCollectionConfigReader(reader: CollectionConfigReader): void;
119
- /** Set the config manager for persisted device activation state. */
120
- setConfigManager(manager: ConfigManager): void;
121
117
  /** Register boot-time dependency edges (from CapabilityDeclaration.dependsOn). */
122
118
  setDependencies(capabilityName: string, dependsOn: readonly string[]): void;
123
119
  /** Set the router factory — called by the server layer once at boot. */
@@ -440,30 +436,14 @@ export declare class CapabilityRegistry {
440
436
  */
441
437
  setActiveSingleton(capability: string, addonId: string, nodeId?: string): Promise<void>;
442
438
  /**
443
- * Check if a specific addon's capability is active system-wide.
439
+ * Check if a specific addon's capability is active.
444
440
  *
445
- * Resolution: 1. explicit system override → 2. autoActivate flag 3. default true
441
+ * Resolution: the manifest's `autoActivate` flag, else active. There is no
442
+ * persisted override layer — see D334: an activation map keyed by
443
+ * `{capability}/{addonId}` is a second authority over a function some addon
444
+ * already owns, which is what D62 forbids.
446
445
  */
447
446
  isActiveForSystem(capability: string, addonId: string): boolean;
448
- /** Set system-wide activation for a capability/addon pair. */
449
- setSystemActivation(capability: string, addonId: string, active: boolean): void;
450
- /**
451
- * Check if a specific addon's capability is active for a device.
452
- *
453
- * Resolution: 1. explicit device override → 2. system activation → 3. autoActivate → 4. default true
454
- */
455
- isActiveForDevice(capability: string, addonId: string, deviceId: string): boolean;
456
- /** Set device activation for a capability/addon pair. */
457
- setDeviceActivation(deviceId: string, capability: string, addonId: string, active: boolean): void;
458
- /**
459
- * Get all addon/capability activations for a device.
460
- * Returns every registered provider with its resolved active status.
461
- */
462
- getDeviceActivations(deviceId: string): ReadonlyArray<{
463
- capability: string;
464
- addonId: string;
465
- active: boolean;
466
- }>;
467
447
  /**
468
448
  * Get all addon/capability activations at system level.
469
449
  * Returns every registered provider with its resolved active status.
@@ -481,7 +461,8 @@ export declare class CapabilityRegistry {
481
461
  getDeviceOverrides(deviceId: string): Map<string, string>;
482
462
  /**
483
463
  * Resolve a singleton provider for a specific device.
484
- * Checks activation (autoActivate + explicit overrides) then per-device override.
464
+ * Checks activation (the manifest's autoActivate) then the per-device
465
+ * singleton override — the in-memory provider pin, not a persisted flag.
485
466
  */
486
467
  resolveForDevice<T = unknown>(capability: string, deviceId: string): T | null;
487
468
  /** Set a per-device collection filter. */
@@ -490,7 +471,7 @@ export declare class CapabilityRegistry {
490
471
  clearDeviceCollectionFilter(deviceId: string, capability: string): void;
491
472
  /**
492
473
  * Resolve collection providers for a specific device.
493
- * Filters by activation (autoActivate + explicit overrides) and optional collection filter.
474
+ * Filters by activation (the manifest's autoActivate) and optional collection filter.
494
475
  */
495
476
  resolveCollectionForDevice<T = unknown>(capability: string, deviceId: string): readonly T[];
496
477
  /** Check if all dependencies for a capability are satisfied. */
@@ -94,8 +94,6 @@ export declare class ConfigManager {
94
94
  private bootstrapConfig;
95
95
  private settingsStore;
96
96
  private settingsDoor;
97
- private runtimeState;
98
- private readonly runtimeStatePath;
99
97
  constructor(configPath: string);
100
98
  /**
101
99
  * Wire the settings-store backend. Called once, after the `settings-store`
@@ -213,35 +211,6 @@ export declare class ConfigManager {
213
211
  private createDoorBackedSettingsView;
214
212
  /** The sync-`ISettingsStore` backend of {@link createSettingsView}. */
215
213
  private createStoreSettingsView;
216
- /** Get all system-wide activation overrides. */
217
- getSystemActivation(): Readonly<Record<string, boolean>>;
218
- /** Set system-wide activation for a capability/addon pair. */
219
- setSystemActivation(capability: string, addonId: string, active: boolean): void;
220
- /**
221
- * Get activation overrides for a device.
222
- * Returns a map of `{capability}/{addonId}` → active boolean.
223
- * Missing entries mean "use system activation or autoActivate default".
224
- */
225
- getDeviceActivation(deviceId: string): Readonly<Record<string, boolean>>;
226
- /**
227
- * Get all device activation overrides.
228
- * Returns deviceId → (`{capability}/{addonId}` → active).
229
- */
230
- getAllDeviceActivation(): Readonly<Record<string, Record<string, boolean>>>;
231
- /**
232
- * Set activation for a specific capability/addon on a device.
233
- * Persists immediately to runtime-state.json.
234
- *
235
- * @param deviceId - The device to configure
236
- * @param capability - Capability name (e.g., 'motion-detection')
237
- * @param addonId - Addon providing the capability (e.g., 'wasm-motion')
238
- * @param active - Whether the capability is active on this device
239
- */
240
- setDeviceActivation(deviceId: string, capability: string, addonId: string, active: boolean): void;
241
- /**
242
- * Clear all activation overrides for a device (resets to autoActivate defaults).
243
- */
244
- clearDeviceActivation(deviceId: string): void;
245
214
  /** Get a value from the parsed bootstrap config.
246
215
  * Generic overload is a documented type-level bridge — callers are responsible
247
216
  * for passing a T that matches the config.yaml shape. */
@@ -281,6 +250,4 @@ export declare class ConfigManager {
281
250
  * Returns an object keyed by the sub-key, or undefined if nothing is found.
282
251
  */
283
252
  private getNestedFromSystemSettings;
284
- private loadRuntimeState;
285
- private saveRuntimeState;
286
253
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.2.170",
3
+ "version": "1.2.171",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",