@camstack/system 1.2.147 → 1.2.149

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 (61) hide show
  1. package/dist/addon-runner.js +2 -1
  2. package/dist/addon-runner.mjs +2 -1
  3. package/dist/auth/auth-manager.d.ts +17 -1
  4. package/dist/auth/token-expiry.d.ts +39 -0
  5. package/dist/auth/user-manager.d.ts +2 -1
  6. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  7. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  8. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  9. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  10. package/dist/builtins/alerts/alerts.addon.js +1 -1
  11. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  12. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  13. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  14. package/dist/builtins/console-logging/index.js +1 -1
  15. package/dist/builtins/console-logging/index.mjs +1 -1
  16. package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
  17. package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
  18. package/dist/builtins/device-manager/device-manager.addon.js +2 -2
  19. package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
  20. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  21. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  22. package/dist/builtins/hub-forwarder/index.js +1 -1
  23. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  24. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  25. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  26. package/dist/builtins/local-auth/auth-config-reader.d.ts +20 -0
  27. package/dist/builtins/local-auth/local-auth.addon.js +211 -17
  28. package/dist/builtins/local-auth/local-auth.addon.mjs +211 -17
  29. package/dist/builtins/local-network/local-network.addon.js +1 -1
  30. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  31. package/dist/builtins/loki-logging/index.js +1 -1
  32. package/dist/builtins/loki-logging/index.mjs +1 -1
  33. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  34. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  35. package/dist/builtins/platform-probe/index.js +1 -1
  36. package/dist/builtins/platform-probe/index.mjs +1 -1
  37. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  38. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  39. package/dist/builtins/snapshot/index.js +1 -1
  40. package/dist/builtins/snapshot/index.mjs +1 -1
  41. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  42. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  43. package/dist/builtins/sqlite-storage/retired-settings-keys.d.ts +16 -0
  44. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
  45. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
  46. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  47. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  48. package/dist/builtins/system-config/system-config.addon.js +12 -11
  49. package/dist/builtins/system-config/system-config.addon.mjs +12 -11
  50. package/dist/builtins/winston-logging/index.js +1 -1
  51. package/dist/builtins/winston-logging/index.mjs +1 -1
  52. package/dist/{dist-DrBc-7Y3.mjs → dist-CZWAU40-.mjs} +129 -1
  53. package/dist/{dist-Dl6MFXPr.js → dist-DdEXjTDo.js} +129 -1
  54. package/dist/index.js +2 -2
  55. package/dist/index.mjs +2 -2
  56. package/dist/kernel/transport/child-cap-protocol.d.ts +2 -2
  57. package/dist/{manifest-python-deps-FYZBHc3v.js → manifest-python-deps-CivtrAha.js} +1 -1
  58. package/dist/{manifest-python-deps-DhT0oFOZ.mjs → manifest-python-deps-HFh_iE0E.mjs} +1 -1
  59. package/dist/{retired-settings-keys-6w_JOqBg.js → retired-settings-keys-BXaTgLyZ.js} +90 -14
  60. package/dist/{retired-settings-keys-CF5r4YKq.mjs → retired-settings-keys-BynPjBHV.mjs} +90 -14
  61. package/package.json +6 -4
@@ -1,5 +1,5 @@
1
1
  import { i as __require, o as __toESM, t as __commonJSMin } from "../../chunk-CNf5ZN-e.mjs";
2
- import { E as authProviderCapability, Tt as userManagementCapability, kt as BaseAddon, r as ApiKeyRecordSchema, v as ScopedTokenSchema, x as UserRecordSchema } from "../../dist-DrBc-7Y3.mjs";
2
+ import { E as authProviderCapability, Tt as userManagementCapability, kt as BaseAddon, r as ApiKeyRecordSchema, v as ScopedTokenSchema, x as UserRecordSchema } from "../../dist-CZWAU40-.mjs";
3
3
  import * as crypto$2 from "node:crypto";
4
4
  import { createHash, randomUUID, timingSafeEqual } from "node:crypto";
5
5
  import nodeCrypto from "crypto";
@@ -6000,7 +6000,7 @@ var require_sign = /* @__PURE__ */ __commonJSMin(((exports, module) => {
6000
6000
  };
6001
6001
  }));
6002
6002
  //#endregion
6003
- //#region src/auth/auth-manager.ts
6003
+ //#region src/auth/token-expiry.ts
6004
6004
  var import_jsonwebtoken = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
6005
6005
  module.exports = {
6006
6006
  decode: require_decode(),
@@ -6011,6 +6011,156 @@ var import_jsonwebtoken = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin
6011
6011
  TokenExpiredError: require_TokenExpiredError()
6012
6012
  };
6013
6013
  })))());
6014
+ /**
6015
+ * Validation for the operator-configured session-JWT lifetime
6016
+ * (`auth.tokenExpiry`, System → Settings → Authentication → Token Expiry).
6017
+ *
6018
+ * WHY THIS EXISTS. The field is a free-text box that reaches `jwt.sign`'s
6019
+ * `expiresIn`. Two things go wrong without a gate in front of it:
6020
+ *
6021
+ * 1. `jsonwebtoken` THROWS on a value it cannot parse. The only caller is
6022
+ * the login/refresh path, so one typo in a settings form turns every
6023
+ * login into a 500 — a self-inflicted outage from a text field.
6024
+ * 2. `jsonwebtoken` hands a bare numeric STRING to `ms()`, which reads it
6025
+ * as MILLISECONDS. An operator who types `3600` meaning "an hour" gets
6026
+ * a token that dies in 3.6 seconds. A bare number is therefore rejected
6027
+ * rather than interpreted — the field's own description, placeholder and
6028
+ * default are all duration strings (`24h`, `7d`, `30d`).
6029
+ *
6030
+ * A rejection never becomes an unbounded lifetime — it resolves to
6031
+ * {@link DEFAULT_TOKEN_EXPIRY}, the single documented default — and it is
6032
+ * never silent: `parseTokenExpiry` reports the refusal in its result and
6033
+ * `logTokenExpiryRejection` renders it. The two are separate so the caller
6034
+ * owns how often it speaks; the signer re-reads on every mint.
6035
+ */
6036
+ /**
6037
+ * The `ms`-compatible duration grammar `jsonwebtoken` accepts, MINUS the bare
6038
+ * number (see the docblock above). A unit is mandatory.
6039
+ */
6040
+ var DURATION_PATTERN = /^(\d+(?:\.\d+)?)\s*(ms|milliseconds?|msecs?|s|secs?|seconds?|m|mins?|minutes?|h|hrs?|hours?|d|days?|w|weeks?|y|yrs?|years?)$/i;
6041
+ /** Multiplier from each accepted unit to milliseconds. */
6042
+ var UNIT_MS = {
6043
+ ms: 1,
6044
+ msec: 1,
6045
+ msecs: 1,
6046
+ millisecond: 1,
6047
+ milliseconds: 1,
6048
+ s: 1e3,
6049
+ sec: 1e3,
6050
+ secs: 1e3,
6051
+ second: 1e3,
6052
+ seconds: 1e3,
6053
+ m: 6e4,
6054
+ min: 6e4,
6055
+ mins: 6e4,
6056
+ minute: 6e4,
6057
+ minutes: 6e4,
6058
+ h: 36e5,
6059
+ hr: 36e5,
6060
+ hrs: 36e5,
6061
+ hour: 36e5,
6062
+ hours: 36e5,
6063
+ d: 864e5,
6064
+ day: 864e5,
6065
+ days: 864e5,
6066
+ w: 6048e5,
6067
+ week: 6048e5,
6068
+ weeks: 6048e5,
6069
+ y: 315576e5,
6070
+ yr: 315576e5,
6071
+ yrs: 315576e5,
6072
+ year: 315576e5,
6073
+ years: 315576e5
6074
+ };
6075
+ /**
6076
+ * Shortest accepted lifetime. Below a minute the token expires inside the
6077
+ * round trip that issued it and the operator sees "logged out immediately",
6078
+ * which reads as a broken server rather than as a bad setting.
6079
+ */
6080
+ var MIN_EXPIRY_MS = 6e4;
6081
+ /**
6082
+ * Longest accepted lifetime. A year is already far past "a device left
6083
+ * unopened for weeks"; anything longer is an infinite-lifetime token wearing
6084
+ * a duration string.
6085
+ */
6086
+ var MAX_EXPIRY_MS = 365 * 864e5;
6087
+ /** Milliseconds for a duration string, or `null` when it is not one. */
6088
+ function durationMs(candidate) {
6089
+ const match = DURATION_PATTERN.exec(candidate);
6090
+ if (match === null) return null;
6091
+ const amount = Number(match[1]);
6092
+ const unitMs = UNIT_MS[match[2].toLowerCase()];
6093
+ if (!Number.isFinite(amount) || unitMs === void 0) return null;
6094
+ return amount * unitMs;
6095
+ }
6096
+ /**
6097
+ * The default, pre-parsed. Computed from {@link DEFAULT_TOKEN_EXPIRY} rather
6098
+ * than written out again — a second spelling of the same default is the defect
6099
+ * this module exists to close.
6100
+ */
6101
+ var DEFAULT_SECONDS = (() => {
6102
+ const ms = durationMs("30d");
6103
+ /* c8 ignore next -- unreachable unless DEFAULT_TOKEN_EXPIRY stops being a duration */
6104
+ if (ms === null) throw new Error(`DEFAULT_TOKEN_EXPIRY is not a duration: 30d`);
6105
+ return ms / 1e3;
6106
+ })();
6107
+ function refuse(reason) {
6108
+ return {
6109
+ ok: false,
6110
+ reason,
6111
+ seconds: DEFAULT_SECONDS,
6112
+ value: "30d"
6113
+ };
6114
+ }
6115
+ /**
6116
+ * Parse a configured `auth.tokenExpiry`. An absent/blank value is not a
6117
+ * rejection — it is "operator never set it" and resolves to the default
6118
+ * without a log line.
6119
+ */
6120
+ function parseTokenExpiry(configured) {
6121
+ if (configured === void 0 || configured === null) return {
6122
+ ok: true,
6123
+ seconds: DEFAULT_SECONDS,
6124
+ value: "30d"
6125
+ };
6126
+ if (typeof configured !== "string") return refuse("not-a-string");
6127
+ const trimmed = configured.trim();
6128
+ if (trimmed === "") return {
6129
+ ok: true,
6130
+ seconds: DEFAULT_SECONDS,
6131
+ value: "30d"
6132
+ };
6133
+ const totalMs = durationMs(trimmed);
6134
+ if (totalMs === null) return refuse("malformed");
6135
+ if (totalMs < MIN_EXPIRY_MS) return refuse("too-short");
6136
+ if (totalMs > MAX_EXPIRY_MS) return refuse("too-long");
6137
+ return {
6138
+ ok: true,
6139
+ seconds: totalMs / 1e3,
6140
+ value: trimmed
6141
+ };
6142
+ }
6143
+ /** Human-readable tail for the rejection log line. */
6144
+ var REJECTION_DETAIL = {
6145
+ "not-a-string": "value is not a string",
6146
+ malformed: "not a duration string (expected e.g. 24h, 7d, 30d — a bare number is NOT seconds)",
6147
+ "too-short": `shorter than the ${MIN_EXPIRY_MS / 1e3}s minimum`,
6148
+ "too-long": `longer than the ${MAX_EXPIRY_MS / 864e5}d maximum`
6149
+ };
6150
+ /**
6151
+ * Report a refused `auth.tokenExpiry`. Separate from {@link parseTokenExpiry}
6152
+ * so the caller owns HOW OFTEN it speaks — the signer re-reads the setting on
6153
+ * every mint and must not turn one bad save into a line per login.
6154
+ */
6155
+ function logTokenExpiryRejection(configured, rejection, logger) {
6156
+ logger.warn(`auth.tokenExpiry REJECTED — ${REJECTION_DETAIL[rejection.reason]}; signing with the default 30d instead`, { meta: {
6157
+ configured,
6158
+ reason: rejection.reason,
6159
+ applied: rejection.value
6160
+ } });
6161
+ }
6162
+ //#endregion
6163
+ //#region src/auth/auth-manager.ts
6014
6164
  /** Minimal no-op logger for default parameter */
6015
6165
  var noopLogger = {
6016
6166
  debug() {},
@@ -6028,6 +6178,16 @@ var AuthManager = class {
6028
6178
  config;
6029
6179
  jwtSecret;
6030
6180
  logger;
6181
+ /**
6182
+ * Offending `auth.tokenExpiry` values already reported by this instance.
6183
+ *
6184
+ * `signToken` re-reads the setting on EVERY mint so an operator's change
6185
+ * takes effect without a restart — which also means a bad value would log
6186
+ * once per login and once per silent refresh from every viewer. The refusal
6187
+ * must be visible, not repeated: the first mint after a bad save logs, the
6188
+ * rest resolve silently to the same default until the value changes.
6189
+ */
6190
+ reportedInvalidExpiries = /* @__PURE__ */ new Set();
6031
6191
  constructor(config, logger = noopLogger) {
6032
6192
  this.config = config;
6033
6193
  this.logger = logger;
@@ -6042,8 +6202,15 @@ var AuthManager = class {
6042
6202
  }
6043
6203
  signToken(payload) {
6044
6204
  const configured = this.config.get("auth.tokenExpiry");
6045
- const expiresIn = typeof configured === "string" && configured.trim() !== "" ? configured.trim() : "30d";
6046
- return import_jsonwebtoken.sign({ ...payload }, this.jwtSecret, { expiresIn });
6205
+ const parsed = parseTokenExpiry(configured);
6206
+ if (!parsed.ok) {
6207
+ const seen = typeof configured === "string" ? configured : JSON.stringify(configured);
6208
+ if (!this.reportedInvalidExpiries.has(seen)) {
6209
+ this.reportedInvalidExpiries.add(seen);
6210
+ logTokenExpiryRejection(configured, parsed, this.logger);
6211
+ }
6212
+ }
6213
+ return import_jsonwebtoken.sign({ ...payload }, this.jwtSecret, { expiresIn: parsed.seconds });
6047
6214
  }
6048
6215
  verifyToken(token) {
6049
6216
  return import_jsonwebtoken.verify(token, this.jwtSecret);
@@ -8814,6 +8981,38 @@ var TotpManager = class {
8814
8981
  }
8815
8982
  };
8816
8983
  //#endregion
8984
+ //#region src/builtins/local-auth/auth-config-reader.ts
8985
+ /**
8986
+ * Every config path this reader can answer. Anything else resolves to
8987
+ * `undefined` by construction — see the module docblock.
8988
+ */
8989
+ function createAuthConfigReader(resolved, writeAuthSection) {
8990
+ return {
8991
+ get(path) {
8992
+ switch (path) {
8993
+ case "auth.jwtSecret": return narrow(resolved.jwtSecret);
8994
+ case "auth.adminUsername": return narrow(resolved.adminUsername);
8995
+ case "auth.adminPassword": return narrow(resolved.adminPassword);
8996
+ case "auth.tokenExpiry": return narrow(resolved.tokenExpiry);
8997
+ default: return;
8998
+ }
8999
+ },
9000
+ update(_section, data) {
9001
+ if (typeof data["jwtSecret"] === "string") writeAuthSection({ jwtSecret: data["jwtSecret"] });
9002
+ }
9003
+ };
9004
+ }
9005
+ /**
9006
+ * The one documented type boundary in this module. `AuthConfigReader.get` is
9007
+ * the legacy `get<T>(path)` shape shared with `ConfigManager.get`, which is
9008
+ * likewise unchecked at runtime — every value returned here is a `string |
9009
+ * undefined` the caller immediately re-validates (`parseTokenExpiry`, the
9010
+ * truthiness gate on `jwtSecret`).
9011
+ */
9012
+ function narrow(value) {
9013
+ return value;
9014
+ }
9015
+ //#endregion
8817
9016
  //#region src/builtins/local-auth/auth-schema.ts
8818
9017
  /**
8819
9018
  * @durable class=config owner=local-auth
@@ -9462,19 +9661,14 @@ var LocalAuthAddon = class extends BaseAddon {
9462
9661
  }
9463
9662
  async onInitialize() {
9464
9663
  const authSection = await this.ctx.settings?.getSection("auth") ?? {};
9465
- const resolvedJwtSecret = typeof authSection["jwtSecret"] === "string" ? authSection["jwtSecret"] : this.config.jwtSecret ?? "";
9466
- const resolvedAdminUser = typeof authSection["adminUsername"] === "string" && authSection["adminUsername"] ? authSection["adminUsername"] : this.config.adminUsername ?? "";
9467
- const resolvedAdminPass = typeof authSection["adminPassword"] === "string" && authSection["adminPassword"] ? authSection["adminPassword"] : this.config.adminPassword ?? "";
9468
- const reader = {
9469
- get(path) {
9470
- if (path === "auth.jwtSecret") return resolvedJwtSecret;
9471
- if (path === "auth.adminUsername") return resolvedAdminUser;
9472
- if (path === "auth.adminPassword") return resolvedAdminPass;
9473
- },
9474
- update: (_section, data) => {
9475
- if (typeof data["jwtSecret"] === "string") this.ctx.settings?.setSection("auth", { jwtSecret: data["jwtSecret"] });
9476
- }
9477
- };
9664
+ const reader = createAuthConfigReader({
9665
+ jwtSecret: typeof authSection["jwtSecret"] === "string" ? authSection["jwtSecret"] : this.config.jwtSecret ?? "",
9666
+ adminUsername: typeof authSection["adminUsername"] === "string" && authSection["adminUsername"] ? authSection["adminUsername"] : this.config.adminUsername ?? "",
9667
+ adminPassword: typeof authSection["adminPassword"] === "string" && authSection["adminPassword"] ? authSection["adminPassword"] : this.config.adminPassword ?? "",
9668
+ tokenExpiry: typeof authSection["tokenExpiry"] === "string" && authSection["tokenExpiry"] ? authSection["tokenExpiry"] : void 0
9669
+ }, (patch) => {
9670
+ this.ctx.settings?.setSection("auth", patch);
9671
+ });
9478
9672
  this.authManager = new AuthManager(reader, this.ctx.logger);
9479
9673
  const store = this.ctx.api?.settingsStore;
9480
9674
  if (store) {
@@ -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-Dl6MFXPr.js");
3
+ const require_dist = require("../../dist-DdEXjTDo.js");
4
4
  const require_tls = require("../../tls-u8QCJCFE.js");
5
5
  let node_fs_promises = require("node:fs/promises");
6
6
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { kt as BaseAddon, nt as localNetworkCapability, tn as EventCategory } from "../../dist-DrBc-7Y3.mjs";
1
+ import { kt as BaseAddon, nt as localNetworkCapability, tn as EventCategory } from "../../dist-CZWAU40-.mjs";
2
2
  import { S as readLanHttpState, _ as DEFAULT_LAN_HTTP_PORT, a as writeTlsMode, i as writeExtraSans, l as reissueTlsLeaf, n as readTlsAccessStatus, o as validateUploadedTls, r as readTlsMode, s as ensureTlsCert, t as readExtraSans, y as applyLanHttp } from "../../tls-CQhPGSJm.mjs";
3
3
  import { mkdir, writeFile } from "node:fs/promises";
4
4
  import { join } from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-Dl6MFXPr.js");
6
+ const require_dist = require("../../dist-DdEXjTDo.js");
7
7
  //#region src/builtins/loki-logging/loki-payload.ts
8
8
  /**
9
9
  * Loki rejects a label name that is not a valid Prometheus label
@@ -1,4 +1,4 @@
1
- import { kt as BaseAddon, rt as logDestinationCapability } from "../../dist-DrBc-7Y3.mjs";
1
+ import { kt as BaseAddon, rt as logDestinationCapability } from "../../dist-CZWAU40-.mjs";
2
2
  //#region src/builtins/loki-logging/loki-payload.ts
3
3
  /**
4
4
  * Loki rejects a label name that is not a valid Prometheus label
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-Dl6MFXPr.js");
6
+ const require_dist = require("../../dist-DdEXjTDo.js");
7
7
  let node_fs_promises = require("node:fs/promises");
8
8
  let node_child_process = require("node:child_process");
9
9
  let node_util = require("node:util");
@@ -1,4 +1,4 @@
1
- import { Ht as createEvent, Ot as errMsg, ft as reducePoints, kt as BaseAddon, ot as metricsProviderCapability, pt as resolveBucketMs, q as foldSnapshotByFunction, tn as EventCategory } from "../../dist-DrBc-7Y3.mjs";
1
+ import { Ht as createEvent, Ot as errMsg, ft as reducePoints, kt as BaseAddon, ot as metricsProviderCapability, pt as resolveBucketMs, q as foldSnapshotByFunction, tn as EventCategory } from "../../dist-CZWAU40-.mjs";
2
2
  import { readFile, readdir } from "node:fs/promises";
3
3
  import { execFile, execFileSync } from "node:child_process";
4
4
  import { promisify } from "node:util";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-Dl6MFXPr.js");
6
+ const require_dist = require("../../dist-DdEXjTDo.js");
7
7
  let node_child_process = require("node:child_process");
8
8
  let node_util = require("node:util");
9
9
  let node_os = require("node:os");
@@ -1,5 +1,5 @@
1
1
  import { o as __toESM } from "../../chunk-CNf5ZN-e.mjs";
2
- import { Ot as errMsg, V as enumerateInferenceDevices, Wt as emitReadiness, kt as BaseAddon, tn as EventCategory, ut as platformProbeCapability, vt as scoreRuntimes } from "../../dist-DrBc-7Y3.mjs";
2
+ import { Ot as errMsg, V as enumerateInferenceDevices, Wt as emitReadiness, kt as BaseAddon, tn as EventCategory, ut as platformProbeCapability, vt as scoreRuntimes } from "../../dist-CZWAU40-.mjs";
3
3
  import { execFile } from "node:child_process";
4
4
  import { promisify } from "node:util";
5
5
  import * as os from "node:os";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-Dl6MFXPr.js");
6
+ const require_dist = require("../../dist-DdEXjTDo.js");
7
7
  //#region src/builtins/remote-access-orchestrator/enabled-providers-reconcile.ts
8
8
  /**
9
9
  * Reconcile the durable `enabledProviders` set against authoritative
@@ -1,4 +1,4 @@
1
- import { kt as BaseAddon, tn as EventCategory } from "../../dist-DrBc-7Y3.mjs";
1
+ import { kt as BaseAddon, tn as EventCategory } from "../../dist-CZWAU40-.mjs";
2
2
  //#region src/builtins/remote-access-orchestrator/enabled-providers-reconcile.ts
3
3
  /**
4
4
  * Reconcile the durable `enabledProviders` set against authoritative
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-Dl6MFXPr.js");
6
+ const require_dist = require("../../dist-DdEXjTDo.js");
7
7
  let zod = require("zod");
8
8
  let node_crypto = require("node:crypto");
9
9
  let _camstack_types_node = require("@camstack/types/node");
@@ -1,4 +1,4 @@
1
- import { Ft as DeviceType, I as deriveBatteryPresence, Jt as nodePin, Nt as DeviceFeature, O as bareAddonId, Ot as errMsg, bt as snapshotCapability, i as BatteryStatusSchema, k as batteryCapability, kt as BaseAddon, tn as EventCategory, wt as streamQualityLabel } from "../../dist-DrBc-7Y3.mjs";
1
+ import { Ft as DeviceType, I as deriveBatteryPresence, Jt as nodePin, Nt as DeviceFeature, O as bareAddonId, Ot as errMsg, bt as snapshotCapability, i as BatteryStatusSchema, k as batteryCapability, kt as BaseAddon, tn as EventCategory, wt as streamQualityLabel } from "../../dist-CZWAU40-.mjs";
2
2
  import { z } from "zod";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { signExpiringUrl, verifyExpiringUrl } from "@camstack/types/node";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-Dl6MFXPr.js");
6
+ const require_dist = require("../../dist-DdEXjTDo.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let node_fs_promises = require("node:fs/promises");
9
9
  let node_path = require("node:path");
@@ -1,4 +1,4 @@
1
- import { Ct as storageProviderCapability, K as filesystemBrowseCapability, kt as BaseAddon } from "../../dist-DrBc-7Y3.mjs";
1
+ import { Ct as storageProviderCapability, K as filesystemBrowseCapability, kt as BaseAddon } from "../../dist-CZWAU40-.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { mkdir, readdir, realpath, statfs } from "node:fs/promises";
4
4
  import * as path$1 from "node:path";
@@ -88,6 +88,22 @@ export interface RetiredKeyLogger {
88
88
  /**
89
89
  * The dead keys, per row.
90
90
  *
91
+ * ## Addressing these rows
92
+ *
93
+ * Every namespace below is a FORKED addon, whose `ctx.settings` comes from
94
+ * `addon-context-factory` and writes `<addonId>:addon-settings` row `root`. The
95
+ * scoped table is therefore the right target — unlike the hub builtin whose
96
+ * mis-addressed spec is dissected at {@link RetiredRowSpec}. Confirmed per
97
+ * namespace against `packages/<pkg>/package.json`'s manifest `id`.
98
+ *
99
+ * ## `keys` vs `perNodeKeys` is a data-loss decision, not a style choice
100
+ *
101
+ * `perNodeKeys` matches `<key>` AND `<key>@<nodeId>`. That is right for a key
102
+ * whose per-node copies are all dead (the engine cascade, the decoder
103
+ * `backend`). It is WRONG for `probedBestHwaccel` / `probedBestAudioBackend`,
104
+ * where the bare key is unreachable residue but every `@<nodeId>` copy is the
105
+ * node's live probe result — those go under `keys`, which is exact-match.
106
+ *
91
107
  * `detection-pipeline` / `addon-settings` / `root` — every key in this row is
92
108
  * dead; the row itself is kept because the addon writes live keys into it
93
109
  * (`pipelineTemplates`, `videoPipelineSteps`).
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-Dl6MFXPr.js");
6
+ const require_dist = require("../../dist-DdEXjTDo.js");
7
7
  let node_crypto = require("node:crypto");
8
8
  let node_fs_promises = require("node:fs/promises");
9
9
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -1,4 +1,4 @@
1
- import { St as storageMigrationCapability, Yt as parseJsonObject, b as StorageMigrationJobSchema, kt as BaseAddon, xt as storageCapability, y as StorageLocationTypeSchema, yt as settingsStoreCapability } from "../../dist-DrBc-7Y3.mjs";
1
+ import { St as storageMigrationCapability, Yt as parseJsonObject, b as StorageMigrationJobSchema, kt as BaseAddon, xt as storageCapability, y as StorageLocationTypeSchema, yt as settingsStoreCapability } from "../../dist-CZWAU40-.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import * as fs from "node:fs/promises";
4
4
  import * as path$1 from "node:path";
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-Dl6MFXPr.js");
6
+ const require_dist = require("../../dist-DdEXjTDo.js");
7
7
  //#region src/builtins/system-config/system-config.addon.ts
8
8
  /**
9
9
  * Built-in `system-config` addon — Phase 4 of the settings redesign.
@@ -12,25 +12,26 @@ const require_dist = require("../../dist-Dl6MFXPr.js");
12
12
  * loader reads before any addon is instantiated — things that cannot
13
13
  * live inside an addon because changing them requires a server
14
14
  * restart (port, host, dataPath) or because they own no runtime
15
- * state of their own (auth token expiry, global ffmpeg binary path).
15
+ * state of their own (the session token lifetime).
16
16
  *
17
- * Sections exposed:
17
+ * Sections exposed — this list is the whole of it:
18
18
  * - server (port, host, dataPath — READ-ONLY, loaded from config.yaml at bootstrap)
19
19
  * - auth (tokenExpiry)
20
- * - ffmpeg (binaryPath, hwAccel, threadCount)
21
20
  *
22
21
  * Sections NOT exposed (each owned by the addon that implements them):
23
22
  * - logging → `winston-logging` addon (level + retention)
24
23
  * - recording → `recording` addon (segment duration, retention)
25
24
  * - retention → analytics / detection addons (per-table retention)
25
+ * - ffmpeg → deleted outright; see the note beside the schema below.
26
26
  *
27
27
  * Implementation notes:
28
- * - Runs only on the hub process (yml sections are hub-side state).
29
- * On agent nodes this addon would still instantiate, but every
30
- * `ctx.settings.getSection(section)` call would hit an empty
31
- * ConfigManager section so the UI would show the schema defaults.
32
- * In practice the built-in loader can skip it on agents; for now we
33
- * just let it run everywhere because it's harmless.
28
+ * - Hub-only, and the manifest says so. `ctx.settings` here is
29
+ * `ConfigManager.createSettingsView`, whose `getSection`/`setSection`
30
+ * are the `system-settings` keyspace the SAME keyspace
31
+ * `ConfigManager.get('auth.tokenExpiry')` resolves, which is what makes
32
+ * a Save on this form reach `AuthManager.signToken`. An agent's
33
+ * `ctx.settings` is a different view (`sections` collection) and would
34
+ * write somewhere nothing reads.
34
35
  * - Reads via `ctx.settings.getSection(section)` and writes via
35
36
  * `ctx.settings.setSection(section, patch)` — the explicit
36
37
  * yml-section pair on `AddonSettingsApi`.
@@ -108,7 +109,7 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
108
109
  type: "text",
109
110
  key: "tokenExpiry",
110
111
  label: "Token Expiry",
111
- description: "JWT token lifetime (e.g. 24h, 7d, 30d)",
112
+ description: "Lifetime of a session token, as a duration string (e.g. 24h, 7d, 30d). A bare number is rejected — it would be read as milliseconds. Applies to tokens issued from the next login or silent refresh; tokens already handed out keep the lifetime they were signed with.",
112
113
  placeholder: "30d",
113
114
  default: "30d"
114
115
  }]
@@ -1,4 +1,4 @@
1
- import { Kt as hydrateSchema, Ot as errMsg, kt as BaseAddon } from "../../dist-DrBc-7Y3.mjs";
1
+ import { Kt as hydrateSchema, Ot as errMsg, kt as BaseAddon } from "../../dist-CZWAU40-.mjs";
2
2
  //#region src/builtins/system-config/system-config.addon.ts
3
3
  /**
4
4
  * Built-in `system-config` addon — Phase 4 of the settings redesign.
@@ -7,25 +7,26 @@ import { Kt as hydrateSchema, Ot as errMsg, kt as BaseAddon } from "../../dist-D
7
7
  * loader reads before any addon is instantiated — things that cannot
8
8
  * live inside an addon because changing them requires a server
9
9
  * restart (port, host, dataPath) or because they own no runtime
10
- * state of their own (auth token expiry, global ffmpeg binary path).
10
+ * state of their own (the session token lifetime).
11
11
  *
12
- * Sections exposed:
12
+ * Sections exposed — this list is the whole of it:
13
13
  * - server (port, host, dataPath — READ-ONLY, loaded from config.yaml at bootstrap)
14
14
  * - auth (tokenExpiry)
15
- * - ffmpeg (binaryPath, hwAccel, threadCount)
16
15
  *
17
16
  * Sections NOT exposed (each owned by the addon that implements them):
18
17
  * - logging → `winston-logging` addon (level + retention)
19
18
  * - recording → `recording` addon (segment duration, retention)
20
19
  * - retention → analytics / detection addons (per-table retention)
20
+ * - ffmpeg → deleted outright; see the note beside the schema below.
21
21
  *
22
22
  * Implementation notes:
23
- * - Runs only on the hub process (yml sections are hub-side state).
24
- * On agent nodes this addon would still instantiate, but every
25
- * `ctx.settings.getSection(section)` call would hit an empty
26
- * ConfigManager section so the UI would show the schema defaults.
27
- * In practice the built-in loader can skip it on agents; for now we
28
- * just let it run everywhere because it's harmless.
23
+ * - Hub-only, and the manifest says so. `ctx.settings` here is
24
+ * `ConfigManager.createSettingsView`, whose `getSection`/`setSection`
25
+ * are the `system-settings` keyspace the SAME keyspace
26
+ * `ConfigManager.get('auth.tokenExpiry')` resolves, which is what makes
27
+ * a Save on this form reach `AuthManager.signToken`. An agent's
28
+ * `ctx.settings` is a different view (`sections` collection) and would
29
+ * write somewhere nothing reads.
29
30
  * - Reads via `ctx.settings.getSection(section)` and writes via
30
31
  * `ctx.settings.setSection(section, patch)` — the explicit
31
32
  * yml-section pair on `AddonSettingsApi`.
@@ -103,7 +104,7 @@ var SystemConfigAddon = class extends BaseAddon {
103
104
  type: "text",
104
105
  key: "tokenExpiry",
105
106
  label: "Token Expiry",
106
- description: "JWT token lifetime (e.g. 24h, 7d, 30d)",
107
+ description: "Lifetime of a session token, as a duration string (e.g. 24h, 7d, 30d). A bare number is rejected — it would be read as milliseconds. Applies to tokens issued from the next login or silent refresh; tokens already handed out keep the lifetime they were signed with.",
107
108
  placeholder: "30d",
108
109
  default: "30d"
109
110
  }]
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_chunk = require("../../chunk-Cek0wNdY.js");
6
- const require_dist = require("../../dist-Dl6MFXPr.js");
6
+ const require_dist = require("../../dist-DdEXjTDo.js");
7
7
  const require_formatter = require("../../formatter-DqAKDlvN.js");
8
8
  let node_path = require("node:path");
9
9
  node_path = require_chunk.__toESM(node_path);
@@ -1,4 +1,4 @@
1
- import { kt as BaseAddon, rt as logDestinationCapability } from "../../dist-DrBc-7Y3.mjs";
1
+ import { kt as BaseAddon, rt as logDestinationCapability } from "../../dist-CZWAU40-.mjs";
2
2
  import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
3
3
  import * as path$1 from "node:path";
4
4
  import path from "node:path";