@camstack/system 1.2.85 → 1.2.87

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 (54) hide show
  1. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  2. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  3. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/alerts/alerts.addon.js +1 -1
  6. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  7. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  8. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  9. package/dist/builtins/console-logging/index.js +1 -1
  10. package/dist/builtins/console-logging/index.mjs +1 -1
  11. package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
  12. package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
  13. package/dist/builtins/device-manager/device-manager.addon.js +155 -18
  14. package/dist/builtins/device-manager/device-manager.addon.mjs +155 -18
  15. package/dist/builtins/device-manager/device-state-mirror.d.ts +51 -6
  16. package/dist/builtins/device-manager/runtime-state-persist-gate.d.ts +32 -0
  17. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  18. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  19. package/dist/builtins/hub-forwarder/index.js +1 -1
  20. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  21. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  22. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  23. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  24. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  25. package/dist/builtins/local-network/local-network.addon.js +1 -1
  26. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  27. package/dist/builtins/loki-logging/index.js +1 -1
  28. package/dist/builtins/loki-logging/index.mjs +1 -1
  29. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  30. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  31. package/dist/builtins/platform-probe/index.js +1 -1
  32. package/dist/builtins/platform-probe/index.mjs +1 -1
  33. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  34. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  35. package/dist/builtins/snapshot/index.js +1 -1
  36. package/dist/builtins/snapshot/index.mjs +1 -1
  37. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  38. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  39. package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +15 -0
  40. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +37 -1
  41. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +37 -1
  42. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  43. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  44. package/dist/builtins/system-config/system-config.addon.js +1 -1
  45. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  46. package/dist/builtins/winston-logging/index.js +1 -1
  47. package/dist/builtins/winston-logging/index.mjs +1 -1
  48. package/dist/{dist-DWuNENzg.mjs → dist-CuAaqtdt.mjs} +996 -109
  49. package/dist/{dist-DiScsb8j.js → dist-D4nuaPdd.js} +1001 -108
  50. package/dist/index.js +38 -20
  51. package/dist/index.mjs +38 -20
  52. package/dist/kernel/addon-installer.d.ts +7 -15
  53. package/dist/kernel/config-manager.d.ts +32 -0
  54. 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-DiScsb8j.js");
3
+ const require_dist = require("./dist-D4nuaPdd.js");
4
4
  const require_builtins_alerts_alerts_addon = require("./builtins/alerts/alerts.addon.js");
5
5
  require("./builtins/alerts/index.js");
6
6
  const require_formatter = require("./formatter-DqAKDlvN.js");
@@ -4227,23 +4227,15 @@ var AddonInstaller = class AddonInstaller {
4227
4227
  * installs from the admin UI go through `install()` instead, which
4228
4228
  * defaults to npm in production.
4229
4229
  *
4230
- * @param packages optional custom package list (default: REQUIRED_PACKAGES)
4231
- * @param pins — optional `name exact version` map. A named package is
4232
- * fetched at THAT version instead of the registry's `latest`.
4233
- *
4234
- * Preparation for [D45](../../../../docs/decisions/adr-0045.md) task 32: the
4235
- * image seed answers first today, so `latest` has never been the version a
4236
- * node actually got. Once the image stops baking an addon tree under `/opt`
4237
- * this call IS the answer, and it has to be the version the running closure was
4238
- * published with — otherwise a node fetches latest-of-everything and its
4239
- * addon set depends on the minute it first booted. Passing nothing keeps
4240
- * exactly today's behaviour, and `launcher.ts` passes nothing yet.
4230
+ * There is no version argument and there is deliberately no pin: the system is
4231
+ * addons-agnostic and `latest` is the whole contract at first boot (operator,
4232
+ * 2026-08-13). A copy already under the addon root is never replaced either —
4233
+ * bootstrap is seed-only, and overwriting a deployed bundle would be an
4234
+ * un-deploy ([D90](../../../../docs/decisions/adr-0090.md)).
4241
4235
  *
4242
- * A pin never triggers a re-install: bootstrap stays seed-only, so a copy
4243
- * already under the addon root is left alone whatever its version. Replacing
4244
- * it would be an un-deploy ([D90](../../../../docs/decisions/adr-0090.md)).
4236
+ * @param packages optional custom package list (default: REQUIRED_PACKAGES)
4245
4237
  */
4246
- async ensureRequiredPackages(packages, pins) {
4238
+ async ensureRequiredPackages(packages) {
4247
4239
  const pkgList = packages ?? AddonInstaller.REQUIRED_PACKAGES;
4248
4240
  ensureDir(this.addonsDir);
4249
4241
  const isLocal = this.installSource !== "npm" && this.workspaceDir != null;
@@ -4271,7 +4263,7 @@ var AddonInstaller = class AddonInstaller {
4271
4263
  }
4272
4264
  this.logger.info(`${packageName} — not found locally, trying npm`);
4273
4265
  }
4274
- await this.installFromNpm(packageName, pins?.[packageName]);
4266
+ await this.installFromNpm(packageName);
4275
4267
  } catch (err) {
4276
4268
  const msg = require_dist.errMsg(err);
4277
4269
  if (packageName === "@camstack/system") throw new Error(`Required package ${packageName} failed to install: ${msg}`, { cause: err });
@@ -9646,6 +9638,32 @@ var ConfigManager = class ConfigManager {
9646
9638
  if (this.settingsStore === null) return;
9647
9639
  this.settingsStore.clearAddonDevice(addonId, deviceId);
9648
9640
  }
9641
+ /**
9642
+ * The device's persisted runtime-state blob. `{}` before the settings store
9643
+ * is wired — the same answer as "this device has never persisted a slice",
9644
+ * which is what every caller already handles.
9645
+ */
9646
+ getDeviceRuntimeState(deviceId) {
9647
+ if (this.settingsStore === null) return {};
9648
+ return this.settingsStore.getDeviceRuntimeState(deviceId);
9649
+ }
9650
+ /**
9651
+ * Replace the device's persisted runtime-state blob.
9652
+ *
9653
+ * THROWS when the store is not wired, and that is deliberate: the caller
9654
+ * (`DeviceStateMirror.scheduleRuntimeStateDiskWrite`) catches and logs, so a
9655
+ * persist that cannot happen leaves a line naming the device. A silent no-op
9656
+ * here is the shape that let a whole collection read zero for months.
9657
+ */
9658
+ setDeviceRuntimeState(deviceId, blob) {
9659
+ if (this.settingsStore === null) throw new Error("[ConfigManager] SettingsStore not initialized -- call setSettingsStore() first");
9660
+ this.settingsStore.setDeviceRuntimeState(deviceId, blob);
9661
+ }
9662
+ /** Forget the device's runtime state. No-op before the store is wired. */
9663
+ clearDeviceRuntimeState(deviceId) {
9664
+ if (this.settingsStore === null) return;
9665
+ this.settingsStore.clearDeviceRuntimeState(deviceId);
9666
+ }
9649
9667
  createSettingsView(addonId) {
9650
9668
  const cm = this;
9651
9669
  return {
@@ -9674,13 +9692,13 @@ var ConfigManager = class ConfigManager {
9674
9692
  cm.clearAddonDevice(addonId, String(deviceId));
9675
9693
  },
9676
9694
  async readDeviceRuntimeState(deviceId) {
9677
- return cm.getAddonDevice("__device-state", String(deviceId));
9695
+ return cm.getDeviceRuntimeState(String(deviceId));
9678
9696
  },
9679
9697
  async writeDeviceRuntimeState(deviceId, data) {
9680
- cm.setAddonDevice("__device-state", String(deviceId), data);
9698
+ cm.setDeviceRuntimeState(String(deviceId), data);
9681
9699
  },
9682
9700
  async clearDeviceRuntimeState(deviceId) {
9683
- cm.clearAddonDevice("__device-state", String(deviceId));
9701
+ cm.clearDeviceRuntimeState(String(deviceId));
9684
9702
  },
9685
9703
  async getSection(section) {
9686
9704
  return cm.getSection(section);
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 objectInputDeclaresAddonId, At as emitDownForOwnedCaps, B as isArrayOutputSchema, Bt as scopeKey, Ct as ReadinessRegistry, Dt as asNumber, Et as asJsonObject$1, G as kebabToCamel, H as isObjectInput, Ht as EventCategory$1, It as parseJsonObject, K as lifecycleJobSchema, Lt as parseJsonUnknown$1, Mt as expandCapMethods, Ot as asString$1, R as extractNestedAddonId, Rt as readinessKey, V as isCollectionArrayMethod, W as isVoidInput, X as looseSchema, Y as logLevelAtMost, _t as DATAPLANE_SECRET_HEADER$1, d as METHOD_ACCESS_MAP, f as RUNTIME_DEFAULTS, ht as errMsg$1, it as scopesAllowDeviceCap, kt as createEvent, nt as procedureAuthKey, rt as scopesAllowAddon, t as ALL_CAPABILITY_DEFINITIONS, vt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, wt as ReadinessTimeoutError, y as addonSettingsCapability, yt as DEVICE_STATUS_METHOD, zt as resolveCapMount } from "./dist-DWuNENzg.mjs";
2
+ import { $ as objectInputDeclaresAddonId, At as createEvent, B as isArrayOutputSchema, Bt as resolveCapMount, Dt as asJsonObject$1, G as kebabToCamel, H as isObjectInput, K as lifecycleJobSchema, Lt as parseJsonObject, Nt as expandCapMethods, Ot as asNumber, R as extractNestedAddonId, Rt as parseJsonUnknown$1, Tt as ReadinessTimeoutError, Ut as EventCategory$1, V as isCollectionArrayMethod, Vt as scopeKey, W as isVoidInput, X as looseSchema, Y as logLevelAtMost, at as scopesAllowDeviceCap, bt as DEVICE_STATUS_METHOD, d as METHOD_ACCESS_MAP, f as RUNTIME_DEFAULTS, gt as errMsg$1, it as scopesAllowAddon, jt as emitDownForOwnedCaps, kt as asString$1, nt as procedureAuthKey, t as ALL_CAPABILITY_DEFINITIONS, vt as DATAPLANE_SECRET_HEADER$1, wt as ReadinessRegistry, y as addonSettingsCapability, yt as DEVICE_SETTINGS_CONTRIBUTION_METHODS, zt as readinessKey } from "./dist-CuAaqtdt.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";
@@ -4219,23 +4219,15 @@ var AddonInstaller = class AddonInstaller {
4219
4219
  * installs from the admin UI go through `install()` instead, which
4220
4220
  * defaults to npm in production.
4221
4221
  *
4222
- * @param packages optional custom package list (default: REQUIRED_PACKAGES)
4223
- * @param pins — optional `name exact version` map. A named package is
4224
- * fetched at THAT version instead of the registry's `latest`.
4225
- *
4226
- * Preparation for [D45](../../../../docs/decisions/adr-0045.md) task 32: the
4227
- * image seed answers first today, so `latest` has never been the version a
4228
- * node actually got. Once the image stops baking an addon tree under `/opt`
4229
- * this call IS the answer, and it has to be the version the running closure was
4230
- * published with — otherwise a node fetches latest-of-everything and its
4231
- * addon set depends on the minute it first booted. Passing nothing keeps
4232
- * exactly today's behaviour, and `launcher.ts` passes nothing yet.
4222
+ * There is no version argument and there is deliberately no pin: the system is
4223
+ * addons-agnostic and `latest` is the whole contract at first boot (operator,
4224
+ * 2026-08-13). A copy already under the addon root is never replaced either —
4225
+ * bootstrap is seed-only, and overwriting a deployed bundle would be an
4226
+ * un-deploy ([D90](../../../../docs/decisions/adr-0090.md)).
4233
4227
  *
4234
- * A pin never triggers a re-install: bootstrap stays seed-only, so a copy
4235
- * already under the addon root is left alone whatever its version. Replacing
4236
- * it would be an un-deploy ([D90](../../../../docs/decisions/adr-0090.md)).
4228
+ * @param packages optional custom package list (default: REQUIRED_PACKAGES)
4237
4229
  */
4238
- async ensureRequiredPackages(packages, pins) {
4230
+ async ensureRequiredPackages(packages) {
4239
4231
  const pkgList = packages ?? AddonInstaller.REQUIRED_PACKAGES;
4240
4232
  ensureDir(this.addonsDir);
4241
4233
  const isLocal = this.installSource !== "npm" && this.workspaceDir != null;
@@ -4263,7 +4255,7 @@ var AddonInstaller = class AddonInstaller {
4263
4255
  }
4264
4256
  this.logger.info(`${packageName} — not found locally, trying npm`);
4265
4257
  }
4266
- await this.installFromNpm(packageName, pins?.[packageName]);
4258
+ await this.installFromNpm(packageName);
4267
4259
  } catch (err) {
4268
4260
  const msg = errMsg$1(err);
4269
4261
  if (packageName === "@camstack/system") throw new Error(`Required package ${packageName} failed to install: ${msg}`, { cause: err });
@@ -9638,6 +9630,32 @@ var ConfigManager = class ConfigManager {
9638
9630
  if (this.settingsStore === null) return;
9639
9631
  this.settingsStore.clearAddonDevice(addonId, deviceId);
9640
9632
  }
9633
+ /**
9634
+ * The device's persisted runtime-state blob. `{}` before the settings store
9635
+ * is wired — the same answer as "this device has never persisted a slice",
9636
+ * which is what every caller already handles.
9637
+ */
9638
+ getDeviceRuntimeState(deviceId) {
9639
+ if (this.settingsStore === null) return {};
9640
+ return this.settingsStore.getDeviceRuntimeState(deviceId);
9641
+ }
9642
+ /**
9643
+ * Replace the device's persisted runtime-state blob.
9644
+ *
9645
+ * THROWS when the store is not wired, and that is deliberate: the caller
9646
+ * (`DeviceStateMirror.scheduleRuntimeStateDiskWrite`) catches and logs, so a
9647
+ * persist that cannot happen leaves a line naming the device. A silent no-op
9648
+ * here is the shape that let a whole collection read zero for months.
9649
+ */
9650
+ setDeviceRuntimeState(deviceId, blob) {
9651
+ if (this.settingsStore === null) throw new Error("[ConfigManager] SettingsStore not initialized -- call setSettingsStore() first");
9652
+ this.settingsStore.setDeviceRuntimeState(deviceId, blob);
9653
+ }
9654
+ /** Forget the device's runtime state. No-op before the store is wired. */
9655
+ clearDeviceRuntimeState(deviceId) {
9656
+ if (this.settingsStore === null) return;
9657
+ this.settingsStore.clearDeviceRuntimeState(deviceId);
9658
+ }
9641
9659
  createSettingsView(addonId) {
9642
9660
  const cm = this;
9643
9661
  return {
@@ -9666,13 +9684,13 @@ var ConfigManager = class ConfigManager {
9666
9684
  cm.clearAddonDevice(addonId, String(deviceId));
9667
9685
  },
9668
9686
  async readDeviceRuntimeState(deviceId) {
9669
- return cm.getAddonDevice("__device-state", String(deviceId));
9687
+ return cm.getDeviceRuntimeState(String(deviceId));
9670
9688
  },
9671
9689
  async writeDeviceRuntimeState(deviceId, data) {
9672
- cm.setAddonDevice("__device-state", String(deviceId), data);
9690
+ cm.setDeviceRuntimeState(String(deviceId), data);
9673
9691
  },
9674
9692
  async clearDeviceRuntimeState(deviceId) {
9675
- cm.clearAddonDevice("__device-state", String(deviceId));
9693
+ cm.clearDeviceRuntimeState(String(deviceId));
9676
9694
  },
9677
9695
  async getSection(section) {
9678
9696
  return cm.getSection(section);
@@ -186,23 +186,15 @@ export declare class AddonInstaller {
186
186
  * installs from the admin UI go through `install()` instead, which
187
187
  * defaults to npm in production.
188
188
  *
189
+ * There is no version argument and there is deliberately no pin: the system is
190
+ * addons-agnostic and `latest` is the whole contract at first boot (operator,
191
+ * 2026-08-13). A copy already under the addon root is never replaced either —
192
+ * bootstrap is seed-only, and overwriting a deployed bundle would be an
193
+ * un-deploy ([D90](../../../../docs/decisions/adr-0090.md)).
194
+ *
189
195
  * @param packages — optional custom package list (default: REQUIRED_PACKAGES)
190
- * @param pins — optional `name → exact version` map. A named package is
191
- * fetched at THAT version instead of the registry's `latest`.
192
- *
193
- * Preparation for [D45](../../../../docs/decisions/adr-0045.md) task 32: the
194
- * image seed answers first today, so `latest` has never been the version a
195
- * node actually got. Once the image stops baking an addon tree under `/opt`
196
- * this call IS the answer, and it has to be the version the running closure was
197
- * published with — otherwise a node fetches latest-of-everything and its
198
- * addon set depends on the minute it first booted. Passing nothing keeps
199
- * exactly today's behaviour, and `launcher.ts` passes nothing yet.
200
- *
201
- * A pin never triggers a re-install: bootstrap stays seed-only, so a copy
202
- * already under the addon root is left alone whatever its version. Replacing
203
- * it would be an un-deploy ([D90](../../../../docs/decisions/adr-0090.md)).
204
196
  */
205
- ensureRequiredPackages(packages?: readonly string[], pins?: Readonly<Record<string, string>>): Promise<void>;
197
+ ensureRequiredPackages(packages?: readonly string[]): Promise<void>;
206
198
  /**
207
199
  * Reconcile the install manifest against the addons actually present on
208
200
  * disk: register seeded addons, correct a version that disagrees with the
@@ -56,6 +56,21 @@ export interface ISettingsStore {
56
56
  getAddonDevice(addonId: string, deviceId: string): Record<string, unknown>;
57
57
  setAddonDevice(addonId: string, deviceId: string, values: Record<string, unknown>): void;
58
58
  clearAddonDevice(addonId: string, deviceId: string): void;
59
+ /**
60
+ * Per-device runtime state — the whole cap-slice map as ONE row in the
61
+ * `device-runtime-state` collection.
62
+ *
63
+ * These are separate from `getAddonDevice`/`setAddonDevice` because runtime
64
+ * state is not an addon's config: it belongs to the device, it is replaced
65
+ * wholesale on every flush, and it is written orders of magnitude more often.
66
+ * It USED to share that keyspace under a synthetic `__device-state` addonId,
67
+ * which cost one row (and one INSERT) per cap slice per flush and left the
68
+ * collection it is named for empty on every installation. The backend keeps
69
+ * reading the legacy prefix; see `SqliteSettingsBackend.getDeviceRuntimeState`.
70
+ */
71
+ getDeviceRuntimeState(deviceId: string): Record<string, unknown>;
72
+ setDeviceRuntimeState(deviceId: string, blob: Record<string, unknown>): void;
73
+ clearDeviceRuntimeState(deviceId: string): void;
59
74
  }
60
75
  export declare class ConfigManager {
61
76
  private readonly configPath;
@@ -138,6 +153,23 @@ export declare class ConfigManager {
138
153
  * No-op if the settings store is not yet wired.
139
154
  */
140
155
  clearAddonDevice(addonId: string, deviceId: string): void;
156
+ /**
157
+ * The device's persisted runtime-state blob. `{}` before the settings store
158
+ * is wired — the same answer as "this device has never persisted a slice",
159
+ * which is what every caller already handles.
160
+ */
161
+ getDeviceRuntimeState(deviceId: string): Record<string, unknown>;
162
+ /**
163
+ * Replace the device's persisted runtime-state blob.
164
+ *
165
+ * THROWS when the store is not wired, and that is deliberate: the caller
166
+ * (`DeviceStateMirror.scheduleRuntimeStateDiskWrite`) catches and logs, so a
167
+ * persist that cannot happen leaves a line naming the device. A silent no-op
168
+ * here is the shape that let a whole collection read zero for months.
169
+ */
170
+ setDeviceRuntimeState(deviceId: string, blob: Record<string, unknown>): void;
171
+ /** Forget the device's runtime state. No-op before the store is wired. */
172
+ clearDeviceRuntimeState(deviceId: string): void;
141
173
  createSettingsView(addonId: string): AddonSettingsView;
142
174
  /** Get all system-wide activation overrides. */
143
175
  getSystemActivation(): Readonly<Record<string, boolean>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/system",
3
- "version": "1.2.85",
3
+ "version": "1.2.87",
4
4
  "description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
5
5
  "keywords": [
6
6
  "camstack",