@camstack/system 1.0.2

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 (262) hide show
  1. package/dist/addon/addon-api-factory.d.ts +35 -0
  2. package/dist/addon-routes/addon-route-registry.d.ts +37 -0
  3. package/dist/addon-runner.js +599 -0
  4. package/dist/addon-runner.mjs +597 -0
  5. package/dist/auth/api-key-manager.d.ts +26 -0
  6. package/dist/auth/auth-manager.d.ts +109 -0
  7. package/dist/auth/parse-record.d.ts +18 -0
  8. package/dist/auth/scope-matcher.d.ts +7 -0
  9. package/dist/auth/scoped-token-manager.d.ts +40 -0
  10. package/dist/auth/totp-manager.d.ts +51 -0
  11. package/dist/auth/user-manager.d.ts +34 -0
  12. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.d.ts +53 -0
  13. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +259 -0
  14. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +251 -0
  15. package/dist/builtins/addon-pages-aggregator/dedupe-pages.d.ts +6 -0
  16. package/dist/builtins/addon-pages-aggregator/index.d.ts +1 -0
  17. package/dist/builtins/addon-pages-aggregator/index.js +8 -0
  18. package/dist/builtins/addon-pages-aggregator/index.mjs +2 -0
  19. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.d.ts +47 -0
  20. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +228 -0
  21. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +220 -0
  22. package/dist/builtins/addon-widgets-aggregator/index.d.ts +1 -0
  23. package/dist/builtins/addon-widgets-aggregator/index.js +8 -0
  24. package/dist/builtins/addon-widgets-aggregator/index.mjs +2 -0
  25. package/dist/builtins/alerts/alerts.addon.d.ts +81 -0
  26. package/dist/builtins/alerts/alerts.addon.js +601 -0
  27. package/dist/builtins/alerts/alerts.addon.mjs +595 -0
  28. package/dist/builtins/alerts/index.d.ts +1 -0
  29. package/dist/builtins/alerts/index.js +4 -0
  30. package/dist/builtins/alerts/index.mjs +2 -0
  31. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts +147 -0
  32. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2229 -0
  33. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2220 -0
  34. package/dist/builtins/backup-orchestrator/cron-helpers.d.ts +23 -0
  35. package/dist/builtins/backup-orchestrator/destination-policy.d.ts +72 -0
  36. package/dist/builtins/backup-orchestrator/download-helpers.d.ts +12 -0
  37. package/dist/builtins/backup-orchestrator/index.d.ts +2 -0
  38. package/dist/builtins/backup-orchestrator/index.js +8 -0
  39. package/dist/builtins/backup-orchestrator/index.mjs +2 -0
  40. package/dist/builtins/backup-orchestrator/manifest-store.d.ts +77 -0
  41. package/dist/builtins/console-logging/console-destination.d.ts +13 -0
  42. package/dist/builtins/console-logging/console-logging.addon.d.ts +25 -0
  43. package/dist/builtins/console-logging/index.d.ts +3 -0
  44. package/dist/builtins/console-logging/index.js +104 -0
  45. package/dist/builtins/console-logging/index.mjs +95 -0
  46. package/dist/builtins/device-manager/device-config-contribution.d.ts +32 -0
  47. package/dist/builtins/device-manager/device-event-propagator.d.ts +26 -0
  48. package/dist/builtins/device-manager/device-link-overlay.d.ts +23 -0
  49. package/dist/builtins/device-manager/device-link-resolver.d.ts +15 -0
  50. package/dist/builtins/device-manager/device-manager.addon.d.ts +452 -0
  51. package/dist/builtins/device-manager/device-manager.addon.js +3299 -0
  52. package/dist/builtins/device-manager/device-manager.addon.mjs +3292 -0
  53. package/dist/builtins/device-manager/index.d.ts +2 -0
  54. package/dist/builtins/device-manager/index.js +8 -0
  55. package/dist/builtins/device-manager/index.mjs +2 -0
  56. package/dist/builtins/hub-forwarder/hub-forwarder-destination.d.ts +44 -0
  57. package/dist/builtins/hub-forwarder/hub-forwarder.addon.d.ts +15 -0
  58. package/dist/builtins/hub-forwarder/index.d.ts +3 -0
  59. package/dist/builtins/hub-forwarder/index.js +154 -0
  60. package/dist/builtins/hub-forwarder/index.mjs +145 -0
  61. package/dist/builtins/local-auth/auth-schema.d.ts +26 -0
  62. package/dist/builtins/local-auth/index.d.ts +1 -0
  63. package/dist/builtins/local-auth/index.js +4 -0
  64. package/dist/builtins/local-auth/index.mjs +2 -0
  65. package/dist/builtins/local-auth/local-auth.addon.d.ts +18 -0
  66. package/dist/builtins/local-auth/local-auth.addon.js +8094 -0
  67. package/dist/builtins/local-auth/local-auth.addon.mjs +8063 -0
  68. package/dist/builtins/local-auth/oauth-grants.d.ts +45 -0
  69. package/dist/builtins/local-auth/oauth-session-manager.d.ts +50 -0
  70. package/dist/builtins/local-network/index.d.ts +2 -0
  71. package/dist/builtins/local-network/index.js +10 -0
  72. package/dist/builtins/local-network/index.mjs +2 -0
  73. package/dist/builtins/local-network/local-network.addon.d.ts +150 -0
  74. package/dist/builtins/local-network/local-network.addon.js +489 -0
  75. package/dist/builtins/local-network/local-network.addon.mjs +477 -0
  76. package/dist/builtins/native-metrics/index.d.ts +2 -0
  77. package/dist/builtins/native-metrics/native-metrics-provider.d.ts +48 -0
  78. package/dist/builtins/native-metrics/native-metrics.addon.d.ts +73 -0
  79. package/dist/builtins/native-metrics/native-metrics.addon.js +922 -0
  80. package/dist/builtins/native-metrics/native-metrics.addon.mjs +914 -0
  81. package/dist/builtins/platform-probe/hardware-decode-accel-probe.d.ts +37 -0
  82. package/dist/builtins/platform-probe/hardware-encoder-probe.d.ts +13 -0
  83. package/dist/builtins/platform-probe/index.d.ts +22 -0
  84. package/dist/builtins/platform-probe/index.js +834 -0
  85. package/dist/builtins/platform-probe/index.mjs +822 -0
  86. package/dist/builtins/platform-probe/inference-config-resolver.d.ts +29 -0
  87. package/dist/builtins/platform-probe/intel-accelerators.d.ts +11 -0
  88. package/dist/builtins/platform-probe/platform-scorer.d.ts +30 -0
  89. package/dist/builtins/platform-probe/runtime-packages.d.ts +6 -0
  90. package/dist/builtins/remote-access-orchestrator/enabled-providers-reconcile.d.ts +96 -0
  91. package/dist/builtins/remote-access-orchestrator/index.d.ts +1 -0
  92. package/dist/builtins/remote-access-orchestrator/index.js +8 -0
  93. package/dist/builtins/remote-access-orchestrator/index.mjs +2 -0
  94. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.d.ts +40 -0
  95. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +214 -0
  96. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +208 -0
  97. package/dist/builtins/shared/settle-sources.d.ts +22 -0
  98. package/dist/builtins/snapshot/index.d.ts +2 -0
  99. package/dist/builtins/snapshot/index.js +494 -0
  100. package/dist/builtins/snapshot/index.mjs +488 -0
  101. package/dist/builtins/snapshot/snapshot.addon.d.ts +120 -0
  102. package/dist/builtins/sqlite-storage/config-store.d.ts +8 -0
  103. package/dist/builtins/sqlite-storage/device-store.d.ts +23 -0
  104. package/dist/builtins/sqlite-storage/filesystem-browse-provider.d.ts +25 -0
  105. package/dist/builtins/sqlite-storage/filesystem-storage-provider.d.ts +83 -0
  106. package/dist/builtins/sqlite-storage/filesystem-storage.addon.d.ts +32 -0
  107. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +396 -0
  108. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +388 -0
  109. package/dist/builtins/sqlite-storage/index.d.ts +8 -0
  110. package/dist/builtins/sqlite-storage/index.js +62 -0
  111. package/dist/builtins/sqlite-storage/index.mjs +49 -0
  112. package/dist/builtins/sqlite-storage/integration-registry.d.ts +27 -0
  113. package/dist/builtins/sqlite-storage/path-guard.d.ts +4 -0
  114. package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +102 -0
  115. package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +14 -0
  116. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +644 -0
  117. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +636 -0
  118. package/dist/builtins/storage-orchestrator/index.d.ts +6 -0
  119. package/dist/builtins/storage-orchestrator/index.js +10 -0
  120. package/dist/builtins/storage-orchestrator/index.mjs +2 -0
  121. package/dist/builtins/storage-orchestrator/location-store.d.ts +49 -0
  122. package/dist/builtins/storage-orchestrator/provider-discovery.d.ts +10 -0
  123. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +103 -0
  124. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1138 -0
  125. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1128 -0
  126. package/dist/builtins/storage-orchestrator/storage-orchestrator.service.d.ts +236 -0
  127. package/dist/builtins/storage-orchestrator/storage-pressure-manager.d.ts +38 -0
  128. package/dist/builtins/system-backup/system-backup.service.d.ts +137 -0
  129. package/dist/builtins/system-config/index.d.ts +1 -0
  130. package/dist/builtins/system-config/index.js +8 -0
  131. package/dist/builtins/system-config/index.mjs +2 -0
  132. package/dist/builtins/system-config/system-config.addon.d.ts +10 -0
  133. package/dist/builtins/system-config/system-config.addon.js +232 -0
  134. package/dist/builtins/system-config/system-config.addon.mjs +226 -0
  135. package/dist/builtins/winston-logging/index.d.ts +3 -0
  136. package/dist/builtins/winston-logging/index.js +156 -0
  137. package/dist/builtins/winston-logging/index.mjs +144 -0
  138. package/dist/builtins/winston-logging/winston-destination.d.ts +21 -0
  139. package/dist/builtins/winston-logging/winston-logging.addon.d.ts +19 -0
  140. package/dist/chunk-CNf5ZN-e.mjs +37 -0
  141. package/dist/chunk-Cek0wNdY.js +64 -0
  142. package/dist/download/model-download-service.d.ts +41 -0
  143. package/dist/download/model-downloader.d.ts +31 -0
  144. package/dist/events/event-bus.d.ts +10 -0
  145. package/dist/events/system-event-bus.d.ts +14 -0
  146. package/dist/feature/feature-manager.d.ts +11 -0
  147. package/dist/formatter-B7qW8bPJ.mjs +162 -0
  148. package/dist/formatter-DqAKDlvN.js +167 -0
  149. package/dist/http/authenticated-file-server.d.ts +53 -0
  150. package/dist/http/data-plane-registry.d.ts +23 -0
  151. package/dist/http/file-data-plane.d.ts +10 -0
  152. package/dist/http/reverse-proxy.d.ts +15 -0
  153. package/dist/index.d.ts +82 -0
  154. package/dist/index.js +93485 -0
  155. package/dist/index.mjs +93179 -0
  156. package/dist/intel-accelerators-Gg0P5mnl.js +20 -0
  157. package/dist/intel-accelerators-hGgpZ0pX.mjs +19 -0
  158. package/dist/kernel/addon-class-resolver.d.ts +4 -0
  159. package/dist/kernel/addon-engine-manager.d.ts +22 -0
  160. package/dist/kernel/addon-health-monitor.d.ts +154 -0
  161. package/dist/kernel/addon-installer.d.ts +208 -0
  162. package/dist/kernel/addon-loader.d.ts +106 -0
  163. package/dist/kernel/addon-manifest.d.ts +77 -0
  164. package/dist/kernel/capability-handle.d.ts +46 -0
  165. package/dist/kernel/capability-registry.d.ts +412 -0
  166. package/dist/kernel/config-manager.d.ts +212 -0
  167. package/dist/kernel/config-schema.d.ts +93 -0
  168. package/dist/kernel/custom-action-registry.d.ts +23 -0
  169. package/dist/kernel/deps/addon-deps-manager.d.ts +19 -0
  170. package/dist/kernel/deps/manifest-native-deps.d.ts +25 -0
  171. package/dist/kernel/deps/manifest-python-deps.d.ts +20 -0
  172. package/dist/kernel/device-registry.d.ts +29 -0
  173. package/dist/kernel/fs-utils.d.ts +41 -0
  174. package/dist/kernel/hwaccel/hwaccel-resolver.d.ts +19 -0
  175. package/dist/kernel/hwaccel/hwaccel-service.d.ts +4 -0
  176. package/dist/kernel/index.d.ts +74 -0
  177. package/dist/kernel/infra-capabilities.d.ts +13 -0
  178. package/dist/kernel/moleculer/addon-context-factory.d.ts +91 -0
  179. package/dist/kernel/moleculer/addon-data-plane-facility.d.ts +19 -0
  180. package/dist/kernel/moleculer/addon-runner.d.ts +1 -0
  181. package/dist/kernel/moleculer/addon-service-factory.d.ts +50 -0
  182. package/dist/kernel/moleculer/broker-factory.d.ts +50 -0
  183. package/dist/kernel/moleculer/cap-usage-registry.d.ts +46 -0
  184. package/dist/kernel/moleculer/capabilities-access.d.ts +21 -0
  185. package/dist/kernel/moleculer/child-addon-call-dispatch.d.ts +46 -0
  186. package/dist/kernel/moleculer/child-cap-dispatch.d.ts +20 -0
  187. package/dist/kernel/moleculer/cluster-secret.d.ts +15 -0
  188. package/dist/kernel/moleculer/core-cap-service.d.ts +50 -0
  189. package/dist/kernel/moleculer/crash-supervisor.d.ts +50 -0
  190. package/dist/kernel/moleculer/device-cap-proxy.d.ts +79 -0
  191. package/dist/kernel/moleculer/event-bus-core.d.ts +53 -0
  192. package/dist/kernel/moleculer/event-bus.d.ts +53 -0
  193. package/dist/kernel/moleculer/hub-log-forwarder.d.ts +36 -0
  194. package/dist/kernel/moleculer/hub-service.d.ts +35 -0
  195. package/dist/kernel/moleculer/node-registry.d.ts +126 -0
  196. package/dist/kernel/moleculer/process-context.d.ts +4 -0
  197. package/dist/kernel/moleculer/process-service.d.ts +72 -0
  198. package/dist/kernel/moleculer/provider-registry.d.ts +28 -0
  199. package/dist/kernel/moleculer/readiness-context.d.ts +62 -0
  200. package/dist/kernel/moleculer/readiness-service.d.ts +7 -0
  201. package/dist/kernel/moleculer/register-node-client.d.ts +35 -0
  202. package/dist/kernel/moleculer/remote-logger.d.ts +43 -0
  203. package/dist/kernel/moleculer/resilient-cap-call.d.ts +28 -0
  204. package/dist/kernel/moleculer/stream-probe-service.d.ts +9 -0
  205. package/dist/kernel/moleculer/trpc-links.d.ts +189 -0
  206. package/dist/kernel/moleculer/typed-array-serde.d.ts +25 -0
  207. package/dist/kernel/moleculer/worker-device-restore.d.ts +10 -0
  208. package/dist/kernel/provider-kind-drift.d.ts +12 -0
  209. package/dist/kernel/restart-coordinator.d.ts +90 -0
  210. package/dist/kernel/storage-location-registry.d.ts +40 -0
  211. package/dist/kernel/transport/cap-action-name.d.ts +100 -0
  212. package/dist/kernel/transport/cap-route-resolver.d.ts +148 -0
  213. package/dist/kernel/transport/cap-route.d.ts +148 -0
  214. package/dist/kernel/transport/child-cap-protocol.d.ts +136 -0
  215. package/dist/kernel/transport/create-local-transport.d.ts +7 -0
  216. package/dist/kernel/transport/frame-codec.d.ts +7 -0
  217. package/dist/kernel/transport/index.d.ts +27 -0
  218. package/dist/kernel/transport/local-child-client.d.ts +136 -0
  219. package/dist/kernel/transport/local-child-registry.d.ts +179 -0
  220. package/dist/kernel/transport/local-endpoint-path.d.ts +6 -0
  221. package/dist/kernel/transport/local-transport.d.ts +46 -0
  222. package/dist/kernel/transport/parent-unowned-call.d.ts +75 -0
  223. package/dist/kernel/transport/socket-channel.d.ts +27 -0
  224. package/dist/kernel/transport/uds-event-bridge.d.ts +36 -0
  225. package/dist/kernel/transport/uds-event-bus.d.ts +22 -0
  226. package/dist/kernel/transport/uds-local-transport.d.ts +18 -0
  227. package/dist/kernel/transport/uds-log-ingest.d.ts +28 -0
  228. package/dist/kernel/transport/uds-logger.d.ts +44 -0
  229. package/dist/kernel/utils/ring-buffer.d.ts +15 -0
  230. package/dist/kernel/workspace-detect.d.ts +9 -0
  231. package/dist/lifecycle/lifecycle-state-machine.d.ts +28 -0
  232. package/dist/logging/formatter.d.ts +30 -0
  233. package/dist/logging/log-manager.d.ts +54 -0
  234. package/dist/logging/log-ring-buffer.d.ts +47 -0
  235. package/dist/logging/partitioned-log-buffer.d.ts +35 -0
  236. package/dist/logging/scoped-logger.d.ts +17 -0
  237. package/dist/main-DNnMW7Z2.js +9983 -0
  238. package/dist/main-rtjOwPBR.mjs +9976 -0
  239. package/dist/manifest-python-deps-D1DbAQEv.js +6724 -0
  240. package/dist/manifest-python-deps-DZsKTbs1.mjs +6315 -0
  241. package/dist/network/network-quality.d.ts +11 -0
  242. package/dist/notification/notification-service.d.ts +37 -0
  243. package/dist/notification/toast-service.d.ts +22 -0
  244. package/dist/pipeline/engine-manager-resolver.d.ts +15 -0
  245. package/dist/pipeline/pipeline-runner.d.ts +8 -0
  246. package/dist/pipeline/pipeline-validator.d.ts +13 -0
  247. package/dist/process/resource-monitor.d.ts +11 -0
  248. package/dist/python/python-env-manager.d.ts +12 -0
  249. package/dist/repl/interfaces.d.ts +31 -0
  250. package/dist/repl/repl-engine.d.ts +8 -0
  251. package/dist/resource-monitor-ClDGFyf6.mjs +57 -0
  252. package/dist/resource-monitor-IIEanuJt.js +74 -0
  253. package/dist/settle-sources-Bhsy57y-.js +38 -0
  254. package/dist/settle-sources-CDtNC8ub.mjs +33 -0
  255. package/dist/storage/fs-storage-backend.d.ts +40 -0
  256. package/dist/storage/storage-location-manager.d.ts +23 -0
  257. package/dist/storage/storage-manager.d.ts +83 -0
  258. package/dist/tar-BgAEMRBR.js +5434 -0
  259. package/dist/tar-ByMOPNM0.mjs +5429 -0
  260. package/dist/tls/cert-manager.d.ts +26 -0
  261. package/dist/tls/index.d.ts +1 -0
  262. package/package.json +343 -0
@@ -0,0 +1,236 @@
1
+ import { IScopedLogger, IStorageProviderImpl, StorageLocation, StorageLocationDeclaration, StorageLocationRef } from '@camstack/types';
2
+ import { ILocationStore } from './location-store.js';
3
+ export interface ListLocationsFilter {
4
+ readonly type?: string;
5
+ }
6
+ /**
7
+ * Minimal structural shape the orchestrator needs from the kernel's
8
+ * `StorageLocationRegistry` — the cardinality lookup plus the full
9
+ * declaration list (the admin-UI Data screen renders one group per
10
+ * declaration). Declared locally so core's builtins don't import the
11
+ * kernel's registry type directly; the addon passes the real
12
+ * `buildStorageLocationRegistry(...)` result, which structurally
13
+ * satisfies this interface.
14
+ */
15
+ export interface DeclarationSource {
16
+ cardinalityOf(id: string): 'single' | 'multi' | null;
17
+ list(): readonly StorageLocationDeclaration[];
18
+ }
19
+ /**
20
+ * Provider lookup callback. Returns the live set of `storage-provider`
21
+ * registrants. Called per-dispatch (cheap registry scan) so newly
22
+ * loaded addons surface immediately.
23
+ */
24
+ export type StorageProviderLookup = () => readonly IStorageProviderImpl[];
25
+ /**
26
+ * Synchronous `providerId → nodeLocal` resolver, injected by the addon
27
+ * from a cached snapshot of `storage-provider.getProviderInfo()` (the
28
+ * `getProviderInfo` round-trip is async, so a sync cache keeps
29
+ * `upsertLocation` synchronous — the contract its many callers rely on).
30
+ *
31
+ * Returns:
32
+ * - `true` — node-local provider (filesystem): its locations bind to a
33
+ * single node, so a `nodeId` is required.
34
+ * - `false` — node-agnostic provider (S3/SFTP/WebDAV): `nodeId` optional.
35
+ * - `undefined` — provider not (yet) known. Treated as non-node-local:
36
+ * validation does not reject (the provider may register later / be
37
+ * remote), the safe default for the early-boot / in-memory path.
38
+ */
39
+ export type NodeLocalResolver = (providerId: string) => boolean | undefined;
40
+ export declare class StorageOrchestratorService {
41
+ private readonly logger;
42
+ private readonly getProviders;
43
+ /**
44
+ * Optional persistence backend. When supplied, `initialize()`
45
+ * hydrates the in-memory map from the store, and every mutation
46
+ * (upsert/delete) mirrors to it. When `null` / `undefined`, the
47
+ * service is in-memory only — the contract used by the existing
48
+ * routing tests, where re-creating the service deliberately
49
+ * forgets every location.
50
+ *
51
+ * Mutable because production boot wires it late: the `settings-store`
52
+ * cap often isn't registered when the orchestrator initializes, so the
53
+ * service starts store-less and the addon calls {@link attachStore} once
54
+ * the provider appears. See {@link attachStore}.
55
+ */
56
+ private locationStore;
57
+ private readonly locations;
58
+ /**
59
+ * Declaration-driven cardinality source, injected by the addon after
60
+ * the kernel aggregates `storageLocations` declarations. `null` until
61
+ * `setRegistry` runs — `upsertLocation` then treats every type as
62
+ * `'multi'` (no singleton enforcement), the safe default for the
63
+ * in-memory-only / early-boot path.
64
+ */
65
+ private registry;
66
+ /**
67
+ * Injected `providerId → nodeLocal` resolver (see {@link NodeLocalResolver}).
68
+ * `null` until {@link setNodeLocalResolver} runs — `upsertLocation` then
69
+ * skips the node-local requirement check entirely (every provider is
70
+ * treated as node-agnostic), the safe default for the in-memory-only /
71
+ * early-boot path that predates the resolver wiring.
72
+ */
73
+ private nodeLocalResolver;
74
+ constructor(logger: IScopedLogger, getProviders: StorageProviderLookup,
75
+ /**
76
+ * Optional persistence backend. When supplied, `initialize()`
77
+ * hydrates the in-memory map from the store, and every mutation
78
+ * (upsert/delete) mirrors to it. When `null` / `undefined`, the
79
+ * service is in-memory only — the contract used by the existing
80
+ * routing tests, where re-creating the service deliberately
81
+ * forgets every location.
82
+ *
83
+ * Mutable because production boot wires it late: the `settings-store`
84
+ * cap often isn't registered when the orchestrator initializes, so the
85
+ * service starts store-less and the addon calls {@link attachStore} once
86
+ * the provider appears. See {@link attachStore}.
87
+ */
88
+ locationStore?: ILocationStore | null);
89
+ /** True once a persistence store is wired (constructor or {@link attachStore}). */
90
+ hasStore(): boolean;
91
+ /**
92
+ * Late-bind the persistence store (production boot: the `settings-store`
93
+ * cap registers after the orchestrator initializes, so the service runs
94
+ * in-memory-only until then). Idempotent — a second call once a store is
95
+ * wired is a no-op.
96
+ *
97
+ * Reconciles both directions so operator edits survive a reboot:
98
+ * 1. hydrate — DB rows win over any early in-memory seed (restores
99
+ * operator config like `minFreePercent` that the pre-store boot
100
+ * can't see), with the same `isSystem` upgrade as {@link initialize};
101
+ * 2. backfill — in-memory locations the DB doesn't have yet (the
102
+ * pre-store seed defaults on a fresh install) are persisted, so the
103
+ * store becomes the durable source of truth from here on.
104
+ */
105
+ attachStore(store: ILocationStore): Promise<void>;
106
+ /**
107
+ * Inject the declaration-driven cardinality source. Called once by the
108
+ * addon after the kernel aggregates every addon's `storageLocations`
109
+ * declarations into a `StorageLocationRegistry`.
110
+ */
111
+ setRegistry(registry: DeclarationSource | null): void;
112
+ /**
113
+ * Inject the synchronous `providerId → nodeLocal` resolver (SP1). Called
114
+ * by the addon from a cached snapshot of every `storage-provider`'s
115
+ * `getProviderInfo().nodeLocal`, refreshed when the provider collection
116
+ * changes. Powers the node-local upsert guard and the boot backfill.
117
+ */
118
+ setNodeLocalResolver(resolver: NodeLocalResolver | null): void;
119
+ /**
120
+ * The full set of addon-declared storage locations, as aggregated by
121
+ * the kernel and injected via {@link setRegistry}. Powers the admin-UI
122
+ * Data screen's per-declaration grouping. Empty until the registry is
123
+ * injected (early-boot / in-memory-only path).
124
+ */
125
+ listDeclarations(): readonly StorageLocationDeclaration[];
126
+ /**
127
+ * Hydrate the in-memory map from the persistence layer. Called once
128
+ * by the addon during `onInitialize`, before the eager seed pass.
129
+ * Idempotent — running it twice with the same store contents
130
+ * produces the same map. No-op when the service was constructed
131
+ * without a store.
132
+ *
133
+ * Errors loading individual rows are tolerated: the bad row is
134
+ * skipped and logged so a single corrupted record doesn't lock the
135
+ * whole orchestrator out of boot. (The store-side validation pass
136
+ * before insert means only schema-invalid SQL state can produce
137
+ * such a row.)
138
+ */
139
+ initialize(): Promise<void>;
140
+ /**
141
+ * Boot backfill (SP1): stamp `nodeId` on every persisted node-local
142
+ * location that lacks one. Single-node deployments seeded their
143
+ * filesystem locations before `nodeId` existed — they live on `hubNodeId`
144
+ * (the hub). Node-agnostic (remote) locations are left untouched: their
145
+ * absent `nodeId` is correct (reachable from any node).
146
+ *
147
+ * Idempotent — a location that already carries a `nodeId` (any value) is
148
+ * never re-touched, so re-running on a populated map (or a re-boot) is a
149
+ * no-op. A plain local update, not versioned-migration machinery: only
150
+ * the rows missing `nodeId` are mutated + persisted.
151
+ *
152
+ * No-op until the node-local resolver is wired (it classifies which
153
+ * providers are node-local).
154
+ */
155
+ backfillNodeIds(hubNodeId: string): Promise<void>;
156
+ listLocations(filter?: ListLocationsFilter): readonly StorageLocation[];
157
+ getDefaultLocation(type: string): StorageLocation | null;
158
+ /**
159
+ * Insert or update a location. If `isDefault: true`, atomically
160
+ * demotes any other default for the same type — operators always see
161
+ * exactly one default per type.
162
+ *
163
+ * When a persistence store is wired (Task 6), the new record AND any
164
+ * implicitly-demoted siblings are persisted before the in-memory map
165
+ * mutation returns. Persistence errors propagate to the caller.
166
+ */
167
+ upsertLocation(input: Omit<StorageLocation, 'createdAt' | 'updatedAt'>): StorageLocation;
168
+ /**
169
+ * Remove a location. Refuses to remove the default of a type unless a
170
+ * sibling default exists (defensive — `upsertLocation` already ensures
171
+ * at most one default per type, but the logic guards against future
172
+ * bypass paths e.g. SQLite migration that imports two defaults).
173
+ *
174
+ * Persistence (Task 6) mirrors the delete asynchronously, with errors
175
+ * routed to the logger — see `upsertLocation` for the rationale.
176
+ */
177
+ deleteLocation(id: string): void;
178
+ /**
179
+ * Remove system-seeded locations whose type is no longer declared by any
180
+ * addon (stale defaults from a removed location type). Operator-added
181
+ * (non-system) locations of an undeclared type are KEPT but warned — the
182
+ * operator owns them. Requires the registry to be set first.
183
+ *
184
+ * FAIL-SAFE: if the registry is EMPTY (no addon declared any location), we
185
+ * refuse to prune anything. An empty registry almost always means
186
+ * declarations failed to load (boot ordering, a stale install) — pruning
187
+ * "everything undeclared" in that state would wipe every system location
188
+ * (data/logs/recordings/…). Better to keep stale rows than destroy live ones.
189
+ */
190
+ pruneUndeclaredSystemLocations(): void;
191
+ /**
192
+ * Resolve a `StorageLocationRef` to a concrete `StorageLocation`.
193
+ * - bare type (e.g. `'backups'`) → default location of that type
194
+ * - fully-qualified id (e.g. `'backups:nas-01'`) → that exact instance
195
+ *
196
+ * Throws an actionable error when nothing matches — every consumer of
197
+ * the singleton `storage` cap funnels through here, so the error
198
+ * message is what operators see when the orchestrator's view of the
199
+ * world doesn't match expectations.
200
+ */
201
+ resolveRef(ref: StorageLocationRef): StorageLocation;
202
+ /**
203
+ * Find the storage-provider that backs a given location. Lookup is by
204
+ * `location.providerId` against `getProviderInfo().providerId` from
205
+ * each registered collection provider. Throws with both the missing
206
+ * providerId and the offending location id so the operator can pick
207
+ * the right place to fix the config.
208
+ */
209
+ getProviderFor(location: StorageLocation): Promise<IStorageProviderImpl>;
210
+ /** Convenience: lookup by id (returns `undefined` if not found). */
211
+ getLocationById(id: string): StorageLocation | undefined;
212
+ /**
213
+ * Seed one default `StorageLocation` per addon-declared location that
214
+ * doesn't already have one. Idempotent — re-running with the same
215
+ * declarations on a populated map is a no-op (each declared `id`
216
+ * already resolves to an existing `<id>:default`).
217
+ *
218
+ * Convention: the bare-type ref `'recordings'` resolves via
219
+ * `getDefaultLocation('recordings')` (walks `isDefault === true`); the
220
+ * actual stored `id` is `'recordings:default'` so it satisfies the
221
+ * `^[a-z][a-z0-9-]*:[a-z0-9-]+$` regex on `StorageLocationSchema.id`.
222
+ *
223
+ * `basePath` is the storage root (e.g. `<CAMSTACK_DATA>`). Each
224
+ * location's `config.basePath` is `<basePath>/<id>`, except when the
225
+ * declaration sets `defaultsTo` — then it inherits the resolved root of
226
+ * the referenced location's default instance (sharing the same root
227
+ * directory for derivative slots like `recordingsLow` → `recordings`).
228
+ */
229
+ seedDefaults(input: {
230
+ readonly providerId: string;
231
+ readonly basePath: string;
232
+ readonly declarations: readonly StorageLocationDeclaration[];
233
+ }): void;
234
+ /** Internal: check whether any location of the given type exists. */
235
+ private hasAnyLocationOfType;
236
+ }
@@ -0,0 +1,38 @@
1
+ import { IScopedLogger, IStorageEvictableProvider } from '@camstack/types';
2
+ /**
3
+ * StoragePressureManager — core-owned TRIGGER for disk-space relief.
4
+ *
5
+ * Monitors free space per managed location and, when a location drops below its
6
+ * `minFreePercent`, asks each registered `storage-evictable` provider to free a
7
+ * proportional share of the byte deficit. The PROVIDER decides what to delete
8
+ * and does the deletion — core never deletes data it doesn't understand. This
9
+ * makes disk-pressure one cross-consumer concern instead of per-addon guards.
10
+ *
11
+ * Convergence: a bounded round loop re-reads free% after each fan-out and stops
12
+ * when the location recovers, when nothing is evictable, or when a round makes
13
+ * no progress (every provider exhausted). Lossless feedback (`reclaimedBytes`)
14
+ * drives the stop condition; the addon re-runs `sweep()` on a timer so a partial
15
+ * relief finishes on the next tick.
16
+ */
17
+ export interface PressureManagerDeps {
18
+ readonly logger: IScopedLogger;
19
+ /** Free capacity (%) on the location's volume. */
20
+ readonly getFreePercent: (locationId: string) => Promise<number>;
21
+ /** Total bytes on the location's volume (to turn a deficit % into a byte target). */
22
+ readonly getVolumeTotalBytes: (locationId: string) => Promise<number>;
23
+ /** Registered `storage-evictable` providers (cross-process proxies). */
24
+ readonly getEvictableProviders: () => readonly IStorageEvictableProvider[];
25
+ /** locationId → minFreePercent threshold; entries with `<= 0` have the guard off. */
26
+ readonly getLocationThresholds: () => Promise<ReadonlyMap<string, number>>;
27
+ /** Max relief rounds per location per sweep (backstop, default 8). */
28
+ readonly maxRounds?: number;
29
+ /** Extra headroom % freed beyond the threshold to avoid re-breaching immediately (default 1). */
30
+ readonly hysteresisPercent?: number;
31
+ }
32
+ export declare class StoragePressureManager {
33
+ private readonly deps;
34
+ constructor(deps: PressureManagerDeps);
35
+ /** Relieve every managed location currently under its threshold. */
36
+ sweep(): Promise<void>;
37
+ private relieveLocation;
38
+ }
@@ -0,0 +1,137 @@
1
+ import { IScopedLogger } from '@camstack/types';
2
+ /**
3
+ * Default set of paths considered part of a "system backup". Includes
4
+ * everything that isn't pure backend code — config, sqlite, addons
5
+ * (runtime overlay), addons-data (per-addon private dir), TLS certs,
6
+ * auto-update marker.
7
+ *
8
+ * Excluded by default: recordings/, media/, models/, logs/, cache/
9
+ * (too large or fully recreatable).
10
+ */
11
+ export declare const DEFAULT_BACKUP_LOCATIONS: readonly ["config.yaml", "addons", "addons-data", "tls", "auto-update.json"];
12
+ /** Path of the manifest file embedded inside every archive. */
13
+ export declare const ARCHIVE_MANIFEST_NAME = ".camstack-backup-manifest.json";
14
+ export type ArchiveEntryKind = 'file' | 'dir' | 'symlink';
15
+ export interface ArchiveEntry {
16
+ /** Path relative to the archive root (== relative to dataDir). */
17
+ readonly path: string;
18
+ readonly kind: ArchiveEntryKind;
19
+ /** Content bytes. 0 for dirs / symlinks. */
20
+ readonly sizeBytes: number;
21
+ /** ms epoch from filesystem mtime. */
22
+ readonly mtime: number;
23
+ }
24
+ export interface ArchiveManifest {
25
+ archiveVersion: 1;
26
+ createdAt: number;
27
+ dataDir: string;
28
+ /**
29
+ * Mutable arrays — same shape as the zod-inferred type returned by
30
+ * `ArchiveManifestSchema.parse()`. `BaseAddon` providers receive
31
+ * this exact type via cap inputs, so making the interface readonly
32
+ * here would force callers to clone before forwarding.
33
+ */
34
+ locations: string[];
35
+ entries: ArchiveEntry[];
36
+ /** Sum of file `sizeBytes` (uncompressed). */
37
+ totalBytes: number;
38
+ totalFiles: number;
39
+ }
40
+ export interface CreateArchiveResult {
41
+ archivePath: string;
42
+ includedLocations: readonly string[];
43
+ /** Archive size in bytes (compressed, on disk). */
44
+ sizeBytes: number;
45
+ /** Embedded manifest — same shape as `getArchiveManifest()`. */
46
+ manifest: ArchiveManifest;
47
+ }
48
+ export interface RestoreMarker {
49
+ archivePath: string;
50
+ requestedAt: number;
51
+ /** Caller-supplied identifier (e.g. backup id) for traceability. */
52
+ source: string;
53
+ /**
54
+ * Optional whitelist of top-level locations to restore from the
55
+ * archive. When omitted the boot-time hook applies everything in
56
+ * the archive (full restore — same as the legacy behavior).
57
+ */
58
+ locations?: readonly string[];
59
+ }
60
+ export interface LocationStat {
61
+ readonly name: string;
62
+ readonly sizeBytes: number;
63
+ readonly fileCount: number;
64
+ /** False when the location doesn't exist under dataDir. */
65
+ readonly present: boolean;
66
+ }
67
+ /**
68
+ * System-level archive primitives. Construct one per server boot;
69
+ * methods are pure I/O.
70
+ */
71
+ export declare class SystemBackupService {
72
+ private readonly dataDir;
73
+ private readonly logger;
74
+ constructor(dataDir: string, logger: IScopedLogger);
75
+ /**
76
+ * Snapshot the current size + file count of each well-known
77
+ * location. Used by the admin UI to render an opt-in checklist
78
+ * before triggering a backup, and by `createArchive` to derive the
79
+ * embedded manifest.
80
+ */
81
+ statLocations(locations?: readonly string[]): readonly LocationStat[];
82
+ /**
83
+ * Create a tar.gz of the given locations. Uses the `tar` npm package
84
+ * (used by npm itself) instead of shelling out — gives us:
85
+ *
86
+ * - Symlink dereference (`follow: true`) so dev mode's
87
+ * `addons/<name> → packages/<name>` overlay archives content,
88
+ * not just link stubs.
89
+ * - Programmatic walk → we build a manifest of every entry while
90
+ * copying so the archive can self-describe.
91
+ *
92
+ * Locations that don't exist are silently skipped. Throws if zero
93
+ * locations would be included.
94
+ */
95
+ createArchive(opts: {
96
+ archivePath: string;
97
+ locations?: readonly string[];
98
+ }): Promise<CreateArchiveResult>;
99
+ /**
100
+ * Read the embedded manifest from a previously-created archive
101
+ * without extracting payload files. Streams the tar.gz, parses the
102
+ * one entry we care about, then aborts.
103
+ */
104
+ readArchiveManifest(archivePath: string): Promise<ArchiveManifest | null>;
105
+ /**
106
+ * Extract a previously-created archive over `targetDir`. Used at boot
107
+ * by the restore hook — never call from a running server (would
108
+ * corrupt sqlite mid-run).
109
+ *
110
+ * `locations` is an optional whitelist: only entries whose path
111
+ * starts with one of the locations get extracted. Used by the
112
+ * partial-restore flow where the operator picks a subset of the
113
+ * archive contents to apply (e.g. "restore my devices but keep
114
+ * my current TLS certs").
115
+ */
116
+ extractArchive(opts: {
117
+ archivePath: string;
118
+ targetDir: string;
119
+ locations?: readonly string[];
120
+ }): Promise<void>;
121
+ /**
122
+ * Schedule a restore for the next boot by writing a marker file.
123
+ * `locations` (optional) carries through to the boot-time
124
+ * extractArchive call so the operator's "restore only X and Y"
125
+ * choice survives the process restart.
126
+ */
127
+ scheduleRestoreMarker(opts: {
128
+ archivePath: string;
129
+ source: string;
130
+ locations?: readonly string[];
131
+ }): string;
132
+ /** Read the pending-restore marker if one is present. */
133
+ readPendingMarker(): RestoreMarker | null;
134
+ /** Drop the marker after a successful boot-time restore. */
135
+ clearPendingMarker(): void;
136
+ private getRestoreMarkerPath;
137
+ }
@@ -0,0 +1 @@
1
+ export { SystemConfigAddon, default } from './system-config.addon.js';
@@ -0,0 +1,8 @@
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ require("../../chunk-Cek0wNdY.js");
6
+ const require_builtins_system_config_system_config_addon = require("./system-config.addon.js");
7
+ exports.SystemConfigAddon = require_builtins_system_config_system_config_addon.SystemConfigAddon;
8
+ exports.default = require_builtins_system_config_system_config_addon.SystemConfigAddon;
@@ -0,0 +1,2 @@
1
+ import { SystemConfigAddon } from "./system-config.addon.mjs";
2
+ export { SystemConfigAddon, SystemConfigAddon as default };
@@ -0,0 +1,10 @@
1
+ import { ConfigUISchemaWithValues, BaseAddon } from '@camstack/types';
2
+ export declare class SystemConfigAddon extends BaseAddon {
3
+ readonly id = "system-config";
4
+ constructor();
5
+ protected onInitialize(): Promise<void>;
6
+ private buildGlobalSchema;
7
+ getGlobalSettings(): Promise<ConfigUISchemaWithValues>;
8
+ updateGlobalSettings(patch: Record<string, unknown>): Promise<void>;
9
+ }
10
+ export default SystemConfigAddon;
@@ -0,0 +1,232 @@
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ require("../../chunk-Cek0wNdY.js");
6
+ let _camstack_types = require("@camstack/types");
7
+ //#region src/builtins/system-config/system-config.addon.ts
8
+ /**
9
+ * Built-in `system-config` addon — Phase 4 of the settings redesign.
10
+ *
11
+ * Exposes the cluster-wide yml-backed sections that the bootstrap
12
+ * loader reads before any addon is instantiated — things that cannot
13
+ * live inside an addon because changing them requires a server
14
+ * restart (port, host, dataPath) or because they own no runtime
15
+ * state of their own (auth token expiry, global ffmpeg binary path).
16
+ *
17
+ * Sections exposed:
18
+ * - server (port, host, dataPath — READ-ONLY, loaded from config.yaml at bootstrap)
19
+ * - auth (tokenExpiry)
20
+ * - ffmpeg (binaryPath, hwAccel, threadCount)
21
+ *
22
+ * Sections NOT exposed (each owned by the addon that implements them):
23
+ * - logging → `winston-logging` addon (level + retention)
24
+ * - recording → `recording` addon (segment duration, retention)
25
+ * - retention → analytics / detection addons (per-table retention)
26
+ *
27
+ * Implementation notes:
28
+ * - Runs only on the hub process (yml sections are hub-side state).
29
+ * On agent nodes this addon would still instantiate, but every
30
+ * `ctx.settings.getSection(section)` call would hit an empty
31
+ * ConfigManager section so the UI would show the schema defaults.
32
+ * In practice the built-in loader can skip it on agents; for now we
33
+ * just let it run everywhere because it's harmless.
34
+ * - Reads via `ctx.settings.getSection(section)` and writes via
35
+ * `ctx.settings.setSection(section, patch)` — the explicit
36
+ * yml-section pair on `AddonSettingsApi`.
37
+ * - Does NOT register as a capability provider. It's a pure "settings
38
+ * surface" addon — its sole purpose is to expose the yml sections
39
+ * through the new three-level settings API.
40
+ *
41
+ * This addon is declared in `@camstack/system`'s package.json `camstack.addons[]`
42
+ * and loaded automatically via AddonLoader like any other core built-in.
43
+ */
44
+ /** Section key → user-facing section title. */
45
+ var SECTION_TITLES = {
46
+ server: "Server",
47
+ auth: "Authentication",
48
+ ffmpeg: "FFmpeg"
49
+ };
50
+ /** Keys that map 1:1 to a given yml section — used by `updateGlobalSettings`
51
+ * to figure out which section owns each key in the incoming patch. */
52
+ var KEY_TO_SECTION = {
53
+ port: "server",
54
+ host: "server",
55
+ dataPath: "server",
56
+ tokenExpiry: "auth",
57
+ binaryPath: "ffmpeg",
58
+ hwAccel: "ffmpeg",
59
+ threadCount: "ffmpeg"
60
+ };
61
+ var SystemConfigAddon = class extends _camstack_types.BaseAddon {
62
+ id = "system-config";
63
+ constructor() {
64
+ super({});
65
+ }
66
+ async onInitialize() {
67
+ this.ctx.logger.info("Initialized — exposes yml-backed sections via getGlobalSettings");
68
+ }
69
+ buildGlobalSchema() {
70
+ return { sections: [
71
+ {
72
+ id: "system-config-server",
73
+ title: SECTION_TITLES["server"],
74
+ description: "Core server connection settings — read-only, loaded from config.yaml at bootstrap.",
75
+ columns: 2,
76
+ fields: [
77
+ {
78
+ type: "info",
79
+ key: "server-restart-note",
80
+ label: "Restart required",
81
+ content: "Server settings are read-only. Change them in config.yaml and restart.",
82
+ variant: "warning"
83
+ },
84
+ {
85
+ type: "text",
86
+ key: "port",
87
+ label: "Port",
88
+ description: "Listening port",
89
+ disabled: true
90
+ },
91
+ {
92
+ type: "text",
93
+ key: "host",
94
+ label: "Host",
95
+ description: "Bind address",
96
+ disabled: true
97
+ },
98
+ {
99
+ type: "text",
100
+ key: "dataPath",
101
+ label: "Data Path",
102
+ description: "Root data directory",
103
+ disabled: true,
104
+ span: 2
105
+ }
106
+ ]
107
+ },
108
+ {
109
+ id: "system-config-auth",
110
+ title: SECTION_TITLES["auth"],
111
+ description: "Token and session settings.",
112
+ columns: 1,
113
+ fields: [{
114
+ type: "text",
115
+ key: "tokenExpiry",
116
+ label: "Token Expiry",
117
+ description: "JWT token lifetime (e.g. 24h, 7d, 1h)",
118
+ placeholder: "24h",
119
+ default: "24h"
120
+ }]
121
+ },
122
+ {
123
+ id: "system-config-ffmpeg",
124
+ title: SECTION_TITLES["ffmpeg"],
125
+ description: "FFmpeg binary and hardware acceleration settings.",
126
+ columns: 2,
127
+ fields: [
128
+ {
129
+ type: "text",
130
+ key: "binaryPath",
131
+ label: "Binary Path",
132
+ description: "Path to ffmpeg executable",
133
+ placeholder: "ffmpeg",
134
+ default: "ffmpeg",
135
+ span: 2
136
+ },
137
+ {
138
+ type: "select",
139
+ key: "hwAccel",
140
+ label: "Hardware Acceleration",
141
+ description: "GPU decoding/encoding backend",
142
+ default: "auto",
143
+ options: [
144
+ {
145
+ value: "auto",
146
+ label: "Auto-detect"
147
+ },
148
+ {
149
+ value: "none",
150
+ label: "None (CPU only)"
151
+ },
152
+ {
153
+ value: "videotoolbox",
154
+ label: "VideoToolbox (macOS)"
155
+ },
156
+ {
157
+ value: "vaapi",
158
+ label: "VA-API (Linux Intel/AMD)"
159
+ },
160
+ {
161
+ value: "qsv",
162
+ label: "QSV (Intel Quick Sync)"
163
+ },
164
+ {
165
+ value: "cuda",
166
+ label: "CUDA (NVIDIA)"
167
+ }
168
+ ]
169
+ },
170
+ {
171
+ type: "number",
172
+ key: "threadCount",
173
+ label: "Thread Count",
174
+ description: "0 = auto (let FFmpeg decide)",
175
+ min: 0,
176
+ max: 16,
177
+ step: 1,
178
+ default: 0
179
+ }
180
+ ]
181
+ }
182
+ ] };
183
+ }
184
+ async getGlobalSettings() {
185
+ const schema = this.buildGlobalSchema();
186
+ if (!this.ctx.settings) return (0, _camstack_types.hydrateSchema)(schema, {});
187
+ const sectionNames = Object.keys(SECTION_TITLES);
188
+ const merged = {};
189
+ for (const section of sectionNames) try {
190
+ const values = await this.ctx.settings.getSection(section);
191
+ Object.assign(merged, values);
192
+ } catch (err) {
193
+ const msg = (0, _camstack_types.errMsg)(err);
194
+ this.ctx.logger.debug("Failed to read section", { meta: {
195
+ section,
196
+ error: msg
197
+ } });
198
+ }
199
+ return (0, _camstack_types.hydrateSchema)(schema, merged);
200
+ }
201
+ async updateGlobalSettings(patch) {
202
+ if (!this.ctx.settings) throw new Error("system-config: ctx.settings not available — cannot write sections");
203
+ const perSection = /* @__PURE__ */ new Map();
204
+ for (const [key, value] of Object.entries(patch)) {
205
+ const section = KEY_TO_SECTION[key];
206
+ if (section === void 0) {
207
+ this.ctx.logger.warn("update ignored unknown key (not mapped to any section)", { meta: { key } });
208
+ continue;
209
+ }
210
+ if (section === "server") {
211
+ this.ctx.logger.warn("update ignored read-only server-section key", { meta: { key } });
212
+ continue;
213
+ }
214
+ let bucket = perSection.get(section);
215
+ if (!bucket) {
216
+ bucket = {};
217
+ perSection.set(section, bucket);
218
+ }
219
+ bucket[key] = value;
220
+ }
221
+ for (const [section, sectionPatch] of perSection) {
222
+ await this.ctx.settings.setSection(section, sectionPatch);
223
+ this.ctx.logger.info("Wrote keys to section", { meta: {
224
+ section,
225
+ keyCount: Object.keys(sectionPatch).length
226
+ } });
227
+ }
228
+ }
229
+ };
230
+ //#endregion
231
+ exports.SystemConfigAddon = SystemConfigAddon;
232
+ exports.default = SystemConfigAddon;