@camstack/system 1.2.437 → 1.2.439

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 (109) hide show
  1. package/dist/addon-runner.js +64 -12
  2. package/dist/addon-runner.mjs +65 -13
  3. package/dist/{agent-https-BZIwS4xF.js → agent-https-DlpTMDqA.js} +252 -22
  4. package/dist/{agent-https-BPfHrI4c.mjs → agent-https-U0d4uvn2.mjs} +211 -23
  5. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  8. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  9. package/dist/builtins/alerts/alerts.addon.js +7 -1
  10. package/dist/builtins/alerts/alerts.addon.mjs +7 -1
  11. package/dist/builtins/autotrack/index.js +1 -1
  12. package/dist/builtins/autotrack/index.mjs +1 -1
  13. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2 -2
  14. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2 -2
  15. package/dist/builtins/calendars/calendars.addon.js +1 -1
  16. package/dist/builtins/calendars/calendars.addon.mjs +1 -1
  17. package/dist/builtins/camera-grid/index.js +9 -1
  18. package/dist/builtins/camera-grid/index.mjs +9 -1
  19. package/dist/builtins/composer/composer.addon.js +2 -2
  20. package/dist/builtins/composer/composer.addon.mjs +2 -2
  21. package/dist/builtins/console-logging/index.js +12 -5
  22. package/dist/builtins/console-logging/index.mjs +12 -5
  23. package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
  24. package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
  25. package/dist/builtins/device-manager/device-manager.addon.d.ts +5 -0
  26. package/dist/builtins/device-manager/device-manager.addon.js +717 -28
  27. package/dist/builtins/device-manager/device-manager.addon.mjs +717 -28
  28. package/dist/builtins/device-manager/device-meta-types.d.ts +4 -0
  29. package/dist/builtins/device-manager/device-provider-context.d.ts +9 -0
  30. package/dist/builtins/device-manager/device-removal-hooks.d.ts +103 -0
  31. package/dist/builtins/device-manager/device-row-store.d.ts +1 -0
  32. package/dist/builtins/device-manager/device-tombstone-store.d.ts +68 -0
  33. package/dist/builtins/device-manager/removal-cleanup.d.ts +50 -0
  34. package/dist/builtins/hub-forwarder/index.js +1 -1
  35. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  36. package/dist/builtins/keychain/index.js +37 -4
  37. package/dist/builtins/keychain/index.mjs +37 -4
  38. package/dist/builtins/keychain/keychain-service.d.ts +14 -0
  39. package/dist/builtins/keychain/keychain-store.d.ts +1 -1
  40. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  41. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  42. package/dist/builtins/local-auth/local-auth.addon.js +12 -12
  43. package/dist/builtins/local-auth/local-auth.addon.mjs +12 -12
  44. package/dist/builtins/local-network/local-network.addon.js +16 -2
  45. package/dist/builtins/local-network/local-network.addon.mjs +16 -2
  46. package/dist/builtins/loki-logging/index.js +28 -5
  47. package/dist/builtins/loki-logging/index.mjs +28 -5
  48. package/dist/builtins/native-metrics/native-metrics.addon.js +11 -1
  49. package/dist/builtins/native-metrics/native-metrics.addon.mjs +11 -1
  50. package/dist/builtins/platform-probe/index.js +1 -1
  51. package/dist/builtins/platform-probe/index.mjs +1 -1
  52. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  53. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  54. package/dist/builtins/snapshot/index.js +11 -1
  55. package/dist/builtins/snapshot/index.mjs +11 -1
  56. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +4 -1
  57. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +4 -1
  58. package/dist/builtins/sqlite-storage/index.js +1 -1
  59. package/dist/builtins/sqlite-storage/index.mjs +1 -1
  60. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +3 -3
  61. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +3 -3
  62. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  63. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  64. package/dist/builtins/system-config/system-config.addon.js +22 -4
  65. package/dist/builtins/system-config/system-config.addon.mjs +22 -4
  66. package/dist/builtins/winston-logging/index.js +14 -5
  67. package/dist/builtins/winston-logging/index.mjs +14 -5
  68. package/dist/{composition-sources-BIT8IUKm.js → composition-sources-B4jC2FC7.js} +1 -1
  69. package/dist/{composition-sources-tpYR0f1x.mjs → composition-sources-BGOSCGWa.mjs} +1 -1
  70. package/dist/{constants-Bc6trhoW.mjs → constants-B92BjObl.mjs} +1 -1
  71. package/dist/{constants-CwRY32Nx.js → constants-BRsjQwi-.js} +1 -1
  72. package/dist/{device-ca-BhdBByGD.mjs → device-ca-46BUsWD1.mjs} +2 -2
  73. package/dist/{device-ca-DImD8IzR.js → device-ca-DHG9OW2m.js} +2 -2
  74. package/dist/{dist-CEAyXW3Q.js → dist-BOWdLjoK.js} +341 -13
  75. package/dist/{dist-m5JkT8UN.mjs → dist-yI6kF6r6.mjs} +306 -14
  76. package/dist/file-host-worker.js +1 -1
  77. package/dist/file-host-worker.mjs +1 -1
  78. package/dist/{hub-mdns-ciao-CBLvq2oj.js → hub-mdns-ciao-D7S5AJRU.js} +377 -69
  79. package/dist/{hub-mdns-ciao-DMlQTdPU.mjs → hub-mdns-ciao-DGwVc2uh.mjs} +344 -72
  80. package/dist/i18n/catalog-registry.d.ts +35 -0
  81. package/dist/i18n/index.d.ts +2 -0
  82. package/dist/index.d.ts +1 -0
  83. package/dist/index.js +698 -22
  84. package/dist/index.mjs +681 -24
  85. package/dist/kernel/gc-census.d.ts +18 -1
  86. package/dist/kernel/settings-view-types.d.ts +2 -0
  87. package/dist/kernel/transport/local-transport.d.ts +3 -0
  88. package/dist/kernel/transport/peer-answered-error.d.ts +5 -1
  89. package/dist/{lib-NNxHSOIE.js → lib-8oZrELLm.js} +1 -1
  90. package/dist/{lib-BeGzVQcd.mjs → lib-DK38ompL.mjs} +1 -1
  91. package/dist/{restore-archive-DNxAStrJ.mjs → restore-archive-CpdUO-uS.mjs} +1 -1
  92. package/dist/{restore-archive-C75srVbG.js → restore-archive-DiGiI6Jp.js} +1 -1
  93. package/dist/{retired-settings-keys-DNfV28R_.js → retired-settings-keys-CyQ7uvta.js} +1 -1
  94. package/dist/{retired-settings-keys-C5qP9QIf.mjs → retired-settings-keys-UsVtLOT0.mjs} +1 -1
  95. package/dist/tls/agent-https.d.ts +2 -2
  96. package/dist/tls/boot-tls.d.ts +6 -0
  97. package/dist/tls/cert-evaluation.d.ts +1 -1
  98. package/dist/tls/cert-issue.d.ts +5 -1
  99. package/dist/tls/cert-manager.d.ts +18 -0
  100. package/dist/tls/cert-name-constraints.d.ts +53 -0
  101. package/dist/tls/index.d.ts +5 -4
  102. package/dist/tls/tls-actions.d.ts +27 -7
  103. package/dist/tls/tls-status.d.ts +22 -0
  104. package/dist/tls/uploaded-cert.d.ts +36 -4
  105. package/dist/{wal-maintenance-Ch79gy9S.js → wal-maintenance-DEL_jeG0.js} +0 -0
  106. package/dist/{wal-maintenance-DvnVO5IK.mjs → wal-maintenance-xsvdT5Go.mjs} +0 -0
  107. package/dist/{x509.es-r7Ht1thA.js → x509.es-C4cOo48M.js} +36 -0
  108. package/dist/{x509.es-CDvj67p1.mjs → x509.es-DK__ETIe.mjs} +1 -1
  109. package/package.json +3 -1
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_chunk = require("./chunk-Cek0wNdY.js");
3
- const require_dist = require("./dist-CEAyXW3Q.js");
4
- const require_device_ca = require("./device-ca-DImD8IzR.js");
3
+ const require_dist = require("./dist-BOWdLjoK.js");
4
+ const require_device_ca = require("./device-ca-DHG9OW2m.js");
5
5
  const require_builtins_alerts_alerts_addon = require("./builtins/alerts/alerts.addon.js");
6
6
  require("./builtins/alerts/index.js");
7
7
  const require_builtins_calendars_calendars_addon = require("./builtins/calendars/calendars.addon.js");
@@ -22,21 +22,21 @@ require("./builtins/local-auth/index.js");
22
22
  const require_builtins_loki_logging_index = require("./builtins/loki-logging/index.js");
23
23
  const require_builtins_native_metrics_native_metrics_addon = require("./builtins/native-metrics/native-metrics.addon.js");
24
24
  const require_builtins_sqlite_storage_filesystem_storage_addon = require("./builtins/sqlite-storage/filesystem-storage.addon.js");
25
- const require_wal_maintenance = require("./wal-maintenance-Ch79gy9S.js");
25
+ const require_wal_maintenance = require("./wal-maintenance-DEL_jeG0.js");
26
26
  const require_builtins_sqlite_storage_sqlite_settings_addon = require("./builtins/sqlite-storage/sqlite-settings.addon.js");
27
27
  const require_builtins_sqlite_storage_index = require("./builtins/sqlite-storage/index.js");
28
28
  const require_builtins_storage_orchestrator_storage_orchestrator_addon = require("./builtins/storage-orchestrator/storage-orchestrator.addon.js");
29
29
  require("./builtins/storage-orchestrator/index.js");
30
- const require_agent_https = require("./agent-https-BZIwS4xF.js");
31
- const require_constants = require("./constants-CwRY32Nx.js");
30
+ const require_agent_https = require("./agent-https-DlpTMDqA.js");
31
+ const require_constants = require("./constants-BRsjQwi-.js");
32
32
  const require_builtins_system_config_system_config_addon = require("./builtins/system-config/system-config.addon.js");
33
33
  require("./builtins/system-config/index.js");
34
34
  const require_builtins_winston_logging_index = require("./builtins/winston-logging/index.js");
35
35
  const require_custom_action_registry = require("./custom-action-registry-Bf_YnagS.js");
36
- const require_hub_mdns_ciao = require("./hub-mdns-ciao-CBLvq2oj.js");
36
+ const require_hub_mdns_ciao = require("./hub-mdns-ciao-D7S5AJRU.js");
37
37
  const require_platform_key_source = require("./platform-key-source-Di7HrlGR.js");
38
38
  const require_resource_monitor = require("./resource-monitor-mio9dSCT.js");
39
- const require_restore_archive = require("./restore-archive-C75srVbG.js");
39
+ const require_restore_archive = require("./restore-archive-DiGiI6Jp.js");
40
40
  let zod = require("zod");
41
41
  let node_crypto = require("node:crypto");
42
42
  node_crypto = require_chunk.__toESM(node_crypto);
@@ -1802,7 +1802,8 @@ function formatArrayBufferCensus(label, report, context) {
1802
1802
  }
1803
1803
  //#endregion
1804
1804
  //#region src/kernel/gc-census.ts
1805
- function countsOf(entries, kinds) {
1805
+ function countsOf(entries, kinds, flagBits) {
1806
+ const flags = {};
1806
1807
  let majors = 0;
1807
1808
  let minors = 0;
1808
1809
  let incrementals = 0;
@@ -1812,13 +1813,17 @@ function countsOf(entries, kinds) {
1812
1813
  else if (e.kind === kinds.minor) minors++;
1813
1814
  else if (e.kind === kinds.incremental) incrementals++;
1814
1815
  pauseMs += e.durationMs;
1816
+ if (e.flags !== void 0) {
1817
+ for (const f of flagBits) if ((e.flags & f.bit) !== 0) flags[f.name] = (flags[f.name] ?? 0) + 1;
1818
+ }
1815
1819
  }
1816
1820
  return {
1817
1821
  majors,
1818
1822
  minors,
1819
1823
  incrementals,
1820
1824
  pauseMs,
1821
- windowMs: 0
1825
+ windowMs: 0,
1826
+ ...Object.keys(flags).length > 0 ? { flags } : {}
1822
1827
  };
1823
1828
  }
1824
1829
  /**
@@ -1830,7 +1835,7 @@ function countsOf(entries, kinds) {
1830
1835
  * observed and a process that is not collecting look identical on the line, and
1831
1836
  * they are the two answers furthest apart.
1832
1837
  */
1833
- function createGcCensus(install, kinds, startedAt) {
1838
+ function createGcCensus(install, kinds, startedAt, flagBits = []) {
1834
1839
  let pending = [];
1835
1840
  const stopObserving = install((entry) => {
1836
1841
  pending.push(entry);
@@ -1845,7 +1850,7 @@ function createGcCensus(install, kinds, startedAt) {
1845
1850
  pending = [];
1846
1851
  windowStart = at;
1847
1852
  return {
1848
- ...countsOf(taken, kinds),
1853
+ ...countsOf(taken, kinds, flagBits),
1849
1854
  windowMs
1850
1855
  };
1851
1856
  },
@@ -1870,14 +1875,18 @@ function nodeGcObserver() {
1870
1875
  minor: 1,
1871
1876
  incremental: 8
1872
1877
  }),
1878
+ flagBits: readFlagBits(),
1873
1879
  install: (observe) => {
1874
1880
  try {
1875
1881
  const observer = new (process.getBuiltinModule("node:perf_hooks")).PerformanceObserver((list) => {
1876
1882
  for (const entry of list.getEntries()) {
1877
1883
  const detail = "detail" in entry ? entry.detail : void 0;
1884
+ const kind = typeof detail === "object" && detail !== null && "kind" in detail && typeof detail.kind === "number" ? detail.kind : -1;
1885
+ const flags = typeof detail === "object" && detail !== null && "flags" in detail && typeof detail.flags === "number" ? detail.flags : void 0;
1878
1886
  observe({
1879
- kind: typeof detail === "object" && detail !== null && "kind" in detail && typeof detail.kind === "number" ? detail.kind : -1,
1880
- durationMs: entry.duration
1887
+ kind,
1888
+ durationMs: entry.duration,
1889
+ ...flags !== void 0 ? { flags } : {}
1881
1890
  });
1882
1891
  }
1883
1892
  });
@@ -1891,6 +1900,25 @@ function nodeGcObserver() {
1891
1900
  }
1892
1901
  };
1893
1902
  }
1903
+ var GC_FLAG_PREFIX = "NODE_PERFORMANCE_GC_FLAGS_";
1904
+ /**
1905
+ * The flag bits, read from `perf_hooks.constants` by their prefix so a flag V8
1906
+ * adds tomorrow gets a name without anyone editing a table. `NO` (0) can never
1907
+ * match a bit and is dropped.
1908
+ */
1909
+ function readFlagBits() {
1910
+ try {
1911
+ const perf = process.getBuiltinModule("node:perf_hooks");
1912
+ const bits = [];
1913
+ for (const [key, value] of Object.entries(perf.constants)) if (key.startsWith(GC_FLAG_PREFIX) && typeof value === "number" && value > 0) bits.push({
1914
+ name: key.slice(26),
1915
+ bit: value
1916
+ });
1917
+ return bits;
1918
+ } catch {
1919
+ return [];
1920
+ }
1921
+ }
1894
1922
  function readKinds(fallback) {
1895
1923
  try {
1896
1924
  const c = process.getBuiltinModule("node:perf_hooks").constants;
@@ -1917,7 +1945,14 @@ function readKinds(fallback) {
1917
1945
  function formatGcCensus(window) {
1918
1946
  if (window === null || window === void 0) return "";
1919
1947
  const perMin = (n) => window.windowMs <= 0 ? "?" : (n / (window.windowMs / 6e4)).toFixed(1);
1920
- return ` gc=maj${window.majors}/min${window.minors}/inc${window.incrementals}@${Math.round(window.windowMs / 1e3)}s gcMajPerMin=${perMin(window.majors)} gcPauseMs=${Math.round(window.pauseMs)}`;
1948
+ return ` gc=maj${window.majors}/min${window.minors}/inc${window.incrementals}@${Math.round(window.windowMs / 1e3)}s gcMajPerMin=${perMin(window.majors)} gcPauseMs=${Math.round(window.pauseMs)}` + formatGcFlags(window.flags);
1949
+ }
1950
+ /** ` gcFlags=ALL_EXTERNAL_MEMORY:12,FORCED:1` — most frequent first; empty when none. */
1951
+ function formatGcFlags(flags) {
1952
+ if (flags === void 0) return "";
1953
+ const entries = Object.entries(flags).toSorted((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]));
1954
+ if (entries.length === 0) return "";
1955
+ return ` gcFlags=${entries.map(([name, n]) => `${name}:${n}`).join(",")}`;
1921
1956
  }
1922
1957
  /**
1923
1958
  * The census. Always exists — `process.cpuUsage()` is available on every
@@ -2645,7 +2680,7 @@ function startHeapWatch(label = HUB_MAIN_HEAP_WATCH_LABEL, sink = consoleSink, i
2645
2680
  const readMemory = reclaimOptions?.readMemory ?? (() => process.memoryUsage());
2646
2681
  const now = reclaimOptions?.now ?? (() => Date.now());
2647
2682
  const gcObserver = probes?.gcObserver ?? nodeGcObserver();
2648
- const gcCensus = createGcCensus(gcObserver.install, gcObserver.kinds, now());
2683
+ const gcCensus = createGcCensus(gcObserver.install, gcObserver.kinds, now(), gcObserver.flagBits);
2649
2684
  const cpuProbe = probes?.processCpu;
2650
2685
  const processCpu = createProcessCpuCensus({
2651
2686
  cpuUsageUs: cpuProbe?.cpuUsageUs ?? (() => {
@@ -2699,6 +2734,7 @@ function startHeapWatch(label = HUB_MAIN_HEAP_WATCH_LABEL, sink = consoleSink, i
2699
2734
  };
2700
2735
  let mode = "steady";
2701
2736
  let lastLoggedAt = Number.NEGATIVE_INFINITY;
2737
+ let firstLinePending = true;
2702
2738
  const budgetMb = rssBudget?.budgetMb !== void 0 && rssBudget.budgetMb > 0 ? rssBudget.budgetMb : void 0;
2703
2739
  const budgetSource = rssBudget?.source ?? "unspecified";
2704
2740
  const releaseRatio = rssBudget?.releaseRatio ?? .9;
@@ -2757,7 +2793,9 @@ function startHeapWatch(label = HUB_MAIN_HEAP_WATCH_LABEL, sink = consoleSink, i
2757
2793
  const due = at - lastLoggedAt >= intervalMs;
2758
2794
  if (mode === "escalated" || due) {
2759
2795
  lastLoggedAt = at;
2760
- const line = format(label, sample, loopDelay?.read(), budgetMb, `${formatHeapSpaces(readSpaces())}${formatEventPlane(eventPlane?.read())}` + formatSocketPlane(socketPlane?.read()) + formatMeshQueue(meshQueue?.()) + formatGcCensus(gcCensus?.read(at)) + formatProcessCpu(processCpu.read(at)));
2796
+ const firstLine = firstLinePending;
2797
+ firstLinePending = false;
2798
+ const line = format(label, sample, loopDelay?.read(), budgetMb, `${formatHeapSpaces(readSpaces(), firstLine ? 0 : void 0)}${formatEventPlane(eventPlane?.read())}` + formatSocketPlane(socketPlane?.read()) + formatMeshQueue(meshQueue?.()) + formatGcCensus(gcCensus?.read(at)) + formatProcessCpu(processCpu.read(at)));
2761
2799
  if (sample.nearLimit) sink.warn(`${line} — APPROACHING HEAP LIMIT`);
2762
2800
  else if (mode === "escalated") sink.warn(`${line} — heap elevated, sampling every ${probeIntervalMs}ms`);
2763
2801
  else sink.info(line);
@@ -4963,7 +5001,7 @@ var PythonEnvManager = class {
4963
5001
  }
4964
5002
  async ensure(options) {
4965
5003
  const probe = await this.probe();
4966
- if (!probe.available || !probe.path) throw new Error("Python 3.10+ is required but not found on this system");
5004
+ if (!probe.available || !probe.path) throw require_dist.userError("system.python-required", void 0, "Python 3.10+ is required but not found on this system");
4967
5005
  if (!node_fs.existsSync(node_path.join(this.venvPath, "bin", "python"))) await execFileAsync$7(probe.path, [
4968
5006
  "-m",
4969
5007
  "venv",
@@ -5231,7 +5269,7 @@ var StorageManager = class {
5231
5269
  }
5232
5270
  getProvider() {
5233
5271
  if (this.legacyProvider) return this.legacyProvider;
5234
- if (!this.newStorageProvider && !this.settingsBackend && !this.locationManager) throw new Error("No storage provider configured");
5272
+ if (!this.newStorageProvider && !this.settingsBackend && !this.locationManager) throw require_dist.userError("storage.no-provider", void 0, "No storage provider configured");
5235
5273
  return this.createLegacyShim();
5236
5274
  }
5237
5275
  setLocationManager(manager) {
@@ -5254,7 +5292,7 @@ var StorageManager = class {
5254
5292
  * Builds IStorageLocation from settingsBackend (structured) + locationManager (files).
5255
5293
  */
5256
5294
  getLocation(name, namespace) {
5257
- if (!this.legacyProvider && !this.newStorageProvider && !this.settingsBackend && !this.locationManager) throw new Error("No storage provider configured");
5295
+ if (!this.legacyProvider && !this.newStorageProvider && !this.settingsBackend && !this.locationManager) throw require_dist.userError("storage.no-provider", void 0, "No storage provider configured");
5258
5296
  if (this.legacyProvider) try {
5259
5297
  const LEGACY_MAP = {
5260
5298
  config: "data",
@@ -11680,6 +11718,17 @@ function createDoorSettingsView(addonId, door, sections) {
11680
11718
  }
11681
11719
  return out;
11682
11720
  },
11721
+ async listDeviceStoreIds() {
11722
+ const all = await loadPrefixed(door, "addon-device-settings", `${addonId}:`, () => null);
11723
+ const ids = /* @__PURE__ */ new Set();
11724
+ for (const suffix of Object.keys(all)) {
11725
+ const dot = suffix.indexOf(".");
11726
+ if (dot <= 0) continue;
11727
+ const deviceId = Number(suffix.slice(0, dot));
11728
+ if (Number.isInteger(deviceId) && deviceId > 0) ids.add(deviceId);
11729
+ }
11730
+ return [...ids].toSorted((a, b) => a - b);
11731
+ },
11683
11732
  async writeDeviceStore(deviceId, patch) {
11684
11733
  const scope = `${addonId}:${String(deviceId)}.`;
11685
11734
  await replacePrefixed(door, "addon-device-settings", scope, {
@@ -14888,6 +14937,11 @@ var ConfigManager = class {
14888
14937
  writeAddonStore: (patch) => active().writeAddonStore(patch),
14889
14938
  readDeviceStore: (deviceId) => active().readDeviceStore(deviceId),
14890
14939
  readDeviceStoreBatch: (deviceIds) => active().readDeviceStoreBatch(deviceIds),
14940
+ listDeviceStoreIds: async () => {
14941
+ const list = active().listDeviceStoreIds;
14942
+ if (list === void 0) throw new Error("listDeviceStoreIds is not available on this settings view");
14943
+ return list.call(active());
14944
+ },
14891
14945
  writeDeviceStore: (deviceId, patch) => active().writeDeviceStore(deviceId, patch),
14892
14946
  clearDeviceStore: (deviceId) => active().clearDeviceStore(deviceId),
14893
14947
  getSection: (section) => active().getSection(section),
@@ -18562,9 +18616,14 @@ function localEndpointPath(nodeId) {
18562
18616
  * node had answered (2026-09-25, device 3836).
18563
18617
  */
18564
18618
  var PeerAnsweredError = class extends Error {
18565
- constructor(message) {
18619
+ /** The far end's stable error code (D863), carried so the hub can translate it. */
18620
+ i18nCode;
18621
+ i18nParams;
18622
+ constructor(message, i18n) {
18566
18623
  super(message);
18567
18624
  this.name = "PeerAnsweredError";
18625
+ this.i18nCode = i18n?.code;
18626
+ this.i18nParams = i18n?.params;
18568
18627
  }
18569
18628
  };
18570
18629
  //#endregion
@@ -18586,6 +18645,13 @@ var PayloadReply = class {
18586
18645
  this.payload = payload;
18587
18646
  }
18588
18647
  };
18648
+ //#endregion
18649
+ //#region src/kernel/transport/socket-channel.ts
18650
+ /** A peer's `i18n` is untrusted wire data: a malformed one is dropped, the message still travels. */
18651
+ function parseWireI18n(raw) {
18652
+ const parsed = _camstack_types_addon.ErrorI18nPayloadSchema.safeParse(raw);
18653
+ return parsed.success ? parsed.data : void 0;
18654
+ }
18589
18655
  var SocketChannel = class {
18590
18656
  socket;
18591
18657
  nextId = 1;
@@ -18797,11 +18863,13 @@ var SocketChannel = class {
18797
18863
  body: result
18798
18864
  });
18799
18865
  } catch (err) {
18866
+ const i18n = (0, _camstack_types_addon.readErrorI18n)(err);
18800
18867
  resBytes = this.send({
18801
18868
  k: "res",
18802
18869
  id: frame.id,
18803
18870
  ok: false,
18804
- err: err instanceof Error ? err.message : String(err)
18871
+ err: err instanceof Error ? err.message : String(err),
18872
+ ...i18n !== null ? { i18n } : {}
18805
18873
  });
18806
18874
  }
18807
18875
  if (label !== void 0) this.recordAction(label, wireBytes, resBytes);
@@ -18813,7 +18881,7 @@ var SocketChannel = class {
18813
18881
  this.pending.delete(frame.id);
18814
18882
  if (p.timer !== null) clearTimeout(p.timer);
18815
18883
  if (p.action !== null) this.recordAction(p.action.label, p.action.reqBytes, wireBytes);
18816
- if (!frame.ok) p.reject(new PeerAnsweredError(frame.err));
18884
+ if (!frame.ok) p.reject(new PeerAnsweredError(frame.err, parseWireI18n(frame.i18n)));
18817
18885
  else if (frame.pl !== void 0) p.resolve(new PayloadReply(frame.body, frame.pl));
18818
18886
  else p.resolve(frame.body);
18819
18887
  return;
@@ -26495,6 +26563,595 @@ var LifecycleJobEngine = class {
26495
26563
  */
26496
26564
  var CAP_METHOD_NOT_IMPLEMENTED = "CAP_METHOD_NOT_IMPLEMENTED";
26497
26565
  //#endregion
26566
+ //#region src/i18n/en.json
26567
+ var en_default = {
26568
+ "auth.invalid-credentials": "Invalid credentials",
26569
+ "auth.invalid-totp": "Invalid TOTP code",
26570
+ "auth.not-authenticated": "Not authenticated",
26571
+ "auth.login-challenge-expired": "Invalid or expired login challenge — please re-enter your password",
26572
+ "auth.passkey-verification-failed": "Passkey verification failed",
26573
+ "auth.user-gone": "User no longer exists",
26574
+ "auth.no-session-cookie": "No session cookie",
26575
+ "auth.invalid-session-cookie": "Invalid session cookie",
26576
+ "auth.handoff-code-invalid": "Invalid or expired handoff code",
26577
+ "auth.share-never-expiring-extend": "A never-expiring share token cannot be extended",
26578
+ "auth.share-owner-only-extend": "Only the token owner or an admin can extend a share token",
26579
+ "auth.share-owner-only-revoke": "Only the token owner or an admin can revoke a share token",
26580
+ "auth.share-token-not-found": "Share token not found: {id}",
26581
+ "auth.password-incorrect": "Password is incorrect",
26582
+ "auth.session-required": "Requires a signed-in user session",
26583
+ "auth.admin-required": "Admin required",
26584
+ "auth.session-ended": "Session ended — sign in again",
26585
+ "auth.access-denied": "Access denied",
26586
+ "auth.totp-confirm-failed": "TOTP confirmation failed — code did not match",
26587
+ "device.certificates-unavailable": "Device certificates are not available",
26588
+ "device.not-found": "Device {id} not found",
26589
+ "device.credentials-unavailable": "Device credentials not available",
26590
+ "device.credential-not-found": "Device credential not found: {id}",
26591
+ "storage.no-provider": "No storage provider configured",
26592
+ "recording.export-unknown": "Unknown export \"{id}\"",
26593
+ "recording.export-invalid-range": "Invalid time range {fromMs}..{toMs}",
26594
+ "recording.export-no-profiles": "The export needs at least one stream profile",
26595
+ "recording.export-not-ready": "Export \"{id}\" is not ready ({state})",
26596
+ "recording.export-expired": "Export \"{id}\" has expired",
26597
+ "recording.export-no-file": "Export \"{id}\" has no file on disk",
26598
+ "recording.clip-render-unavailable": "Clip rendering is unavailable on this node",
26599
+ "reolink.hub-host-missing": "Reolink Hub: host not configured",
26600
+ "reolink.hub-password-missing": "Reolink Hub: password not configured",
26601
+ "reolink.email-push-hub-attached": "Email push is not available for hub-attached cameras",
26602
+ "reolink.email-push-not-wired": "Email Push Server is not wired — restart the Reolink addon",
26603
+ "reolink.webhook-not-wired": "HaCfg Webhook Server is not wired — restart the Reolink addon",
26604
+ "reolink.webhook-unsupported": "Camera firmware does not support Baichuan HaCfg webhook (cmd 806)",
26605
+ "reolink.preset-invalid": "Invalid presetId: {presetId}",
26606
+ "reolink.home-preset-not-baichuan": "Configured home preset is not a Baichuan id: {presetId}",
26607
+ "reolink.day-night-schedule-unsupported": "Reolink cameras do not support a scheduled day/night mode",
26608
+ "reolink.clip-device-not-reolink": "clip refresh: device {deviceId} is not a Reolink camera here",
26609
+ "notifiers.gotify-server-url-required": "gotify: serverUrl is required",
26610
+ "notifiers.gotify-app-token-required": "gotify: appToken is required",
26611
+ "notifiers.email-to-required": "email: missing required config 'to'",
26612
+ "hikvision.camera-name-required": "Camera name is required",
26613
+ "hikvision.camera-ip-required": "Camera IP is required",
26614
+ "hikvision.password-required": "Password is required",
26615
+ "hikvision.home-preset-missing": "No home preset configured for this camera — set one in the PTZ settings",
26616
+ "amcrest.camera-name-required": "Camera name is required",
26617
+ "amcrest.camera-ip-required": "Camera IP is required",
26618
+ "amcrest.password-required": "Password is required",
26619
+ "amcrest.home-preset-missing": "No home preset configured for this camera — set one in the PTZ settings",
26620
+ "wyze.camera-name-required": "Camera name is required",
26621
+ "wyze.camera-mac-required": "Wyze: cannot persist a camera without a MAC address",
26622
+ "dreame.manual-create-refused": "Dreame devices are adopted from the cloud, not created manually",
26623
+ "rtsp.camera-name-required": "Camera name is required",
26624
+ "rtsp.stream-required": "At least one RTSP stream URL is required",
26625
+ "rtsp.too-many-streams": "At most 3 RTSP stream URLs are supported",
26626
+ "gree.name-required": "Air conditioner name is required",
26627
+ "gree.ip-required": "Air conditioner IP address is required",
26628
+ "ecowitt.name-required": "Gateway name is required",
26629
+ "ecowitt.host-required": "Gateway host is required for local-poll transport",
26630
+ "unifi.name-required": "Controller name is required",
26631
+ "unifi.host-required": "Controller host is required",
26632
+ "vesync.name-required": "Account name is required",
26633
+ "vesync.email-required": "Account email is required",
26634
+ "unraid.name-required": "Server name is required",
26635
+ "unraid.host-required": "Server host is required",
26636
+ "velux.name-required": "Gateway name is required",
26637
+ "velux.host-required": "Gateway host is required",
26638
+ "cloudflare.custom-not-configured": "Custom tunnel not configured — run \"Enable\" from settings first",
26639
+ "cloudflare.custom-needs-settings": "Custom tunnel needs: {missing}. Fill the settings above first.",
26640
+ "cloudflare.zone-token-missing": "listZones: no Cloudflare API token is set",
26641
+ "cloudflare.zone-not-visible": "Selected zone {zoneId} is not visible to this token",
26642
+ "google.from-address-required": "Set From address on the Google broker (or Connect an account).",
26643
+ "google.client-credentials-required": "Configure Client ID and Client secret before refreshing the Google token",
26644
+ "globalSettings.s_alerts.title": "Alert Center",
26645
+ "globalSettings.s_alerts.description": "Configure alert storage and retention.",
26646
+ "globalSettings.s_alerts.maxAlerts.label": "Maximum stored alerts",
26647
+ "globalSettings.s_alerts.maxAlerts.description": "Oldest read alerts are deleted when this limit is exceeded.",
26648
+ "globalSettings.s_alerts.retentionDays.label": "Alert retention (days)",
26649
+ "globalSettings.s_alerts.retentionDays.description": "Alerts older than this are automatically removed.",
26650
+ "globalSettings.s_camera-grids.title": "Camera grids",
26651
+ "globalSettings.s_camera-grids.description": "A grid is a composite camera: several cameras composed into one picture, recorded and played back like any other camera. Create one here with a name; open its camera to lay it out. Object detection is switched OFF on a new grid — the cameras it is composed from are already analysed.",
26652
+ "globalSettings.s_camera-grids.cameraGrids.label": "Grids",
26653
+ "globalSettings.s_camera-grids.cameraGrids.name.label": "Name",
26654
+ "globalSettings.s_camera-grids.cameraGrids.enabled.label": "Enabled",
26655
+ "globalSettings.s_camera-grids.cameraGrids.enabled.description": "A disabled grid withdraws its camera.",
26656
+ "gridDevice.s_camera-grid-layout.title": "Grid layout",
26657
+ "gridDevice.s_camera-grid-layout._gridLayout.label": "",
26658
+ "globalSettings.s_console-logging.title": "Console Logging",
26659
+ "globalSettings.s_console-logging.description": "Minimum log level to emit on stdout/stderr. Independent from the rotated-file (Winston) destination.",
26660
+ "globalSettings.s_console-logging.level.label": "Log Level",
26661
+ "globalSettings.s_console-logging.level.o_debug.label": "Debug",
26662
+ "globalSettings.s_console-logging.level.o_info.label": "Info",
26663
+ "globalSettings.s_console-logging.level.o_warn.label": "Warn",
26664
+ "globalSettings.s_console-logging.level.o_error.label": "Error",
26665
+ "dayNightConfig.dayNight_mode.label": "Mode",
26666
+ "dayNightConfig.dayNight_sensitivity.label": "IR-cut sensitivity",
26667
+ "dayNightConfig.dayNight_switchDelaySec.label": "Switch delay",
26668
+ "section.s_day-night.title": "Day / Night",
26669
+ "section.s_day-night.description": "IR-cut switching mode and the photocell knobs that gate it.",
26670
+ "baseDeviceSection.s_driver-settings-unavailable.title": "Driver Settings",
26671
+ "baseDeviceSection.s_driver-settings-unavailable.driver-settings-unavailable-notice.label": "Temporarily unavailable",
26672
+ "imageSettingsConfig.imageSettings_brightness.label": "Brightness",
26673
+ "imageSettingsConfig.imageSettings_contrast.label": "Contrast",
26674
+ "imageSettingsConfig.imageSettings_saturation.label": "Saturation",
26675
+ "imageSettingsConfig.imageSettings_sharpness.label": "Sharpness",
26676
+ "imageSettingsConfig.imageSettings_mirror.label": "Mirror",
26677
+ "imageSettingsConfig.imageSettings_flip.label": "Flip",
26678
+ "imageSettingsConfig.imageSettings_rotate.label": "Rotation",
26679
+ "imageSettingsConfig.imageSettings_whiteBalance.label": "White balance",
26680
+ "imageSettingsConfig.imageSettings_warmth.label": "Warmth",
26681
+ "imageSettingsConfig.imageSettings_exposureMode.label": "Exposure mode",
26682
+ "imageSettingsConfig.imageSettings_backlightMode.label": "Backlight compensation",
26683
+ "section.s_image-settings.title": "Image adjustment",
26684
+ "section.s_image-settings.description": "Picture sliders, orientation and exposure. Option lists are read live from the camera — fields the firmware doesn't expose are hidden.",
26685
+ "volumesField.id.label": "Id",
26686
+ "volumesField.label.label": "Name",
26687
+ "volumesField.status.label": "Status",
26688
+ "volumesField.capacity.label": "Capacity",
26689
+ "volumesField.free.label": "Free",
26690
+ "tracksField.id.label": "Track",
26691
+ "tracksField.primary.label": "Primary",
26692
+ "tracksField.enabled.label": "Enabled",
26693
+ "tracksField.codec.label": "Codec",
26694
+ "tracksField.resolution.label": "Resolution",
26695
+ "storageSection.s_recording-onboard-storage.title": "Camera storage",
26696
+ "storageSection.s_recording-onboard-storage.description": "The card in the camera, as the camera itself describes it.",
26697
+ "recordingSection.s_recording-onboard-recording.title": "Camera recording",
26698
+ "recordingSection.s_recording-onboard-recording.description": "What the camera records to its own card. This writes the camera, not CamStack's recorder.",
26699
+ "globalSettings.s_local-access.title": "LAN HTTP",
26700
+ "globalSettings.s_local-access.description": "Native apps on this Wi-Fi use http:// and skip the private certificate. The tunnel and this admin UI stay on HTTPS. Turn off once a publicly-trusted certificate covers the LAN name.",
26701
+ "globalSettings.s_local-access.httpEnabled.label": "Enable HTTP on the LAN",
26702
+ "globalSettings.s_local-access.httpPort.label": "HTTP port",
26703
+ "globalSettings.s_local-access.httpPort.description": "Dedicated listener. Must not equal the HTTPS port (4443 by default).",
26704
+ "globalSettings.s_local-access.mdnsAdvertise.label": "Announce this hub on the LAN (mDNS)",
26705
+ "globalSettings.s_local-access.mdnsAdvertise.description": "Lets `camstack login` find the hub without an address. Advertises only the HTTPS address, never a secret. Needs UDP 5353 multicast to reach the LAN (host networking or a dedicated container IP).",
26706
+ "globalSettings.s_local-access.localHostname.label": "Local hostname",
26707
+ "globalSettings.s_local-access.localHostname.description": "Advertised to the viewer instead of the raw LAN IP, and added to the certificate SAN. Requires this name to resolve on the LAN (router DNS, mDNS, or a hosts file). Leave empty to keep using the IP.",
26708
+ "globalSettings.s_loki-logging.title": "Loki",
26709
+ "globalSettings.s_loki-logging.description": "Ship this node’s logs to a Grafana Loki instance. Independent of the rotated-file and console destinations. Turn it on or off with the Enable/Disable control on this destination — the same one every other destination uses.",
26710
+ "globalSettings.s_loki-logging.url.label": "Loki URL",
26711
+ "globalSettings.s_loki-logging.url.description": "Base URL, e.g. http://loki:3100 — the /loki/api/v1/push path is added.",
26712
+ "globalSettings.s_loki-logging.level.label": "Minimum level",
26713
+ "globalSettings.s_loki-logging.level.o_debug.label": "Debug",
26714
+ "globalSettings.s_loki-logging.level.o_info.label": "Info",
26715
+ "globalSettings.s_loki-logging.level.o_warn.label": "Warn",
26716
+ "globalSettings.s_loki-logging.level.o_error.label": "Error",
26717
+ "globalSettings.s_loki-logging.job.label": "Job label",
26718
+ "globalSettings.s_loki-logging.job.description": "The Loki `job` label. Keep it fixed — labels are indexed.",
26719
+ "globalSettings.s_loki-logging.extraLabels.label": "Extra labels",
26720
+ "globalSettings.s_loki-logging.extraLabels.description": "Static `key=value,key2=value2`. Low-cardinality only: per-entry values belong in the line body, and a high-cardinality label will bring Loki down.",
26721
+ "globalSettings.s_loki-logging.tenantId.label": "Tenant ID",
26722
+ "globalSettings.s_loki-logging.tenantId.description": "Sent as X-Scope-OrgID. Required by Grafana Cloud and multi-tenant Loki.",
26723
+ "globalSettings.s_loki-logging.username.label": "Username",
26724
+ "globalSettings.s_loki-logging.username.description": "HTTP basic auth. Leave empty for none.",
26725
+ "globalSettings.s_loki-logging.password.label": "Password",
26726
+ "globalSettings.s_loki-logging.batchIntervalMs.label": "Flush interval",
26727
+ "globalSettings.s_loki-logging.batchIntervalMs.description": "How often a partial batch is pushed.",
26728
+ "globalSettings.s_loki-logging.batchSize.label": "Batch size",
26729
+ "globalSettings.s_loki-logging.batchSize.description": "Push early once this many entries are queued.",
26730
+ "globalSettings.s_loki-logging.timeoutMs.label": "Request timeout",
26731
+ "globalSettings.s_native-metrics-settings.title": "System Metrics",
26732
+ "globalSettings.s_native-metrics-settings.samplingIntervalMs.label": "Sampling Interval",
26733
+ "globalSettings.s_native-metrics-settings.samplingIntervalMs.description": "How often to collect system metrics",
26734
+ "globalSettings.s_native-metrics-load-series.title": "Load history",
26735
+ "globalSettings.s_native-metrics-load-series.loadSeriesCadenceSec.label": "Sampling cadence",
26736
+ "globalSettings.s_native-metrics-load-series.loadSeriesCadenceSec.description": "How often every node reports its process tree. FIXED — a sample is emitted on every interval whether or not anything changed, so a gap in the chart means one thing only: nobody reported. Outside 5-60 s the value is refused.",
26737
+ "globalSettings.s_native-metrics-load-series.loadSeriesRetentionHours.label": "Retention",
26738
+ "globalSettings.s_native-metrics-load-series.loadSeriesRetentionHours.description": "How long the load history is kept on disk (the hub database, on the NVMe cache — never the recordings disk). This is the INTENTION; the row cap below is the guarantee.",
26739
+ "globalSettings.s_native-metrics-load-series.load-series-cost.label": "What this configuration costs",
26740
+ "globalSettings.s_native-metrics-load-series.load-series-cap.label": "Hard row cap",
26741
+ "globalSettings.s_snapshot-cache.title": "Snapshot Cache",
26742
+ "globalSettings.s_snapshot-cache.description": "Stale fallback when live capture fails. Per-device freshness is configured under Device → Snapshot → Max cache age.",
26743
+ "globalSettings.s_snapshot-cache.staleTtlMs.label": "Stale fallback TTL (ms)",
26744
+ "globalSettings.s_snapshot-cache.staleTtlMs.description": "If live capture fails, cached snapshot younger than this is still returned.",
26745
+ "deviceSettingsContribution.s_snapshot-preferences.title": "Snapshot",
26746
+ "deviceSettingsContribution.s_snapshot-preferences.snapshotStreamId.label": "Preferred stream",
26747
+ "deviceSettingsContribution.s_snapshot-preferences.snapshotStreamId.description": "Stream used when grabbing a snapshot",
26748
+ "deviceSettingsContribution.s_snapshot-preferences.snapshotMaxAgeS.label": "Max cache age (s)",
26749
+ "deviceSettingsContribution.s_snapshot-preferences.snapshotDebug.label": "Debug logging",
26750
+ "deviceSettingsContribution.s_snapshot-preferences.snapshotDebug.description": "Log stream selection and timing details for this device.",
26751
+ "providerInfo.s_filesystem-storage.title": "Filesystem",
26752
+ "providerInfo.s_filesystem-storage.basePath.label": "Base path",
26753
+ "providerInfo.s_filesystem-storage.basePath.description": "Absolute directory path where files are stored.",
26754
+ "global.s_system-config-server.description": "The name of this server, and its connection settings (read-only, loaded from config.yaml at bootstrap).",
26755
+ "global.s_system-config-server.server-restart-note.label": "Restart required",
26756
+ "global.s_system-config-server.port.label": "Port",
26757
+ "global.s_system-config-server.port.description": "Listening port",
26758
+ "global.s_system-config-server.host.label": "Host",
26759
+ "global.s_system-config-server.host.description": "Bind address",
26760
+ "global.s_system-config-server.dataPath.label": "Data Path",
26761
+ "global.s_system-config-server.dataPath.description": "Root data directory",
26762
+ "global.s_system-config-auth.description": "Token and session settings.",
26763
+ "global.s_system-config-auth.tokenExpiry.label": "Session lifetime",
26764
+ "global.s_system-config-auth.tokenExpiry.description": "How long a sign-in lasts without being used, as a duration string (e.g. 7d, 30d). Every refresh starts it again, so a device in use stays signed in; one left unopened this long must sign in again. A bare number is rejected — it would be read as milliseconds. Applies from the next sign-in or refresh.",
26765
+ "global.s_system-config-auth.accessTokenExpiry.label": "Access token lifetime",
26766
+ "global.s_system-config-auth.accessTokenExpiry.description": "How long one access token lives before the app silently swaps it for a new one (e.g. 2h; between 5m and 24h, never longer than the session). Shorter limits how long a copied token is useful. Apps that predate refresh tokens get one token for the whole session instead.",
26767
+ "global.s_system-config-auth.trustedProxies.label": "Trusted reverse proxies",
26768
+ "global.s_system-config-auth.trustedProxies.description": "Addresses or CIDR ranges (e.g. 192.168.1.2 or 10.0.0.0/24) of reverse proxies in front of the hub. Only a request whose direct sender is one of these — or this host itself, as with the Cloudflare tunnel — has its X-Forwarded-For / CF-Connecting-IP read as the real client address for rate limits. Leave empty unless a proxy on another host forwards to the hub.",
26769
+ "global.s_system-config-auth.trustedNetworksWarning.label": "Skipping two-factor authentication",
26770
+ "global.s_system-config-auth.trustedNetworks.label": "Trusted networks (skip the second factor)",
26771
+ "global.s_system-config-auth.trustedNetworks.description": "Addresses or CIDR ranges, e.g. 192.168.1.0/24. Keep it as narrow as you can — a single trusted VLAN, not the whole LAN.",
26772
+ "globalSettings.s_winston-logging.title": "Logging",
26773
+ "globalSettings.s_winston-logging.description": "Global log verbosity + retention for rotated log files on this node.",
26774
+ "globalSettings.s_winston-logging.level.label": "Log Level",
26775
+ "globalSettings.s_winston-logging.level.o_debug.label": "Debug",
26776
+ "globalSettings.s_winston-logging.level.o_info.label": "Info",
26777
+ "globalSettings.s_winston-logging.level.o_warn.label": "Warn",
26778
+ "globalSettings.s_winston-logging.level.o_error.label": "Error",
26779
+ "globalSettings.s_winston-logging.retentionDays.label": "Retention (days)",
26780
+ "globalSettings.s_winston-logging.retentionDays.description": "Number of days to keep rotated log files before deletion",
26781
+ "system.python-required": "Python 3.10+ is required but not found on this system",
26782
+ "system.device-enrollment-busy": "Too many pending device enrollments — try again shortly",
26783
+ "system.admin-token-expiry-too-long": "An admin token must expire within 90 days",
26784
+ "system.admin-token-name-required": "An admin token needs a name",
26785
+ "system.user-exists": "User with username \"{username}\" already exists",
26786
+ "system.user-not-found": "User with id \"{id}\" not found",
26787
+ "system.addon-no-discovery": "Addon \"{addonId}\" does not support device discovery",
26788
+ "system.addon-no-adoption": "Addon \"{addonId}\" does not support device adoption",
26789
+ "system.addon-no-manual-create": "Addon \"{addonId}\" does not support manual device creation",
26790
+ "system.location-name-required": "[device-manager] addLocation: name must be non-empty",
26791
+ "system.location-required": "[device-manager] setLocationIcon: location must be non-empty",
26792
+ "system.site-zone-name-required": "[device-manager] setSiteZone: name must be non-empty",
26793
+ "server.handoff-busy": "Too many pending handoff codes — try again shortly",
26794
+ "server.app-confirmations-busy": "Too many pending app confirmations",
26795
+ "server.step-up-busy": "Too many pending step-up proofs",
26796
+ "server.login-unavailable": "Login unavailable — `user-management` capability not registered",
26797
+ "server.share-token-expired": "Share token expired: {id}",
26798
+ "server.package-not-allowed": "Package \"{name}\" is not an allowed @camstack/* package",
26799
+ "server.package-protected": "Cannot uninstall protected package \"{name}\"",
26800
+ "server.package-required": "Package {packageName} is required and cannot be uninstalled",
26801
+ "tls.cert-unparsable": "The certificate PEM could not be parsed.",
26802
+ "tls.key-unparsable": "The private key PEM could not be parsed.",
26803
+ "tls.key-mismatch": "The private key does not match the certificate.",
26804
+ "tls.missing-server-auth": "The certificate is missing extendedKeyUsage = serverAuth.",
26805
+ "tls.ca-required": "This certificate was not issued by a public certificate authority, so its CA certificate is required: devices need it to trust the hub. Paste the CA certificate (for mkcert, the rootCA.pem in the folder `mkcert -CAROOT` prints).",
26806
+ "tls.ca-unparsable": "The CA certificate could not be parsed.",
26807
+ "tls.ca-not-issuer": "The certificate was not issued by the CA certificate you supplied.",
26808
+ "tls.ca-not-a-ca": "The supplied CA certificate is not a certificate authority (CA:TRUE is missing).",
26809
+ "tls.ca-expired": "The supplied CA certificate has expired or is not valid yet.",
26810
+ "tls.no-stored-upload": "No uploaded certificate is kept on this node."
26811
+ };
26812
+ //#endregion
26813
+ //#region src/i18n/it.json
26814
+ var it_default = {
26815
+ "auth.invalid-credentials": "Credenziali non valide",
26816
+ "auth.invalid-totp": "Codice TOTP non valido",
26817
+ "auth.not-authenticated": "Non autenticato",
26818
+ "auth.login-challenge-expired": "Richiesta di accesso non valida o scaduta — reinserisci la password",
26819
+ "auth.passkey-verification-failed": "Verifica della passkey non riuscita",
26820
+ "auth.user-gone": "L'utente non esiste più",
26821
+ "auth.no-session-cookie": "Nessun cookie di sessione",
26822
+ "auth.invalid-session-cookie": "Cookie di sessione non valido",
26823
+ "auth.handoff-code-invalid": "Codice di passaggio non valido o scaduto",
26824
+ "auth.share-never-expiring-extend": "Un token di condivisione senza scadenza non può essere prorogato",
26825
+ "auth.share-owner-only-extend": "Solo il proprietario del token o un amministratore può prorogare un token di condivisione",
26826
+ "auth.share-owner-only-revoke": "Solo il proprietario del token o un amministratore può revocare un token di condivisione",
26827
+ "auth.share-token-not-found": "Token di condivisione non trovato: {id}",
26828
+ "auth.password-incorrect": "La password non è corretta",
26829
+ "auth.session-required": "Serve una sessione utente con accesso effettuato",
26830
+ "auth.admin-required": "Serve un amministratore",
26831
+ "auth.session-ended": "Sessione terminata — accedi di nuovo",
26832
+ "auth.access-denied": "Accesso negato",
26833
+ "auth.totp-confirm-failed": "Conferma TOTP non riuscita — il codice non corrisponde",
26834
+ "device.certificates-unavailable": "I certificati dei dispositivi non sono disponibili",
26835
+ "device.not-found": "Dispositivo {id} non trovato",
26836
+ "device.credentials-unavailable": "Le credenziali del dispositivo non sono disponibili",
26837
+ "device.credential-not-found": "Credenziale del dispositivo non trovata: {id}",
26838
+ "storage.no-provider": "Nessun provider di archiviazione configurato",
26839
+ "recording.export-unknown": "Esportazione \"{id}\" sconosciuta",
26840
+ "recording.export-invalid-range": "Intervallo di tempo non valido {fromMs}..{toMs}",
26841
+ "recording.export-no-profiles": "L'esportazione richiede almeno un profilo di flusso",
26842
+ "recording.export-not-ready": "L'esportazione \"{id}\" non è pronta ({state})",
26843
+ "recording.export-expired": "L'esportazione \"{id}\" è scaduta",
26844
+ "recording.export-no-file": "L'esportazione \"{id}\" non ha alcun file su disco",
26845
+ "recording.clip-render-unavailable": "La creazione delle clip non è disponibile su questo nodo",
26846
+ "reolink.hub-host-missing": "Hub Reolink: host non configurato",
26847
+ "reolink.hub-password-missing": "Hub Reolink: password non configurata",
26848
+ "reolink.email-push-hub-attached": "Email push non è disponibile per le telecamere collegate a un hub",
26849
+ "reolink.email-push-not-wired": "Il server Email Push non è collegato — riavvia l'addon Reolink",
26850
+ "reolink.webhook-not-wired": "Il server webhook HaCfg non è collegato — riavvia l'addon Reolink",
26851
+ "reolink.webhook-unsupported": "Il firmware della telecamera non supporta il webhook HaCfg Baichuan (cmd 806)",
26852
+ "reolink.preset-invalid": "presetId non valido: {presetId}",
26853
+ "reolink.home-preset-not-baichuan": "Il preset home configurato non è un id Baichuan: {presetId}",
26854
+ "reolink.day-night-schedule-unsupported": "Le telecamere Reolink non supportano una modalità giorno/notte programmata",
26855
+ "reolink.clip-device-not-reolink": "aggiornamento clip: il dispositivo {deviceId} non è una telecamera Reolink qui",
26856
+ "notifiers.gotify-server-url-required": "gotify: serverUrl è obbligatorio",
26857
+ "notifiers.gotify-app-token-required": "gotify: appToken è obbligatorio",
26858
+ "notifiers.email-to-required": "email: manca la configurazione obbligatoria 'to'",
26859
+ "hikvision.camera-name-required": "Il nome della telecamera è obbligatorio",
26860
+ "hikvision.camera-ip-required": "L'IP della telecamera è obbligatorio",
26861
+ "hikvision.password-required": "La password è obbligatoria",
26862
+ "hikvision.home-preset-missing": "Nessun preset home configurato per questa telecamera — impostane uno nelle impostazioni PTZ",
26863
+ "amcrest.camera-name-required": "Il nome della telecamera è obbligatorio",
26864
+ "amcrest.camera-ip-required": "L'IP della telecamera è obbligatorio",
26865
+ "amcrest.password-required": "La password è obbligatoria",
26866
+ "amcrest.home-preset-missing": "Nessun preset home configurato per questa telecamera — impostane uno nelle impostazioni PTZ",
26867
+ "wyze.camera-name-required": "Il nome della telecamera è obbligatorio",
26868
+ "wyze.camera-mac-required": "Wyze: impossibile salvare una telecamera senza indirizzo MAC",
26869
+ "dreame.manual-create-refused": "I dispositivi Dreame si acquisiscono dal cloud, non si creano a mano",
26870
+ "rtsp.camera-name-required": "Il nome della telecamera è obbligatorio",
26871
+ "rtsp.stream-required": "È richiesto almeno un URL di flusso RTSP",
26872
+ "rtsp.too-many-streams": "Sono supportati al massimo 3 URL di flusso RTSP",
26873
+ "gree.name-required": "Il nome del condizionatore è obbligatorio",
26874
+ "gree.ip-required": "L'indirizzo IP del condizionatore è obbligatorio",
26875
+ "ecowitt.name-required": "Il nome del gateway è obbligatorio",
26876
+ "ecowitt.host-required": "L'host del gateway è obbligatorio per la lettura locale",
26877
+ "unifi.name-required": "Il nome del controller è obbligatorio",
26878
+ "unifi.host-required": "L'host del controller è obbligatorio",
26879
+ "vesync.name-required": "Il nome dell'account è obbligatorio",
26880
+ "vesync.email-required": "L'email dell'account è obbligatoria",
26881
+ "unraid.name-required": "Il nome del server è obbligatorio",
26882
+ "unraid.host-required": "L'host del server è obbligatorio",
26883
+ "velux.name-required": "Il nome del gateway è obbligatorio",
26884
+ "velux.host-required": "L'host del gateway è obbligatorio",
26885
+ "cloudflare.custom-not-configured": "Tunnel personalizzato non configurato — avvia «Attiva» dalle impostazioni",
26886
+ "cloudflare.custom-needs-settings": "Il tunnel personalizzato richiede: {missing}. Compila prima le impostazioni qui sopra.",
26887
+ "cloudflare.zone-token-missing": "listZones: nessun token API Cloudflare impostato",
26888
+ "cloudflare.zone-not-visible": "La zona selezionata {zoneId} non è visibile a questo token",
26889
+ "google.from-address-required": "Imposta l'indirizzo del mittente sul broker Google (oppure collega un account).",
26890
+ "google.client-credentials-required": "Configura ID client e segreto del client prima di aggiornare il token Google",
26891
+ "globalSettings.s_alerts.title": "Centro avvisi",
26892
+ "globalSettings.s_alerts.description": "Configura l'archiviazione e la conservazione degli avvisi.",
26893
+ "globalSettings.s_alerts.maxAlerts.label": "Numero massimo di avvisi memorizzati",
26894
+ "globalSettings.s_alerts.maxAlerts.description": "Quando si supera questo limite vengono eliminati gli avvisi letti più vecchi.",
26895
+ "globalSettings.s_alerts.retentionDays.label": "Conservazione degli avvisi (giorni)",
26896
+ "globalSettings.s_alerts.retentionDays.description": "Gli avvisi più vecchi di questo valore vengono rimossi automaticamente.",
26897
+ "globalSettings.s_camera-grids.title": "Griglie di telecamere",
26898
+ "globalSettings.s_camera-grids.description": "Una griglia è una telecamera composita: più telecamere unite in un'unica immagine, registrata e riprodotta come qualsiasi altra telecamera. Creane una qui con un nome; apri la sua telecamera per disporne i riquadri. Il rilevamento oggetti è DISATTIVATO su una nuova griglia, perché le telecamere che la compongono sono già analizzate.",
26899
+ "globalSettings.s_camera-grids.cameraGrids.label": "Griglie",
26900
+ "globalSettings.s_camera-grids.cameraGrids.name.label": "Nome",
26901
+ "globalSettings.s_camera-grids.cameraGrids.enabled.label": "Attiva",
26902
+ "globalSettings.s_camera-grids.cameraGrids.enabled.description": "Una griglia disattivata ritira la sua telecamera.",
26903
+ "gridDevice.s_camera-grid-layout.title": "Disposizione della griglia",
26904
+ "gridDevice.s_camera-grid-layout._gridLayout.label": "",
26905
+ "globalSettings.s_console-logging.title": "Log su console",
26906
+ "globalSettings.s_console-logging.description": "Livello minimo di log da emettere su stdout/stderr. Indipendente dalla destinazione su file ruotati (Winston).",
26907
+ "globalSettings.s_console-logging.level.label": "Livello di log",
26908
+ "globalSettings.s_console-logging.level.o_debug.label": "Debug",
26909
+ "globalSettings.s_console-logging.level.o_info.label": "Info",
26910
+ "globalSettings.s_console-logging.level.o_warn.label": "Avviso",
26911
+ "globalSettings.s_console-logging.level.o_error.label": "Errore",
26912
+ "dayNightConfig.dayNight_mode.label": "Modalità",
26913
+ "dayNightConfig.dayNight_sensitivity.label": "Sensibilità del filtro IR-cut",
26914
+ "dayNightConfig.dayNight_switchDelaySec.label": "Ritardo di commutazione",
26915
+ "section.s_day-night.title": "Giorno / Notte",
26916
+ "section.s_day-night.description": "Modalità di commutazione del filtro IR-cut e i parametri della fotocellula che la regolano.",
26917
+ "baseDeviceSection.s_driver-settings-unavailable.title": "Impostazioni del driver",
26918
+ "baseDeviceSection.s_driver-settings-unavailable.driver-settings-unavailable-notice.label": "Temporaneamente non disponibile",
26919
+ "imageSettingsConfig.imageSettings_brightness.label": "Luminosità",
26920
+ "imageSettingsConfig.imageSettings_contrast.label": "Contrasto",
26921
+ "imageSettingsConfig.imageSettings_saturation.label": "Saturazione",
26922
+ "imageSettingsConfig.imageSettings_sharpness.label": "Nitidezza",
26923
+ "imageSettingsConfig.imageSettings_mirror.label": "Specchio",
26924
+ "imageSettingsConfig.imageSettings_flip.label": "Capovolgi",
26925
+ "imageSettingsConfig.imageSettings_rotate.label": "Rotazione",
26926
+ "imageSettingsConfig.imageSettings_whiteBalance.label": "Bilanciamento del bianco",
26927
+ "imageSettingsConfig.imageSettings_warmth.label": "Calore",
26928
+ "imageSettingsConfig.imageSettings_exposureMode.label": "Modalità di esposizione",
26929
+ "imageSettingsConfig.imageSettings_backlightMode.label": "Compensazione del controluce",
26930
+ "section.s_image-settings.title": "Regolazione immagine",
26931
+ "section.s_image-settings.description": "Cursori dell'immagine, orientamento ed esposizione. Gli elenchi delle opzioni sono letti in tempo reale dalla telecamera: i campi che il firmware non espone sono nascosti.",
26932
+ "volumesField.id.label": "ID",
26933
+ "volumesField.label.label": "Nome",
26934
+ "volumesField.status.label": "Stato",
26935
+ "volumesField.capacity.label": "Capacità",
26936
+ "volumesField.free.label": "Libero",
26937
+ "tracksField.id.label": "Traccia",
26938
+ "tracksField.primary.label": "Principale",
26939
+ "tracksField.enabled.label": "Attiva",
26940
+ "tracksField.codec.label": "Codec",
26941
+ "tracksField.resolution.label": "Risoluzione",
26942
+ "storageSection.s_recording-onboard-storage.title": "Memoria della telecamera",
26943
+ "storageSection.s_recording-onboard-storage.description": "La scheda nella telecamera, come la descrive la telecamera stessa.",
26944
+ "recordingSection.s_recording-onboard-recording.title": "Registrazione sulla telecamera",
26945
+ "recordingSection.s_recording-onboard-recording.description": "Ciò che la telecamera registra sulla propria scheda. Questo configura la telecamera, non il registratore di CamStack.",
26946
+ "globalSettings.s_local-access.title": "HTTP sulla LAN",
26947
+ "globalSettings.s_local-access.description": "Le app native su questo Wi-Fi usano http:// e saltano il certificato privato. Il tunnel e questa interfaccia restano su HTTPS. Disattivalo quando un certificato pubblicamente attendibile copre il nome della LAN.",
26948
+ "globalSettings.s_local-access.httpEnabled.label": "Attiva HTTP sulla LAN",
26949
+ "globalSettings.s_local-access.httpPort.label": "Porta HTTP",
26950
+ "globalSettings.s_local-access.httpPort.description": "Listener dedicato. Non deve coincidere con la porta HTTPS (4443 per impostazione predefinita).",
26951
+ "globalSettings.s_local-access.mdnsAdvertise.label": "Annuncia questo hub sulla LAN (mDNS)",
26952
+ "globalSettings.s_local-access.mdnsAdvertise.description": "Permette a `camstack login` di trovare l'hub senza indirizzo. Annuncia solo l'indirizzo HTTPS, mai un segreto. Richiede il multicast UDP 5353 per raggiungere la LAN (rete host o IP dedicato del container).",
26953
+ "globalSettings.s_local-access.localHostname.label": "Nome host locale",
26954
+ "globalSettings.s_local-access.localHostname.description": "Annunciato al visualizzatore al posto dell'IP LAN grezzo e aggiunto al SAN del certificato. Richiede che questo nome si risolva sulla LAN (DNS del router, mDNS o file hosts). Lascia vuoto per continuare a usare l'IP.",
26955
+ "globalSettings.s_loki-logging.title": "Loki",
26956
+ "globalSettings.s_loki-logging.description": "Invia i log di questo nodo a un'istanza Grafana Loki. Indipendente dalle destinazioni su file ruotati e su console. Attivala o disattivala con il controllo Attiva/Disattiva di questa destinazione, lo stesso usato da tutte le altre.",
26957
+ "globalSettings.s_loki-logging.url.label": "URL di Loki",
26958
+ "globalSettings.s_loki-logging.url.description": "URL base, ad es. http://loki:3100: il percorso /loki/api/v1/push viene aggiunto.",
26959
+ "globalSettings.s_loki-logging.level.label": "Livello minimo",
26960
+ "globalSettings.s_loki-logging.level.o_debug.label": "Debug",
26961
+ "globalSettings.s_loki-logging.level.o_info.label": "Info",
26962
+ "globalSettings.s_loki-logging.level.o_warn.label": "Avviso",
26963
+ "globalSettings.s_loki-logging.level.o_error.label": "Errore",
26964
+ "globalSettings.s_loki-logging.job.label": "Etichetta job",
26965
+ "globalSettings.s_loki-logging.job.description": "L'etichetta `job` di Loki. Tienila fissa: le etichette sono indicizzate.",
26966
+ "globalSettings.s_loki-logging.extraLabels.label": "Etichette aggiuntive",
26967
+ "globalSettings.s_loki-logging.extraLabels.description": "`chiave=valore,chiave2=valore2` statici. Solo a bassa cardinalità: i valori per singola voce vanno nel corpo della riga, e un'etichetta ad alta cardinalità manderà in crisi Loki.",
26968
+ "globalSettings.s_loki-logging.tenantId.label": "ID tenant",
26969
+ "globalSettings.s_loki-logging.tenantId.description": "Inviato come X-Scope-OrgID. Richiesto da Grafana Cloud e da Loki multi-tenant.",
26970
+ "globalSettings.s_loki-logging.username.label": "Nome utente",
26971
+ "globalSettings.s_loki-logging.username.description": "Autenticazione HTTP basic. Lascia vuoto se non serve.",
26972
+ "globalSettings.s_loki-logging.password.label": "Password",
26973
+ "globalSettings.s_loki-logging.batchIntervalMs.label": "Intervallo di invio",
26974
+ "globalSettings.s_loki-logging.batchIntervalMs.description": "Ogni quanto viene inviato un lotto parziale.",
26975
+ "globalSettings.s_loki-logging.batchSize.label": "Dimensione del lotto",
26976
+ "globalSettings.s_loki-logging.batchSize.description": "Invia in anticipo quando sono in coda così tante voci.",
26977
+ "globalSettings.s_loki-logging.timeoutMs.label": "Timeout della richiesta",
26978
+ "globalSettings.s_native-metrics-settings.title": "Metriche di sistema",
26979
+ "globalSettings.s_native-metrics-settings.samplingIntervalMs.label": "Intervallo di campionamento",
26980
+ "globalSettings.s_native-metrics-settings.samplingIntervalMs.description": "Ogni quanto raccogliere le metriche di sistema",
26981
+ "globalSettings.s_native-metrics-load-series.title": "Storico del carico",
26982
+ "globalSettings.s_native-metrics-load-series.loadSeriesCadenceSec.label": "Cadenza di campionamento",
26983
+ "globalSettings.s_native-metrics-load-series.loadSeriesCadenceSec.description": "Ogni quanto ogni nodo riporta il proprio albero di processi. FISSO: un campione viene emesso a ogni intervallo, che qualcosa sia cambiato o no, quindi un buco nel grafico significa una sola cosa: nessuno ha riportato. Fuori dall'intervallo 5-60 s il valore viene rifiutato.",
26984
+ "globalSettings.s_native-metrics-load-series.loadSeriesRetentionHours.label": "Conservazione",
26985
+ "globalSettings.s_native-metrics-load-series.loadSeriesRetentionHours.description": "Per quanto tempo lo storico del carico viene conservato su disco (il database dell'hub, sulla cache NVMe, mai sul disco delle registrazioni). Questa è l'INTENZIONE; il limite di righe qui sotto è la garanzia.",
26986
+ "globalSettings.s_native-metrics-load-series.load-series-cost.label": "Costo di questa configurazione",
26987
+ "globalSettings.s_native-metrics-load-series.load-series-cap.label": "Limite rigido di righe",
26988
+ "globalSettings.s_snapshot-cache.title": "Cache degli snapshot",
26989
+ "globalSettings.s_snapshot-cache.description": "Ripiego obsoleto quando la cattura dal vivo fallisce. La freschezza per dispositivo si configura in Dispositivo → Snapshot → Età massima della cache.",
26990
+ "globalSettings.s_snapshot-cache.staleTtlMs.label": "TTL del ripiego obsoleto (ms)",
26991
+ "globalSettings.s_snapshot-cache.staleTtlMs.description": "Se la cattura dal vivo fallisce, viene comunque restituito uno snapshot in cache più recente di questo valore.",
26992
+ "deviceSettingsContribution.s_snapshot-preferences.title": "Snapshot",
26993
+ "deviceSettingsContribution.s_snapshot-preferences.snapshotStreamId.label": "Flusso preferito",
26994
+ "deviceSettingsContribution.s_snapshot-preferences.snapshotStreamId.description": "Flusso usato per acquisire uno snapshot",
26995
+ "deviceSettingsContribution.s_snapshot-preferences.snapshotMaxAgeS.label": "Età massima della cache (s)",
26996
+ "deviceSettingsContribution.s_snapshot-preferences.snapshotDebug.label": "Log di debug",
26997
+ "deviceSettingsContribution.s_snapshot-preferences.snapshotDebug.description": "Registra la scelta del flusso e i tempi per questo dispositivo.",
26998
+ "providerInfo.s_filesystem-storage.title": "File system",
26999
+ "providerInfo.s_filesystem-storage.basePath.label": "Percorso base",
27000
+ "providerInfo.s_filesystem-storage.basePath.description": "Percorso assoluto della cartella dove vengono salvati i file.",
27001
+ "global.s_system-config-server.description": "Il nome di questo server e le sue impostazioni di connessione (sola lettura, caricate da config.yaml all'avvio).",
27002
+ "global.s_system-config-server.server-restart-note.label": "Riavvio necessario",
27003
+ "global.s_system-config-server.port.label": "Porta",
27004
+ "global.s_system-config-server.port.description": "Porta di ascolto",
27005
+ "global.s_system-config-server.host.label": "Host",
27006
+ "global.s_system-config-server.host.description": "Indirizzo di bind",
27007
+ "global.s_system-config-server.dataPath.label": "Percorso dei dati",
27008
+ "global.s_system-config-server.dataPath.description": "Cartella radice dei dati",
27009
+ "global.s_system-config-auth.description": "Impostazioni di token e sessione.",
27010
+ "global.s_system-config-auth.tokenExpiry.label": "Durata della sessione",
27011
+ "global.s_system-config-auth.tokenExpiry.description": "Per quanto tempo resta valido un accesso senza essere usato, come stringa di durata (ad es. 7d, 30d). Ogni rinnovo lo fa ripartire, quindi un dispositivo in uso resta connesso; uno lasciato inutilizzato per questo tempo deve accedere di nuovo. Un numero senza unità viene rifiutato: sarebbe letto come millisecondi. Si applica dal prossimo accesso o rinnovo.",
27012
+ "global.s_system-config-auth.accessTokenExpiry.label": "Durata del token di accesso",
27013
+ "global.s_system-config-auth.accessTokenExpiry.description": "Per quanto vive un token di accesso prima che l'app lo sostituisca in silenzio con uno nuovo (ad es. 2h; tra 5m e 24h, mai più della sessione). Più breve significa che un token copiato è utile per meno tempo. Le app precedenti ai token di rinnovo ricevono invece un unico token per tutta la sessione.",
27014
+ "global.s_system-config-auth.trustedProxies.label": "Reverse proxy fidati",
27015
+ "global.s_system-config-auth.trustedProxies.description": "Indirizzi o intervalli CIDR (ad es. 192.168.1.2 o 10.0.0.0/24) dei reverse proxy davanti all'hub. Solo una richiesta il cui mittente diretto è uno di questi, o questo stesso host come con il tunnel Cloudflare, ha X-Forwarded-For / CF-Connecting-IP letto come indirizzo reale del client per i limiti di frequenza. Lascia vuoto a meno che un proxy su un altro host inoltri verso l'hub.",
27016
+ "global.s_system-config-auth.trustedNetworksWarning.label": "Salto dell'autenticazione a due fattori",
27017
+ "global.s_system-config-auth.trustedNetworks.label": "Reti fidate (salta il secondo fattore)",
27018
+ "global.s_system-config-auth.trustedNetworks.description": "Indirizzi o intervalli CIDR, ad es. 192.168.1.0/24. Mantienili il più stretti possibile: una singola VLAN fidata, non tutta la LAN.",
27019
+ "globalSettings.s_winston-logging.title": "Log",
27020
+ "globalSettings.s_winston-logging.description": "Dettaglio globale dei log e conservazione dei file di log ruotati su questo nodo.",
27021
+ "globalSettings.s_winston-logging.level.label": "Livello di log",
27022
+ "globalSettings.s_winston-logging.level.o_debug.label": "Debug",
27023
+ "globalSettings.s_winston-logging.level.o_info.label": "Info",
27024
+ "globalSettings.s_winston-logging.level.o_warn.label": "Avviso",
27025
+ "globalSettings.s_winston-logging.level.o_error.label": "Errore",
27026
+ "globalSettings.s_winston-logging.retentionDays.label": "Conservazione (giorni)",
27027
+ "globalSettings.s_winston-logging.retentionDays.description": "Numero di giorni per cui conservare i file di log ruotati prima dell'eliminazione",
27028
+ "system.python-required": "Serve Python 3.10 o successivo, ma non è stato trovato su questo sistema",
27029
+ "system.device-enrollment-busy": "Troppe registrazioni di dispositivi in attesa — riprova tra poco",
27030
+ "system.admin-token-expiry-too-long": "Un token amministratore deve scadere entro 90 giorni",
27031
+ "system.admin-token-name-required": "Un token amministratore richiede un nome",
27032
+ "system.user-exists": "Esiste già un utente con nome utente \"{username}\"",
27033
+ "system.user-not-found": "Utente con ID \"{id}\" non trovato",
27034
+ "system.addon-no-discovery": "L'addon \"{addonId}\" non supporta il rilevamento dei dispositivi",
27035
+ "system.addon-no-adoption": "L'addon \"{addonId}\" non supporta l'acquisizione dei dispositivi",
27036
+ "system.addon-no-manual-create": "L'addon \"{addonId}\" non supporta la creazione manuale di dispositivi",
27037
+ "system.location-name-required": "Il nome del luogo non può essere vuoto",
27038
+ "system.location-required": "Il luogo non può essere vuoto",
27039
+ "system.site-zone-name-required": "Il nome della zona non può essere vuoto",
27040
+ "server.handoff-busy": "Troppi codici di passaggio in attesa — riprova tra poco",
27041
+ "server.app-confirmations-busy": "Troppe conferme di app in attesa",
27042
+ "server.step-up-busy": "Troppe verifiche di sicurezza in attesa",
27043
+ "server.login-unavailable": "Accesso non disponibile — la capacità `user-management` non è registrata",
27044
+ "server.share-token-expired": "Token di condivisione scaduto: {id}",
27045
+ "server.package-not-allowed": "Il pacchetto \"{name}\" non è un pacchetto @camstack/* consentito",
27046
+ "server.package-protected": "Impossibile disinstallare il pacchetto protetto \"{name}\"",
27047
+ "server.package-required": "Il pacchetto {packageName} è necessario e non può essere disinstallato",
27048
+ "tls.cert-unparsable": "Impossibile leggere il PEM del certificato.",
27049
+ "tls.key-unparsable": "Impossibile leggere il PEM della chiave privata.",
27050
+ "tls.key-mismatch": "La chiave privata non corrisponde al certificato.",
27051
+ "tls.missing-server-auth": "Al certificato manca extendedKeyUsage = serverAuth.",
27052
+ "tls.ca-required": "Questo certificato non è stato emesso da una CA pubblica, quindi serve il certificato della sua CA: i dispositivi ne hanno bisogno per fidarsi dell'hub. Incolla il certificato della CA (per mkcert, il rootCA.pem nella cartella indicata da `mkcert -CAROOT`).",
27053
+ "tls.ca-unparsable": "Impossibile leggere il certificato della CA.",
27054
+ "tls.ca-not-issuer": "Il certificato non è stato emesso dalla CA che hai fornito.",
27055
+ "tls.ca-not-a-ca": "Il certificato fornito non è una autorità di certificazione (manca CA:TRUE).",
27056
+ "tls.ca-expired": "Il certificato della CA fornito è scaduto o non è ancora valido.",
27057
+ "tls.no-stored-upload": "Su questo nodo non è conservato nessun certificato caricato."
27058
+ };
27059
+ //#endregion
27060
+ //#region src/i18n/catalog-registry.ts
27061
+ /**
27062
+ * The hub's translation catalogs (D863).
27063
+ *
27064
+ * Core namespace `server` ships inside this package (`en.json` / `it.json`:
27065
+ * user-facing error texts + core schema labels). Every installed addon may add
27066
+ * `i18n/<lang>.json` in its package directory; its namespace is its addon id.
27067
+ * Every file is validated with zod; a broken file is logged and ignored, never
27068
+ * fatal - the English text that travels beside every key is the floor.
27069
+ */
27070
+ /** The core namespace: user-facing error texts and core schema labels. */
27071
+ var SERVER_NAMESPACE = "server";
27072
+ /** `@camstack/addon-provider-reolink` -> `provider-reolink`; `@camstack/system` -> `system`. */
27073
+ function catalogNamespaceOf(packageName) {
27074
+ return packageName.replace(/^@camstack\//, "").replace(/^addon-/, "");
27075
+ }
27076
+ var CatalogRegistry = class {
27077
+ warn;
27078
+ namespaces = /* @__PURE__ */ new Map();
27079
+ constructor(warn = () => void 0) {
27080
+ this.warn = warn;
27081
+ }
27082
+ /** Validates `raw` and installs it; returns false (after warning) when it is not a flat string map. */
27083
+ set(ns, lang, raw, origin) {
27084
+ const parsed = require_dist.CatalogFileSchema.safeParse(raw);
27085
+ if (!parsed.success) {
27086
+ this.warn(`i18n catalog ignored (${origin}): ${parsed.error.issues[0]?.message ?? "invalid"}`);
27087
+ return false;
27088
+ }
27089
+ const langs = this.namespaces.get(ns) ?? /* @__PURE__ */ new Map();
27090
+ langs.set(lang, parsed.data);
27091
+ this.namespaces.set(ns, langs);
27092
+ return true;
27093
+ }
27094
+ /** Loads `<packageDir>/i18n/<lang>.json` for every language that has a file. */
27095
+ loadAddonDir(ns, packageDir) {
27096
+ for (const lang of require_dist.CATALOG_LANGS) {
27097
+ const file = node_path.join(packageDir, "i18n", `${lang}.json`);
27098
+ let text;
27099
+ try {
27100
+ text = node_fs.readFileSync(file, "utf8");
27101
+ } catch {
27102
+ continue;
27103
+ }
27104
+ try {
27105
+ this.set(ns, lang, JSON.parse(text), file);
27106
+ } catch (err) {
27107
+ this.warn(`i18n catalog ignored (${file}): ${err instanceof Error ? err.message : "bad JSON"}`);
27108
+ }
27109
+ }
27110
+ }
27111
+ /** Drops a namespace (addon uninstalled or redeployed before a reload). */
27112
+ clear(ns) {
27113
+ this.namespaces.delete(ns);
27114
+ }
27115
+ /** The text for `ns:key` in `lang`, or `undefined`. Never falls back across languages. */
27116
+ lookup(lang, ns, key) {
27117
+ return this.namespaces.get(ns)?.get(lang)?.[key];
27118
+ }
27119
+ /**
27120
+ * `t(ns, key, params, fallbackEnglish)` - the translation in `lang`, else
27121
+ * the English fallback (also interpolated). English is never looked up: the
27122
+ * fallback IS the English text.
27123
+ */
27124
+ t(lang, ns, key, params, fallbackEnglish) {
27125
+ return require_dist.interpolate((lang === "en" ? void 0 : this.lookup(lang, ns, key)) ?? fallbackEnglish, params);
27126
+ }
27127
+ /** A lookup bound to one language, for `localizeConfigTree`. English never substitutes. */
27128
+ lookupFor(lang) {
27129
+ return (ns, key) => lang === "en" ? void 0 : this.lookup(lang, ns, key);
27130
+ }
27131
+ /** `t` for a `"ns:key"` reference. */
27132
+ tRef(lang, ref, params, fallbackEnglish) {
27133
+ const parts = require_dist.splitTranslationRef(ref);
27134
+ return parts === null ? require_dist.interpolate(fallbackEnglish, params) : this.t(lang, parts.ns, parts.key, params, fallbackEnglish);
27135
+ }
27136
+ };
27137
+ var shared = null;
27138
+ /** A fresh registry holding the core `server` namespace (specs build their own). */
27139
+ function createCoreCatalogRegistry(warn) {
27140
+ const registry = new CatalogRegistry(warn);
27141
+ registry.set(SERVER_NAMESPACE, "en", en_default, "server/en.json");
27142
+ registry.set(SERVER_NAMESPACE, "it", it_default, "server/it.json");
27143
+ return registry;
27144
+ }
27145
+ /** The hub's one registry, core catalogs preloaded. */
27146
+ function getCatalogRegistry(warn) {
27147
+ if (shared === null) shared = createCoreCatalogRegistry(warn);
27148
+ return shared;
27149
+ }
27150
+ /** Spec hook: forget the shared registry. */
27151
+ function resetCatalogRegistryForTests() {
27152
+ shared = null;
27153
+ }
27154
+ //#endregion
26498
27155
  exports.ADMIN_TOKEN_MAX_LIFETIME_MS = require_builtins_local_auth_local_auth_addon.ADMIN_TOKEN_MAX_LIFETIME_MS;
26499
27156
  exports.ADMIN_TOKEN_PREFIX = require_builtins_local_auth_local_auth_addon.ADMIN_TOKEN_PREFIX;
26500
27157
  exports.AGENT_CAP_FWD_ACTION = AGENT_CAP_FWD_ACTION;
@@ -26547,6 +27204,7 @@ exports.CapUsageRegistry = CapUsageRegistry;
26547
27204
  exports.CapabilityHandle = CapabilityHandle;
26548
27205
  exports.CapabilityRegistry = CapabilityRegistry;
26549
27206
  exports.CapabilityUnavailableError = CapabilityUnavailableError;
27207
+ exports.CatalogRegistry = CatalogRegistry;
26550
27208
  exports.ComposerAddon = require_builtins_composer_composer_addon.ComposerAddon;
26551
27209
  exports.ConfigManager = ConfigManager;
26552
27210
  exports.ConfigStore = require_builtins_sqlite_storage_index.ConfigStore$1;
@@ -26654,6 +27312,8 @@ exports.PAIRING_PIN_DIGITS = require_builtins_system_config_system_config_addon.
26654
27312
  exports.PAIRING_PROTOCOL = require_builtins_system_config_system_config_addon.PAIRING_PROTOCOL;
26655
27313
  exports.PAIRING_TTL_MS = require_builtins_system_config_system_config_addon.PAIRING_TTL_MS;
26656
27314
  exports.PARENT_ROUTED_PROVIDER_ADDON_ID = PARENT_ROUTED_PROVIDER_ADDON_ID;
27315
+ exports.PERMITTED_DNS_SUFFIXES = require_agent_https.PERMITTED_DNS_SUFFIXES;
27316
+ exports.PERMITTED_IP_RANGES = require_agent_https.PERMITTED_IP_RANGES;
26657
27317
  exports.PREVIOUS_LEAF_GRACE_MS = require_builtins_local_auth_local_auth_addon.PREVIOUS_LEAF_GRACE_MS;
26658
27318
  Object.defineProperty(exports, "PYTHON_VERSION", {
26659
27319
  enumerable: true,
@@ -26680,6 +27340,7 @@ exports.ReadinessTimeoutError = require_dist.ReadinessTimeoutError;
26680
27340
  exports.ReplEngine = ReplEngine;
26681
27341
  exports.RingBuffer = RingBuffer;
26682
27342
  exports.SERVER_AUTH_OID = require_agent_https.SERVER_AUTH_OID;
27343
+ exports.SERVER_NAMESPACE = SERVER_NAMESPACE;
26683
27344
  exports.SOCKET_PLANE_TOP_N = SOCKET_PLANE_TOP_N;
26684
27345
  exports.SOCKET_QUEUE_TOP_N = SOCKET_QUEUE_TOP_N;
26685
27346
  exports.STALL_REPORT_MS = require_custom_action_registry.STALL_REPORT_MS;
@@ -26742,6 +27403,7 @@ Object.defineProperty(exports, "buildBinaryPath", {
26742
27403
  exports.buildCapRouters = buildCapRouters;
26743
27404
  exports.buildHeapSample = buildHeapSample;
26744
27405
  exports.buildLinkChain = buildLinkChain;
27406
+ exports.buildNameConstraintSet = require_agent_https.buildNameConstraintSet;
26745
27407
  exports.buildNativeCapProxy = buildNativeCapProxy;
26746
27408
  exports.buildNodeManifest = buildNodeManifest;
26747
27409
  exports.buildNpmChildEnv = buildNpmChildEnv;
@@ -26750,6 +27412,7 @@ exports.buildTransporter = buildTransporter;
26750
27412
  exports.builderMountedCapNames = builderMountedCapNames;
26751
27413
  exports.caFingerprint = require_builtins_system_config_system_config_addon.caFingerprint;
26752
27414
  exports.caFingerprintCompact = require_builtins_system_config_system_config_addon.caFingerprintCompact;
27415
+ exports.caReplacementMarkerFile = require_hub_mdns_ciao.caReplacementMarkerFile;
26753
27416
  exports.callRegisterNodeWithRetry = callRegisterNodeWithRetry;
26754
27417
  exports.callWithServiceDiscovery = callWithServiceDiscovery;
26755
27418
  exports.canServeDataPlane = canServeDataPlane;
@@ -26758,7 +27421,10 @@ exports.capActionName = capActionName;
26758
27421
  exports.capActionSuffix = capActionSuffix;
26759
27422
  exports.capBareAction = capBareAction;
26760
27423
  exports.capServiceName = capServiceName;
27424
+ exports.catalogNamespaceOf = catalogNamespaceOf;
26761
27425
  exports.certificateNames = require_agent_https.certificateNames;
27426
+ exports.chainsToPublicRoot = require_hub_mdns_ciao.chainsToPublicRoot;
27427
+ exports.checkUploadedCa = require_hub_mdns_ciao.checkUploadedCa;
26762
27428
  exports.classifyAddonDir = classifyAddonDir;
26763
27429
  exports.classifyCapRoute = classifyCapRoute;
26764
27430
  exports.clearHttpsListener = require_hub_mdns_ciao.clearHttpsListener;
@@ -26790,6 +27456,7 @@ exports.createCapActionCensus = createCapActionCensus;
26790
27456
  exports.createCiaoPublisher = require_hub_mdns_ciao.createCiaoPublisher;
26791
27457
  exports.createCidrMatcher = require_builtins_system_config_system_config_addon.createCidrMatcher;
26792
27458
  exports.createCoreCapService = createCoreCapService;
27459
+ exports.createCoreCatalogRegistry = createCoreCatalogRegistry;
26793
27460
  exports.createDeferredHeapWatchSink = createDeferredHeapWatchSink;
26794
27461
  exports.createDoorSettingsView = createDoorSettingsView;
26795
27462
  exports.createEventPlaneMeter = createEventPlaneMeter;
@@ -26897,6 +27564,7 @@ exports.generateMeshKeyPair = require_builtins_system_config_system_config_addon
26897
27564
  exports.getBrokerEventBus = getBrokerEventBus;
26898
27565
  exports.getBrokerTlsTransporter = getBrokerTlsTransporter;
26899
27566
  exports.getCapUsageRegistry = getCapUsageRegistry;
27567
+ exports.getCatalogRegistry = getCatalogRegistry;
26900
27568
  Object.defineProperty(exports, "getFfmpegDownloadUrl", {
26901
27569
  enumerable: true,
26902
27570
  get: function() {
@@ -26962,6 +27630,7 @@ exports.isAllowedAgentDashboardReturnTo = require_builtins_system_config_system_
26962
27630
  exports.isArrayBufferCensusReport = isArrayBufferCensusReport;
26963
27631
  exports.isArrayOutputSchema = require_dist.isArrayOutputSchema;
26964
27632
  exports.isCollectionArrayMethod = require_dist.isCollectionArrayMethod;
27633
+ exports.isConstrainedCa = require_agent_https.isConstrainedCa;
26965
27634
  exports.isContainerBridgeAddress = require_agent_https.isContainerBridgeAddress;
26966
27635
  exports.isCredentialKeyName = isCredentialKeyName;
26967
27636
  exports.isInfraCapability = isInfraCapability;
@@ -27009,6 +27678,8 @@ exports.parseTokenExpiry = require_builtins_local_auth_local_auth_addon.parseTok
27009
27678
  exports.parseTokenizedUrl = require_custom_action_registry.parseTokenizedUrl;
27010
27679
  exports.partitionIsolatedBuiltinIds = partitionIsolatedBuiltinIds;
27011
27680
  exports.pemDigest = require_agent_https.pemDigest;
27681
+ exports.permitsIdentity = require_agent_https.permitsIdentity;
27682
+ exports.permitsName = require_agent_https.permitsName;
27012
27683
  exports.pinnedHttpsCaFingerprint = require_agent_https.pinnedHttpsCaFingerprint;
27013
27684
  exports.prepareBootTls = require_hub_mdns_ciao.prepareBootTls;
27014
27685
  exports.prepareRestoreArchive = require_restore_archive.prepareRestoreArchive;
@@ -27022,6 +27693,7 @@ exports.readCidrSetting = require_builtins_system_config_system_config_addon.rea
27022
27693
  exports.readExtraSans = require_hub_mdns_ciao.readExtraSans;
27023
27694
  exports.readHeapSpaces = readHeapSpaces;
27024
27695
  exports.readLanHttpState = require_hub_mdns_ciao.readLanHttpState;
27696
+ exports.readNameConstraints = require_agent_https.readNameConstraints;
27025
27697
  exports.readPendingRestart = readPendingRestart;
27026
27698
  exports.readSocketQueues = readSocketQueues;
27027
27699
  exports.readTlsAccessStatus = require_hub_mdns_ciao.readTlsAccessStatus;
@@ -27039,11 +27711,14 @@ exports.registerLanHttpHandler = require_hub_mdns_ciao.registerLanHttpHandler;
27039
27711
  exports.reissueTlsLeaf = require_hub_mdns_ciao.reissueTlsLeaf;
27040
27712
  exports.reloadHttpsListener = require_hub_mdns_ciao.reloadHttpsListener;
27041
27713
  exports.renewMeshCertificate = require_builtins_system_config_system_config_addon.renewMeshCertificate;
27714
+ exports.replaceUnconstrainedLocalCa = require_hub_mdns_ciao.replaceUnconstrainedLocalCa;
27042
27715
  exports.requireProcessMeshCa = require_builtins_system_config_system_config_addon.requireProcessMeshCa;
27716
+ exports.resetCatalogRegistryForTests = resetCatalogRegistryForTests;
27043
27717
  exports.resolveFilePath = require_custom_action_registry.resolveFilePath;
27044
27718
  exports.resolveFormatRevision = require_custom_action_registry.resolveFormatRevision;
27045
27719
  exports.resolveHwAccel = resolveHwAccel;
27046
27720
  exports.resolveNpmInvocation = resolveNpmInvocation;
27721
+ exports.retirePreviousLocalCa = require_hub_mdns_ciao.retirePreviousLocalCa;
27047
27722
  exports.revertToGeneratedCertificate = require_hub_mdns_ciao.revertToGeneratedCertificate;
27048
27723
  exports.revisionWeightUrl = require_custom_action_registry.revisionWeightUrl;
27049
27724
  exports.revokeMeshCertificate = require_builtins_system_config_system_config_addon.revokeMeshCertificate;
@@ -27087,6 +27762,7 @@ exports.stripForwardedCaller = require_builtins_storage_orchestrator_storage_orc
27087
27762
  exports.subscribePassthrough = subscribePassthrough;
27088
27763
  exports.systemHostFacts = require_agent_https.systemHostFacts;
27089
27764
  exports.udsChildLogToWorkerEntry = udsChildLogToWorkerEntry;
27765
+ exports.useStoredUploadedCertificate = require_hub_mdns_ciao.useStoredUploadedCertificate;
27090
27766
  exports.validateProviderRegistrations = validateProviderRegistrations;
27091
27767
  exports.validateUploadedTls = require_hub_mdns_ciao.validateUploadedTls;
27092
27768
  exports.verifyAgentUiUnlockTicket = require_builtins_system_config_system_config_addon.verifyAgentUiUnlockTicket;