@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.
- package/dist/addon/addon-api-factory.d.ts +35 -0
- package/dist/addon-routes/addon-route-registry.d.ts +37 -0
- package/dist/addon-runner.js +599 -0
- package/dist/addon-runner.mjs +597 -0
- package/dist/auth/api-key-manager.d.ts +26 -0
- package/dist/auth/auth-manager.d.ts +109 -0
- package/dist/auth/parse-record.d.ts +18 -0
- package/dist/auth/scope-matcher.d.ts +7 -0
- package/dist/auth/scoped-token-manager.d.ts +40 -0
- package/dist/auth/totp-manager.d.ts +51 -0
- package/dist/auth/user-manager.d.ts +34 -0
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.d.ts +53 -0
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +259 -0
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +251 -0
- package/dist/builtins/addon-pages-aggregator/dedupe-pages.d.ts +6 -0
- package/dist/builtins/addon-pages-aggregator/index.d.ts +1 -0
- package/dist/builtins/addon-pages-aggregator/index.js +8 -0
- package/dist/builtins/addon-pages-aggregator/index.mjs +2 -0
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.d.ts +47 -0
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +228 -0
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +220 -0
- package/dist/builtins/addon-widgets-aggregator/index.d.ts +1 -0
- package/dist/builtins/addon-widgets-aggregator/index.js +8 -0
- package/dist/builtins/addon-widgets-aggregator/index.mjs +2 -0
- package/dist/builtins/alerts/alerts.addon.d.ts +81 -0
- package/dist/builtins/alerts/alerts.addon.js +601 -0
- package/dist/builtins/alerts/alerts.addon.mjs +595 -0
- package/dist/builtins/alerts/index.d.ts +1 -0
- package/dist/builtins/alerts/index.js +4 -0
- package/dist/builtins/alerts/index.mjs +2 -0
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts +147 -0
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2229 -0
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2220 -0
- package/dist/builtins/backup-orchestrator/cron-helpers.d.ts +23 -0
- package/dist/builtins/backup-orchestrator/destination-policy.d.ts +72 -0
- package/dist/builtins/backup-orchestrator/download-helpers.d.ts +12 -0
- package/dist/builtins/backup-orchestrator/index.d.ts +2 -0
- package/dist/builtins/backup-orchestrator/index.js +8 -0
- package/dist/builtins/backup-orchestrator/index.mjs +2 -0
- package/dist/builtins/backup-orchestrator/manifest-store.d.ts +77 -0
- package/dist/builtins/console-logging/console-destination.d.ts +13 -0
- package/dist/builtins/console-logging/console-logging.addon.d.ts +25 -0
- package/dist/builtins/console-logging/index.d.ts +3 -0
- package/dist/builtins/console-logging/index.js +104 -0
- package/dist/builtins/console-logging/index.mjs +95 -0
- package/dist/builtins/device-manager/device-config-contribution.d.ts +32 -0
- package/dist/builtins/device-manager/device-event-propagator.d.ts +26 -0
- package/dist/builtins/device-manager/device-link-overlay.d.ts +23 -0
- package/dist/builtins/device-manager/device-link-resolver.d.ts +15 -0
- package/dist/builtins/device-manager/device-manager.addon.d.ts +452 -0
- package/dist/builtins/device-manager/device-manager.addon.js +3299 -0
- package/dist/builtins/device-manager/device-manager.addon.mjs +3292 -0
- package/dist/builtins/device-manager/index.d.ts +2 -0
- package/dist/builtins/device-manager/index.js +8 -0
- package/dist/builtins/device-manager/index.mjs +2 -0
- package/dist/builtins/hub-forwarder/hub-forwarder-destination.d.ts +44 -0
- package/dist/builtins/hub-forwarder/hub-forwarder.addon.d.ts +15 -0
- package/dist/builtins/hub-forwarder/index.d.ts +3 -0
- package/dist/builtins/hub-forwarder/index.js +154 -0
- package/dist/builtins/hub-forwarder/index.mjs +145 -0
- package/dist/builtins/local-auth/auth-schema.d.ts +26 -0
- package/dist/builtins/local-auth/index.d.ts +1 -0
- package/dist/builtins/local-auth/index.js +4 -0
- package/dist/builtins/local-auth/index.mjs +2 -0
- package/dist/builtins/local-auth/local-auth.addon.d.ts +18 -0
- package/dist/builtins/local-auth/local-auth.addon.js +8094 -0
- package/dist/builtins/local-auth/local-auth.addon.mjs +8063 -0
- package/dist/builtins/local-auth/oauth-grants.d.ts +45 -0
- package/dist/builtins/local-auth/oauth-session-manager.d.ts +50 -0
- package/dist/builtins/local-network/index.d.ts +2 -0
- package/dist/builtins/local-network/index.js +10 -0
- package/dist/builtins/local-network/index.mjs +2 -0
- package/dist/builtins/local-network/local-network.addon.d.ts +150 -0
- package/dist/builtins/local-network/local-network.addon.js +489 -0
- package/dist/builtins/local-network/local-network.addon.mjs +477 -0
- package/dist/builtins/native-metrics/index.d.ts +2 -0
- package/dist/builtins/native-metrics/native-metrics-provider.d.ts +48 -0
- package/dist/builtins/native-metrics/native-metrics.addon.d.ts +73 -0
- package/dist/builtins/native-metrics/native-metrics.addon.js +922 -0
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +914 -0
- package/dist/builtins/platform-probe/hardware-decode-accel-probe.d.ts +37 -0
- package/dist/builtins/platform-probe/hardware-encoder-probe.d.ts +13 -0
- package/dist/builtins/platform-probe/index.d.ts +22 -0
- package/dist/builtins/platform-probe/index.js +834 -0
- package/dist/builtins/platform-probe/index.mjs +822 -0
- package/dist/builtins/platform-probe/inference-config-resolver.d.ts +29 -0
- package/dist/builtins/platform-probe/intel-accelerators.d.ts +11 -0
- package/dist/builtins/platform-probe/platform-scorer.d.ts +30 -0
- package/dist/builtins/platform-probe/runtime-packages.d.ts +6 -0
- package/dist/builtins/remote-access-orchestrator/enabled-providers-reconcile.d.ts +96 -0
- package/dist/builtins/remote-access-orchestrator/index.d.ts +1 -0
- package/dist/builtins/remote-access-orchestrator/index.js +8 -0
- package/dist/builtins/remote-access-orchestrator/index.mjs +2 -0
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.d.ts +40 -0
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +214 -0
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +208 -0
- package/dist/builtins/shared/settle-sources.d.ts +22 -0
- package/dist/builtins/snapshot/index.d.ts +2 -0
- package/dist/builtins/snapshot/index.js +494 -0
- package/dist/builtins/snapshot/index.mjs +488 -0
- package/dist/builtins/snapshot/snapshot.addon.d.ts +120 -0
- package/dist/builtins/sqlite-storage/config-store.d.ts +8 -0
- package/dist/builtins/sqlite-storage/device-store.d.ts +23 -0
- package/dist/builtins/sqlite-storage/filesystem-browse-provider.d.ts +25 -0
- package/dist/builtins/sqlite-storage/filesystem-storage-provider.d.ts +83 -0
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.d.ts +32 -0
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +396 -0
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +388 -0
- package/dist/builtins/sqlite-storage/index.d.ts +8 -0
- package/dist/builtins/sqlite-storage/index.js +62 -0
- package/dist/builtins/sqlite-storage/index.mjs +49 -0
- package/dist/builtins/sqlite-storage/integration-registry.d.ts +27 -0
- package/dist/builtins/sqlite-storage/path-guard.d.ts +4 -0
- package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +102 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +14 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +644 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +636 -0
- package/dist/builtins/storage-orchestrator/index.d.ts +6 -0
- package/dist/builtins/storage-orchestrator/index.js +10 -0
- package/dist/builtins/storage-orchestrator/index.mjs +2 -0
- package/dist/builtins/storage-orchestrator/location-store.d.ts +49 -0
- package/dist/builtins/storage-orchestrator/provider-discovery.d.ts +10 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +103 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1138 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1128 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.service.d.ts +236 -0
- package/dist/builtins/storage-orchestrator/storage-pressure-manager.d.ts +38 -0
- package/dist/builtins/system-backup/system-backup.service.d.ts +137 -0
- package/dist/builtins/system-config/index.d.ts +1 -0
- package/dist/builtins/system-config/index.js +8 -0
- package/dist/builtins/system-config/index.mjs +2 -0
- package/dist/builtins/system-config/system-config.addon.d.ts +10 -0
- package/dist/builtins/system-config/system-config.addon.js +232 -0
- package/dist/builtins/system-config/system-config.addon.mjs +226 -0
- package/dist/builtins/winston-logging/index.d.ts +3 -0
- package/dist/builtins/winston-logging/index.js +156 -0
- package/dist/builtins/winston-logging/index.mjs +144 -0
- package/dist/builtins/winston-logging/winston-destination.d.ts +21 -0
- package/dist/builtins/winston-logging/winston-logging.addon.d.ts +19 -0
- package/dist/chunk-CNf5ZN-e.mjs +37 -0
- package/dist/chunk-Cek0wNdY.js +64 -0
- package/dist/download/model-download-service.d.ts +41 -0
- package/dist/download/model-downloader.d.ts +31 -0
- package/dist/events/event-bus.d.ts +10 -0
- package/dist/events/system-event-bus.d.ts +14 -0
- package/dist/feature/feature-manager.d.ts +11 -0
- package/dist/formatter-B7qW8bPJ.mjs +162 -0
- package/dist/formatter-DqAKDlvN.js +167 -0
- package/dist/http/authenticated-file-server.d.ts +53 -0
- package/dist/http/data-plane-registry.d.ts +23 -0
- package/dist/http/file-data-plane.d.ts +10 -0
- package/dist/http/reverse-proxy.d.ts +15 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.js +93485 -0
- package/dist/index.mjs +93179 -0
- package/dist/intel-accelerators-Gg0P5mnl.js +20 -0
- package/dist/intel-accelerators-hGgpZ0pX.mjs +19 -0
- package/dist/kernel/addon-class-resolver.d.ts +4 -0
- package/dist/kernel/addon-engine-manager.d.ts +22 -0
- package/dist/kernel/addon-health-monitor.d.ts +154 -0
- package/dist/kernel/addon-installer.d.ts +208 -0
- package/dist/kernel/addon-loader.d.ts +106 -0
- package/dist/kernel/addon-manifest.d.ts +77 -0
- package/dist/kernel/capability-handle.d.ts +46 -0
- package/dist/kernel/capability-registry.d.ts +412 -0
- package/dist/kernel/config-manager.d.ts +212 -0
- package/dist/kernel/config-schema.d.ts +93 -0
- package/dist/kernel/custom-action-registry.d.ts +23 -0
- package/dist/kernel/deps/addon-deps-manager.d.ts +19 -0
- package/dist/kernel/deps/manifest-native-deps.d.ts +25 -0
- package/dist/kernel/deps/manifest-python-deps.d.ts +20 -0
- package/dist/kernel/device-registry.d.ts +29 -0
- package/dist/kernel/fs-utils.d.ts +41 -0
- package/dist/kernel/hwaccel/hwaccel-resolver.d.ts +19 -0
- package/dist/kernel/hwaccel/hwaccel-service.d.ts +4 -0
- package/dist/kernel/index.d.ts +74 -0
- package/dist/kernel/infra-capabilities.d.ts +13 -0
- package/dist/kernel/moleculer/addon-context-factory.d.ts +91 -0
- package/dist/kernel/moleculer/addon-data-plane-facility.d.ts +19 -0
- package/dist/kernel/moleculer/addon-runner.d.ts +1 -0
- package/dist/kernel/moleculer/addon-service-factory.d.ts +50 -0
- package/dist/kernel/moleculer/broker-factory.d.ts +50 -0
- package/dist/kernel/moleculer/cap-usage-registry.d.ts +46 -0
- package/dist/kernel/moleculer/capabilities-access.d.ts +21 -0
- package/dist/kernel/moleculer/child-addon-call-dispatch.d.ts +46 -0
- package/dist/kernel/moleculer/child-cap-dispatch.d.ts +20 -0
- package/dist/kernel/moleculer/cluster-secret.d.ts +15 -0
- package/dist/kernel/moleculer/core-cap-service.d.ts +50 -0
- package/dist/kernel/moleculer/crash-supervisor.d.ts +50 -0
- package/dist/kernel/moleculer/device-cap-proxy.d.ts +79 -0
- package/dist/kernel/moleculer/event-bus-core.d.ts +53 -0
- package/dist/kernel/moleculer/event-bus.d.ts +53 -0
- package/dist/kernel/moleculer/hub-log-forwarder.d.ts +36 -0
- package/dist/kernel/moleculer/hub-service.d.ts +35 -0
- package/dist/kernel/moleculer/node-registry.d.ts +126 -0
- package/dist/kernel/moleculer/process-context.d.ts +4 -0
- package/dist/kernel/moleculer/process-service.d.ts +72 -0
- package/dist/kernel/moleculer/provider-registry.d.ts +28 -0
- package/dist/kernel/moleculer/readiness-context.d.ts +62 -0
- package/dist/kernel/moleculer/readiness-service.d.ts +7 -0
- package/dist/kernel/moleculer/register-node-client.d.ts +35 -0
- package/dist/kernel/moleculer/remote-logger.d.ts +43 -0
- package/dist/kernel/moleculer/resilient-cap-call.d.ts +28 -0
- package/dist/kernel/moleculer/stream-probe-service.d.ts +9 -0
- package/dist/kernel/moleculer/trpc-links.d.ts +189 -0
- package/dist/kernel/moleculer/typed-array-serde.d.ts +25 -0
- package/dist/kernel/moleculer/worker-device-restore.d.ts +10 -0
- package/dist/kernel/provider-kind-drift.d.ts +12 -0
- package/dist/kernel/restart-coordinator.d.ts +90 -0
- package/dist/kernel/storage-location-registry.d.ts +40 -0
- package/dist/kernel/transport/cap-action-name.d.ts +100 -0
- package/dist/kernel/transport/cap-route-resolver.d.ts +148 -0
- package/dist/kernel/transport/cap-route.d.ts +148 -0
- package/dist/kernel/transport/child-cap-protocol.d.ts +136 -0
- package/dist/kernel/transport/create-local-transport.d.ts +7 -0
- package/dist/kernel/transport/frame-codec.d.ts +7 -0
- package/dist/kernel/transport/index.d.ts +27 -0
- package/dist/kernel/transport/local-child-client.d.ts +136 -0
- package/dist/kernel/transport/local-child-registry.d.ts +179 -0
- package/dist/kernel/transport/local-endpoint-path.d.ts +6 -0
- package/dist/kernel/transport/local-transport.d.ts +46 -0
- package/dist/kernel/transport/parent-unowned-call.d.ts +75 -0
- package/dist/kernel/transport/socket-channel.d.ts +27 -0
- package/dist/kernel/transport/uds-event-bridge.d.ts +36 -0
- package/dist/kernel/transport/uds-event-bus.d.ts +22 -0
- package/dist/kernel/transport/uds-local-transport.d.ts +18 -0
- package/dist/kernel/transport/uds-log-ingest.d.ts +28 -0
- package/dist/kernel/transport/uds-logger.d.ts +44 -0
- package/dist/kernel/utils/ring-buffer.d.ts +15 -0
- package/dist/kernel/workspace-detect.d.ts +9 -0
- package/dist/lifecycle/lifecycle-state-machine.d.ts +28 -0
- package/dist/logging/formatter.d.ts +30 -0
- package/dist/logging/log-manager.d.ts +54 -0
- package/dist/logging/log-ring-buffer.d.ts +47 -0
- package/dist/logging/partitioned-log-buffer.d.ts +35 -0
- package/dist/logging/scoped-logger.d.ts +17 -0
- package/dist/main-DNnMW7Z2.js +9983 -0
- package/dist/main-rtjOwPBR.mjs +9976 -0
- package/dist/manifest-python-deps-D1DbAQEv.js +6724 -0
- package/dist/manifest-python-deps-DZsKTbs1.mjs +6315 -0
- package/dist/network/network-quality.d.ts +11 -0
- package/dist/notification/notification-service.d.ts +37 -0
- package/dist/notification/toast-service.d.ts +22 -0
- package/dist/pipeline/engine-manager-resolver.d.ts +15 -0
- package/dist/pipeline/pipeline-runner.d.ts +8 -0
- package/dist/pipeline/pipeline-validator.d.ts +13 -0
- package/dist/process/resource-monitor.d.ts +11 -0
- package/dist/python/python-env-manager.d.ts +12 -0
- package/dist/repl/interfaces.d.ts +31 -0
- package/dist/repl/repl-engine.d.ts +8 -0
- package/dist/resource-monitor-ClDGFyf6.mjs +57 -0
- package/dist/resource-monitor-IIEanuJt.js +74 -0
- package/dist/settle-sources-Bhsy57y-.js +38 -0
- package/dist/settle-sources-CDtNC8ub.mjs +33 -0
- package/dist/storage/fs-storage-backend.d.ts +40 -0
- package/dist/storage/storage-location-manager.d.ts +23 -0
- package/dist/storage/storage-manager.d.ts +83 -0
- package/dist/tar-BgAEMRBR.js +5434 -0
- package/dist/tar-ByMOPNM0.mjs +5429 -0
- package/dist/tls/cert-manager.d.ts +26 -0
- package/dist/tls/index.d.ts +1 -0
- 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,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;
|