@camstack/core 0.1.14 → 0.1.15
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/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +220 -0
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js.map +1 -0
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +9 -0
- package/dist/builtins/addon-pages-aggregator/index.js +222 -0
- package/dist/builtins/addon-pages-aggregator/index.js.map +1 -0
- package/dist/builtins/addon-pages-aggregator/index.mjs +9 -0
- package/dist/builtins/addon-pages-aggregator/index.mjs.map +1 -0
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +200 -0
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js.map +1 -0
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +9 -0
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs.map +1 -0
- package/dist/builtins/addon-widgets-aggregator/index.js +202 -0
- package/dist/builtins/addon-widgets-aggregator/index.js.map +1 -0
- package/dist/builtins/addon-widgets-aggregator/index.mjs +9 -0
- package/dist/builtins/addon-widgets-aggregator/index.mjs.map +1 -0
- package/dist/builtins/alerts/alerts.addon.js +443 -0
- package/dist/builtins/alerts/alerts.addon.js.map +1 -0
- package/dist/builtins/alerts/alerts.addon.mjs +9 -0
- package/dist/builtins/alerts/alerts.addon.mjs.map +1 -0
- package/dist/builtins/alerts/index.js +443 -0
- package/dist/builtins/alerts/index.js.map +1 -0
- package/dist/builtins/alerts/index.mjs +8 -0
- package/dist/builtins/alerts/index.mjs.map +1 -0
- package/dist/builtins/console-logging/index.js +242 -0
- package/dist/builtins/console-logging/index.js.map +1 -0
- package/dist/builtins/console-logging/index.mjs +11 -0
- package/dist/builtins/console-logging/index.mjs.map +1 -0
- package/dist/builtins/device-manager/device-manager.addon.js +2155 -0
- package/dist/builtins/device-manager/device-manager.addon.js.map +1 -0
- package/dist/builtins/device-manager/device-manager.addon.mjs +9 -0
- package/dist/builtins/device-manager/device-manager.addon.mjs.map +1 -0
- package/dist/builtins/device-manager/index.js +2157 -0
- package/dist/builtins/device-manager/index.js.map +1 -0
- package/dist/builtins/device-manager/index.mjs +10 -0
- package/dist/builtins/device-manager/index.mjs.map +1 -0
- package/dist/builtins/hub-forwarder/index.js +297 -0
- package/dist/builtins/hub-forwarder/index.js.map +1 -0
- package/dist/builtins/hub-forwarder/index.mjs +11 -0
- package/dist/builtins/hub-forwarder/index.mjs.map +1 -0
- package/dist/builtins/local-auth/index.js +623 -0
- package/dist/builtins/local-auth/index.js.map +1 -0
- package/dist/builtins/local-auth/index.mjs +8 -0
- package/dist/builtins/local-auth/index.mjs.map +1 -0
- package/dist/builtins/local-auth/local-auth.addon.js +623 -0
- package/dist/builtins/local-auth/local-auth.addon.js.map +1 -0
- package/dist/builtins/local-auth/local-auth.addon.mjs +9 -0
- package/dist/builtins/local-auth/local-auth.addon.mjs.map +1 -0
- package/dist/builtins/local-backup/index.js +53 -68
- package/dist/builtins/local-backup/index.js.map +1 -1
- package/dist/builtins/local-backup/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +898 -0
- package/dist/builtins/native-metrics/native-metrics.addon.js.map +1 -0
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +7 -0
- package/dist/builtins/native-metrics/native-metrics.addon.mjs.map +1 -0
- package/dist/builtins/snapshot/index.js +504 -0
- package/dist/builtins/snapshot/index.js.map +1 -0
- package/dist/builtins/snapshot/index.mjs +477 -0
- package/dist/builtins/snapshot/index.mjs.map +1 -0
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +16 -166
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js.map +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/index.js +554 -621
- package/dist/builtins/sqlite-storage/index.js.map +1 -1
- package/dist/builtins/sqlite-storage/index.mjs +9 -11
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +368 -130
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js.map +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +1 -1
- package/dist/builtins/system-config/index.js +189 -0
- package/dist/builtins/system-config/index.js.map +1 -0
- package/dist/builtins/system-config/index.mjs +10 -0
- package/dist/builtins/system-config/index.mjs.map +1 -0
- package/dist/builtins/system-config/system-config.addon.js +187 -0
- package/dist/builtins/system-config/system-config.addon.js.map +1 -0
- package/dist/builtins/system-config/system-config.addon.mjs +9 -0
- package/dist/builtins/system-config/system-config.addon.mjs.map +1 -0
- package/dist/builtins/winston-logging/index.js +185 -65
- package/dist/builtins/winston-logging/index.js.map +1 -1
- package/dist/builtins/winston-logging/index.mjs +2 -1
- package/dist/chunk-2CIYKDRN.mjs +1 -0
- package/dist/chunk-2CIYKDRN.mjs.map +1 -0
- package/dist/chunk-2F76X6NL.mjs +136 -0
- package/dist/chunk-2F76X6NL.mjs.map +1 -0
- package/dist/chunk-2QUFBZ7M.mjs +1 -0
- package/dist/chunk-2QUFBZ7M.mjs.map +1 -0
- package/dist/chunk-3BK2Y7GY.mjs +593 -0
- package/dist/chunk-3BK2Y7GY.mjs.map +1 -0
- package/dist/chunk-4OOHFJHT.mjs +421 -0
- package/dist/chunk-4OOHFJHT.mjs.map +1 -0
- package/dist/chunk-4XHB7IHT.mjs +809 -0
- package/dist/chunk-4XHB7IHT.mjs.map +1 -0
- package/dist/{chunk-2F3XZYRW.mjs → chunk-6M2HSSTQ.mjs} +16 -7
- package/dist/chunk-6M2HSSTQ.mjs.map +1 -0
- package/dist/{chunk-SO4LROOT.mjs → chunk-7FI7SQS7.mjs} +54 -69
- package/dist/chunk-7FI7SQS7.mjs.map +1 -0
- package/dist/chunk-ED57RCQE.mjs +171 -0
- package/dist/chunk-ED57RCQE.mjs.map +1 -0
- package/dist/chunk-FZN56HGQ.mjs +626 -0
- package/dist/chunk-FZN56HGQ.mjs.map +1 -0
- package/dist/chunk-GL4OOB25.mjs +51 -0
- package/dist/chunk-GL4OOB25.mjs.map +1 -0
- package/dist/chunk-KDG2NTDB.mjs +137 -0
- package/dist/chunk-KDG2NTDB.mjs.map +1 -0
- package/dist/chunk-NRBQWBDM.mjs +191 -0
- package/dist/chunk-NRBQWBDM.mjs.map +1 -0
- package/dist/chunk-O4V246GG.mjs +2137 -0
- package/dist/chunk-O4V246GG.mjs.map +1 -0
- package/dist/chunk-QT57H266.mjs +163 -0
- package/dist/chunk-QT57H266.mjs.map +1 -0
- package/dist/chunk-QX4RH25I.mjs +141 -0
- package/dist/chunk-QX4RH25I.mjs.map +1 -0
- package/dist/chunk-TB562PZX.mjs +86 -0
- package/dist/chunk-TB562PZX.mjs.map +1 -0
- package/dist/chunk-TDYPZXK5.mjs +1 -0
- package/dist/chunk-TDYPZXK5.mjs.map +1 -0
- package/dist/chunk-UJI4LN5P.mjs +36 -0
- package/dist/chunk-UJI4LN5P.mjs.map +1 -0
- package/dist/chunk-W6RTHQGP.mjs +1 -0
- package/dist/chunk-W6RTHQGP.mjs.map +1 -0
- package/dist/chunk-ZELBCPDC.mjs +369 -0
- package/dist/chunk-ZELBCPDC.mjs.map +1 -0
- package/dist/index.d.mts +1103 -544
- package/dist/index.d.ts +1103 -544
- package/dist/index.js +7032 -6033
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +568 -2226
- package/dist/index.mjs.map +1 -1
- package/dist/resource-monitor-UZUGPIAU.mjs +9 -0
- package/dist/resource-monitor-UZUGPIAU.mjs.map +1 -0
- package/dist/storage-location-manager-HFNB3PCS.mjs +7 -0
- package/dist/storage-location-manager-HFNB3PCS.mjs.map +1 -0
- package/package.json +123 -2
- package/dist/builtins/local-backup/index.d.mts +0 -42
- package/dist/builtins/local-backup/index.d.ts +0 -42
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.d.mts +0 -2
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.d.ts +0 -2
- package/dist/builtins/sqlite-storage/index.d.mts +0 -4
- package/dist/builtins/sqlite-storage/index.d.ts +0 -4
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.mts +0 -2
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +0 -2
- package/dist/builtins/winston-logging/index.d.mts +0 -30
- package/dist/builtins/winston-logging/index.d.ts +0 -30
- package/dist/chunk-2F3XZYRW.mjs.map +0 -1
- package/dist/chunk-LQFPAEQF.mjs +0 -147
- package/dist/chunk-LQFPAEQF.mjs.map +0 -1
- package/dist/chunk-R3DIIBBX.mjs +0 -532
- package/dist/chunk-R3DIIBBX.mjs.map +0 -1
- package/dist/chunk-SMNR44VG.mjs +0 -386
- package/dist/chunk-SMNR44VG.mjs.map +0 -1
- package/dist/chunk-SO4LROOT.mjs.map +0 -1
- package/dist/chunk-SPA4JBKN.mjs +0 -175
- package/dist/chunk-SPA4JBKN.mjs.map +0 -1
- package/dist/dist-3BY63UQ5.mjs +0 -2151
- package/dist/dist-3BY63UQ5.mjs.map +0 -1
- package/dist/filesystem-storage.addon-C42r589X.d.mts +0 -57
- package/dist/filesystem-storage.addon-C42r589X.d.ts +0 -57
- package/dist/sql-schema-CKz78rId.d.mts +0 -97
- package/dist/sql-schema-CKz78rId.d.ts +0 -97
- package/dist/sqlite-settings.addon-KwG-uKMP.d.mts +0 -79
- package/dist/sqlite-settings.addon-KwG-uKMP.d.ts +0 -79
- package/dist/storage-location-manager-KKDQNAKA.mjs +0 -7
- /package/dist/{storage-location-manager-KKDQNAKA.mjs.map → builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs.map} +0 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,71 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { FilesystemStorageProvider } from '@camstack/types/node';
|
|
2
|
+
export { FilesystemStorageProvider, PYTHON_VERSION, PlatformInfo, buildBinaryPath, downloadBinary, ensureBinary, ensureFfmpeg, ensurePython, findInPath, getFfmpegDownloadUrl, getPlatformInfo, getPythonDownloadUrl, installPythonPackages, installPythonRequirements } from '@camstack/types/node';
|
|
3
|
+
import * as _camstack_types from '@camstack/types';
|
|
4
|
+
import { ModelCatalogEntry, ModelFormat, ModelDownloadOptions, ModelDownloadResult, IAddonModelManager, IPythonEnvironment, PythonProbeResult, PythonEnvReady, PipelineConfig, ValidationResult, IAddonResolver, FrameInput, PipelineResult, IEngineManager, IAddonCaller, INetworkQualityTracker, ClientNetworkStats, DeviceNetworkStats, ReplResult, BaseAddon, ProviderRegistration, ISettingsBackend, SettingsGetInput, SettingsSetInput, SettingsQueryInput, SettingsRecord, SettingsInsertInput, SettingsUpdateInput, SettingsDeleteInput, SettingsCountInput, SettingsIsEmptyInput, CollectionColumn, CollectionIndex, TableSchema, TableQueryOptions, ILogDestination as ILogDestination$1, LogEntry, LogFilter, IScopedLogger, IClusterBroker, IEventBus, BackupManifest, Alert, SystemResourceSnapshot, DiskSpaceInfo, MetricsGpuInfo, PidResourceStats, MemoryInfo, ConfigUISchemaWithValues, DeviceBindingEntry, FeatureManifest, FeatureFlag, SystemEvent, EventFilter, LogTags, LogExtras, IStorageProvider as IStorageProvider$1, SettingsStoreClient, TokenScope, ScopedToken, TokenPayload, UserRole, ApiKeyRecord, UserRecord, ICapabilityRegistry, INotificationOutput, Notification, Toast, IAddonRouteProvider, IAddonHttpRoute, IIntegrationRegistry, CreateIntegrationInput, Integration, CreateDeviceInput, PersistedDevice } from '@camstack/types';
|
|
5
|
+
export { ApiKeyRecord, BackupManifest, ClientNetworkStats, DeviceNetworkStats, EventFilter, EventSource, FeatureFlag, FeatureManifest, INetworkQualityTracker, IScopedLogger, LogEntry, LogFilter, LogLevel, ReplResult, StreamNetworkStats, SystemEvent, TokenPayload, UserRecord, UserRole, ValidationIssue, ValidationResult } from '@camstack/types';
|
|
3
6
|
import { ChildProcess } from 'node:child_process';
|
|
4
|
-
import
|
|
5
|
-
export { A as AddonTableSchema, C as CORE_TABLE_DDL, F as FileSystemStorage, S as SettingsStore, a as SqliteStorageAddon, b as SqliteStorageProvider, c as addonTableToDdl } from './sql-schema-CKz78rId.js';
|
|
6
|
-
export { WinstonDestination, WinstonLoggingAddon } from './builtins/winston-logging/index.js';
|
|
7
|
-
export { BackupConfig, LocalBackupAddon, LocalBackupService } from './builtins/local-backup/index.js';
|
|
8
|
-
|
|
9
|
-
interface PlatformInfo {
|
|
10
|
-
readonly platform: NodeJS.Platform;
|
|
11
|
-
readonly arch: NodeJS.Architecture;
|
|
12
|
-
}
|
|
13
|
-
declare function getPlatformInfo(): PlatformInfo;
|
|
14
|
-
declare function buildBinaryPath(dataDir: string, name: string, platform?: string): string;
|
|
15
|
-
/** Check if a binary exists in PATH */
|
|
16
|
-
declare function findInPath(name: string): string | null;
|
|
17
|
-
interface DownloadOptions {
|
|
18
|
-
readonly name: string;
|
|
19
|
-
readonly url: string;
|
|
20
|
-
readonly targetDir: string;
|
|
21
|
-
readonly targetName: string;
|
|
22
|
-
readonly logger: IScopedLogger;
|
|
23
|
-
readonly isArchive?: boolean;
|
|
24
|
-
readonly archiveFormat?: 'zip' | 'tar.gz' | 'tar.xz';
|
|
25
|
-
/** Relative path within archive to the binary (e.g., 'ffmpeg-6.1/bin/ffmpeg') */
|
|
26
|
-
readonly archiveInnerPath?: string;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Download a binary to the target directory.
|
|
30
|
-
* Handles archives (zip, tar.gz, tar.xz) and raw binaries.
|
|
31
|
-
*/
|
|
32
|
-
declare function downloadBinary(opts: DownloadOptions): Promise<string>;
|
|
33
|
-
/**
|
|
34
|
-
* Ensure a binary is available. Checks:
|
|
35
|
-
* 1. Target path (already downloaded)
|
|
36
|
-
* 2. System PATH
|
|
37
|
-
* 3. Download from URL
|
|
38
|
-
*/
|
|
39
|
-
declare function ensureBinary(opts: {
|
|
40
|
-
readonly name: string;
|
|
41
|
-
readonly targetDir: string;
|
|
42
|
-
readonly downloadUrl: string;
|
|
43
|
-
readonly logger: IScopedLogger;
|
|
44
|
-
readonly isArchive?: boolean;
|
|
45
|
-
readonly archiveFormat?: 'zip' | 'tar.gz' | 'tar.xz';
|
|
46
|
-
readonly archiveInnerPath?: string;
|
|
47
|
-
}): Promise<string>;
|
|
48
|
-
|
|
49
|
-
declare function getFfmpegDownloadUrl(platform: string, arch: string): string;
|
|
50
|
-
/**
|
|
51
|
-
* Ensure ffmpeg binary is available.
|
|
52
|
-
* Checks: deps dir → system PATH → download.
|
|
53
|
-
*/
|
|
54
|
-
declare function ensureFfmpeg(dataDir: string, logger: IScopedLogger): Promise<string>;
|
|
55
|
-
|
|
56
|
-
declare const PYTHON_VERSION = "3.12.12";
|
|
57
|
-
declare function getPythonDownloadUrl(platform: string, arch: string): string;
|
|
58
|
-
/**
|
|
59
|
-
* Ensure a portable Python is available.
|
|
60
|
-
* Checks: embedded python → system PATH → download portable.
|
|
61
|
-
*
|
|
62
|
-
* Returns the path to the python3 binary.
|
|
63
|
-
*/
|
|
64
|
-
declare function ensurePython(dataDir: string, logger: IScopedLogger): Promise<string | null>;
|
|
65
|
-
/**
|
|
66
|
-
* Install Python packages into the portable Python environment.
|
|
67
|
-
*/
|
|
68
|
-
declare function installPythonPackages(pythonPath: string, packages: readonly string[], logger: IScopedLogger): Promise<void>;
|
|
7
|
+
import Database from 'better-sqlite3';
|
|
69
8
|
|
|
70
9
|
type EventCallback<T = unknown> = (data: T) => void;
|
|
71
10
|
declare class EventBus {
|
|
@@ -93,6 +32,20 @@ declare function fetchJson(url: string): Promise<unknown>;
|
|
|
93
32
|
* Legacy API preserved for backward compatibility -- delegates to downloadFile().
|
|
94
33
|
*/
|
|
95
34
|
declare function downloadModel(options: ModelDownloadOptions): Promise<ModelDownloadResult>;
|
|
35
|
+
/** Progress callback: (downloadedBytes, totalBytes | undefined) */
|
|
36
|
+
type DownloadProgressCallback = (downloaded: number, total: number | undefined) => void;
|
|
37
|
+
/**
|
|
38
|
+
* Resolve a `ModelCatalogEntry` against `modelsDir`: download model file
|
|
39
|
+
* (or directory bundle) + extra files (labels JSON, charset dict, …),
|
|
40
|
+
* skip if already on disk. Returns the local model path.
|
|
41
|
+
*/
|
|
42
|
+
declare function ensureModel(modelsDir: string, entry: ModelCatalogEntry, format: ModelFormat, onProgress?: DownloadProgressCallback): Promise<string>;
|
|
43
|
+
/** Compute the on-disk path for a given model + format, even when not yet downloaded. */
|
|
44
|
+
declare function getModelFilePath(modelsDir: string, entry: ModelCatalogEntry, format: ModelFormat): string | null;
|
|
45
|
+
/** True iff the model file (or `Manifest.json` for directory bundles) exists and is non-empty. */
|
|
46
|
+
declare function isModelDownloaded(modelsDir: string, entry: ModelCatalogEntry, format: ModelFormat): boolean;
|
|
47
|
+
/** Remove the on-disk model file/directory. Returns true if something was deleted. */
|
|
48
|
+
declare function deleteModelFromDisk(modelsDir: string, entry: ModelCatalogEntry, format: ModelFormat): boolean;
|
|
96
49
|
|
|
97
50
|
/**
|
|
98
51
|
* Unified model download service.
|
|
@@ -122,11 +75,6 @@ declare class ModelDownloadService implements IAddonModelManager {
|
|
|
122
75
|
getModelsDir(): string;
|
|
123
76
|
/** Check if a model file is already present on disk. */
|
|
124
77
|
isDownloaded(modelId: string, format?: ModelFormat): boolean;
|
|
125
|
-
/**
|
|
126
|
-
* Legacy API: download a model by ID (delegates to ensure with default format).
|
|
127
|
-
* Required by IAddonModelManager interface.
|
|
128
|
-
*/
|
|
129
|
-
downloadModel(id: string): Promise<string>;
|
|
130
78
|
/** Get the catalog entry for a model by ID. */
|
|
131
79
|
getEntry(modelId: string): ModelCatalogEntry | undefined;
|
|
132
80
|
private pickDefaultFormat;
|
|
@@ -141,7 +89,6 @@ declare class ModelDownloadService implements IAddonModelManager {
|
|
|
141
89
|
}
|
|
142
90
|
|
|
143
91
|
declare class PythonEnvManager implements IPythonEnvironment {
|
|
144
|
-
private readonly dataDir;
|
|
145
92
|
private venvPath;
|
|
146
93
|
private cachedProbe;
|
|
147
94
|
constructor(dataDir: string);
|
|
@@ -152,79 +99,59 @@ declare class PythonEnvManager implements IPythonEnvironment {
|
|
|
152
99
|
spawn(script: string, args: readonly string[]): ChildProcess;
|
|
153
100
|
}
|
|
154
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Check if a pipeline step is available in the system.
|
|
104
|
+
* Implementations should check the capability registry for `pipeline-step:{stepId}`.
|
|
105
|
+
*/
|
|
106
|
+
type StepExistsFn = (stepId: string) => boolean;
|
|
155
107
|
declare class PipelineValidator {
|
|
156
|
-
private readonly
|
|
157
|
-
constructor(
|
|
108
|
+
private readonly stepExists;
|
|
109
|
+
constructor(stepExists: StepExistsFn);
|
|
158
110
|
validate(config: PipelineConfig): ValidationResult;
|
|
159
111
|
private validateNode;
|
|
160
112
|
}
|
|
161
113
|
|
|
162
114
|
declare class PipelineRunner {
|
|
163
|
-
private readonly
|
|
164
|
-
|
|
165
|
-
constructor(engineManager: AddonEngineManager, addonConfigs: Map<string, Record<string, unknown>>);
|
|
115
|
+
private readonly addonResolver;
|
|
116
|
+
constructor(addonResolver: IAddonResolver);
|
|
166
117
|
run(frame: FrameInput, config: PipelineConfig): Promise<PipelineResult>;
|
|
167
|
-
/**
|
|
168
|
-
* Run only the audio classification node on an audio chunk.
|
|
169
|
-
* Used by the audio path in DetectionWiringService (separate from video pipeline).
|
|
170
|
-
*/
|
|
171
|
-
runAudioNode(chunk: AudioChunkInput, audioNode: PipelineNode): Promise<PipelineResult>;
|
|
172
118
|
private executeNode;
|
|
173
119
|
private executeChildren;
|
|
174
120
|
}
|
|
175
121
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
private readonly events;
|
|
190
|
-
private readonly logger;
|
|
191
|
-
private childProcess;
|
|
192
|
-
private _state;
|
|
193
|
-
private _startedAt?;
|
|
194
|
-
private restartTimer?;
|
|
195
|
-
private _restartCount;
|
|
196
|
-
private _lastCrashAt?;
|
|
197
|
-
private _lastCrashError?;
|
|
198
|
-
constructor(config: ProcessConfig, events: ProcessEventEmitter, logger: IScopedLogger);
|
|
199
|
-
get state(): ProcessState;
|
|
200
|
-
start(): Promise<void>;
|
|
201
|
-
stop(): Promise<void>;
|
|
202
|
-
getStatus(): ManagedProcessStatus;
|
|
203
|
-
private scheduleRestart;
|
|
204
|
-
private getStats;
|
|
205
|
-
private getNextRestartTime;
|
|
122
|
+
/**
|
|
123
|
+
* Adapter that wraps an IEngineManager + addonConfigs as an IAddonResolver.
|
|
124
|
+
*
|
|
125
|
+
* Used for backwards compatibility — the in-process AddonEngineManager
|
|
126
|
+
* still uses the old getOrCreateEngine(addonId, globalConfig, override) API.
|
|
127
|
+
* This adapter bridges it to the new resolve(addonId, config) interface.
|
|
128
|
+
*/
|
|
129
|
+
declare class EngineManagerResolver implements IAddonResolver {
|
|
130
|
+
private readonly engineManager;
|
|
131
|
+
private readonly addonConfigs;
|
|
132
|
+
constructor(engineManager: IEngineManager, addonConfigs: Map<string, Record<string, unknown>>);
|
|
133
|
+
resolve(addonId: string, config: Record<string, unknown>): Promise<IAddonCaller>;
|
|
134
|
+
shutdownAll(): Promise<void>;
|
|
206
135
|
}
|
|
207
136
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
private readonly processes;
|
|
212
|
-
constructor(events: ProcessEventEmitter, loggerFactory: ProcessLoggerFactory);
|
|
213
|
-
register(config: ProcessConfig): ManagedProcess;
|
|
214
|
-
start(id: string): Promise<void>;
|
|
215
|
-
stop(id: string): Promise<void>;
|
|
216
|
-
restart(id: string): Promise<void>;
|
|
217
|
-
get(id: string): ManagedProcess;
|
|
218
|
-
listAll(): readonly ManagedProcessStatus[];
|
|
219
|
-
shutdownAll(): Promise<void>;
|
|
137
|
+
interface PidStats {
|
|
138
|
+
cpu: number;
|
|
139
|
+
memory: number;
|
|
220
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Get CPU% and memory RSS for one or more PIDs.
|
|
143
|
+
* Returns a map of pid → stats. Missing/dead PIDs are silently omitted.
|
|
144
|
+
*/
|
|
145
|
+
declare function getPidStats(pids: number | readonly number[]): Promise<ReadonlyMap<number, PidStats>>;
|
|
146
|
+
/** Get CPU% and memory RSS for a single PID. Returns null if dead. */
|
|
147
|
+
declare function getSinglePidStats(pid: number): Promise<PidStats | null>;
|
|
221
148
|
|
|
222
149
|
declare class NetworkQualityTracker implements INetworkQualityTracker {
|
|
223
150
|
private readonly devices;
|
|
224
151
|
private static readonly MAX_SAMPLES;
|
|
225
|
-
reportStreamStats(deviceId:
|
|
226
|
-
reportClientStats(deviceId:
|
|
227
|
-
getDeviceStats(deviceId:
|
|
152
|
+
reportStreamStats(deviceId: number, streamId: string, bitrateKbps: number, packetLoss?: number): void;
|
|
153
|
+
reportClientStats(deviceId: number, stats: Omit<ClientNetworkStats, 'lastUpdated'>): void;
|
|
154
|
+
getDeviceStats(deviceId: number): DeviceNetworkStats | null;
|
|
228
155
|
getAllStats(): readonly DeviceNetworkStats[];
|
|
229
156
|
private getOrCreateDevice;
|
|
230
157
|
}
|
|
@@ -232,7 +159,7 @@ declare class NetworkQualityTracker implements INetworkQualityTracker {
|
|
|
232
159
|
interface ReplScope {
|
|
233
160
|
readonly type: 'system' | 'provider' | 'device' | 'addon';
|
|
234
161
|
readonly providerId?: string;
|
|
235
|
-
readonly deviceId?:
|
|
162
|
+
readonly deviceId?: number;
|
|
236
163
|
readonly addonId?: string;
|
|
237
164
|
}
|
|
238
165
|
interface ReplSessionContext {
|
|
@@ -248,12 +175,16 @@ interface IReplEngine {
|
|
|
248
175
|
/**
|
|
249
176
|
* Context provider that the server kernel implements.
|
|
250
177
|
* The REPL engine calls this to build the sandbox for each scope type.
|
|
178
|
+
*
|
|
179
|
+
* Methods may return a Promise so the kernel can warm up async
|
|
180
|
+
* resources (e.g. `SystemManager.init()`) before exposing them — the
|
|
181
|
+
* engine awaits each before evaluating user code.
|
|
251
182
|
*/
|
|
252
183
|
interface IReplContextProvider {
|
|
253
|
-
getSystemSandbox(): Record<string, unknown
|
|
254
|
-
getDeviceSandbox(deviceId:
|
|
255
|
-
getProviderSandbox(providerId: string): Record<string, unknown
|
|
256
|
-
getAddonSandbox(addonId: string): Record<string, unknown
|
|
184
|
+
getSystemSandbox(): Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
185
|
+
getDeviceSandbox(deviceId: number): Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
186
|
+
getProviderSandbox(providerId: string): Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
187
|
+
getAddonSandbox(addonId: string): Record<string, unknown> | Promise<Record<string, unknown>>;
|
|
257
188
|
}
|
|
258
189
|
|
|
259
190
|
declare class ReplEngine implements IReplEngine {
|
|
@@ -264,203 +195,866 @@ declare class ReplEngine implements IReplEngine {
|
|
|
264
195
|
private buildSandbox;
|
|
265
196
|
}
|
|
266
197
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
198
|
+
interface FilesystemStorageConfig {
|
|
199
|
+
readonly rootPath: string;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Filesystem Storage addon — provides local disk storage for all location types.
|
|
203
|
+
* Capability: 'storage' (collection)
|
|
204
|
+
*/
|
|
205
|
+
declare class FilesystemStorageAddon extends BaseAddon<FilesystemStorageConfig> {
|
|
206
|
+
private provider;
|
|
207
|
+
constructor();
|
|
208
|
+
protected onInitialize(): Promise<ProviderRegistration[]>;
|
|
209
|
+
protected onShutdown(): Promise<void>;
|
|
210
|
+
getProvider(): FilesystemStorageProvider | null;
|
|
211
|
+
}
|
|
275
212
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
213
|
+
/**
|
|
214
|
+
* SQLite implementation of ISettingsBackend.
|
|
215
|
+
*
|
|
216
|
+
* Every collection is structured: declared at boot (canonical KV
|
|
217
|
+
* collections) or via `declareCollection` (typed schemas like
|
|
218
|
+
* `pipeline-analytics:tracks`). The legacy auto-create-on-first-access
|
|
219
|
+
* path was removed — see commit history for the migration. Operations
|
|
220
|
+
* on undeclared collections throw at runtime so callers fail fast.
|
|
221
|
+
*
|
|
222
|
+
* WAL mode for concurrent reads.
|
|
223
|
+
*/
|
|
224
|
+
declare class SqliteSettingsBackend implements ISettingsBackend {
|
|
225
|
+
private readonly dbPath;
|
|
226
|
+
private db;
|
|
227
|
+
private readonly structuredTables;
|
|
228
|
+
/** Map from scoped collection name → set of column names (non-id) that
|
|
229
|
+
* the structured schema owns. Routes set/get/insert/update/query to
|
|
230
|
+
* typed columns. Every collection MUST be declared here before use. */
|
|
231
|
+
private readonly declaredCollections;
|
|
232
|
+
private readonly runtimeDefaults;
|
|
233
|
+
/**
|
|
234
|
+
* Canonical key/value collections — declared with a `(id TEXT PK,
|
|
235
|
+
* data TEXT NOT NULL)` schema at boot so existing JSON-blob rows
|
|
236
|
+
* keep working through the structured path. Generates SQL identical
|
|
237
|
+
* to the previous legacy path; only the routing is unified.
|
|
238
|
+
*/
|
|
239
|
+
private static readonly CANONICAL_KV_COLLECTIONS;
|
|
240
|
+
constructor(dbPath: string, runtimeDefaults?: Record<string, unknown>);
|
|
241
|
+
initialize(): Promise<void>;
|
|
242
|
+
private requireDeclared;
|
|
243
|
+
shutdown(): Promise<void>;
|
|
244
|
+
get({ namespace, collection, key }: SettingsGetInput): Promise<unknown>;
|
|
245
|
+
set({ namespace, collection, key, value }: SettingsSetInput): Promise<void>;
|
|
246
|
+
query<T extends object = Record<string, unknown>>({ namespace, collection, filter }: SettingsQueryInput): Promise<readonly SettingsRecord<T>[]>;
|
|
247
|
+
insert<T extends object = Record<string, unknown>>({ namespace, collection, record }: SettingsInsertInput<T>): Promise<void>;
|
|
248
|
+
update({ namespace, collection, id, data }: SettingsUpdateInput): Promise<void>;
|
|
249
|
+
delete({ namespace, collection, key }: SettingsDeleteInput): Promise<void>;
|
|
250
|
+
count({ namespace, collection, filter }: SettingsCountInput): Promise<number>;
|
|
251
|
+
isEmpty({ namespace, collection }: SettingsIsEmptyInput): Promise<boolean>;
|
|
252
|
+
private queryDeclared;
|
|
253
|
+
/** Get a system setting by dot-notation key */
|
|
254
|
+
getSystem(key: string): unknown;
|
|
255
|
+
/** Set a system setting */
|
|
256
|
+
setSystem(key: string, value: unknown): void;
|
|
257
|
+
/** Get all system settings as flat key-value */
|
|
258
|
+
getAllSystem(): Record<string, unknown>;
|
|
259
|
+
/** Get all settings for an addon */
|
|
260
|
+
getAllAddon(addonId: string): Record<string, unknown>;
|
|
261
|
+
/** Bulk-set all settings for an addon */
|
|
262
|
+
setAllAddon(addonId: string, config: Record<string, unknown>): void;
|
|
263
|
+
/** Get all settings for a provider */
|
|
264
|
+
getAllProvider(providerId: string): Record<string, unknown>;
|
|
265
|
+
/** Set a provider setting */
|
|
266
|
+
setProvider(providerId: string, key: string, value: unknown): void;
|
|
267
|
+
/** Get all settings for a device */
|
|
268
|
+
getAllDevice(deviceId: string): Record<string, unknown>;
|
|
269
|
+
/** Set a device setting */
|
|
270
|
+
setDevice(deviceId: string, key: string, value: unknown): void;
|
|
271
|
+
getAddonDevice(addonId: string, deviceId: string): Record<string, unknown>;
|
|
272
|
+
setAddonDevice(addonId: string, deviceId: string, values: Record<string, unknown>): void;
|
|
273
|
+
clearAddonDevice(addonId: string, deviceId: string): void;
|
|
274
|
+
/** Seed system-settings with runtime defaults (first boot) */
|
|
275
|
+
private seedDefaults;
|
|
276
|
+
/**
|
|
277
|
+
* Expose the raw better-sqlite3 Database instance for components that
|
|
278
|
+
* need direct SQL access (e.g. DeviceStore, ConfigStore).
|
|
279
|
+
* Returns null if the backend has not been initialized yet.
|
|
280
|
+
*/
|
|
281
|
+
getDatabase(): Database.Database | null;
|
|
282
|
+
private getDb;
|
|
283
|
+
private getAllScoped;
|
|
284
|
+
private setScopedKey;
|
|
285
|
+
private scopedName;
|
|
286
|
+
declareCollection(input: {
|
|
287
|
+
namespace?: string;
|
|
288
|
+
collection: string;
|
|
289
|
+
columns: readonly CollectionColumn[];
|
|
290
|
+
indexes?: readonly CollectionIndex[];
|
|
291
|
+
}): Promise<void>;
|
|
292
|
+
/** Serialise per-column values for SQL binding: objects → JSON, booleans → 0/1. */
|
|
293
|
+
private serializeColumnValue;
|
|
294
|
+
ensureTable(table: string, schema: TableSchema): Promise<void>;
|
|
295
|
+
tableInsert(table: string, row: Record<string, unknown>): Promise<void>;
|
|
296
|
+
tableUpdate(table: string, filter: Record<string, unknown>, updates: Record<string, unknown>): Promise<number>;
|
|
297
|
+
tableDelete(table: string, filter: Record<string, unknown>): Promise<number>;
|
|
298
|
+
tableQuery(table: string, options?: TableQueryOptions): Promise<readonly Record<string, unknown>[]>;
|
|
299
|
+
tableGet(table: string, filter: Record<string, unknown>): Promise<Record<string, unknown> | null>;
|
|
300
|
+
tableCount(table: string, filter?: Record<string, unknown>): Promise<number>;
|
|
301
|
+
private buildWhere;
|
|
300
302
|
}
|
|
301
303
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
/** Called when an agent returns a result */
|
|
313
|
-
handleTaskResult(result: AgentTaskResult): void;
|
|
314
|
-
private executeLocally;
|
|
315
|
-
private sendToAgent;
|
|
304
|
+
/**
|
|
305
|
+
* SQLite Settings addon — provides persistent settings storage.
|
|
306
|
+
* Capability: 'settings-store' (singleton)
|
|
307
|
+
*/
|
|
308
|
+
declare class SqliteSettingsAddon extends BaseAddon {
|
|
309
|
+
private backend;
|
|
310
|
+
constructor();
|
|
311
|
+
protected onInitialize(): Promise<ProviderRegistration[]>;
|
|
312
|
+
protected onShutdown(): Promise<void>;
|
|
313
|
+
getBackend(): SqliteSettingsBackend | null;
|
|
316
314
|
}
|
|
317
315
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
316
|
+
/**
|
|
317
|
+
* Thin wrapper over better-sqlite3 that manages the four settings tables:
|
|
318
|
+
* system_settings, addon_settings, provider_settings, device_settings.
|
|
319
|
+
*
|
|
320
|
+
* All values are stored as JSON text and deserialized on read.
|
|
321
|
+
*/
|
|
322
|
+
declare class SettingsStore {
|
|
323
|
+
private readonly db;
|
|
324
|
+
constructor(dbPath: string);
|
|
325
|
+
getSystem(key: string): unknown;
|
|
326
|
+
setSystem(key: string, value: unknown): void;
|
|
327
|
+
getAllSystem(): Record<string, unknown>;
|
|
328
|
+
getAddon(addonId: string, key: string): unknown;
|
|
329
|
+
setAddon(addonId: string, key: string, value: unknown): void;
|
|
330
|
+
getAllAddon(addonId: string): Record<string, unknown>;
|
|
331
|
+
/** Bulk-replace all keys for an addon (within a transaction). */
|
|
332
|
+
setAllAddon(addonId: string, config: Record<string, unknown>): void;
|
|
333
|
+
getProvider(providerId: string, key: string): unknown;
|
|
334
|
+
setProvider(providerId: string, key: string, value: unknown): void;
|
|
335
|
+
getAllProvider(providerId: string): Record<string, unknown>;
|
|
336
|
+
getDevice(deviceId: string, key: string): unknown;
|
|
337
|
+
setDevice(deviceId: string, key: string, value: unknown): void;
|
|
338
|
+
getAllDevice(deviceId: string): Record<string, unknown>;
|
|
339
|
+
getAddonDevice(addonId: string, deviceId: string): Record<string, unknown>;
|
|
340
|
+
/**
|
|
341
|
+
* Bulk-replace all per-device overrides for (addonId, deviceId) in a
|
|
342
|
+
* single transaction. Empty input clears the override set — caller
|
|
343
|
+
* should use `clearAddonDevice` for explicit resets.
|
|
344
|
+
*/
|
|
345
|
+
setAddonDevice(addonId: string, deviceId: string, values: Record<string, unknown>): void;
|
|
346
|
+
clearAddonDevice(addonId: string, deviceId: string): void;
|
|
347
|
+
/** Close the SQLite connection (call on shutdown). */
|
|
348
|
+
close(): void;
|
|
349
|
+
/** Check if system_settings is empty (used for first-boot seeding). */
|
|
350
|
+
isSystemSettingsEmpty(): boolean;
|
|
351
|
+
/** Seed system_settings with RUNTIME_DEFAULTS (only on first boot). */
|
|
352
|
+
seedDefaults(): void;
|
|
353
|
+
private initTables;
|
|
327
354
|
}
|
|
328
355
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
356
|
+
/** Core table DDL statements -- executed on first boot */
|
|
357
|
+
declare const CORE_TABLE_DDL: readonly string[];
|
|
358
|
+
/** Addon table schema declaration */
|
|
359
|
+
interface AddonTableSchema {
|
|
360
|
+
readonly name: string;
|
|
361
|
+
readonly columns: ReadonlyArray<{
|
|
362
|
+
readonly name: string;
|
|
363
|
+
readonly type: 'TEXT' | 'INTEGER' | 'REAL' | 'JSON';
|
|
364
|
+
readonly primaryKey?: boolean;
|
|
365
|
+
readonly notNull?: boolean;
|
|
366
|
+
}>;
|
|
367
|
+
readonly indexes?: ReadonlyArray<{
|
|
368
|
+
readonly name: string;
|
|
369
|
+
readonly columns: readonly string[];
|
|
370
|
+
readonly unique?: boolean;
|
|
371
|
+
}>;
|
|
372
|
+
}
|
|
373
|
+
/** Generate CREATE TABLE DDL from addon schema */
|
|
374
|
+
declare function addonTableToDdl(schema: AddonTableSchema): string[];
|
|
375
|
+
|
|
376
|
+
interface DeviceRow {
|
|
377
|
+
readonly stableId: string;
|
|
378
|
+
readonly type: string;
|
|
379
|
+
readonly name: string;
|
|
380
|
+
readonly parentStableId: string | null;
|
|
381
|
+
readonly enabled: boolean;
|
|
382
|
+
}
|
|
383
|
+
interface InsertInput {
|
|
384
|
+
readonly stableId: string;
|
|
385
|
+
readonly type: string;
|
|
386
|
+
readonly name: string;
|
|
387
|
+
readonly parentStableId: string | null;
|
|
388
|
+
}
|
|
389
|
+
declare class DeviceStore {
|
|
390
|
+
private readonly db;
|
|
391
|
+
constructor(db: Database.Database);
|
|
392
|
+
insert(addonId: string, device: InsertInput): void;
|
|
393
|
+
listByAddon(addonId: string): readonly DeviceRow[];
|
|
394
|
+
listChildren(addonId: string, parentStableId: string): readonly DeviceRow[];
|
|
395
|
+
remove(addonId: string, stableId: string): void;
|
|
339
396
|
}
|
|
340
397
|
|
|
341
|
-
|
|
342
|
-
readonly
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
398
|
+
declare class ConfigStore {
|
|
399
|
+
private readonly db;
|
|
400
|
+
constructor(db: Database.Database);
|
|
401
|
+
save(addonId: string, stableId: string | null, data: Record<string, unknown>): void;
|
|
402
|
+
load(addonId: string, stableId: string | null): Record<string, unknown>;
|
|
403
|
+
remove(addonId: string, stableId: string | null): void;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
interface WinstonConfig$1 {
|
|
407
|
+
readonly level: string;
|
|
408
|
+
readonly retentionDays: number;
|
|
409
|
+
/** Resolved absolute path to the logs directory (replaces the old dataPath field). */
|
|
410
|
+
readonly logsDir: string;
|
|
411
|
+
}
|
|
350
412
|
/**
|
|
351
|
-
*
|
|
352
|
-
*
|
|
353
|
-
*
|
|
413
|
+
* Rotated-file log destination. Console output goes through the shared
|
|
414
|
+
* `formatLogLine` so every console sink (Winston, ConsoleDestination,
|
|
415
|
+
* HubForwarderDestination) emits identical lines. File output keeps a
|
|
416
|
+
* structured JSON shape so log tooling can query tags/meta.
|
|
354
417
|
*/
|
|
355
|
-
declare class
|
|
356
|
-
private
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
/**
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
private
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
418
|
+
declare class WinstonDestination implements ILogDestination$1 {
|
|
419
|
+
private logger;
|
|
420
|
+
initialize(config?: WinstonConfig$1): Promise<void>;
|
|
421
|
+
write(entry: LogEntry): void;
|
|
422
|
+
query(_filter: LogFilter): Promise<readonly LogEntry[]>;
|
|
423
|
+
shutdown(): Promise<void>;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
interface WinstonConfig {
|
|
427
|
+
readonly level: string;
|
|
428
|
+
readonly retentionDays: number;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Winston logging addon — rotated log files + console output.
|
|
432
|
+
* Settings appear under Cluster → NodeDetail → Settings.
|
|
433
|
+
*/
|
|
434
|
+
declare class WinstonLoggingAddon extends BaseAddon<WinstonConfig> {
|
|
435
|
+
private destination;
|
|
436
|
+
constructor();
|
|
437
|
+
protected onInitialize(): Promise<ProviderRegistration[]>;
|
|
438
|
+
protected onShutdown(): Promise<void>;
|
|
439
|
+
getDestination(): WinstonDestination;
|
|
440
|
+
protected globalSettingsSchema(): _camstack_types.ConfigUISchema;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Zero-dependency log destination that writes every entry to stdout /
|
|
445
|
+
* stderr via the shared `formatLogLine` formatter. Same surface as
|
|
446
|
+
* `WinstonDestination` (full `ILogDestination` contract) but without
|
|
447
|
+
* the rotating-file transport — ideal fallback when the Winston addon
|
|
448
|
+
* is disabled or unavailable (e.g. bare-bones agents, tests).
|
|
449
|
+
*/
|
|
450
|
+
|
|
451
|
+
interface ConsoleConfig$1 {
|
|
452
|
+
/** Minimum log level to emit. Entries below this level are dropped. */
|
|
453
|
+
readonly level?: 'debug' | 'info' | 'warn' | 'error';
|
|
454
|
+
}
|
|
455
|
+
declare class ConsoleDestination implements ILogDestination$1 {
|
|
456
|
+
private minLevel;
|
|
457
|
+
initialize(config?: ConsoleConfig$1): Promise<void>;
|
|
458
|
+
write(entry: LogEntry): void;
|
|
459
|
+
query(_filter: LogFilter): Promise<readonly LogEntry[]>;
|
|
460
|
+
shutdown(): Promise<void>;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
interface ConsoleConfig {
|
|
464
|
+
readonly level: 'debug' | 'info' | 'warn' | 'error';
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Console logging addon — zero-dependency stdout/stderr sink that
|
|
468
|
+
* produces the same canonical line format as the Winston built-in.
|
|
469
|
+
* Registers as a `log-destination` capability provider so the shared
|
|
470
|
+
* LogManager fans every entry to both sinks when both are active.
|
|
471
|
+
*
|
|
472
|
+
* Settings live under Cluster → NodeDetail → Settings alongside the
|
|
473
|
+
* Winston addon. Disable one without disabling the other — the
|
|
474
|
+
* LogManager keeps working as long as at least one destination is
|
|
475
|
+
* registered.
|
|
476
|
+
*/
|
|
477
|
+
declare class ConsoleLoggingAddon extends BaseAddon<ConsoleConfig> {
|
|
478
|
+
private destination;
|
|
479
|
+
constructor();
|
|
480
|
+
protected onInitialize(): Promise<ProviderRegistration[]>;
|
|
481
|
+
protected onShutdown(): Promise<void>;
|
|
482
|
+
getDestination(): ConsoleDestination;
|
|
483
|
+
protected globalSettingsSchema(): _camstack_types.ConfigUISchema;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Log destination for agent mode.
|
|
488
|
+
*
|
|
489
|
+
* - Writes to console ONLY when hub is not yet reachable (cold-start
|
|
490
|
+
* fallback). Forked-worker agents share stdout with their parent
|
|
491
|
+
* hub, so logging to local console AND forwarding to hub's
|
|
492
|
+
* `log-receiver` would print the entry twice on the hub terminal.
|
|
493
|
+
* Once the hub is discovered, local console output stops and the
|
|
494
|
+
* hub's own ConsoleDestination owns the render.
|
|
495
|
+
* - When a Moleculer broker is connected and the hub node is reachable,
|
|
496
|
+
* forwards every log entry to the hub via `log-receiver.ingest`.
|
|
497
|
+
* - Entries written before the hub is reachable are buffered internally
|
|
498
|
+
* (ring-buffered to `DEFAULT_OUTBOUND_BUFFER_SIZE`) and flushed on connect,
|
|
499
|
+
* so boot-time logs still reach the hub without any external replay trigger.
|
|
500
|
+
*/
|
|
501
|
+
declare class HubForwarderDestination implements ILogDestination$1 {
|
|
502
|
+
private broker;
|
|
503
|
+
private hubConnected;
|
|
504
|
+
private readonly outboundBuffer;
|
|
505
|
+
private statusLogger;
|
|
506
|
+
initialize(): Promise<void>;
|
|
507
|
+
/**
|
|
508
|
+
* Provide a logger for the destination's own status messages
|
|
509
|
+
* (discovery, disconnect, reconnect). Routed through the agent's
|
|
510
|
+
* LogManager but never through this same destination — the owning
|
|
511
|
+
* addon must hand in a logger that does NOT route back here, or
|
|
512
|
+
* status writes will recurse.
|
|
513
|
+
*/
|
|
514
|
+
setStatusLogger(logger: IScopedLogger): void;
|
|
515
|
+
private status;
|
|
516
|
+
/**
|
|
517
|
+
* Attach the Moleculer broker so hub forwarding can start.
|
|
518
|
+
* Called by the owning addon from `onInitialize(ctx)` with
|
|
519
|
+
* `ctx.kernel.cluster?.broker`.
|
|
520
|
+
*/
|
|
521
|
+
connectBroker(broker: IClusterBroker): void;
|
|
522
|
+
write(entry: LogEntry): void;
|
|
523
|
+
query(_filter: LogFilter): Promise<readonly LogEntry[]>;
|
|
524
|
+
shutdown(): Promise<void>;
|
|
525
|
+
private bufferOutbound;
|
|
526
|
+
private flushOutbound;
|
|
527
|
+
private forward;
|
|
397
528
|
}
|
|
398
529
|
|
|
399
530
|
/**
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
*
|
|
531
|
+
* Agent-only addon that provides the `log-destination` capability.
|
|
532
|
+
* Writes all logs to the console and forwards to the hub via Moleculer when
|
|
533
|
+
* reachable. The broker is read from `ctx.kernel.cluster?.broker`; outbound
|
|
534
|
+
* log replay on hub-connect is handled internally by the destination.
|
|
403
535
|
*/
|
|
404
|
-
declare class
|
|
405
|
-
private
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
536
|
+
declare class HubForwarderAddon extends BaseAddon {
|
|
537
|
+
private destination;
|
|
538
|
+
constructor();
|
|
539
|
+
protected onInitialize(): Promise<ProviderRegistration[]>;
|
|
540
|
+
getDestination(): HubForwarderDestination | null;
|
|
541
|
+
protected onShutdown(): Promise<void>;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
interface BackupConfig {
|
|
545
|
+
readonly backupDir: string;
|
|
546
|
+
readonly retentionCount: number;
|
|
547
|
+
}
|
|
548
|
+
declare class LocalBackupService {
|
|
549
|
+
private readonly config;
|
|
409
550
|
private readonly logger;
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
/**
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
551
|
+
private readonly eventBus;
|
|
552
|
+
private manifests;
|
|
553
|
+
constructor(config: BackupConfig, logger: IScopedLogger, eventBus: IEventBus);
|
|
554
|
+
/** Create a backup of specified locations */
|
|
555
|
+
backup(options?: {
|
|
556
|
+
locations?: string[];
|
|
557
|
+
label?: string;
|
|
558
|
+
}): Promise<BackupManifest>;
|
|
559
|
+
/** Restore from a backup */
|
|
560
|
+
restore(backupId: string): Promise<void>;
|
|
561
|
+
/** List all backups sorted by timestamp descending */
|
|
562
|
+
list(): readonly BackupManifest[];
|
|
563
|
+
/** Delete a specific backup */
|
|
564
|
+
delete(backupId: string): Promise<void>;
|
|
565
|
+
private pruneOldBackups;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
interface LocalBackupAddonConfig {
|
|
569
|
+
readonly retentionCount: number;
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Local backup addon — snapshot-based backup/restore of camstack data.
|
|
573
|
+
* Settings appear under Cluster → NodeDetail → Settings.
|
|
574
|
+
*/
|
|
575
|
+
declare class LocalBackupAddon extends BaseAddon<LocalBackupAddonConfig> {
|
|
576
|
+
private service;
|
|
577
|
+
constructor();
|
|
578
|
+
protected onInitialize(): Promise<ProviderRegistration[]>;
|
|
579
|
+
protected onShutdown(): Promise<void>;
|
|
580
|
+
getService(): LocalBackupService;
|
|
581
|
+
protected globalSettingsSchema(): _camstack_types.ConfigUISchema;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
interface NativeMetricsConfig {
|
|
585
|
+
readonly samplingIntervalMs: number;
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Native metrics — CPU, memory, disk usage sampling.
|
|
589
|
+
* Settings appear under Cluster → NodeDetail → Settings.
|
|
590
|
+
*/
|
|
591
|
+
declare class NativeMetricsAddon extends BaseAddon<NativeMetricsConfig> {
|
|
592
|
+
private provider;
|
|
593
|
+
private startedAtMs;
|
|
594
|
+
private snapshotTimer;
|
|
419
595
|
/**
|
|
420
|
-
*
|
|
421
|
-
*
|
|
596
|
+
* Snapshot-equality cache for the resources + processes emit.
|
|
597
|
+
* Stores the coarsened JSON and timestamp; a tick where the
|
|
598
|
+
* coarsened payload matches the cache (and the heartbeat hasn't
|
|
599
|
+
* elapsed) is skipped.
|
|
422
600
|
*/
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
/**
|
|
429
|
-
|
|
601
|
+
private lastResourcesEmit;
|
|
602
|
+
private lastProcessesEmit;
|
|
603
|
+
constructor();
|
|
604
|
+
protected onInitialize(): Promise<ProviderRegistration[]>;
|
|
605
|
+
protected onShutdown(): Promise<void>;
|
|
606
|
+
/**
|
|
607
|
+
* Emit one `metrics.node-resources-snapshot` + one
|
|
608
|
+
* `metrics.node-processes-snapshot` for this node. UI consumers
|
|
609
|
+
* subscribe and read state directly from the payload.
|
|
610
|
+
*/
|
|
611
|
+
private emitMetricsSnapshots;
|
|
612
|
+
protected onConfigChanged(): Promise<void>;
|
|
613
|
+
private listWorkerInstances;
|
|
614
|
+
private listAddonInstances;
|
|
615
|
+
private getAddonStats;
|
|
616
|
+
/**
|
|
617
|
+
* Walk the OS process table and classify each camstack-shaped process.
|
|
618
|
+
*
|
|
619
|
+
* Classification (ancestry-driven, NOT pattern-driven):
|
|
620
|
+
* - root — the current node's own pid (`process.pid`).
|
|
621
|
+
* - managed — pid is registered in the kernel's `$process.list`
|
|
622
|
+
* (forked addon worker spawned by this hub).
|
|
623
|
+
* - system — ancestry walk crosses a SUPERVISOR_BOUNDARY_RE match
|
|
624
|
+
* (tsx-watch launcher, agent CLI, concurrently, vite,
|
|
625
|
+
* npm exec wrapper). The process belongs to the dev
|
|
626
|
+
* tree even if not in `$process.list`. NEVER killable.
|
|
627
|
+
* - ghost — ancestry walk reaches `ppid=1` without crossing any
|
|
628
|
+
* supervisor boundary AND the parent isn't visible in
|
|
629
|
+
* `ps`. A truly orphaned camstack-shaped process. The
|
|
630
|
+
* ONLY classification that's eligible for kill.
|
|
631
|
+
*
|
|
632
|
+
* Old pattern-only ghost detection produced false positives: every
|
|
633
|
+
* monorepo-path process matched CAMSTACK_CMD_RE, ancestry walk
|
|
634
|
+
* stopping at ppid=hub returned false-positive ghosts whenever a
|
|
635
|
+
* concurrently sibling sat above hub. Ancestry-driven classification
|
|
636
|
+
* fixes that.
|
|
637
|
+
*/
|
|
638
|
+
private listNodeProcesses;
|
|
639
|
+
/**
|
|
640
|
+
* Send SIGTERM / SIGKILL to a pid. Refuses pids that don't appear in
|
|
641
|
+
* `listNodeProcesses()` to prevent arbitrary system kills — a dedicated
|
|
642
|
+
* admin-path for resurrected zombies, not a generic shell replacement.
|
|
643
|
+
*
|
|
644
|
+
* `root`-classified pids (the running launcher / agent CLI / hub itself)
|
|
645
|
+
* are also refused: killing them tears down the whole node and the
|
|
646
|
+
* operator's intent is almost always to nuke a leaked child, not the
|
|
647
|
+
* supervisor that keeps the rest alive. Process restart goes through
|
|
648
|
+
* the dedicated `$process.restart` action, not this kill API.
|
|
649
|
+
*/
|
|
650
|
+
private killProcess;
|
|
651
|
+
/** Raw `ps` scan returning every pid + command + resource stats. */
|
|
652
|
+
private runPs;
|
|
653
|
+
protected globalSettingsSchema(): _camstack_types.ConfigUISchema;
|
|
430
654
|
}
|
|
431
655
|
|
|
656
|
+
interface AlertCenterConfig {
|
|
657
|
+
readonly maxAlerts: number;
|
|
658
|
+
readonly retentionDays: number;
|
|
659
|
+
}
|
|
432
660
|
/**
|
|
433
|
-
*
|
|
434
|
-
*
|
|
435
|
-
*
|
|
661
|
+
* Alert Center addon — core builtin that persists alerts in a
|
|
662
|
+
* structured SQLite table and serves them to the admin UI.
|
|
663
|
+
*
|
|
664
|
+
* Registers as an `alerts` collection provider and subscribes to
|
|
665
|
+
* important EventBus categories to create/update alerts automatically.
|
|
436
666
|
*/
|
|
437
|
-
declare class
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
667
|
+
declare class AlertCenterAddon extends BaseAddon<AlertCenterConfig> {
|
|
668
|
+
private unsubscribers;
|
|
669
|
+
constructor();
|
|
670
|
+
/**
|
|
671
|
+
* Per `(category, source.id)` counter used to rate-limit chatty
|
|
672
|
+
* events. Entries are pruned lazily when they age out of
|
|
673
|
+
* `RATE_LIMIT_WINDOW_MS`; see `shouldSuppressByRate()` below.
|
|
674
|
+
*/
|
|
675
|
+
private readonly rateLimitCounters;
|
|
676
|
+
protected onInitialize(): Promise<ProviderRegistration[]>;
|
|
677
|
+
protected onShutdown(): Promise<void>;
|
|
678
|
+
protected globalSettingsSchema(): _camstack_types.ConfigUISchema;
|
|
679
|
+
listAlerts(filter?: {
|
|
680
|
+
unreadOnly?: boolean;
|
|
681
|
+
limit?: number;
|
|
682
|
+
}): Promise<readonly Alert[]>;
|
|
683
|
+
getUnreadCount(): Promise<number>;
|
|
684
|
+
markRead(alertId: string): Promise<void>;
|
|
685
|
+
markAllRead(): Promise<void>;
|
|
686
|
+
dismiss(alertId: string): Promise<void>;
|
|
687
|
+
private handleEvent;
|
|
688
|
+
private handleModelDownload;
|
|
689
|
+
/**
|
|
690
|
+
* `[ALERT-CENTER-EVENTS]` — rate limit a `(category, source.id)`
|
|
691
|
+
* tuple. Returns `true` when the caller should DROP this event
|
|
692
|
+
* without persisting an alert, and `false` when the alert should
|
|
693
|
+
* proceed normally.
|
|
694
|
+
*
|
|
695
|
+
* Heuristic: the first `RATE_LIMIT_MAX_PER_SOURCE` events within a
|
|
696
|
+
* `RATE_LIMIT_WINDOW_MS` window go through. Once the threshold is
|
|
697
|
+
* crossed, subsequent events are suppressed until the window rolls
|
|
698
|
+
* over. When the threshold is first crossed, the suppression is
|
|
699
|
+
* logged once so operators know why they're not seeing the follow-
|
|
700
|
+
* up alerts; after the window rolls over the next event is
|
|
701
|
+
* un-suppressed and starts a new window.
|
|
702
|
+
*/
|
|
703
|
+
private shouldSuppressByRate;
|
|
704
|
+
private buildMessage;
|
|
705
|
+
private emitAlert;
|
|
706
|
+
private updateAlert;
|
|
707
|
+
/**
|
|
708
|
+
* Read-merge-write: SettingsBackend.update() replaces the entire `data` blob,
|
|
709
|
+
* so we must read the existing record, merge the patch, and write back.
|
|
710
|
+
*/
|
|
711
|
+
private mergeUpdate;
|
|
712
|
+
private persistAlert;
|
|
713
|
+
private emitAlertCreatedEvent;
|
|
714
|
+
private emitAlertUpdatedEvent;
|
|
715
|
+
private enforceMaxAlerts;
|
|
716
|
+
private enforceRetention;
|
|
442
717
|
}
|
|
718
|
+
|
|
719
|
+
interface SamplingDiagnostics {
|
|
720
|
+
warn(message: string, meta?: Record<string, unknown>): void;
|
|
721
|
+
}
|
|
722
|
+
declare class NativeMetricsProvider {
|
|
723
|
+
readonly id = "native";
|
|
724
|
+
private cachedSnapshot;
|
|
725
|
+
private samplingTimer;
|
|
726
|
+
private macMemTimer;
|
|
727
|
+
private prevCpu;
|
|
728
|
+
private diagnostics;
|
|
729
|
+
private consecutiveSampleErrors;
|
|
730
|
+
constructor();
|
|
731
|
+
/**
|
|
732
|
+
* Optional diagnostics sink for sampling errors. The first failure and
|
|
733
|
+
* every Nth failure thereafter are reported so a permanently-broken
|
|
734
|
+
* collector doesn't spam logs but is still observable.
|
|
735
|
+
*/
|
|
736
|
+
setDiagnostics(diag: SamplingDiagnostics): void;
|
|
737
|
+
startSampling(intervalMs: number): void;
|
|
738
|
+
private reportSampleError;
|
|
739
|
+
stopSampling(): void;
|
|
740
|
+
collectSnapshot(): Promise<SystemResourceSnapshot>;
|
|
741
|
+
getCached(): Promise<SystemResourceSnapshot | null>;
|
|
742
|
+
getCurrent(): Promise<{
|
|
743
|
+
cpuPercent: number;
|
|
744
|
+
memoryPercent: number;
|
|
745
|
+
memoryUsedMB: number;
|
|
746
|
+
memoryTotalMB: number;
|
|
747
|
+
diskPercent?: number;
|
|
748
|
+
temperature?: number;
|
|
749
|
+
gpuPercent?: number;
|
|
750
|
+
gpuMemoryPercent?: number;
|
|
751
|
+
}>;
|
|
752
|
+
getDiskSpace(input: {
|
|
753
|
+
dirPath: string;
|
|
754
|
+
}): Promise<DiskSpaceInfo>;
|
|
755
|
+
getGpuInfo(): Promise<MetricsGpuInfo | null>;
|
|
756
|
+
getCpuTemperature(): Promise<number | null>;
|
|
757
|
+
getProcessStats(input: {
|
|
758
|
+
pids: number[];
|
|
759
|
+
}): Promise<PidResourceStats[]>;
|
|
760
|
+
private sampleCpu;
|
|
761
|
+
/** Cached macOS memory (set by sampleMacMemory timer). */
|
|
762
|
+
_cachedMacMem: MemoryInfo | null;
|
|
763
|
+
private getMemoryInfo;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
declare class SystemConfigAddon extends BaseAddon {
|
|
767
|
+
readonly id = "system-config";
|
|
768
|
+
constructor();
|
|
769
|
+
protected onInitialize(): Promise<void>;
|
|
770
|
+
private buildGlobalSchema;
|
|
771
|
+
getGlobalSettings(): Promise<ConfigUISchemaWithValues>;
|
|
772
|
+
updateGlobalSettings(patch: Record<string, unknown>): Promise<void>;
|
|
773
|
+
}
|
|
774
|
+
|
|
443
775
|
/**
|
|
444
|
-
*
|
|
445
|
-
*
|
|
446
|
-
*
|
|
776
|
+
* Local Auth Addon — owns user accounts, API keys, scoped tokens,
|
|
777
|
+
* and local password authentication.
|
|
778
|
+
*
|
|
779
|
+
* Capabilities registered:
|
|
780
|
+
* - `auth-provider` (collection) — local password authentication
|
|
781
|
+
* - `user-management` (singleton) — user CRUD, API keys, scoped tokens
|
|
782
|
+
*
|
|
783
|
+
* Extension: an OIDC addon can register another `auth-provider` entry.
|
|
784
|
+
* The server's login flow iterates the `auth-provider` collection.
|
|
447
785
|
*/
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
786
|
+
|
|
787
|
+
interface LocalAuthConfig {
|
|
788
|
+
jwtSecret?: string;
|
|
789
|
+
adminUsername?: string;
|
|
790
|
+
adminPassword?: string;
|
|
791
|
+
}
|
|
792
|
+
declare class LocalAuthAddon extends BaseAddon<LocalAuthConfig> {
|
|
793
|
+
private authManager;
|
|
794
|
+
private userManager;
|
|
795
|
+
private apiKeyManager;
|
|
796
|
+
private scopedTokenManager;
|
|
797
|
+
constructor();
|
|
798
|
+
protected onInitialize(): Promise<ProviderRegistration[]>;
|
|
799
|
+
protected onShutdown(): Promise<void>;
|
|
453
800
|
}
|
|
801
|
+
|
|
454
802
|
/**
|
|
455
|
-
*
|
|
456
|
-
*
|
|
457
|
-
*
|
|
803
|
+
* Wire shape matching `z.infer<typeof SettingsSchemaWithValuesSchema>` —
|
|
804
|
+
* duplicated as a plain interface because importing the Zod schema across
|
|
805
|
+
* package boundaries confuses `tsc` when the types package pins a
|
|
806
|
+
* different `zod` minor than the core package. Keeping the shape local
|
|
807
|
+
* keeps the addon decoupled from the schema's internal type encoding.
|
|
458
808
|
*/
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
809
|
+
interface ContributionShape {
|
|
810
|
+
tabs?: Array<{
|
|
811
|
+
id: string;
|
|
812
|
+
label: string;
|
|
813
|
+
icon: string;
|
|
814
|
+
order?: number;
|
|
815
|
+
}>;
|
|
816
|
+
sections: Array<{
|
|
817
|
+
id: string;
|
|
818
|
+
title: string;
|
|
819
|
+
description?: string;
|
|
820
|
+
style?: 'card' | 'accordion';
|
|
821
|
+
defaultCollapsed?: boolean;
|
|
822
|
+
columns?: 1 | 2 | 3 | 4;
|
|
823
|
+
tab?: string;
|
|
824
|
+
/** Where the section renders. Default 'settings' (Config tab); 'top-tab' hoists into the device-detail tab bar via DeviceDetail discovery. */
|
|
825
|
+
location?: 'settings' | 'top-tab';
|
|
826
|
+
order?: number;
|
|
827
|
+
fields: unknown[];
|
|
828
|
+
}>;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
declare class DeviceManagerAddon extends BaseAddon {
|
|
832
|
+
constructor();
|
|
833
|
+
/** Shorthand for the kernel-injected capability registry. */
|
|
834
|
+
private get capabilityRegistry();
|
|
835
|
+
/**
|
|
836
|
+
* Parent-chain event propagator. Started in `onInitialize` once the
|
|
837
|
+
* hub's `deviceRegistry` is available; listens to every device-sourced
|
|
838
|
+
* event and re-emits a copy on each ancestor scope with `via[]`
|
|
839
|
+
* populated. Stopped in `onShutdown`.
|
|
840
|
+
*/
|
|
841
|
+
private propagator;
|
|
842
|
+
/**
|
|
843
|
+
* Hub-side mirror of every device's cap-keyed runtime state.
|
|
844
|
+
* Populated whenever any caller writes via `deviceState.setCapSlice`
|
|
845
|
+
* (the canonical cross-layer write entrypoint) and on first load
|
|
846
|
+
* via `loadRuntimeState`. Cross-process consumers reach the mirror
|
|
847
|
+
* through the `deviceState` cap router; per-cap event subscribers
|
|
848
|
+
* (e.g. `battery.onStatusChanged`) get the same data via
|
|
849
|
+
* cap-specific events still emitted by the owning device.
|
|
850
|
+
*
|
|
851
|
+
* Key: deviceId. Value: per-cap slice map. Empty by default —
|
|
852
|
+
* slices show up as `setCapSlice` calls trickle in.
|
|
853
|
+
*/
|
|
854
|
+
private readonly stateMirror;
|
|
855
|
+
/**
|
|
856
|
+
* Per-device disk-write debouncer for runtime-state. `setCapSlice`
|
|
857
|
+
* updates the in-memory mirror synchronously and emits the change
|
|
858
|
+
* event immediately, but the disk write is coalesced — frequent
|
|
859
|
+
* back-to-back writes (motion phase transitions, battery pushes,
|
|
860
|
+
* etc.) collapse to one `writeDeviceRuntimeState` per
|
|
861
|
+
* `RUNTIME_STATE_DEBOUNCE_MS` window. `flushRuntimeStateWrites`
|
|
862
|
+
* awaits any in-flight write + scheduled flush so shutdown is
|
|
863
|
+
* lossless.
|
|
864
|
+
*/
|
|
865
|
+
private readonly runtimeStateDebounce;
|
|
866
|
+
private static readonly RUNTIME_STATE_DEBOUNCE_MS;
|
|
867
|
+
/**
|
|
868
|
+
* Cross-process native-provider cache: deviceId (numeric) → capName → { addonId, nodeId }.
|
|
869
|
+
* Kept in sync with `device.bindings-changed` events emitted by forked
|
|
870
|
+
* workers. Union'd into `getBindings` so hub-side consumers see every
|
|
871
|
+
* native cap regardless of which process owns the IDevice. No persistence
|
|
872
|
+
* — entries re-register when the worker restarts. Purged on
|
|
873
|
+
* `$node.disconnected` to avoid stale routing after a worker crash.
|
|
874
|
+
*/
|
|
875
|
+
private remoteNativeCaps;
|
|
876
|
+
/** Wait for a device-provider by addonId, returning null on timeout. */
|
|
877
|
+
private waitDeviceProvider;
|
|
878
|
+
/** Require a device-provider by addonId — throws if not found. */
|
|
879
|
+
private requireDeviceProvider;
|
|
880
|
+
private readBindingsStore;
|
|
881
|
+
private writeBindingsStore;
|
|
882
|
+
private resolveWrapperNodeId;
|
|
883
|
+
/**
|
|
884
|
+
* Active discovery of native caps registered on a worker node.
|
|
885
|
+
* Called from the `$node.connected` handler to recover from lost
|
|
886
|
+
* `DeviceBindingsChanged` broadcasts after worker restart.
|
|
887
|
+
*
|
|
888
|
+
* Iterates the broker's service registry, picks
|
|
889
|
+
* `<addonId>.native-provider.<capName>` services owned by the
|
|
890
|
+
* connected node, calls each service's `$listDeviceIds` action to
|
|
891
|
+
* fetch the deviceIds the worker has registered that cap on, then
|
|
892
|
+
* writes entries into `remoteNativeCaps`.
|
|
893
|
+
*
|
|
894
|
+
* Best-effort: per-service failures are logged and swallowed so a
|
|
895
|
+
* single bad service doesn't abort the whole rebuild.
|
|
896
|
+
*/
|
|
897
|
+
private discoverWorkerNativeCaps;
|
|
898
|
+
getBindings(input: {
|
|
899
|
+
deviceId: number;
|
|
900
|
+
}): Promise<{
|
|
901
|
+
deviceId: number;
|
|
902
|
+
entries: DeviceBindingEntry[];
|
|
903
|
+
}>;
|
|
904
|
+
/**
|
|
905
|
+
* Whole-fleet binding dump. Iterates every device known to the
|
|
906
|
+
* deviceRegistry and reuses the per-device `getBindings` resolver
|
|
907
|
+
* for each — same routing rules, single round-trip. Used by
|
|
908
|
+
* `SystemManager.init()` for warm-boot.
|
|
909
|
+
*
|
|
910
|
+
* Bindings change rarely (wrapper toggle, device add/remove) so
|
|
911
|
+
* clients invalidate via the existing
|
|
912
|
+
* `capability.binding-changed` event rather than re-fetching this
|
|
913
|
+
* payload periodically.
|
|
914
|
+
*/
|
|
915
|
+
getAllBindings(): Promise<Array<{
|
|
916
|
+
deviceId: number;
|
|
917
|
+
entries: DeviceBindingEntry[];
|
|
918
|
+
}>>;
|
|
919
|
+
/**
|
|
920
|
+
* Resolve a numeric deviceId to a stableId via persisted meta.
|
|
921
|
+
* Used only by the device-identity section of the device-details
|
|
922
|
+
* aggregator (see `buildBaseDeviceSection`) to surface the stableId as
|
|
923
|
+
* a readonly display field. All runtime/registry lookups are keyed by
|
|
924
|
+
* numeric deviceId; this helper is display-only.
|
|
925
|
+
*/
|
|
926
|
+
private lookupPersistedStableId;
|
|
927
|
+
getDeviceAggregate(deviceId: number, kind: 'settings' | 'live'): Promise<ContributionShape | null>;
|
|
928
|
+
/**
|
|
929
|
+
* Build the device-manager's own contribution to the aggregator — the
|
|
930
|
+
* device identity (id, stableId, addonId, type, online) + the
|
|
931
|
+
* driver-specific config exposed by the device class via
|
|
932
|
+
* `zodEntriesToConfigUI`.
|
|
933
|
+
*
|
|
934
|
+
* Two paths, deliberately symmetric with `getSettingsSchema`:
|
|
935
|
+
*
|
|
936
|
+
* - Hub-local: device's IDevice instance lives in this process'
|
|
937
|
+
* DeviceRegistry, we read config + schema directly by reference.
|
|
938
|
+
* - Cross-process: device lives in a forked worker (RtspCamera on
|
|
939
|
+
* provider-rtsp, ONVIF on provider-onvif, …). We ask the worker's
|
|
940
|
+
* `device-ops.getSettingsSchema` native provider for a wire-
|
|
941
|
+
* serializable ConfigUISchema and merge it in under the same
|
|
942
|
+
* "Driver Config" section, so the UI sees the same shape regardless
|
|
943
|
+
* of where the IDevice physically runs.
|
|
944
|
+
*
|
|
945
|
+
* Returns `null` only when the device genuinely doesn't exist anywhere
|
|
946
|
+
* (no hub-local, no persisted ownership, no device-ops native). The
|
|
947
|
+
* aggregator falls back to contributor sections only in that case.
|
|
948
|
+
*/
|
|
949
|
+
private buildBaseDeviceSection;
|
|
950
|
+
/**
|
|
951
|
+
* Lookup the native owner for `device-ops` on `deviceId` — the native-cap
|
|
952
|
+
* registry (hub-local and remote) is keyed by numeric id.
|
|
953
|
+
*/
|
|
954
|
+
private resolveNativeDeviceOwner;
|
|
955
|
+
/**
|
|
956
|
+
* Aggregate `status` across every registered cap for a device.
|
|
957
|
+
*
|
|
958
|
+
* Walks the supplied cap list (or `CAP_NAMES_WITH_STATUS` when
|
|
959
|
+
* omitted), looks up a native provider per cap via the capability
|
|
960
|
+
* registry, calls `provider.getStatus({ deviceId })`, and validates
|
|
961
|
+
* the return against the cap's own `status.schema`. Validation
|
|
962
|
+
* failures log a warning and yield `null` for that cap so the
|
|
963
|
+
* overall aggregate stays usable — a single misbehaving provider
|
|
964
|
+
* must not blank out a device's entire status view.
|
|
965
|
+
*
|
|
966
|
+
* Returned shape is `Record<capName, unknown | null>`; the client-
|
|
967
|
+
* side hook tightens this to `CapStatusTypeMap` via the generated
|
|
968
|
+
* `cap-status-types.ts`.
|
|
969
|
+
*/
|
|
970
|
+
private getDeviceStatusAggregate;
|
|
971
|
+
/**
|
|
972
|
+
* Return the driver-specific device-settings contribution. Hub-local
|
|
973
|
+
* devices call `getSettingsUISchema()` directly; forked-worker devices
|
|
974
|
+
* go through the `device-ops.getSettingsSchema` cap method on the
|
|
975
|
+
* numeric-id-keyed native registry.
|
|
976
|
+
*/
|
|
977
|
+
private resolveDriverConfigSchema;
|
|
978
|
+
updateDeviceField(input: {
|
|
979
|
+
deviceId: number;
|
|
980
|
+
writerCapName: string;
|
|
981
|
+
writerAddonId: string;
|
|
982
|
+
key: string;
|
|
983
|
+
value: unknown;
|
|
984
|
+
}): Promise<{
|
|
985
|
+
success: true;
|
|
986
|
+
}>;
|
|
987
|
+
/**
|
|
988
|
+
* Batched counterpart of `updateDeviceField`. Groups changes by
|
|
989
|
+
* `(writerCapName, writerAddonId)` so each contributor receives a
|
|
990
|
+
* single `applyDeviceSettingsPatch` with all of its updates merged —
|
|
991
|
+
* avoids N round-trips for simultaneous edits in the same save.
|
|
992
|
+
*
|
|
993
|
+
* Per-provider failures are captured in the `failures[]` output so the
|
|
994
|
+
* admin UI can highlight which sections didn't persist; a failure on
|
|
995
|
+
* one provider does NOT abort the others.
|
|
996
|
+
*/
|
|
997
|
+
updateDeviceFieldsBatch(input: {
|
|
998
|
+
deviceId: number;
|
|
999
|
+
changes: ReadonlyArray<{
|
|
1000
|
+
writerCapName: string;
|
|
1001
|
+
writerAddonId: string;
|
|
1002
|
+
key: string;
|
|
1003
|
+
value: unknown;
|
|
1004
|
+
}>;
|
|
1005
|
+
}): Promise<{
|
|
1006
|
+
success: true;
|
|
1007
|
+
failures: {
|
|
1008
|
+
writerCapName: string;
|
|
1009
|
+
writerAddonId: string;
|
|
1010
|
+
error: string;
|
|
1011
|
+
}[];
|
|
1012
|
+
}>;
|
|
1013
|
+
/** Apply a single grouped patch to the appropriate provider. Mirrors
|
|
1014
|
+
* `updateDeviceField` routing (special-case device-manager, else
|
|
1015
|
+
* registry lookup). Used by `updateDeviceFieldsBatch`. */
|
|
1016
|
+
private applyGroupPatch;
|
|
1017
|
+
listWrappersForCap(input: {
|
|
1018
|
+
capName: string;
|
|
1019
|
+
}): Promise<string[]>;
|
|
1020
|
+
listBindableCapsForDeviceType(input: {
|
|
1021
|
+
deviceType: string;
|
|
1022
|
+
}): Promise<Array<{
|
|
1023
|
+
capName: string;
|
|
1024
|
+
wrappers: string[];
|
|
1025
|
+
}>>;
|
|
1026
|
+
setWrapperActive(input: {
|
|
1027
|
+
deviceId: number;
|
|
1028
|
+
capName: string;
|
|
1029
|
+
wrapperAddonId: string;
|
|
1030
|
+
active: boolean;
|
|
1031
|
+
}): Promise<void>;
|
|
1032
|
+
protected onInitialize(): Promise<ProviderRegistration[] | void>;
|
|
1033
|
+
/**
|
|
1034
|
+
* Single-cap mirror update — diff against the current mirror,
|
|
1035
|
+
* persist the new slice in-memory, emit `DeviceStateChanged` for
|
|
1036
|
+
* this cap. No-op on identical writes (both same shape and same
|
|
1037
|
+
* values). Called by `setCapSlice` provider.
|
|
1038
|
+
*/
|
|
1039
|
+
private applySingleCapUpdate;
|
|
1040
|
+
/**
|
|
1041
|
+
* Debounced disk writer. Coalesces frequent writes (motion phase
|
|
1042
|
+
* transitions, battery pushes) into one `writeDeviceRuntimeState`
|
|
1043
|
+
* per `RUNTIME_STATE_DEBOUNCE_MS` window. Reads the per-device
|
|
1044
|
+
* blob from the live mirror at flush time so the disk picture is
|
|
1045
|
+
* always the latest state — no risk of writing a stale snapshot.
|
|
1046
|
+
*/
|
|
1047
|
+
private scheduleRuntimeStateDiskWrite;
|
|
1048
|
+
/**
|
|
1049
|
+
* One-shot mirror seed used by `loadRuntimeState` at boot so the
|
|
1050
|
+
* hub knows about every persisted slice without waiting for the
|
|
1051
|
+
* first `setCapSlice` call. No events emitted — this is
|
|
1052
|
+
* initial-state population, not a transition.
|
|
1053
|
+
*/
|
|
1054
|
+
private seedMirror;
|
|
1055
|
+
private snapshotForDevice;
|
|
1056
|
+
private emitStateChanged;
|
|
1057
|
+
protected onShutdown(): Promise<void>;
|
|
464
1058
|
}
|
|
465
1059
|
|
|
466
1060
|
type ElementState = 'stopped' | 'starting' | 'running' | 'stopping' | 'error' | 'disabled';
|
|
@@ -506,10 +1100,52 @@ declare class SystemEventBus implements IEventBus {
|
|
|
506
1100
|
private readonly subscribers;
|
|
507
1101
|
constructor(bufferSize?: number);
|
|
508
1102
|
emit(event: SystemEvent): void;
|
|
1103
|
+
/**
|
|
1104
|
+
* Subscribe to events matching a filter.
|
|
1105
|
+
* When called with a typed category filter, the handler receives typed event data.
|
|
1106
|
+
*/
|
|
509
1107
|
subscribe(filter: EventFilter, handler: (event: SystemEvent) => void): () => void;
|
|
510
1108
|
getRecent(filter?: EventFilter, limit?: number): readonly SystemEvent[];
|
|
511
1109
|
}
|
|
512
1110
|
|
|
1111
|
+
declare class LogRingBuffer {
|
|
1112
|
+
private readonly capacity;
|
|
1113
|
+
private readonly buffer;
|
|
1114
|
+
private head;
|
|
1115
|
+
private count;
|
|
1116
|
+
constructor(capacity?: number);
|
|
1117
|
+
push(entry: LogEntry): void;
|
|
1118
|
+
getAll(): LogEntry[];
|
|
1119
|
+
query(filter: LogFilter): LogEntry[];
|
|
1120
|
+
/**
|
|
1121
|
+
* Drop entries that match `filter`. Returns the number of entries
|
|
1122
|
+
* removed. Triggered by the UI's "Clear logs" button so the operator
|
|
1123
|
+
* can wipe the historical buffer for a specific scope (per-device,
|
|
1124
|
+
* per-addon, per-agent) — without it, closing and reopening the
|
|
1125
|
+
* panel re-populates the cleared rows from the server's ring buffer.
|
|
1126
|
+
*
|
|
1127
|
+
* Filter semantics mirror `query` (same level / since / until / tags
|
|
1128
|
+
* handling) — whatever you'd see listed by `query(filter)` is what
|
|
1129
|
+
* gets removed.
|
|
1130
|
+
*/
|
|
1131
|
+
clear(filter?: LogFilter): number;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
declare class ScopedLogger implements IScopedLogger {
|
|
1135
|
+
private readonly scope;
|
|
1136
|
+
private readonly writeFn;
|
|
1137
|
+
private readonly tags?;
|
|
1138
|
+
constructor(scope: string | undefined, writeFn: (entry: LogEntry) => void, tags?: LogTags | undefined);
|
|
1139
|
+
debug(message: string, extras?: LogExtras): void;
|
|
1140
|
+
info(message: string, extras?: LogExtras): void;
|
|
1141
|
+
warn(message: string, extras?: LogExtras): void;
|
|
1142
|
+
error(message: string, extras?: LogExtras): void;
|
|
1143
|
+
child(childScope: string): IScopedLogger;
|
|
1144
|
+
withTags(tags: LogTags): IScopedLogger;
|
|
1145
|
+
private write;
|
|
1146
|
+
private mergeTags;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
513
1149
|
interface ILogDestination {
|
|
514
1150
|
initialize(): Promise<void>;
|
|
515
1151
|
shutdown(): Promise<void>;
|
|
@@ -520,15 +1156,103 @@ declare class LogManager {
|
|
|
520
1156
|
private readonly ringBuffer;
|
|
521
1157
|
private readonly destinations;
|
|
522
1158
|
private readonly subscribers;
|
|
1159
|
+
private deviceNameLookup;
|
|
523
1160
|
constructor(bufferSize?: number);
|
|
524
|
-
|
|
1161
|
+
/**
|
|
1162
|
+
* Register a callback that resolves `deviceId → deviceName`. Called
|
|
1163
|
+
* for every emitted entry that carries `tags.deviceId` but no
|
|
1164
|
+
* explicit `tags.deviceName` — the LogManager injects the resolved
|
|
1165
|
+
* name directly into the entry's tags BEFORE ring-buffer / destination
|
|
1166
|
+
* write, so every destination (local console, file, remote forwarder,
|
|
1167
|
+
* addon-bundled copies of core) sees the enriched shape regardless of
|
|
1168
|
+
* which module instance the destination was built from.
|
|
1169
|
+
*/
|
|
1170
|
+
setDeviceNameLookup(lookup: ((deviceId: number) => string | null) | null): void;
|
|
1171
|
+
createLogger(scope?: string): IScopedLogger;
|
|
1172
|
+
private enrichDeviceName;
|
|
525
1173
|
/** Subscribe to live logs matching a filter. Returns an unsubscribe function. */
|
|
526
1174
|
subscribe(filter: Partial<LogFilter>, callback: (entry: LogEntry) => void): () => void;
|
|
527
1175
|
private matchesFilter;
|
|
528
|
-
|
|
1176
|
+
/**
|
|
1177
|
+
* Register a log destination.
|
|
1178
|
+
*
|
|
1179
|
+
* @param opts.replay If true (default), replay every entry currently in
|
|
1180
|
+
* the ring buffer to the new destination before live
|
|
1181
|
+
* traffic starts. Lets a destination added mid-boot
|
|
1182
|
+
* still receive boot-time log entries.
|
|
1183
|
+
*/
|
|
1184
|
+
addDestination(dest: ILogDestination, opts?: {
|
|
1185
|
+
replay?: boolean;
|
|
1186
|
+
}): void;
|
|
529
1187
|
removeDestination(dest: ILogDestination): void;
|
|
530
1188
|
query(filter: LogFilter): LogEntry[];
|
|
1189
|
+
/**
|
|
1190
|
+
* Drop ring-buffer entries matching `filter`. Returns the count
|
|
1191
|
+
* removed. Backs the UI's "Clear logs" admin action so an operator
|
|
1192
|
+
* can wipe the historical window for a scope (per-device, per-addon,
|
|
1193
|
+
* agent-level) without restarting the server. External destinations
|
|
1194
|
+
* (file, forwarder) are NOT touched — only the in-memory ring.
|
|
1195
|
+
*/
|
|
1196
|
+
clear(filter?: LogFilter): number;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
/**
|
|
1200
|
+
* Canonical single-line formatter for every `LogEntry` that reaches a
|
|
1201
|
+
* console transport — hub-side `WinstonDestination` +
|
|
1202
|
+
* `ConsoleDestination`, agent-side `HubForwarderDestination`. One
|
|
1203
|
+
* definition so the three paths can't drift.
|
|
1204
|
+
*
|
|
1205
|
+
* Layout mirrors NestJS `ConsoleLogger` output:
|
|
1206
|
+
*
|
|
1207
|
+
* [Nest] 54994 - 04/20/2026, 12:45:53 AM LOG [InstanceLoader] TrpcModule dependencies initialized +0ms
|
|
1208
|
+
*
|
|
1209
|
+
* Mapping for camstack — cluster-aware:
|
|
1210
|
+
* - `[Nest]` (brand bracket) → `[<agent>/<addonId>]` so operators see
|
|
1211
|
+
* at a glance which node emitted the line
|
|
1212
|
+
* (matches the cluster topology)
|
|
1213
|
+
* - `54994` (pid) → `process.pid`
|
|
1214
|
+
* - `<timestamp>` → `M/D/YYYY, H:MM:SS AM`
|
|
1215
|
+
* - `LOG` / `WARN` / `ERROR` → `entry.level` upper-cased, colour per level
|
|
1216
|
+
* - `[InstanceLoader]` (ctx) → `[<device>]` — shown only when a device
|
|
1217
|
+
* tag is present; omitted otherwise
|
|
1218
|
+
* - `<message>` → `entry.message`
|
|
1219
|
+
* - trailing `+Nms` → we don't compute timing yet; omitted
|
|
1220
|
+
*
|
|
1221
|
+
* Rendered examples:
|
|
1222
|
+
* [hub/winston-logging] 71184 - 04/20/2026, 12:45:53 AM INFO Winston logging initialized
|
|
1223
|
+
* [hub/provider-rtsp] 71184 - 04/20/2026, 12:46:01 AM WARN [salone] probe failed {err="timeout"}
|
|
1224
|
+
* [dev-agent-0/detection] 12345 - 04/20/2026, 12:47:15 AM ERROR [cortile] no detector {codec=av1}
|
|
1225
|
+
*/
|
|
1226
|
+
|
|
1227
|
+
/** Options for `formatLogLine`. */
|
|
1228
|
+
interface FormatLogLineOptions {
|
|
1229
|
+
/**
|
|
1230
|
+
* Emit ANSI colour codes. When omitted, falls back to the shell-env
|
|
1231
|
+
* heuristic (`NO_COLOR`/`FORCE_COLOR`/`isTTY`). Destinations that
|
|
1232
|
+
* always target a console (ConsoleDestination, HubForwarderDestination)
|
|
1233
|
+
* pass `true`; file sinks (Winston JSON) pass `false` so logs on disk
|
|
1234
|
+
* stay plain text regardless of the shell env.
|
|
1235
|
+
*
|
|
1236
|
+
* `NO_COLOR=1` in the environment still wins — consumer opt-in beats
|
|
1237
|
+
* producer opt-in, matching the https://no-color.org/ convention.
|
|
1238
|
+
*/
|
|
1239
|
+
readonly colorize?: boolean;
|
|
531
1240
|
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Render a `LogEntry` as one complete console line — no trailing newline.
|
|
1243
|
+
* Caller appends `\n` (file sinks) or relies on `console.log` (stdout sink).
|
|
1244
|
+
*
|
|
1245
|
+
* PID column prefers `entry.tags.pid` when set (so forked-worker entries
|
|
1246
|
+
* carry the worker's OS pid even when the hub renders them), falling back
|
|
1247
|
+
* to the renderer's own `process.pid`.
|
|
1248
|
+
*
|
|
1249
|
+
* Colours (when enabled) follow the NestJS convention: the level token
|
|
1250
|
+
* AND the message body share the level colour (green/yellow/red/gray for
|
|
1251
|
+
* info/warn/error/debug). Brand, device context, scope and meta keep
|
|
1252
|
+
* their fixed hues so the structural fields stay visually distinct from
|
|
1253
|
+
* the message content.
|
|
1254
|
+
*/
|
|
1255
|
+
declare function formatLogLine(entry: LogEntry, options?: FormatLogLineOptions): string;
|
|
532
1256
|
|
|
533
1257
|
interface IStorageBackend {
|
|
534
1258
|
/** Backend type identifier */
|
|
@@ -537,11 +1261,31 @@ interface IStorageBackend {
|
|
|
537
1261
|
readonly basePath: string;
|
|
538
1262
|
/** Resolve a subpath to an absolute path */
|
|
539
1263
|
resolve(subpath: string): string;
|
|
540
|
-
/**
|
|
1264
|
+
/**
|
|
1265
|
+
* Check whether the backend is usable: either the base directory
|
|
1266
|
+
* already exists and is writable, OR we can create it on first
|
|
1267
|
+
* write (i.e. the nearest existing ancestor is writable).
|
|
1268
|
+
*/
|
|
541
1269
|
isAvailable(): boolean;
|
|
542
|
-
/**
|
|
1270
|
+
/** No-op for lazy backends. Kept for API compatibility. */
|
|
543
1271
|
initialize(): Promise<void>;
|
|
544
1272
|
}
|
|
1273
|
+
/**
|
|
1274
|
+
* Filesystem storage backend — lazy by design.
|
|
1275
|
+
*
|
|
1276
|
+
* `initialize()` does NOT create the base directory eagerly. Instead,
|
|
1277
|
+
* consumers that write via `FilesystemStorageProvider` (and other write
|
|
1278
|
+
* helpers in storage-manager.ts) run `fs.mkdir(dirname(filePath), { recursive: true })`
|
|
1279
|
+
* right before every `writeFile`, so the directory tree appears on demand.
|
|
1280
|
+
*
|
|
1281
|
+
* The previous behaviour eagerly mkdir'd every location declared in
|
|
1282
|
+
* `StorageLocationManager.initializeDefaults()` — six directories (`db`,
|
|
1283
|
+
* `media`, `recordings`, `models`, `cache`, `logs`) got created at boot
|
|
1284
|
+
* even if the installation had no cameras, no recording addon, no
|
|
1285
|
+
* analytics addon, etc. That meant every fresh install looked like it
|
|
1286
|
+
* was producing data when it had nothing to write. Laziness fixes that:
|
|
1287
|
+
* a directory only exists once an addon decides to put a file there.
|
|
1288
|
+
*/
|
|
545
1289
|
declare class FsStorageBackend implements IStorageBackend {
|
|
546
1290
|
readonly type = "local";
|
|
547
1291
|
readonly basePath: string;
|
|
@@ -634,6 +1378,7 @@ declare class StorageManager {
|
|
|
634
1378
|
setProvider(provider: IStorageProvider | IStorageProvider$1): void;
|
|
635
1379
|
setNewStorageProvider(provider: IStorageProvider$1): void;
|
|
636
1380
|
setSettingsBackend(backend: ISettingsBackend): void;
|
|
1381
|
+
getSettingsBackend(): ISettingsBackend;
|
|
637
1382
|
getProvider(): IStorageProvider;
|
|
638
1383
|
setLocationManager(manager: StorageLocationManager): void;
|
|
639
1384
|
getLocationManager(): StorageLocationManager;
|
|
@@ -650,38 +1395,18 @@ declare class StorageManager {
|
|
|
650
1395
|
|
|
651
1396
|
/**
|
|
652
1397
|
* Manages scoped API tokens with restricted addon/route/capability access.
|
|
653
|
-
* Framework-agnostic — dependencies injected via constructor.
|
|
654
1398
|
*/
|
|
655
1399
|
declare class ScopedTokenManager {
|
|
656
|
-
private readonly
|
|
657
|
-
constructor(
|
|
658
|
-
/**
|
|
659
|
-
* Create a new scoped token. Returns the raw token string (shown once)
|
|
660
|
-
* and the stored record (with hash, not the raw token).
|
|
661
|
-
*/
|
|
1400
|
+
private readonly store;
|
|
1401
|
+
constructor(store: SettingsStoreClient);
|
|
662
1402
|
create(userId: string, name: string, scopes: TokenScope[], expiresAt?: number): Promise<{
|
|
663
1403
|
token: string;
|
|
664
1404
|
record: ScopedToken;
|
|
665
1405
|
}>;
|
|
666
|
-
/**
|
|
667
|
-
* Validate a raw token string. Returns the token record if valid, null otherwise.
|
|
668
|
-
*/
|
|
669
1406
|
validate(rawToken: string): Promise<ScopedToken | null>;
|
|
670
|
-
/**
|
|
671
|
-
* Check whether a token's scopes grant access to the given addon, route, or capability.
|
|
672
|
-
*/
|
|
673
1407
|
matchesScope(token: ScopedToken, addonId?: string, routePath?: string, capability?: string): boolean;
|
|
674
|
-
/**
|
|
675
|
-
* Revoke a token by ID.
|
|
676
|
-
*/
|
|
677
1408
|
revoke(tokenId: string): Promise<void>;
|
|
678
|
-
/**
|
|
679
|
-
* List all tokens for a user (without exposing the raw token).
|
|
680
|
-
*/
|
|
681
1409
|
listForUser(userId: string): Promise<ScopedToken[]>;
|
|
682
|
-
/**
|
|
683
|
-
* Update the lastUsedAt timestamp for a token.
|
|
684
|
-
*/
|
|
685
1410
|
updateLastUsed(tokenId: string): Promise<void>;
|
|
686
1411
|
}
|
|
687
1412
|
|
|
@@ -693,7 +1418,8 @@ declare class AuthManager {
|
|
|
693
1418
|
private readonly config;
|
|
694
1419
|
private readonly jwtSecret;
|
|
695
1420
|
private scopedTokenManager;
|
|
696
|
-
|
|
1421
|
+
private readonly logger;
|
|
1422
|
+
constructor(config: AuthConfigReader, logger?: IScopedLogger);
|
|
697
1423
|
signToken(payload: Omit<TokenPayload, 'iat' | 'exp'>): string;
|
|
698
1424
|
verifyToken(token: string): TokenPayload;
|
|
699
1425
|
hashPassword(password: string): Promise<string>;
|
|
@@ -728,31 +1454,20 @@ declare class AuthManager {
|
|
|
728
1454
|
matchesScopedTokenScope(token: ScopedToken, addonId?: string, routePath?: string, capability?: string): boolean;
|
|
729
1455
|
}
|
|
730
1456
|
|
|
731
|
-
interface ApiKeyRecord {
|
|
732
|
-
id: string;
|
|
733
|
-
label: string;
|
|
734
|
-
role: UserRole;
|
|
735
|
-
allowedProviders: string[] | '*';
|
|
736
|
-
allowedDevices: Record<string, string[] | '*'>;
|
|
737
|
-
tokenHash: string;
|
|
738
|
-
tokenPrefix: string;
|
|
739
|
-
createdAt: number;
|
|
740
|
-
lastUsedAt?: number;
|
|
741
|
-
}
|
|
742
1457
|
interface CreateApiKeyInput {
|
|
743
1458
|
label: string;
|
|
744
1459
|
role: UserRole;
|
|
745
1460
|
allowedProviders?: string[] | '*';
|
|
746
1461
|
allowedDevices?: Record<string, string[] | '*'>;
|
|
747
1462
|
}
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
}
|
|
1463
|
+
interface ApiKeyStorageAccess {
|
|
1464
|
+
getStore(): SettingsStoreClient;
|
|
1465
|
+
}
|
|
751
1466
|
declare class ApiKeyManager {
|
|
752
1467
|
private readonly storageAccess;
|
|
753
1468
|
private readonly auth;
|
|
754
1469
|
constructor(storageAccess: ApiKeyStorageAccess, auth: AuthManager);
|
|
755
|
-
private get
|
|
1470
|
+
private get store();
|
|
756
1471
|
create(input: CreateApiKeyInput): Promise<{
|
|
757
1472
|
record: ApiKeyRecord;
|
|
758
1473
|
token: string;
|
|
@@ -771,18 +1486,18 @@ interface CreateUserInput {
|
|
|
771
1486
|
allowedDevices?: Record<string, string[] | '*'>;
|
|
772
1487
|
}
|
|
773
1488
|
type UpdatableUserFields = Partial<Pick<UserRecord, 'role' | 'allowedProviders' | 'allowedDevices'>>;
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
}
|
|
777
|
-
|
|
1489
|
+
interface UserStorageAccess {
|
|
1490
|
+
getStore(): SettingsStoreClient;
|
|
1491
|
+
}
|
|
1492
|
+
interface UserConfigReader {
|
|
778
1493
|
get<T>(path: string): T;
|
|
779
|
-
}
|
|
1494
|
+
}
|
|
780
1495
|
declare class UserManager {
|
|
781
1496
|
private readonly storageAccess;
|
|
782
1497
|
private readonly auth;
|
|
783
1498
|
private readonly config;
|
|
784
1499
|
constructor(storageAccess: UserStorageAccess, auth: AuthManager, config: UserConfigReader);
|
|
785
|
-
private get
|
|
1500
|
+
private get store();
|
|
786
1501
|
create(input: CreateUserInput): Promise<UserRecord>;
|
|
787
1502
|
findByUsername(username: string): Promise<UserRecord | null>;
|
|
788
1503
|
findById(id: string): Promise<UserRecord | null>;
|
|
@@ -798,7 +1513,7 @@ declare class UserManager {
|
|
|
798
1513
|
* Central notification service that routes notifications to configured outputs.
|
|
799
1514
|
* Framework-agnostic — dependencies injected via constructor.
|
|
800
1515
|
*
|
|
801
|
-
* Outputs are resolved from the
|
|
1516
|
+
* Outputs are resolved from the ICapabilityRegistry's 'notification-output'
|
|
802
1517
|
* collection on each call (proxy pattern). Falls back to a local map
|
|
803
1518
|
* when no registry is provided (backward compat).
|
|
804
1519
|
*/
|
|
@@ -811,13 +1526,13 @@ declare class NotificationService {
|
|
|
811
1526
|
private registry;
|
|
812
1527
|
constructor(logger: IScopedLogger);
|
|
813
1528
|
/** Set the registry for live output lookup. Called once during boot. */
|
|
814
|
-
setRegistry(registry:
|
|
1529
|
+
setRegistry(registry: ICapabilityRegistry): void;
|
|
815
1530
|
/** Resolve all outputs — prefers registry, falls back to local map */
|
|
816
1531
|
private get outputs();
|
|
817
|
-
/**
|
|
818
|
-
|
|
819
|
-
/**
|
|
820
|
-
|
|
1532
|
+
/** Register an output in the local fallback map (used when no registry is set). */
|
|
1533
|
+
registerLocalOutput(output: INotificationOutput): void;
|
|
1534
|
+
/** Remove an output from the local fallback map. */
|
|
1535
|
+
unregisterLocalOutput(id: string): void;
|
|
821
1536
|
setRouting(category: string, outputIds: string[]): void;
|
|
822
1537
|
setRateLimit(category: string, minIntervalMs: number): void;
|
|
823
1538
|
notify(notification: Notification): Promise<void>;
|
|
@@ -888,54 +1603,6 @@ declare class AddonRouteRegistry {
|
|
|
888
1603
|
}>;
|
|
889
1604
|
}
|
|
890
1605
|
|
|
891
|
-
interface IRegisteredDevice {
|
|
892
|
-
readonly id: string;
|
|
893
|
-
readonly name: string;
|
|
894
|
-
readonly providerId: string;
|
|
895
|
-
readonly capabilities: readonly string[];
|
|
896
|
-
}
|
|
897
|
-
declare class DeviceRegistry<T extends IRegisteredDevice = IRegisteredDevice> {
|
|
898
|
-
private readonly eventBus;
|
|
899
|
-
private readonly devices;
|
|
900
|
-
private readonly logger;
|
|
901
|
-
constructor(eventBus: IEventBus, loggingService: LoggerFactory);
|
|
902
|
-
registerDevice(device: T): void;
|
|
903
|
-
unregisterDevice(id: string): void;
|
|
904
|
-
getDevice(id: string): T | null;
|
|
905
|
-
listDevices(): T[];
|
|
906
|
-
getDevicesByProvider(providerId: string): T[];
|
|
907
|
-
getDevicesWithCapability(cap: string): T[];
|
|
908
|
-
registerProviderDevices(providerId: string, devices: readonly T[]): void;
|
|
909
|
-
unregisterProviderDevices(providerId: string): void;
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
interface IDeviceCapability {
|
|
913
|
-
kind: string;
|
|
914
|
-
}
|
|
915
|
-
interface CapabilityBinding {
|
|
916
|
-
source: 'native' | 'addon' | 'disabled';
|
|
917
|
-
addonId?: string;
|
|
918
|
-
config?: Record<string, unknown>;
|
|
919
|
-
}
|
|
920
|
-
interface IResolvableDevice {
|
|
921
|
-
readonly id: string;
|
|
922
|
-
readonly capabilities: string[];
|
|
923
|
-
getCapability<T extends IDeviceCapability>(cap: string): T | null;
|
|
924
|
-
}
|
|
925
|
-
interface IAddonRegistryAccess {
|
|
926
|
-
getAddon(addonId: string): unknown | null;
|
|
927
|
-
}
|
|
928
|
-
declare class CapabilityResolver {
|
|
929
|
-
private readonly addonRegistry;
|
|
930
|
-
private readonly bindings;
|
|
931
|
-
constructor(addonRegistry: IAddonRegistryAccess);
|
|
932
|
-
resolve<T extends IDeviceCapability>(device: IResolvableDevice, cap: string): T | null;
|
|
933
|
-
setBinding(deviceId: string, cap: string, binding: CapabilityBinding): void;
|
|
934
|
-
removeBinding(deviceId: string, cap: string): void;
|
|
935
|
-
getBindings(deviceId: string): Partial<Record<string, CapabilityBinding>>;
|
|
936
|
-
getEffectiveCapabilities(device: IResolvableDevice): string[];
|
|
937
|
-
}
|
|
938
|
-
|
|
939
1606
|
interface TlsCertPair {
|
|
940
1607
|
readonly cert: Buffer;
|
|
941
1608
|
readonly key: Buffer;
|
|
@@ -966,9 +1633,14 @@ declare function loadTlsCert(certPath: string, keyPath: string): TlsCertPair;
|
|
|
966
1633
|
/**
|
|
967
1634
|
* Factory for creating tRPC clients for addons.
|
|
968
1635
|
*
|
|
969
|
-
*
|
|
970
|
-
*
|
|
971
|
-
*
|
|
1636
|
+
* In-process only: `createDirectCaller()` uses tRPC's `createCallerFactory`
|
|
1637
|
+
* to call procedures directly (zero network overhead) and wraps the raw
|
|
1638
|
+
* caller in a proxy so it matches `CreateTRPCClient<AppRouter>` shape —
|
|
1639
|
+
* addons use `context.api.namespace.method.query(input)` identically to
|
|
1640
|
+
* the cross-process path.
|
|
1641
|
+
*
|
|
1642
|
+
* Cross-process calls (forked workers, remote agents) ride the Moleculer
|
|
1643
|
+
* broker via `brokerTransportLink` in the kernel — not this factory.
|
|
972
1644
|
*/
|
|
973
1645
|
interface DirectCallerOptions {
|
|
974
1646
|
/** The tRPC router instance (from buildAppRouter) */
|
|
@@ -982,156 +1654,43 @@ interface DirectCallerOptions {
|
|
|
982
1654
|
};
|
|
983
1655
|
};
|
|
984
1656
|
}
|
|
985
|
-
interface WssClientOptions {
|
|
986
|
-
/** WebSocket URL (e.g., wss://localhost:4443/trpc) */
|
|
987
|
-
readonly url: string;
|
|
988
|
-
/** Auth token for the connection */
|
|
989
|
-
readonly token: string;
|
|
990
|
-
}
|
|
991
1657
|
declare class AddonApiFactory {
|
|
992
|
-
/**
|
|
993
|
-
* Build a WSS URL from host and port.
|
|
994
|
-
*/
|
|
995
|
-
buildWssUrl(host: string, port: number): string;
|
|
996
1658
|
/**
|
|
997
1659
|
* Create a direct caller -- calls tRPC procedures directly in-process.
|
|
998
1660
|
* Zero network overhead. Used for in-process addons and dev mode.
|
|
999
1661
|
*
|
|
1000
|
-
*
|
|
1001
|
-
*
|
|
1002
|
-
*
|
|
1003
|
-
*/
|
|
1004
|
-
createDirectCaller(options: DirectCallerOptions): Promise<unknown>;
|
|
1005
|
-
/**
|
|
1006
|
-
* Create a WSS tRPC client -- connects to the server via WebSocket.
|
|
1007
|
-
* Used for forked workers and remote agents.
|
|
1008
|
-
*
|
|
1009
|
-
* @param options.url - WSS URL (e.g., wss://localhost:4443/trpc)
|
|
1010
|
-
* @param options.token - Bearer token for authentication
|
|
1011
|
-
* @returns A tRPC client that can be used as context.api
|
|
1662
|
+
* Returns `AddonApi` — the same tRPC client surface that broker-routed
|
|
1663
|
+
* callers get. Callers treat it uniformly as `context.api` regardless
|
|
1664
|
+
* of the underlying transport.
|
|
1012
1665
|
*/
|
|
1013
|
-
|
|
1014
|
-
readonly client: unknown;
|
|
1015
|
-
readonly close: () => void;
|
|
1016
|
-
}>;
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
declare class PlatformScorer {
|
|
1020
|
-
private cached;
|
|
1021
|
-
/** Probe hardware + runtimes and score all backend combos. Cached after first call. */
|
|
1022
|
-
probe(): Promise<PlatformCapabilities>;
|
|
1023
|
-
probeHardware(): Promise<HardwareInfo>;
|
|
1024
|
-
private probeNodeBackends;
|
|
1025
|
-
private probePythonBackends;
|
|
1026
|
-
private scoreBackends;
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
declare class InferenceConfigResolver {
|
|
1030
|
-
private readonly scores;
|
|
1031
|
-
private readonly hardware;
|
|
1032
|
-
constructor(scores: readonly PlatformScore[], hardware: HardwareInfo);
|
|
1033
|
-
/**
|
|
1034
|
-
* Compute accuracy/backend weights based on available system RAM.
|
|
1035
|
-
* availableRAM_MB is now sourced from systeminformation (reliable cross-platform),
|
|
1036
|
-
* not os.freemem() which is broken on macOS.
|
|
1037
|
-
*
|
|
1038
|
-
* - > 16 GB available: prefer larger, more accurate models (accuracy 0.6, backend 0.4)
|
|
1039
|
-
* - > 8 GB available: balanced (accuracy 0.5, backend 0.5)
|
|
1040
|
-
* - <= 8 GB available: prefer speed (accuracy 0.4, backend 0.6)
|
|
1041
|
-
*/
|
|
1042
|
-
private getWeights;
|
|
1043
|
-
/**
|
|
1044
|
-
* Given an addon's model requirements, pick the best model + runtime + backend.
|
|
1045
|
-
*
|
|
1046
|
-
* Algorithm:
|
|
1047
|
-
* 1. Filter models by available RAM (minRAM_MB < 25% of available RAM)
|
|
1048
|
-
* 2. For each remaining model, find the best platform score whose format
|
|
1049
|
-
* is available in the model's formats
|
|
1050
|
-
* 3. Pick the model with the highest combined score using RAM-adaptive weights:
|
|
1051
|
-
* - High RAM (>16 GB): accuracy × 0.6 + backend × 0.4 (prefer accuracy)
|
|
1052
|
-
* - Mid RAM (>8 GB): accuracy × 0.5 + backend × 0.5 (balanced)
|
|
1053
|
-
* - Low RAM (<=8 GB): accuracy × 0.4 + backend × 0.6 (prefer speed)
|
|
1054
|
-
*/
|
|
1055
|
-
resolve(requirements: readonly ModelRequirement[]): ResolvedInferenceConfig;
|
|
1666
|
+
createDirectCaller(options: DirectCallerOptions): Promise<_camstack_types.AddonApi>;
|
|
1056
1667
|
}
|
|
1057
1668
|
|
|
1058
1669
|
declare class IntegrationRegistry implements IIntegrationRegistry {
|
|
1059
1670
|
private readonly backend;
|
|
1060
1671
|
constructor(backend: ISettingsBackend);
|
|
1061
1672
|
initialize(): Promise<void>;
|
|
1062
|
-
createIntegration(input: CreateIntegrationInput): Integration
|
|
1063
|
-
getIntegration(id: string): Integration | null
|
|
1064
|
-
getIntegrationByAddonId(addonId: string): Integration | null
|
|
1065
|
-
listIntegrations(): readonly Integration[]
|
|
1066
|
-
updateIntegration(id: string, updates: Partial<Pick<Integration, 'name' | 'enabled' | 'info'>>): Integration | null
|
|
1067
|
-
deleteIntegration(id: string): boolean
|
|
1068
|
-
getIntegrationSettings(integrationId: string): Record<string, unknown
|
|
1069
|
-
setIntegrationSetting(integrationId: string, key: string, value: unknown): void
|
|
1070
|
-
setIntegrationSettings(integrationId: string, settings: Record<string, unknown>): void
|
|
1071
|
-
createDevice(input: CreateDeviceInput):
|
|
1072
|
-
getDevice(id: string):
|
|
1073
|
-
getDeviceByStableId(stableId: string):
|
|
1074
|
-
listDevices(integrationId?: string): readonly
|
|
1075
|
-
listCameras(): readonly
|
|
1076
|
-
updateDevice(id: string, updates: Partial<Pick<
|
|
1077
|
-
deleteDevice(id: string): boolean
|
|
1078
|
-
getDeviceSettings(deviceId: string): Record<string, unknown
|
|
1079
|
-
setDeviceSetting(deviceId: string, key: string, value: unknown): void
|
|
1080
|
-
setDeviceSettings(deviceId: string, settings: Record<string, unknown>): void
|
|
1673
|
+
createIntegration(input: CreateIntegrationInput): Promise<Integration>;
|
|
1674
|
+
getIntegration(id: string): Promise<Integration | null>;
|
|
1675
|
+
getIntegrationByAddonId(addonId: string): Promise<Integration | null>;
|
|
1676
|
+
listIntegrations(): Promise<readonly Integration[]>;
|
|
1677
|
+
updateIntegration(id: string, updates: Partial<Pick<Integration, 'name' | 'enabled' | 'info'>>): Promise<Integration | null>;
|
|
1678
|
+
deleteIntegration(id: string): Promise<boolean>;
|
|
1679
|
+
getIntegrationSettings(integrationId: string): Promise<Record<string, unknown>>;
|
|
1680
|
+
setIntegrationSetting(integrationId: string, key: string, value: unknown): Promise<void>;
|
|
1681
|
+
setIntegrationSettings(integrationId: string, settings: Record<string, unknown>): Promise<void>;
|
|
1682
|
+
createDevice(input: CreateDeviceInput): Promise<PersistedDevice>;
|
|
1683
|
+
getDevice(id: string): Promise<PersistedDevice | null>;
|
|
1684
|
+
getDeviceByStableId(stableId: string): Promise<PersistedDevice | null>;
|
|
1685
|
+
listDevices(integrationId?: string): Promise<readonly PersistedDevice[]>;
|
|
1686
|
+
listCameras(): Promise<readonly PersistedDevice[]>;
|
|
1687
|
+
updateDevice(id: string, updates: Partial<Pick<PersistedDevice, 'name' | 'enabled' | 'info'>>): Promise<PersistedDevice | null>;
|
|
1688
|
+
deleteDevice(id: string): Promise<boolean>;
|
|
1689
|
+
getDeviceSettings(deviceId: string): Promise<Record<string, unknown>>;
|
|
1690
|
+
setDeviceSetting(deviceId: string, key: string, value: unknown): Promise<void>;
|
|
1691
|
+
setDeviceSettings(deviceId: string, settings: Record<string, unknown>): Promise<void>;
|
|
1081
1692
|
private mapIntegration;
|
|
1082
1693
|
private mapDevice;
|
|
1083
1694
|
}
|
|
1084
1695
|
|
|
1085
|
-
|
|
1086
|
-
type ProviderDeviceRegistry = {
|
|
1087
|
-
registerProviderDevices(providerId: string, devices: readonly IRegistrableDevice[]): void;
|
|
1088
|
-
unregisterProviderDevices(providerId: string): void;
|
|
1089
|
-
};
|
|
1090
|
-
interface IRegistrableDevice {
|
|
1091
|
-
readonly id: string;
|
|
1092
|
-
readonly name: string;
|
|
1093
|
-
readonly providerId: string;
|
|
1094
|
-
readonly capabilities: readonly string[];
|
|
1095
|
-
}
|
|
1096
|
-
interface ProviderStatus {
|
|
1097
|
-
connected: boolean;
|
|
1098
|
-
error?: string;
|
|
1099
|
-
deviceCount: number;
|
|
1100
|
-
}
|
|
1101
|
-
interface LiveEvent {
|
|
1102
|
-
type: string;
|
|
1103
|
-
camera: string;
|
|
1104
|
-
timestamp: number;
|
|
1105
|
-
data: Record<string, unknown>;
|
|
1106
|
-
}
|
|
1107
|
-
interface IManagedProvider {
|
|
1108
|
-
readonly id: string;
|
|
1109
|
-
readonly type: string;
|
|
1110
|
-
readonly name: string;
|
|
1111
|
-
start(): Promise<void>;
|
|
1112
|
-
stop(): Promise<void>;
|
|
1113
|
-
getStatus(): ProviderStatus;
|
|
1114
|
-
getDevices(): readonly IRegistrableDevice[];
|
|
1115
|
-
subscribeLiveEvents(callback: (event: LiveEvent) => void): () => void;
|
|
1116
|
-
}
|
|
1117
|
-
|
|
1118
|
-
declare class ProviderManager<P extends IManagedProvider = IManagedProvider> {
|
|
1119
|
-
private readonly deviceRegistry;
|
|
1120
|
-
private readonly eventBus;
|
|
1121
|
-
private readonly loggingService;
|
|
1122
|
-
private readonly providers;
|
|
1123
|
-
private readonly logger;
|
|
1124
|
-
constructor(deviceRegistry: ProviderDeviceRegistry, eventBus: IEventBus, loggingService: LoggerFactory);
|
|
1125
|
-
registerProvider(provider: P): void;
|
|
1126
|
-
startProvider(id: string): Promise<void>;
|
|
1127
|
-
stopProvider(id: string): Promise<void>;
|
|
1128
|
-
disableProvider(id: string): Promise<void>;
|
|
1129
|
-
enableProvider(id: string): Promise<void>;
|
|
1130
|
-
restartProvider(id: string): Promise<void>;
|
|
1131
|
-
getProvider(id: string): P | null;
|
|
1132
|
-
getProviderStatus(id: string): ElementStatus | null;
|
|
1133
|
-
listProviders(): readonly ProviderListItem[];
|
|
1134
|
-
shutdownAll(): Promise<void>;
|
|
1135
|
-
}
|
|
1136
|
-
|
|
1137
|
-
export { AddonApiFactory, AddonRouteRegistry, AgentClient, type AgentClientConfig, type AgentEventEmitter, AgentRegistry, AgentTaskRunner, ApiKeyManager, type ApiKeyRecord, type ApiKeyStorageAccess, type AuthConfigReader, AuthManager, type BinaryHandler, type CapabilityBinding, CapabilityResolver, type CertOptions, type ConnectionHandler, DecodeTaskHandler, DetectTaskHandler, DeviceRegistry, type DirectCallerOptions, type ElementState, type ElementStatus, type EnsureTlsResult, EventBus, type FeatureConfigReader, FeatureManager, FsStorageBackend, type IAddonRegistryAccess, type IStorageProvider as ICoreStorageProvider, type IDeviceCapability, type IFileStorage, type ILogDestination, type IManagedProvider, type IRegisteredDevice, type IReplContextProvider, type IReplEngine, type IResolvableDevice, type IStorageBackend, type IStorageLocation, type IStructuredStorage, InferenceConfigResolver, IntegrationRegistry, LifecycleStateMachine, LogManager, LogRingBuffer, ManagedProcess, type MessageHandler, ModelDownloadService, NetworkQualityTracker, NotificationService, PYTHON_VERSION, PipelineRunner, PipelineValidator, PlatformScorer, type ProcessEventEmitter, type ProcessLoggerFactory, ProcessManager, type ProcessState, type ProviderDeviceRegistry, ProviderManager, PythonEnvManager, type QueryFilter, RecordTaskHandler, ReplEngine, type ReplScope, type ReplSessionContext, ScopedLogger, ScopedTokenManager, StorageLocationManager, type StorageLocationName, StorageManager, type StorageRecord, SystemEventBus, TaskDispatcher, type TlsCertPair, ToastService, type Unsubscribe, type UserConfigReader, UserManager, type UserStorageAccess, type WssClientOptions, buildBinaryPath, downloadBinary, downloadFile, downloadModel, ensureBinary, ensureFfmpeg, ensurePython, ensureTlsCert, fetchJson, findInPath, getFfmpegDownloadUrl, getPlatformInfo, getPythonDownloadUrl, installPythonPackages, loadTlsCert };
|
|
1696
|
+
export { AddonApiFactory, AddonRouteRegistry, type AddonTableSchema, AlertCenterAddon, ApiKeyManager, type ApiKeyStorageAccess, type AuthConfigReader, AuthManager, type BackupConfig, CORE_TABLE_DDL, type CertOptions, ConfigStore, ConsoleDestination, ConsoleLoggingAddon, DeviceManagerAddon, type DeviceRow, DeviceStore, type DirectCallerOptions, type DownloadProgressCallback, type ElementState, type ElementStatus, EngineManagerResolver, type EnsureTlsResult, EventBus, type FeatureConfigReader, FeatureManager, FilesystemStorageAddon, FsStorageBackend, HubForwarderAddon, HubForwarderDestination, type IStorageProvider as ICoreStorageProvider, type IFileStorage, type ILogDestination, type IReplContextProvider, type IReplEngine, type IStorageBackend, type IStorageLocation, type IStructuredStorage, IntegrationRegistry, LifecycleStateMachine, LocalAuthAddon, LocalBackupAddon, LocalBackupService, LogManager, LogRingBuffer, ModelDownloadService, NativeMetricsAddon, NativeMetricsProvider, NetworkQualityTracker, NotificationService, type PidStats, PipelineRunner, PipelineValidator, PythonEnvManager, type QueryFilter, ReplEngine, type ReplScope, type ReplSessionContext, ScopedLogger, ScopedTokenManager, SettingsStore, SqliteSettingsAddon, SqliteSettingsBackend, StorageLocationManager, type StorageLocationName, StorageManager, type StorageRecord, SystemConfigAddon, SystemEventBus, type TlsCertPair, ToastService, type Unsubscribe, type UserConfigReader, UserManager, type UserStorageAccess, WinstonDestination, WinstonLoggingAddon, addonTableToDdl, deleteModelFromDisk, downloadFile, downloadModel, ensureModel, ensureTlsCert, fetchJson, formatLogLine, getModelFilePath, getPidStats, getSinglePidStats, isModelDownloaded, loadTlsCert };
|