@camstack/system 1.2.436 → 1.2.438

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 (96) hide show
  1. package/dist/addon-runner.js +64 -12
  2. package/dist/addon-runner.mjs +65 -13
  3. package/dist/{agent-https-B8lKYVtU.mjs → agent-https-BPfHrI4c.mjs} +3 -3
  4. package/dist/auth/login-session-manager.d.ts +2 -0
  5. package/dist/auth/session-revocation-bus.d.ts +32 -0
  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 +7 -1
  11. package/dist/builtins/alerts/alerts.addon.mjs +7 -1
  12. package/dist/builtins/autotrack/index.js +1 -1
  13. package/dist/builtins/autotrack/index.mjs +1 -1
  14. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2 -2
  15. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2 -2
  16. package/dist/builtins/calendars/calendars.addon.js +1 -1
  17. package/dist/builtins/calendars/calendars.addon.mjs +1 -1
  18. package/dist/builtins/camera-grid/index.js +9 -1
  19. package/dist/builtins/camera-grid/index.mjs +9 -1
  20. package/dist/builtins/composer/composer.addon.js +2 -2
  21. package/dist/builtins/composer/composer.addon.mjs +2 -2
  22. package/dist/builtins/console-logging/index.js +12 -5
  23. package/dist/builtins/console-logging/index.mjs +12 -5
  24. package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
  25. package/dist/builtins/core-blocks/core-blocks.addon.mjs +5 -5
  26. package/dist/builtins/device-manager/device-manager.addon.d.ts +5 -0
  27. package/dist/builtins/device-manager/device-manager.addon.js +702 -28
  28. package/dist/builtins/device-manager/device-manager.addon.mjs +702 -28
  29. package/dist/builtins/device-manager/device-meta-types.d.ts +4 -0
  30. package/dist/builtins/device-manager/device-provider-context.d.ts +9 -0
  31. package/dist/builtins/device-manager/device-removal-hooks.d.ts +103 -0
  32. package/dist/builtins/device-manager/device-row-store.d.ts +1 -0
  33. package/dist/builtins/device-manager/device-tombstone-store.d.ts +58 -0
  34. package/dist/builtins/device-manager/removal-cleanup.d.ts +50 -0
  35. package/dist/builtins/hub-forwarder/index.js +1 -1
  36. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  37. package/dist/builtins/keychain/index.js +37 -4
  38. package/dist/builtins/keychain/index.mjs +37 -4
  39. package/dist/builtins/keychain/keychain-service.d.ts +14 -0
  40. package/dist/builtins/keychain/keychain-store.d.ts +1 -1
  41. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  42. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  43. package/dist/builtins/local-auth/local-auth.addon.js +53 -12
  44. package/dist/builtins/local-auth/local-auth.addon.mjs +53 -13
  45. package/dist/builtins/local-network/local-network.addon.js +10 -1
  46. package/dist/builtins/local-network/local-network.addon.mjs +13 -4
  47. package/dist/builtins/loki-logging/index.js +28 -5
  48. package/dist/builtins/loki-logging/index.mjs +28 -5
  49. package/dist/builtins/native-metrics/native-metrics.addon.js +11 -1
  50. package/dist/builtins/native-metrics/native-metrics.addon.mjs +20 -10
  51. package/dist/builtins/platform-probe/index.js +1 -1
  52. package/dist/builtins/platform-probe/index.mjs +8 -8
  53. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  54. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  55. package/dist/builtins/snapshot/index.js +11 -1
  56. package/dist/builtins/snapshot/index.mjs +11 -1
  57. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +4 -1
  58. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +4 -1
  59. package/dist/builtins/sqlite-storage/index.js +1 -1
  60. package/dist/builtins/sqlite-storage/index.mjs +1 -1
  61. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +3 -3
  62. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +3 -3
  63. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  64. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  65. package/dist/builtins/system-config/system-config.addon.d.ts +9 -0
  66. package/dist/builtins/system-config/system-config.addon.js +135 -72
  67. package/dist/builtins/system-config/system-config.addon.mjs +135 -73
  68. package/dist/builtins/winston-logging/index.js +14 -5
  69. package/dist/builtins/winston-logging/index.mjs +14 -5
  70. package/dist/{composition-sources-BAOlCu4j.js → composition-sources-DI3Z83vG.js} +1 -1
  71. package/dist/{composition-sources-gN_BWUKp.mjs → composition-sources-DpHGCjdL.mjs} +1 -1
  72. package/dist/{constants-BFpowodq.mjs → constants-DQK705Sb.mjs} +1 -1
  73. package/dist/{constants-GENKqk9k.js → constants-wkcn5Ij3.js} +1 -1
  74. package/dist/{device-ca-CuWuRW9N.js → device-ca-BSvkXqyI.js} +1 -1
  75. package/dist/{device-ca-BNM5ai4t.mjs → device-ca-DvIZjXIl.mjs} +1 -1
  76. package/dist/{dist-DjD2M79P.mjs → dist-Dc8GKC5H.mjs} +301 -6
  77. package/dist/{dist-DVe0Nsp8.js → dist-GgG-7amw.js} +348 -5
  78. package/dist/file-host-worker.js +1 -1
  79. package/dist/file-host-worker.mjs +1 -1
  80. package/dist/{hub-mdns-ciao-DJRwtlA8.mjs → hub-mdns-ciao-DMlQTdPU.mjs} +1 -1
  81. package/dist/i18n/catalog-registry.d.ts +35 -0
  82. package/dist/i18n/index.d.ts +2 -0
  83. package/dist/index.d.ts +3 -0
  84. package/dist/index.js +666 -21
  85. package/dist/index.mjs +676 -38
  86. package/dist/kernel/gc-census.d.ts +18 -1
  87. package/dist/kernel/settings-view-types.d.ts +2 -0
  88. package/dist/kernel/transport/local-transport.d.ts +3 -0
  89. package/dist/kernel/transport/peer-answered-error.d.ts +5 -1
  90. package/dist/{restore-archive-D4h904rb.js → restore-archive-CTRz8v9o.js} +1 -1
  91. package/dist/{restore-archive-BxmP1ChO.mjs → restore-archive-DPg9duVY.mjs} +1 -1
  92. package/dist/{retired-settings-keys-CYP5IZJ5.js → retired-settings-keys-Dr_4lfKu.js} +1 -1
  93. package/dist/{retired-settings-keys-CQaknvx1.mjs → retired-settings-keys-Is0zO8gX.mjs} +1 -1
  94. package/dist/{wal-maintenance-CaDsrJM_.mjs → wal-maintenance-Bx3lcVA7.mjs} +0 -0
  95. package/dist/{wal-maintenance-Br60onAQ.js → wal-maintenance-mjB2i-VR.js} +0 -0
  96. package/package.json +1 -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-DVe0Nsp8.js");
4
- const require_device_ca = require("./device-ca-CuWuRW9N.js");
3
+ const require_dist = require("./dist-GgG-7amw.js");
4
+ const require_device_ca = require("./device-ca-BSvkXqyI.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,13 +22,13 @@ 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-Br60onAQ.js");
25
+ const require_wal_maintenance = require("./wal-maintenance-mjB2i-VR.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
30
  const require_agent_https = require("./agent-https-BZIwS4xF.js");
31
- const require_constants = require("./constants-GENKqk9k.js");
31
+ const require_constants = require("./constants-wkcn5Ij3.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");
@@ -36,7 +36,7 @@ const require_custom_action_registry = require("./custom-action-registry-Bf_Ynag
36
36
  const require_hub_mdns_ciao = require("./hub-mdns-ciao-CBLvq2oj.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-D4h904rb.js");
39
+ const require_restore_archive = require("./restore-archive-CTRz8v9o.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, {
@@ -14451,7 +14500,8 @@ var STORE_READABLE_BOOTSTRAP_KEYS = new Set([
14451
14500
  "auth.tokenExpiry",
14452
14501
  "auth.accessTokenExpiry",
14453
14502
  "auth.trustedProxies",
14454
- "auth.trustedNetworks"
14503
+ "auth.trustedNetworks",
14504
+ "server.name"
14455
14505
  ]);
14456
14506
  /** May the settings store answer `key`, or is it env + config.yaml only? */
14457
14507
  function storeMayAnswer(key) {
@@ -14887,6 +14937,11 @@ var ConfigManager = class {
14887
14937
  writeAddonStore: (patch) => active().writeAddonStore(patch),
14888
14938
  readDeviceStore: (deviceId) => active().readDeviceStore(deviceId),
14889
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
+ },
14890
14945
  writeDeviceStore: (deviceId, patch) => active().writeDeviceStore(deviceId, patch),
14891
14946
  clearDeviceStore: (deviceId) => active().clearDeviceStore(deviceId),
14892
14947
  getSection: (section) => active().getSection(section),
@@ -18561,9 +18616,14 @@ function localEndpointPath(nodeId) {
18561
18616
  * node had answered (2026-09-25, device 3836).
18562
18617
  */
18563
18618
  var PeerAnsweredError = class extends Error {
18564
- 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) {
18565
18623
  super(message);
18566
18624
  this.name = "PeerAnsweredError";
18625
+ this.i18nCode = i18n?.code;
18626
+ this.i18nParams = i18n?.params;
18567
18627
  }
18568
18628
  };
18569
18629
  //#endregion
@@ -18585,6 +18645,13 @@ var PayloadReply = class {
18585
18645
  this.payload = payload;
18586
18646
  }
18587
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
+ }
18588
18655
  var SocketChannel = class {
18589
18656
  socket;
18590
18657
  nextId = 1;
@@ -18796,11 +18863,13 @@ var SocketChannel = class {
18796
18863
  body: result
18797
18864
  });
18798
18865
  } catch (err) {
18866
+ const i18n = (0, _camstack_types_addon.readErrorI18n)(err);
18799
18867
  resBytes = this.send({
18800
18868
  k: "res",
18801
18869
  id: frame.id,
18802
18870
  ok: false,
18803
- err: err instanceof Error ? err.message : String(err)
18871
+ err: err instanceof Error ? err.message : String(err),
18872
+ ...i18n !== null ? { i18n } : {}
18804
18873
  });
18805
18874
  }
18806
18875
  if (label !== void 0) this.recordAction(label, wireBytes, resBytes);
@@ -18812,7 +18881,7 @@ var SocketChannel = class {
18812
18881
  this.pending.delete(frame.id);
18813
18882
  if (p.timer !== null) clearTimeout(p.timer);
18814
18883
  if (p.action !== null) this.recordAction(p.action.label, p.action.reqBytes, wireBytes);
18815
- if (!frame.ok) p.reject(new PeerAnsweredError(frame.err));
18884
+ if (!frame.ok) p.reject(new PeerAnsweredError(frame.err, parseWireI18n(frame.i18n)));
18816
18885
  else if (frame.pl !== void 0) p.resolve(new PayloadReply(frame.body, frame.pl));
18817
18886
  else p.resolve(frame.body);
18818
18887
  return;
@@ -26494,6 +26563,575 @@ var LifecycleJobEngine = class {
26494
26563
  */
26495
26564
  var CAP_METHOD_NOT_IMPLEMENTED = "CAP_METHOD_NOT_IMPLEMENTED";
26496
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
+ };
26802
+ //#endregion
26803
+ //#region src/i18n/it.json
26804
+ var it_default = {
26805
+ "auth.invalid-credentials": "Credenziali non valide",
26806
+ "auth.invalid-totp": "Codice TOTP non valido",
26807
+ "auth.not-authenticated": "Non autenticato",
26808
+ "auth.login-challenge-expired": "Richiesta di accesso non valida o scaduta — reinserisci la password",
26809
+ "auth.passkey-verification-failed": "Verifica della passkey non riuscita",
26810
+ "auth.user-gone": "L'utente non esiste più",
26811
+ "auth.no-session-cookie": "Nessun cookie di sessione",
26812
+ "auth.invalid-session-cookie": "Cookie di sessione non valido",
26813
+ "auth.handoff-code-invalid": "Codice di passaggio non valido o scaduto",
26814
+ "auth.share-never-expiring-extend": "Un token di condivisione senza scadenza non può essere prorogato",
26815
+ "auth.share-owner-only-extend": "Solo il proprietario del token o un amministratore può prorogare un token di condivisione",
26816
+ "auth.share-owner-only-revoke": "Solo il proprietario del token o un amministratore può revocare un token di condivisione",
26817
+ "auth.share-token-not-found": "Token di condivisione non trovato: {id}",
26818
+ "auth.password-incorrect": "La password non è corretta",
26819
+ "auth.session-required": "Serve una sessione utente con accesso effettuato",
26820
+ "auth.admin-required": "Serve un amministratore",
26821
+ "auth.session-ended": "Sessione terminata — accedi di nuovo",
26822
+ "auth.access-denied": "Accesso negato",
26823
+ "auth.totp-confirm-failed": "Conferma TOTP non riuscita — il codice non corrisponde",
26824
+ "device.certificates-unavailable": "I certificati dei dispositivi non sono disponibili",
26825
+ "device.not-found": "Dispositivo {id} non trovato",
26826
+ "device.credentials-unavailable": "Le credenziali del dispositivo non sono disponibili",
26827
+ "device.credential-not-found": "Credenziale del dispositivo non trovata: {id}",
26828
+ "storage.no-provider": "Nessun provider di archiviazione configurato",
26829
+ "recording.export-unknown": "Esportazione \"{id}\" sconosciuta",
26830
+ "recording.export-invalid-range": "Intervallo di tempo non valido {fromMs}..{toMs}",
26831
+ "recording.export-no-profiles": "L'esportazione richiede almeno un profilo di flusso",
26832
+ "recording.export-not-ready": "L'esportazione \"{id}\" non è pronta ({state})",
26833
+ "recording.export-expired": "L'esportazione \"{id}\" è scaduta",
26834
+ "recording.export-no-file": "L'esportazione \"{id}\" non ha alcun file su disco",
26835
+ "recording.clip-render-unavailable": "La creazione delle clip non è disponibile su questo nodo",
26836
+ "reolink.hub-host-missing": "Hub Reolink: host non configurato",
26837
+ "reolink.hub-password-missing": "Hub Reolink: password non configurata",
26838
+ "reolink.email-push-hub-attached": "Email push non è disponibile per le telecamere collegate a un hub",
26839
+ "reolink.email-push-not-wired": "Il server Email Push non è collegato — riavvia l'addon Reolink",
26840
+ "reolink.webhook-not-wired": "Il server webhook HaCfg non è collegato — riavvia l'addon Reolink",
26841
+ "reolink.webhook-unsupported": "Il firmware della telecamera non supporta il webhook HaCfg Baichuan (cmd 806)",
26842
+ "reolink.preset-invalid": "presetId non valido: {presetId}",
26843
+ "reolink.home-preset-not-baichuan": "Il preset home configurato non è un id Baichuan: {presetId}",
26844
+ "reolink.day-night-schedule-unsupported": "Le telecamere Reolink non supportano una modalità giorno/notte programmata",
26845
+ "reolink.clip-device-not-reolink": "aggiornamento clip: il dispositivo {deviceId} non è una telecamera Reolink qui",
26846
+ "notifiers.gotify-server-url-required": "gotify: serverUrl è obbligatorio",
26847
+ "notifiers.gotify-app-token-required": "gotify: appToken è obbligatorio",
26848
+ "notifiers.email-to-required": "email: manca la configurazione obbligatoria 'to'",
26849
+ "hikvision.camera-name-required": "Il nome della telecamera è obbligatorio",
26850
+ "hikvision.camera-ip-required": "L'IP della telecamera è obbligatorio",
26851
+ "hikvision.password-required": "La password è obbligatoria",
26852
+ "hikvision.home-preset-missing": "Nessun preset home configurato per questa telecamera — impostane uno nelle impostazioni PTZ",
26853
+ "amcrest.camera-name-required": "Il nome della telecamera è obbligatorio",
26854
+ "amcrest.camera-ip-required": "L'IP della telecamera è obbligatorio",
26855
+ "amcrest.password-required": "La password è obbligatoria",
26856
+ "amcrest.home-preset-missing": "Nessun preset home configurato per questa telecamera — impostane uno nelle impostazioni PTZ",
26857
+ "wyze.camera-name-required": "Il nome della telecamera è obbligatorio",
26858
+ "wyze.camera-mac-required": "Wyze: impossibile salvare una telecamera senza indirizzo MAC",
26859
+ "dreame.manual-create-refused": "I dispositivi Dreame si acquisiscono dal cloud, non si creano a mano",
26860
+ "rtsp.camera-name-required": "Il nome della telecamera è obbligatorio",
26861
+ "rtsp.stream-required": "È richiesto almeno un URL di flusso RTSP",
26862
+ "rtsp.too-many-streams": "Sono supportati al massimo 3 URL di flusso RTSP",
26863
+ "gree.name-required": "Il nome del condizionatore è obbligatorio",
26864
+ "gree.ip-required": "L'indirizzo IP del condizionatore è obbligatorio",
26865
+ "ecowitt.name-required": "Il nome del gateway è obbligatorio",
26866
+ "ecowitt.host-required": "L'host del gateway è obbligatorio per la lettura locale",
26867
+ "unifi.name-required": "Il nome del controller è obbligatorio",
26868
+ "unifi.host-required": "L'host del controller è obbligatorio",
26869
+ "vesync.name-required": "Il nome dell'account è obbligatorio",
26870
+ "vesync.email-required": "L'email dell'account è obbligatoria",
26871
+ "unraid.name-required": "Il nome del server è obbligatorio",
26872
+ "unraid.host-required": "L'host del server è obbligatorio",
26873
+ "velux.name-required": "Il nome del gateway è obbligatorio",
26874
+ "velux.host-required": "L'host del gateway è obbligatorio",
26875
+ "cloudflare.custom-not-configured": "Tunnel personalizzato non configurato — avvia «Attiva» dalle impostazioni",
26876
+ "cloudflare.custom-needs-settings": "Il tunnel personalizzato richiede: {missing}. Compila prima le impostazioni qui sopra.",
26877
+ "cloudflare.zone-token-missing": "listZones: nessun token API Cloudflare impostato",
26878
+ "cloudflare.zone-not-visible": "La zona selezionata {zoneId} non è visibile a questo token",
26879
+ "google.from-address-required": "Imposta l'indirizzo del mittente sul broker Google (oppure collega un account).",
26880
+ "google.client-credentials-required": "Configura ID client e segreto del client prima di aggiornare il token Google",
26881
+ "globalSettings.s_alerts.title": "Centro avvisi",
26882
+ "globalSettings.s_alerts.description": "Configura l'archiviazione e la conservazione degli avvisi.",
26883
+ "globalSettings.s_alerts.maxAlerts.label": "Numero massimo di avvisi memorizzati",
26884
+ "globalSettings.s_alerts.maxAlerts.description": "Quando si supera questo limite vengono eliminati gli avvisi letti più vecchi.",
26885
+ "globalSettings.s_alerts.retentionDays.label": "Conservazione degli avvisi (giorni)",
26886
+ "globalSettings.s_alerts.retentionDays.description": "Gli avvisi più vecchi di questo valore vengono rimossi automaticamente.",
26887
+ "globalSettings.s_camera-grids.title": "Griglie di telecamere",
26888
+ "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.",
26889
+ "globalSettings.s_camera-grids.cameraGrids.label": "Griglie",
26890
+ "globalSettings.s_camera-grids.cameraGrids.name.label": "Nome",
26891
+ "globalSettings.s_camera-grids.cameraGrids.enabled.label": "Attiva",
26892
+ "globalSettings.s_camera-grids.cameraGrids.enabled.description": "Una griglia disattivata ritira la sua telecamera.",
26893
+ "gridDevice.s_camera-grid-layout.title": "Disposizione della griglia",
26894
+ "gridDevice.s_camera-grid-layout._gridLayout.label": "",
26895
+ "globalSettings.s_console-logging.title": "Log su console",
26896
+ "globalSettings.s_console-logging.description": "Livello minimo di log da emettere su stdout/stderr. Indipendente dalla destinazione su file ruotati (Winston).",
26897
+ "globalSettings.s_console-logging.level.label": "Livello di log",
26898
+ "globalSettings.s_console-logging.level.o_debug.label": "Debug",
26899
+ "globalSettings.s_console-logging.level.o_info.label": "Info",
26900
+ "globalSettings.s_console-logging.level.o_warn.label": "Avviso",
26901
+ "globalSettings.s_console-logging.level.o_error.label": "Errore",
26902
+ "dayNightConfig.dayNight_mode.label": "Modalità",
26903
+ "dayNightConfig.dayNight_sensitivity.label": "Sensibilità del filtro IR-cut",
26904
+ "dayNightConfig.dayNight_switchDelaySec.label": "Ritardo di commutazione",
26905
+ "section.s_day-night.title": "Giorno / Notte",
26906
+ "section.s_day-night.description": "Modalità di commutazione del filtro IR-cut e i parametri della fotocellula che la regolano.",
26907
+ "baseDeviceSection.s_driver-settings-unavailable.title": "Impostazioni del driver",
26908
+ "baseDeviceSection.s_driver-settings-unavailable.driver-settings-unavailable-notice.label": "Temporaneamente non disponibile",
26909
+ "imageSettingsConfig.imageSettings_brightness.label": "Luminosità",
26910
+ "imageSettingsConfig.imageSettings_contrast.label": "Contrasto",
26911
+ "imageSettingsConfig.imageSettings_saturation.label": "Saturazione",
26912
+ "imageSettingsConfig.imageSettings_sharpness.label": "Nitidezza",
26913
+ "imageSettingsConfig.imageSettings_mirror.label": "Specchio",
26914
+ "imageSettingsConfig.imageSettings_flip.label": "Capovolgi",
26915
+ "imageSettingsConfig.imageSettings_rotate.label": "Rotazione",
26916
+ "imageSettingsConfig.imageSettings_whiteBalance.label": "Bilanciamento del bianco",
26917
+ "imageSettingsConfig.imageSettings_warmth.label": "Calore",
26918
+ "imageSettingsConfig.imageSettings_exposureMode.label": "Modalità di esposizione",
26919
+ "imageSettingsConfig.imageSettings_backlightMode.label": "Compensazione del controluce",
26920
+ "section.s_image-settings.title": "Regolazione immagine",
26921
+ "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.",
26922
+ "volumesField.id.label": "ID",
26923
+ "volumesField.label.label": "Nome",
26924
+ "volumesField.status.label": "Stato",
26925
+ "volumesField.capacity.label": "Capacità",
26926
+ "volumesField.free.label": "Libero",
26927
+ "tracksField.id.label": "Traccia",
26928
+ "tracksField.primary.label": "Principale",
26929
+ "tracksField.enabled.label": "Attiva",
26930
+ "tracksField.codec.label": "Codec",
26931
+ "tracksField.resolution.label": "Risoluzione",
26932
+ "storageSection.s_recording-onboard-storage.title": "Memoria della telecamera",
26933
+ "storageSection.s_recording-onboard-storage.description": "La scheda nella telecamera, come la descrive la telecamera stessa.",
26934
+ "recordingSection.s_recording-onboard-recording.title": "Registrazione sulla telecamera",
26935
+ "recordingSection.s_recording-onboard-recording.description": "Ciò che la telecamera registra sulla propria scheda. Questo configura la telecamera, non il registratore di CamStack.",
26936
+ "globalSettings.s_local-access.title": "HTTP sulla LAN",
26937
+ "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.",
26938
+ "globalSettings.s_local-access.httpEnabled.label": "Attiva HTTP sulla LAN",
26939
+ "globalSettings.s_local-access.httpPort.label": "Porta HTTP",
26940
+ "globalSettings.s_local-access.httpPort.description": "Listener dedicato. Non deve coincidere con la porta HTTPS (4443 per impostazione predefinita).",
26941
+ "globalSettings.s_local-access.mdnsAdvertise.label": "Annuncia questo hub sulla LAN (mDNS)",
26942
+ "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).",
26943
+ "globalSettings.s_local-access.localHostname.label": "Nome host locale",
26944
+ "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.",
26945
+ "globalSettings.s_loki-logging.title": "Loki",
26946
+ "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.",
26947
+ "globalSettings.s_loki-logging.url.label": "URL di Loki",
26948
+ "globalSettings.s_loki-logging.url.description": "URL base, ad es. http://loki:3100: il percorso /loki/api/v1/push viene aggiunto.",
26949
+ "globalSettings.s_loki-logging.level.label": "Livello minimo",
26950
+ "globalSettings.s_loki-logging.level.o_debug.label": "Debug",
26951
+ "globalSettings.s_loki-logging.level.o_info.label": "Info",
26952
+ "globalSettings.s_loki-logging.level.o_warn.label": "Avviso",
26953
+ "globalSettings.s_loki-logging.level.o_error.label": "Errore",
26954
+ "globalSettings.s_loki-logging.job.label": "Etichetta job",
26955
+ "globalSettings.s_loki-logging.job.description": "L'etichetta `job` di Loki. Tienila fissa: le etichette sono indicizzate.",
26956
+ "globalSettings.s_loki-logging.extraLabels.label": "Etichette aggiuntive",
26957
+ "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.",
26958
+ "globalSettings.s_loki-logging.tenantId.label": "ID tenant",
26959
+ "globalSettings.s_loki-logging.tenantId.description": "Inviato come X-Scope-OrgID. Richiesto da Grafana Cloud e da Loki multi-tenant.",
26960
+ "globalSettings.s_loki-logging.username.label": "Nome utente",
26961
+ "globalSettings.s_loki-logging.username.description": "Autenticazione HTTP basic. Lascia vuoto se non serve.",
26962
+ "globalSettings.s_loki-logging.password.label": "Password",
26963
+ "globalSettings.s_loki-logging.batchIntervalMs.label": "Intervallo di invio",
26964
+ "globalSettings.s_loki-logging.batchIntervalMs.description": "Ogni quanto viene inviato un lotto parziale.",
26965
+ "globalSettings.s_loki-logging.batchSize.label": "Dimensione del lotto",
26966
+ "globalSettings.s_loki-logging.batchSize.description": "Invia in anticipo quando sono in coda così tante voci.",
26967
+ "globalSettings.s_loki-logging.timeoutMs.label": "Timeout della richiesta",
26968
+ "globalSettings.s_native-metrics-settings.title": "Metriche di sistema",
26969
+ "globalSettings.s_native-metrics-settings.samplingIntervalMs.label": "Intervallo di campionamento",
26970
+ "globalSettings.s_native-metrics-settings.samplingIntervalMs.description": "Ogni quanto raccogliere le metriche di sistema",
26971
+ "globalSettings.s_native-metrics-load-series.title": "Storico del carico",
26972
+ "globalSettings.s_native-metrics-load-series.loadSeriesCadenceSec.label": "Cadenza di campionamento",
26973
+ "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.",
26974
+ "globalSettings.s_native-metrics-load-series.loadSeriesRetentionHours.label": "Conservazione",
26975
+ "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.",
26976
+ "globalSettings.s_native-metrics-load-series.load-series-cost.label": "Costo di questa configurazione",
26977
+ "globalSettings.s_native-metrics-load-series.load-series-cap.label": "Limite rigido di righe",
26978
+ "globalSettings.s_snapshot-cache.title": "Cache degli snapshot",
26979
+ "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.",
26980
+ "globalSettings.s_snapshot-cache.staleTtlMs.label": "TTL del ripiego obsoleto (ms)",
26981
+ "globalSettings.s_snapshot-cache.staleTtlMs.description": "Se la cattura dal vivo fallisce, viene comunque restituito uno snapshot in cache più recente di questo valore.",
26982
+ "deviceSettingsContribution.s_snapshot-preferences.title": "Snapshot",
26983
+ "deviceSettingsContribution.s_snapshot-preferences.snapshotStreamId.label": "Flusso preferito",
26984
+ "deviceSettingsContribution.s_snapshot-preferences.snapshotStreamId.description": "Flusso usato per acquisire uno snapshot",
26985
+ "deviceSettingsContribution.s_snapshot-preferences.snapshotMaxAgeS.label": "Età massima della cache (s)",
26986
+ "deviceSettingsContribution.s_snapshot-preferences.snapshotDebug.label": "Log di debug",
26987
+ "deviceSettingsContribution.s_snapshot-preferences.snapshotDebug.description": "Registra la scelta del flusso e i tempi per questo dispositivo.",
26988
+ "providerInfo.s_filesystem-storage.title": "File system",
26989
+ "providerInfo.s_filesystem-storage.basePath.label": "Percorso base",
26990
+ "providerInfo.s_filesystem-storage.basePath.description": "Percorso assoluto della cartella dove vengono salvati i file.",
26991
+ "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).",
26992
+ "global.s_system-config-server.server-restart-note.label": "Riavvio necessario",
26993
+ "global.s_system-config-server.port.label": "Porta",
26994
+ "global.s_system-config-server.port.description": "Porta di ascolto",
26995
+ "global.s_system-config-server.host.label": "Host",
26996
+ "global.s_system-config-server.host.description": "Indirizzo di bind",
26997
+ "global.s_system-config-server.dataPath.label": "Percorso dei dati",
26998
+ "global.s_system-config-server.dataPath.description": "Cartella radice dei dati",
26999
+ "global.s_system-config-auth.description": "Impostazioni di token e sessione.",
27000
+ "global.s_system-config-auth.tokenExpiry.label": "Durata della sessione",
27001
+ "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.",
27002
+ "global.s_system-config-auth.accessTokenExpiry.label": "Durata del token di accesso",
27003
+ "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.",
27004
+ "global.s_system-config-auth.trustedProxies.label": "Reverse proxy fidati",
27005
+ "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.",
27006
+ "global.s_system-config-auth.trustedNetworksWarning.label": "Salto dell'autenticazione a due fattori",
27007
+ "global.s_system-config-auth.trustedNetworks.label": "Reti fidate (salta il secondo fattore)",
27008
+ "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.",
27009
+ "globalSettings.s_winston-logging.title": "Log",
27010
+ "globalSettings.s_winston-logging.description": "Dettaglio globale dei log e conservazione dei file di log ruotati su questo nodo.",
27011
+ "globalSettings.s_winston-logging.level.label": "Livello di log",
27012
+ "globalSettings.s_winston-logging.level.o_debug.label": "Debug",
27013
+ "globalSettings.s_winston-logging.level.o_info.label": "Info",
27014
+ "globalSettings.s_winston-logging.level.o_warn.label": "Avviso",
27015
+ "globalSettings.s_winston-logging.level.o_error.label": "Errore",
27016
+ "globalSettings.s_winston-logging.retentionDays.label": "Conservazione (giorni)",
27017
+ "globalSettings.s_winston-logging.retentionDays.description": "Numero di giorni per cui conservare i file di log ruotati prima dell'eliminazione",
27018
+ "system.python-required": "Serve Python 3.10 o successivo, ma non è stato trovato su questo sistema",
27019
+ "system.device-enrollment-busy": "Troppe registrazioni di dispositivi in attesa — riprova tra poco",
27020
+ "system.admin-token-expiry-too-long": "Un token amministratore deve scadere entro 90 giorni",
27021
+ "system.admin-token-name-required": "Un token amministratore richiede un nome",
27022
+ "system.user-exists": "Esiste già un utente con nome utente \"{username}\"",
27023
+ "system.user-not-found": "Utente con ID \"{id}\" non trovato",
27024
+ "system.addon-no-discovery": "L'addon \"{addonId}\" non supporta il rilevamento dei dispositivi",
27025
+ "system.addon-no-adoption": "L'addon \"{addonId}\" non supporta l'acquisizione dei dispositivi",
27026
+ "system.addon-no-manual-create": "L'addon \"{addonId}\" non supporta la creazione manuale di dispositivi",
27027
+ "system.location-name-required": "Il nome del luogo non può essere vuoto",
27028
+ "system.location-required": "Il luogo non può essere vuoto",
27029
+ "system.site-zone-name-required": "Il nome della zona non può essere vuoto",
27030
+ "server.handoff-busy": "Troppi codici di passaggio in attesa — riprova tra poco",
27031
+ "server.app-confirmations-busy": "Troppe conferme di app in attesa",
27032
+ "server.step-up-busy": "Troppe verifiche di sicurezza in attesa",
27033
+ "server.login-unavailable": "Accesso non disponibile — la capacità `user-management` non è registrata",
27034
+ "server.share-token-expired": "Token di condivisione scaduto: {id}",
27035
+ "server.package-not-allowed": "Il pacchetto \"{name}\" non è un pacchetto @camstack/* consentito",
27036
+ "server.package-protected": "Impossibile disinstallare il pacchetto protetto \"{name}\"",
27037
+ "server.package-required": "Il pacchetto {packageName} è necessario e non può essere disinstallato"
27038
+ };
27039
+ //#endregion
27040
+ //#region src/i18n/catalog-registry.ts
27041
+ /**
27042
+ * The hub's translation catalogs (D863).
27043
+ *
27044
+ * Core namespace `server` ships inside this package (`en.json` / `it.json`:
27045
+ * user-facing error texts + core schema labels). Every installed addon may add
27046
+ * `i18n/<lang>.json` in its package directory; its namespace is its addon id.
27047
+ * Every file is validated with zod; a broken file is logged and ignored, never
27048
+ * fatal - the English text that travels beside every key is the floor.
27049
+ */
27050
+ /** The core namespace: user-facing error texts and core schema labels. */
27051
+ var SERVER_NAMESPACE = "server";
27052
+ /** `@camstack/addon-provider-reolink` -> `provider-reolink`; `@camstack/system` -> `system`. */
27053
+ function catalogNamespaceOf(packageName) {
27054
+ return packageName.replace(/^@camstack\//, "").replace(/^addon-/, "");
27055
+ }
27056
+ var CatalogRegistry = class {
27057
+ warn;
27058
+ namespaces = /* @__PURE__ */ new Map();
27059
+ constructor(warn = () => void 0) {
27060
+ this.warn = warn;
27061
+ }
27062
+ /** Validates `raw` and installs it; returns false (after warning) when it is not a flat string map. */
27063
+ set(ns, lang, raw, origin) {
27064
+ const parsed = require_dist.CatalogFileSchema.safeParse(raw);
27065
+ if (!parsed.success) {
27066
+ this.warn(`i18n catalog ignored (${origin}): ${parsed.error.issues[0]?.message ?? "invalid"}`);
27067
+ return false;
27068
+ }
27069
+ const langs = this.namespaces.get(ns) ?? /* @__PURE__ */ new Map();
27070
+ langs.set(lang, parsed.data);
27071
+ this.namespaces.set(ns, langs);
27072
+ return true;
27073
+ }
27074
+ /** Loads `<packageDir>/i18n/<lang>.json` for every language that has a file. */
27075
+ loadAddonDir(ns, packageDir) {
27076
+ for (const lang of require_dist.CATALOG_LANGS) {
27077
+ const file = node_path.join(packageDir, "i18n", `${lang}.json`);
27078
+ let text;
27079
+ try {
27080
+ text = node_fs.readFileSync(file, "utf8");
27081
+ } catch {
27082
+ continue;
27083
+ }
27084
+ try {
27085
+ this.set(ns, lang, JSON.parse(text), file);
27086
+ } catch (err) {
27087
+ this.warn(`i18n catalog ignored (${file}): ${err instanceof Error ? err.message : "bad JSON"}`);
27088
+ }
27089
+ }
27090
+ }
27091
+ /** Drops a namespace (addon uninstalled or redeployed before a reload). */
27092
+ clear(ns) {
27093
+ this.namespaces.delete(ns);
27094
+ }
27095
+ /** The text for `ns:key` in `lang`, or `undefined`. Never falls back across languages. */
27096
+ lookup(lang, ns, key) {
27097
+ return this.namespaces.get(ns)?.get(lang)?.[key];
27098
+ }
27099
+ /**
27100
+ * `t(ns, key, params, fallbackEnglish)` - the translation in `lang`, else
27101
+ * the English fallback (also interpolated). English is never looked up: the
27102
+ * fallback IS the English text.
27103
+ */
27104
+ t(lang, ns, key, params, fallbackEnglish) {
27105
+ return require_dist.interpolate((lang === "en" ? void 0 : this.lookup(lang, ns, key)) ?? fallbackEnglish, params);
27106
+ }
27107
+ /** A lookup bound to one language, for `localizeConfigTree`. English never substitutes. */
27108
+ lookupFor(lang) {
27109
+ return (ns, key) => lang === "en" ? void 0 : this.lookup(lang, ns, key);
27110
+ }
27111
+ /** `t` for a `"ns:key"` reference. */
27112
+ tRef(lang, ref, params, fallbackEnglish) {
27113
+ const parts = require_dist.splitTranslationRef(ref);
27114
+ return parts === null ? require_dist.interpolate(fallbackEnglish, params) : this.t(lang, parts.ns, parts.key, params, fallbackEnglish);
27115
+ }
27116
+ };
27117
+ var shared = null;
27118
+ /** A fresh registry holding the core `server` namespace (specs build their own). */
27119
+ function createCoreCatalogRegistry(warn) {
27120
+ const registry = new CatalogRegistry(warn);
27121
+ registry.set(SERVER_NAMESPACE, "en", en_default, "server/en.json");
27122
+ registry.set(SERVER_NAMESPACE, "it", it_default, "server/it.json");
27123
+ return registry;
27124
+ }
27125
+ /** The hub's one registry, core catalogs preloaded. */
27126
+ function getCatalogRegistry(warn) {
27127
+ if (shared === null) shared = createCoreCatalogRegistry(warn);
27128
+ return shared;
27129
+ }
27130
+ /** Spec hook: forget the shared registry. */
27131
+ function resetCatalogRegistryForTests() {
27132
+ shared = null;
27133
+ }
27134
+ //#endregion
26497
27135
  exports.ADMIN_TOKEN_MAX_LIFETIME_MS = require_builtins_local_auth_local_auth_addon.ADMIN_TOKEN_MAX_LIFETIME_MS;
26498
27136
  exports.ADMIN_TOKEN_PREFIX = require_builtins_local_auth_local_auth_addon.ADMIN_TOKEN_PREFIX;
26499
27137
  exports.AGENT_CAP_FWD_ACTION = AGENT_CAP_FWD_ACTION;
@@ -26546,6 +27184,7 @@ exports.CapUsageRegistry = CapUsageRegistry;
26546
27184
  exports.CapabilityHandle = CapabilityHandle;
26547
27185
  exports.CapabilityRegistry = CapabilityRegistry;
26548
27186
  exports.CapabilityUnavailableError = CapabilityUnavailableError;
27187
+ exports.CatalogRegistry = CatalogRegistry;
26549
27188
  exports.ComposerAddon = require_builtins_composer_composer_addon.ComposerAddon;
26550
27189
  exports.ConfigManager = ConfigManager;
26551
27190
  exports.ConfigStore = require_builtins_sqlite_storage_index.ConfigStore$1;
@@ -26679,6 +27318,7 @@ exports.ReadinessTimeoutError = require_dist.ReadinessTimeoutError;
26679
27318
  exports.ReplEngine = ReplEngine;
26680
27319
  exports.RingBuffer = RingBuffer;
26681
27320
  exports.SERVER_AUTH_OID = require_agent_https.SERVER_AUTH_OID;
27321
+ exports.SERVER_NAMESPACE = SERVER_NAMESPACE;
26682
27322
  exports.SOCKET_PLANE_TOP_N = SOCKET_PLANE_TOP_N;
26683
27323
  exports.SOCKET_QUEUE_TOP_N = SOCKET_QUEUE_TOP_N;
26684
27324
  exports.STALL_REPORT_MS = require_custom_action_registry.STALL_REPORT_MS;
@@ -26757,6 +27397,7 @@ exports.capActionName = capActionName;
26757
27397
  exports.capActionSuffix = capActionSuffix;
26758
27398
  exports.capBareAction = capBareAction;
26759
27399
  exports.capServiceName = capServiceName;
27400
+ exports.catalogNamespaceOf = catalogNamespaceOf;
26760
27401
  exports.certificateNames = require_agent_https.certificateNames;
26761
27402
  exports.classifyAddonDir = classifyAddonDir;
26762
27403
  exports.classifyCapRoute = classifyCapRoute;
@@ -26789,6 +27430,7 @@ exports.createCapActionCensus = createCapActionCensus;
26789
27430
  exports.createCiaoPublisher = require_hub_mdns_ciao.createCiaoPublisher;
26790
27431
  exports.createCidrMatcher = require_builtins_system_config_system_config_addon.createCidrMatcher;
26791
27432
  exports.createCoreCapService = createCoreCapService;
27433
+ exports.createCoreCatalogRegistry = createCoreCatalogRegistry;
26792
27434
  exports.createDeferredHeapWatchSink = createDeferredHeapWatchSink;
26793
27435
  exports.createDoorSettingsView = createDoorSettingsView;
26794
27436
  exports.createEventPlaneMeter = createEventPlaneMeter;
@@ -26896,6 +27538,7 @@ exports.generateMeshKeyPair = require_builtins_system_config_system_config_addon
26896
27538
  exports.getBrokerEventBus = getBrokerEventBus;
26897
27539
  exports.getBrokerTlsTransporter = getBrokerTlsTransporter;
26898
27540
  exports.getCapUsageRegistry = getCapUsageRegistry;
27541
+ exports.getCatalogRegistry = getCatalogRegistry;
26899
27542
  Object.defineProperty(exports, "getFfmpegDownloadUrl", {
26900
27543
  enumerable: true,
26901
27544
  get: function() {
@@ -26996,6 +27639,7 @@ exports.mountNativeCapService = mountNativeCapService;
26996
27639
  exports.nextRssBudgetState = nextRssBudgetState;
26997
27640
  exports.normalizeIp = require_builtins_system_config_system_config_addon.normalizeIp;
26998
27641
  exports.onProcessNodeRegistered = require_builtins_system_config_system_config_addon.onProcessNodeRegistered;
27642
+ exports.onSessionsRevoked = require_builtins_local_auth_local_auth_addon.onSessionsRevoked;
26999
27643
  exports.openMeshTlsWhenRevocationsLoaded = require_builtins_system_config_system_config_addon.openMeshTlsWhenRevocationsLoaded;
27000
27644
  exports.overlayGetStatus = overlayGetStatus;
27001
27645
  exports.parseAgentDashboardOrigins = require_builtins_system_config_system_config_addon.parseAgentDashboardOrigins;
@@ -27038,6 +27682,7 @@ exports.reissueTlsLeaf = require_hub_mdns_ciao.reissueTlsLeaf;
27038
27682
  exports.reloadHttpsListener = require_hub_mdns_ciao.reloadHttpsListener;
27039
27683
  exports.renewMeshCertificate = require_builtins_system_config_system_config_addon.renewMeshCertificate;
27040
27684
  exports.requireProcessMeshCa = require_builtins_system_config_system_config_addon.requireProcessMeshCa;
27685
+ exports.resetCatalogRegistryForTests = resetCatalogRegistryForTests;
27041
27686
  exports.resolveFilePath = require_custom_action_registry.resolveFilePath;
27042
27687
  exports.resolveFormatRevision = require_custom_action_registry.resolveFormatRevision;
27043
27688
  exports.resolveHwAccel = resolveHwAccel;