@camstack/core 0.1.15 → 0.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon/addon-api-factory.d.ts +36 -0
- package/dist/addon/addon-api-factory.d.ts.map +1 -0
- package/dist/addon-routes/addon-route-registry.d.ts +38 -0
- package/dist/addon-routes/addon-route-registry.d.ts.map +1 -0
- package/dist/auth/api-key-manager.d.ts +27 -0
- package/dist/auth/api-key-manager.d.ts.map +1 -0
- package/dist/auth/auth-manager.d.ts +47 -0
- package/dist/auth/auth-manager.d.ts.map +1 -0
- package/dist/auth/parse-record.d.ts +19 -0
- package/dist/auth/parse-record.d.ts.map +1 -0
- package/dist/auth/scoped-token-manager.d.ts +18 -0
- package/dist/auth/scoped-token-manager.d.ts.map +1 -0
- package/dist/auth/user-manager.d.ts +34 -0
- package/dist/auth/user-manager.d.ts.map +1 -0
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.d.ts +54 -0
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.d.ts.map +1 -0
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +223 -217
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js.map +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +216 -7
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs.map +1 -1
- package/dist/builtins/addon-pages-aggregator/index.d.ts +2 -0
- package/dist/builtins/addon-pages-aggregator/index.d.ts.map +1 -0
- package/dist/builtins/addon-pages-aggregator/index.js +6 -221
- package/dist/builtins/addon-pages-aggregator/index.mjs +2 -9
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.d.ts +33 -0
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.d.ts.map +1 -0
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +199 -197
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js.map +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +192 -7
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs.map +1 -1
- package/dist/builtins/addon-widgets-aggregator/index.d.ts +2 -0
- package/dist/builtins/addon-widgets-aggregator/index.d.ts.map +1 -0
- package/dist/builtins/addon-widgets-aggregator/index.js +6 -201
- package/dist/builtins/addon-widgets-aggregator/index.mjs +2 -9
- package/dist/builtins/alerts/alerts.addon.d.ts +82 -0
- package/dist/builtins/alerts/alerts.addon.d.ts.map +1 -0
- package/dist/builtins/alerts/alerts.addon.js +590 -430
- package/dist/builtins/alerts/alerts.addon.js.map +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +595 -7
- package/dist/builtins/alerts/alerts.addon.mjs.map +1 -1
- package/dist/builtins/alerts/index.d.ts +2 -0
- package/dist/builtins/alerts/index.d.ts.map +1 -0
- package/dist/builtins/alerts/index.js +3 -443
- package/dist/builtins/alerts/index.mjs +2 -8
- package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.d.ts +8 -0
- package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.d.ts.map +1 -0
- package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.js +56 -0
- package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.js.map +1 -0
- package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.mjs +50 -0
- package/dist/builtins/auth-orchestrator/auth-orchestrator.addon.mjs.map +1 -0
- package/dist/builtins/auth-orchestrator/index.d.ts +2 -0
- package/dist/builtins/auth-orchestrator/index.d.ts.map +1 -0
- package/dist/builtins/auth-orchestrator/index.js +7 -0
- package/dist/builtins/auth-orchestrator/index.mjs +2 -0
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts +148 -0
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts.map +1 -0
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +7639 -0
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js.map +1 -0
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +7627 -0
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs.map +1 -0
- package/dist/builtins/backup-orchestrator/cron-helpers.d.ts +24 -0
- package/dist/builtins/backup-orchestrator/cron-helpers.d.ts.map +1 -0
- package/dist/builtins/backup-orchestrator/destination-policy.d.ts +73 -0
- package/dist/builtins/backup-orchestrator/destination-policy.d.ts.map +1 -0
- package/dist/builtins/backup-orchestrator/download-helpers.d.ts +13 -0
- package/dist/builtins/backup-orchestrator/download-helpers.d.ts.map +1 -0
- package/dist/builtins/backup-orchestrator/index.d.ts +3 -0
- package/dist/builtins/backup-orchestrator/index.d.ts.map +1 -0
- package/dist/builtins/backup-orchestrator/index.js +7 -0
- package/dist/builtins/backup-orchestrator/index.mjs +2 -0
- package/dist/builtins/backup-orchestrator/manifest-store.d.ts +78 -0
- package/dist/builtins/backup-orchestrator/manifest-store.d.ts.map +1 -0
- package/dist/builtins/console-logging/console-destination.d.ts +14 -0
- package/dist/builtins/console-logging/console-destination.d.ts.map +1 -0
- package/dist/builtins/console-logging/console-logging.addon.d.ts +26 -0
- package/dist/builtins/console-logging/console-logging.addon.d.ts.map +1 -0
- package/dist/builtins/console-logging/index.d.ts +4 -0
- package/dist/builtins/console-logging/index.d.ts.map +1 -0
- package/dist/builtins/console-logging/index.js +99 -235
- package/dist/builtins/console-logging/index.js.map +1 -1
- package/dist/builtins/console-logging/index.mjs +95 -9
- package/dist/builtins/console-logging/index.mjs.map +1 -1
- package/dist/builtins/device-manager/device-event-propagator.d.ts +27 -0
- package/dist/builtins/device-manager/device-event-propagator.d.ts.map +1 -0
- package/dist/builtins/device-manager/device-manager.addon.d.ts +259 -0
- package/dist/builtins/device-manager/device-manager.addon.d.ts.map +1 -0
- package/dist/builtins/device-manager/device-manager.addon.js +2125 -2127
- package/dist/builtins/device-manager/device-manager.addon.js.map +1 -1
- package/dist/builtins/device-manager/device-manager.addon.mjs +2145 -7
- package/dist/builtins/device-manager/device-manager.addon.mjs.map +1 -1
- package/dist/builtins/device-manager/index.d.ts +3 -0
- package/dist/builtins/device-manager/index.d.ts.map +1 -0
- package/dist/builtins/device-manager/index.js +6 -2156
- package/dist/builtins/device-manager/index.mjs +2 -10
- package/dist/builtins/hub-forwarder/hub-forwarder-destination.d.ts +45 -0
- package/dist/builtins/hub-forwarder/hub-forwarder-destination.d.ts.map +1 -0
- package/dist/builtins/hub-forwarder/hub-forwarder.addon.d.ts +16 -0
- package/dist/builtins/hub-forwarder/hub-forwarder.addon.d.ts.map +1 -0
- package/dist/builtins/hub-forwarder/index.d.ts +4 -0
- package/dist/builtins/hub-forwarder/index.d.ts.map +1 -0
- package/dist/builtins/hub-forwarder/index.js +150 -291
- package/dist/builtins/hub-forwarder/index.js.map +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +145 -9
- package/dist/builtins/hub-forwarder/index.mjs.map +1 -1
- package/dist/builtins/local-auth/auth-schema.d.ts +12 -0
- package/dist/builtins/local-auth/auth-schema.d.ts.map +1 -0
- package/dist/builtins/local-auth/index.d.ts +2 -0
- package/dist/builtins/local-auth/index.d.ts.map +1 -0
- package/dist/builtins/local-auth/index.js +3 -623
- package/dist/builtins/local-auth/index.mjs +2 -8
- package/dist/builtins/local-auth/local-auth.addon.d.ts +17 -0
- package/dist/builtins/local-auth/local-auth.addon.d.ts.map +1 -0
- package/dist/builtins/local-auth/local-auth.addon.js +6861 -589
- package/dist/builtins/local-auth/local-auth.addon.js.map +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +6883 -7
- package/dist/builtins/local-auth/local-auth.addon.mjs.map +1 -1
- package/dist/builtins/local-network/index.d.ts +3 -0
- package/dist/builtins/local-network/index.d.ts.map +1 -0
- package/dist/builtins/local-network/index.js +9 -0
- package/dist/builtins/local-network/index.mjs +2 -0
- package/dist/builtins/local-network/local-network.addon.d.ts +110 -0
- package/dist/builtins/local-network/local-network.addon.d.ts.map +1 -0
- package/dist/builtins/local-network/local-network.addon.js +399 -0
- package/dist/builtins/local-network/local-network.addon.js.map +1 -0
- package/dist/builtins/local-network/local-network.addon.mjs +387 -0
- package/dist/builtins/local-network/local-network.addon.mjs.map +1 -0
- package/dist/builtins/mesh-orchestrator/index.d.ts +2 -0
- package/dist/builtins/mesh-orchestrator/index.d.ts.map +1 -0
- package/dist/builtins/mesh-orchestrator/index.js +7 -0
- package/dist/builtins/mesh-orchestrator/index.mjs +2 -0
- package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.d.ts +9 -0
- package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.d.ts.map +1 -0
- package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.js +83 -0
- package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.js.map +1 -0
- package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.mjs +77 -0
- package/dist/builtins/mesh-orchestrator/mesh-orchestrator.addon.mjs.map +1 -0
- package/dist/builtins/native-metrics/index.d.ts +3 -0
- package/dist/builtins/native-metrics/index.d.ts.map +1 -0
- package/dist/builtins/native-metrics/native-metrics-provider.d.ts +49 -0
- package/dist/builtins/native-metrics/native-metrics-provider.d.ts.map +1 -0
- package/dist/builtins/native-metrics/native-metrics.addon.d.ts +74 -0
- package/dist/builtins/native-metrics/native-metrics.addon.d.ts.map +1 -0
- package/dist/builtins/native-metrics/native-metrics.addon.js +887 -861
- package/dist/builtins/native-metrics/native-metrics.addon.js.map +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +914 -5
- package/dist/builtins/native-metrics/native-metrics.addon.mjs.map +1 -1
- package/dist/builtins/platform-probe/index.d.ts +12 -0
- package/dist/builtins/platform-probe/index.d.ts.map +1 -0
- package/dist/builtins/platform-probe/index.js +539 -0
- package/dist/builtins/platform-probe/index.js.map +1 -0
- package/dist/builtins/platform-probe/index.mjs +530 -0
- package/dist/builtins/platform-probe/index.mjs.map +1 -0
- package/dist/builtins/platform-probe/inference-config-resolver.d.ts +30 -0
- package/dist/builtins/platform-probe/inference-config-resolver.d.ts.map +1 -0
- package/dist/builtins/platform-probe/platform-scorer.d.ts +22 -0
- package/dist/builtins/platform-probe/platform-scorer.d.ts.map +1 -0
- package/dist/builtins/remote-access-orchestrator/index.d.ts +2 -0
- package/dist/builtins/remote-access-orchestrator/index.d.ts.map +1 -0
- package/dist/builtins/remote-access-orchestrator/index.js +7 -0
- package/dist/builtins/remote-access-orchestrator/index.mjs +2 -0
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.d.ts +9 -0
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.d.ts.map +1 -0
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +72 -0
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js.map +1 -0
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +66 -0
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs.map +1 -0
- package/dist/builtins/snapshot/index.d.ts +3 -0
- package/dist/builtins/snapshot/index.d.ts.map +1 -0
- package/dist/builtins/snapshot/index.js +481 -491
- package/dist/builtins/snapshot/index.js.map +1 -1
- package/dist/builtins/snapshot/index.mjs +475 -464
- package/dist/builtins/snapshot/index.mjs.map +1 -1
- package/dist/builtins/snapshot/snapshot.addon.d.ts +121 -0
- package/dist/builtins/snapshot/snapshot.addon.d.ts.map +1 -0
- package/dist/builtins/sqlite-storage/config-store.d.ts +9 -0
- package/dist/builtins/sqlite-storage/config-store.d.ts.map +1 -0
- package/dist/builtins/sqlite-storage/device-store.d.ts +24 -0
- package/dist/builtins/sqlite-storage/device-store.d.ts.map +1 -0
- package/dist/builtins/sqlite-storage/filesystem-storage-provider.d.ts +87 -0
- package/dist/builtins/sqlite-storage/filesystem-storage-provider.d.ts.map +1 -0
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.d.ts +32 -0
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.d.ts.map +1 -0
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +312 -56
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js.map +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +305 -7
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs.map +1 -1
- package/dist/builtins/sqlite-storage/index.d.ts +12 -0
- package/dist/builtins/sqlite-storage/index.d.ts.map +1 -0
- package/dist/builtins/sqlite-storage/index.js +229 -1001
- package/dist/builtins/sqlite-storage/index.js.map +1 -1
- package/dist/builtins/sqlite-storage/index.mjs +268 -26
- package/dist/builtins/sqlite-storage/index.mjs.map +1 -1
- package/dist/builtins/sqlite-storage/integration-registry.d.ts +28 -0
- package/dist/builtins/sqlite-storage/integration-registry.d.ts.map +1 -0
- package/dist/builtins/sqlite-storage/settings-store.d.ts +40 -0
- package/dist/builtins/sqlite-storage/settings-store.d.ts.map +1 -0
- package/dist/builtins/sqlite-storage/sql-schema.d.ts +33 -0
- package/dist/builtins/sqlite-storage/sql-schema.d.ts.map +1 -0
- package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +94 -0
- package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts.map +1 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +15 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts.map +1 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +586 -653
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js.map +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +582 -7
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs.map +1 -1
- package/dist/builtins/storage-orchestrator/index.d.ts +7 -0
- package/dist/builtins/storage-orchestrator/index.d.ts.map +1 -0
- package/dist/builtins/storage-orchestrator/index.js +9 -0
- package/dist/builtins/storage-orchestrator/index.mjs +2 -0
- package/dist/builtins/storage-orchestrator/location-store.d.ts +50 -0
- package/dist/builtins/storage-orchestrator/location-store.d.ts.map +1 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +60 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts.map +1 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +755 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js.map +1 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +746 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs.map +1 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.service.d.ts +121 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.service.d.ts.map +1 -0
- package/dist/builtins/system-backup/system-backup.service.d.ts +138 -0
- package/dist/builtins/system-backup/system-backup.service.d.ts.map +1 -0
- package/dist/builtins/system-config/index.d.ts +2 -0
- package/dist/builtins/system-config/index.d.ts.map +1 -0
- package/dist/builtins/system-config/index.js +6 -188
- package/dist/builtins/system-config/index.mjs +2 -10
- package/dist/builtins/system-config/system-config.addon.d.ts +11 -0
- package/dist/builtins/system-config/system-config.addon.d.ts.map +1 -0
- package/dist/builtins/system-config/system-config.addon.js +227 -180
- package/dist/builtins/system-config/system-config.addon.js.map +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +226 -7
- package/dist/builtins/system-config/system-config.addon.mjs.map +1 -1
- package/dist/builtins/turn-orchestrator/index.d.ts +2 -0
- package/dist/builtins/turn-orchestrator/index.d.ts.map +1 -0
- package/dist/builtins/turn-orchestrator/index.js +7 -0
- package/dist/builtins/turn-orchestrator/index.mjs +2 -0
- package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.d.ts +10 -0
- package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.d.ts.map +1 -0
- package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.js +78 -0
- package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.js.map +1 -0
- package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.mjs +72 -0
- package/dist/builtins/turn-orchestrator/turn-orchestrator.addon.mjs.map +1 -0
- package/dist/builtins/winston-logging/index.d.ts +4 -0
- package/dist/builtins/winston-logging/index.d.ts.map +1 -0
- package/dist/builtins/winston-logging/index.js +153 -300
- package/dist/builtins/winston-logging/index.js.map +1 -1
- package/dist/builtins/winston-logging/index.mjs +144 -9
- package/dist/builtins/winston-logging/index.mjs.map +1 -1
- package/dist/builtins/winston-logging/winston-destination.d.ts +22 -0
- package/dist/builtins/winston-logging/winston-destination.d.ts.map +1 -0
- package/dist/builtins/winston-logging/winston-logging.addon.d.ts +20 -0
- package/dist/builtins/winston-logging/winston-logging.addon.d.ts.map +1 -0
- package/dist/chunk-C13QxCFV.js +50 -0
- package/dist/chunk-hT5z_Zn9.mjs +35 -0
- package/dist/download/model-download-service.d.ts +42 -0
- package/dist/download/model-download-service.d.ts.map +1 -0
- package/dist/download/model-downloader.d.ts +32 -0
- package/dist/download/model-downloader.d.ts.map +1 -0
- package/dist/events/event-bus.d.ts +11 -0
- package/dist/events/event-bus.d.ts.map +1 -0
- package/dist/events/system-event-bus.d.ts +15 -0
- package/dist/events/system-event-bus.d.ts.map +1 -0
- package/dist/feature/feature-manager.d.ts +12 -0
- package/dist/feature/feature-manager.d.ts.map +1 -0
- package/dist/formatter-C-5An4Bl.mjs +164 -0
- package/dist/formatter-C-5An4Bl.mjs.map +1 -0
- package/dist/formatter-Dr_6NNZc.js +169 -0
- package/dist/formatter-Dr_6NNZc.js.map +1 -0
- package/dist/index.d.ts +76 -1696
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7780 -8035
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7707 -2148
- package/dist/index.mjs.map +1 -1
- package/dist/lifecycle/lifecycle-state-machine.d.ts +29 -0
- package/dist/lifecycle/lifecycle-state-machine.d.ts.map +1 -0
- package/dist/logging/formatter.d.ts +31 -0
- package/dist/logging/formatter.d.ts.map +1 -0
- package/dist/logging/log-manager.d.ts +52 -0
- package/dist/logging/log-manager.d.ts.map +1 -0
- package/dist/logging/log-ring-buffer.d.ts +48 -0
- package/dist/logging/log-ring-buffer.d.ts.map +1 -0
- package/dist/logging/scoped-logger.d.ts +18 -0
- package/dist/logging/scoped-logger.d.ts.map +1 -0
- package/dist/network/network-quality.d.ts +12 -0
- package/dist/network/network-quality.d.ts.map +1 -0
- package/dist/notification/notification-service.d.ts +38 -0
- package/dist/notification/notification-service.d.ts.map +1 -0
- package/dist/notification/toast-service.d.ts +23 -0
- package/dist/notification/toast-service.d.ts.map +1 -0
- package/dist/pipeline/engine-manager-resolver.d.ts +16 -0
- package/dist/pipeline/engine-manager-resolver.d.ts.map +1 -0
- package/dist/pipeline/pipeline-runner.d.ts +9 -0
- package/dist/pipeline/pipeline-runner.d.ts.map +1 -0
- package/dist/pipeline/pipeline-validator.d.ts +14 -0
- package/dist/pipeline/pipeline-validator.d.ts.map +1 -0
- package/dist/process/resource-monitor.d.ts +12 -0
- package/dist/process/resource-monitor.d.ts.map +1 -0
- package/dist/python/python-env-manager.d.ts +13 -0
- package/dist/python/python-env-manager.d.ts.map +1 -0
- package/dist/repl/interfaces.d.ts +32 -0
- package/dist/repl/interfaces.d.ts.map +1 -0
- package/dist/repl/repl-engine.d.ts +9 -0
- package/dist/repl/repl-engine.d.ts.map +1 -0
- package/dist/resource-monitor-CmuWlmap.js +76 -0
- package/dist/resource-monitor-CmuWlmap.js.map +1 -0
- package/dist/resource-monitor-DcQdKGYU.mjs +59 -0
- package/dist/resource-monitor-DcQdKGYU.mjs.map +1 -0
- package/dist/storage/fs-storage-backend.d.ts +41 -0
- package/dist/storage/fs-storage-backend.d.ts.map +1 -0
- package/dist/storage/storage-location-manager.d.ts +24 -0
- package/dist/storage/storage-location-manager.d.ts.map +1 -0
- package/dist/storage/storage-manager.d.ts +77 -0
- package/dist/storage/storage-manager.d.ts.map +1 -0
- package/dist/tls/cert-manager.d.ts +27 -0
- package/dist/tls/cert-manager.d.ts.map +1 -0
- package/dist/tls/index.d.ts +2 -0
- package/dist/tls/index.d.ts.map +1 -0
- package/package.json +119 -23
- package/dist/builtins/addon-pages-aggregator/index.js.map +0 -1
- package/dist/builtins/addon-pages-aggregator/index.mjs.map +0 -1
- package/dist/builtins/addon-widgets-aggregator/index.js.map +0 -1
- package/dist/builtins/addon-widgets-aggregator/index.mjs.map +0 -1
- package/dist/builtins/alerts/index.js.map +0 -1
- package/dist/builtins/alerts/index.mjs.map +0 -1
- package/dist/builtins/device-manager/index.js.map +0 -1
- package/dist/builtins/device-manager/index.mjs.map +0 -1
- package/dist/builtins/local-auth/index.js.map +0 -1
- package/dist/builtins/local-auth/index.mjs.map +0 -1
- package/dist/builtins/local-backup/index.js +0 -173
- package/dist/builtins/local-backup/index.js.map +0 -1
- package/dist/builtins/local-backup/index.mjs +0 -10
- package/dist/builtins/local-backup/index.mjs.map +0 -1
- package/dist/builtins/system-config/index.js.map +0 -1
- package/dist/builtins/system-config/index.mjs.map +0 -1
- package/dist/chunk-2CIYKDRN.mjs +0 -1
- package/dist/chunk-2CIYKDRN.mjs.map +0 -1
- package/dist/chunk-2F76X6NL.mjs +0 -136
- package/dist/chunk-2F76X6NL.mjs.map +0 -1
- package/dist/chunk-2QUFBZ7M.mjs +0 -1
- package/dist/chunk-2QUFBZ7M.mjs.map +0 -1
- package/dist/chunk-3BK2Y7GY.mjs +0 -593
- package/dist/chunk-3BK2Y7GY.mjs.map +0 -1
- package/dist/chunk-4OOHFJHT.mjs +0 -421
- package/dist/chunk-4OOHFJHT.mjs.map +0 -1
- package/dist/chunk-4XHB7IHT.mjs +0 -809
- package/dist/chunk-4XHB7IHT.mjs.map +0 -1
- package/dist/chunk-6M2HSSTQ.mjs +0 -98
- package/dist/chunk-6M2HSSTQ.mjs.map +0 -1
- package/dist/chunk-7FI7SQS7.mjs +0 -135
- package/dist/chunk-7FI7SQS7.mjs.map +0 -1
- package/dist/chunk-ED57RCQE.mjs +0 -171
- package/dist/chunk-ED57RCQE.mjs.map +0 -1
- package/dist/chunk-FZN56HGQ.mjs +0 -626
- package/dist/chunk-FZN56HGQ.mjs.map +0 -1
- package/dist/chunk-GL4OOB25.mjs +0 -51
- package/dist/chunk-GL4OOB25.mjs.map +0 -1
- package/dist/chunk-KDG2NTDB.mjs +0 -137
- package/dist/chunk-KDG2NTDB.mjs.map +0 -1
- package/dist/chunk-NRBQWBDM.mjs +0 -191
- package/dist/chunk-NRBQWBDM.mjs.map +0 -1
- package/dist/chunk-O4V246GG.mjs +0 -2137
- package/dist/chunk-O4V246GG.mjs.map +0 -1
- package/dist/chunk-QT57H266.mjs +0 -163
- package/dist/chunk-QT57H266.mjs.map +0 -1
- package/dist/chunk-QX4RH25I.mjs +0 -141
- package/dist/chunk-QX4RH25I.mjs.map +0 -1
- package/dist/chunk-TB562PZX.mjs +0 -86
- package/dist/chunk-TB562PZX.mjs.map +0 -1
- package/dist/chunk-TDYPZXK5.mjs +0 -1
- package/dist/chunk-TDYPZXK5.mjs.map +0 -1
- package/dist/chunk-UJI4LN5P.mjs +0 -36
- package/dist/chunk-UJI4LN5P.mjs.map +0 -1
- package/dist/chunk-W6RTHQGP.mjs +0 -1
- package/dist/chunk-W6RTHQGP.mjs.map +0 -1
- package/dist/chunk-ZELBCPDC.mjs +0 -369
- package/dist/chunk-ZELBCPDC.mjs.map +0 -1
- package/dist/index.d.mts +0 -1696
- package/dist/resource-monitor-UZUGPIAU.mjs +0 -9
- package/dist/resource-monitor-UZUGPIAU.mjs.map +0 -1
- package/dist/storage-location-manager-HFNB3PCS.mjs +0 -7
- package/dist/storage-location-manager-HFNB3PCS.mjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/builtins/local-auth/local-auth.addon.ts","../src/auth/auth-manager.ts","../src/auth/user-manager.ts","../src/auth/parse-record.ts","../src/auth/api-key-manager.ts","../src/auth/scoped-token-manager.ts","../src/builtins/local-auth/auth-schema.ts"],"sourcesContent":["/**\n * Local Auth Addon — owns user accounts, API keys, scoped tokens,\n * and local password authentication.\n *\n * Capabilities registered:\n * - `auth-provider` (collection) — local password authentication\n * - `user-management` (singleton) — user CRUD, API keys, scoped tokens\n *\n * Extension: an OIDC addon can register another `auth-provider` entry.\n * The server's login flow iterates the `auth-provider` collection.\n */\nimport type { IUserManagementProvider, ProviderRegistration } from '@camstack/types'\nimport { BaseAddon, authProviderCapability, userManagementCapability } from '@camstack/types'\nimport { AuthManager } from '../../auth/auth-manager.js'\nimport { UserManager, type UserRecord, type UserStorageAccess } from '../../auth/user-manager.js'\nimport { ApiKeyManager, type ApiKeyStorageAccess } from '../../auth/api-key-manager.js'\nimport { ScopedTokenManager } from '../../auth/scoped-token-manager.js'\nimport { declareAuthSchema } from './auth-schema.js'\n\n// ── Auth result (mirrors auth-provider cap) ─────────────────────────\n\ninterface AuthResult {\n readonly userId: string\n readonly username: string\n readonly email?: string\n readonly displayName?: string\n readonly roles?: readonly string[]\n}\n\nfunction toAuthResult(user: UserRecord): AuthResult {\n return {\n userId: user.id,\n username: user.username,\n displayName: user.username,\n roles: [user.role],\n }\n}\n\n// ── Config reader shim ──────────────────────────────────────────────\n\ninterface LocalAuthConfig {\n jwtSecret?: string\n adminUsername?: string\n adminPassword?: string\n}\n\nexport class LocalAuthAddon extends BaseAddon<LocalAuthConfig> {\n private authManager: AuthManager | null = null\n private userManager: UserManager | null = null\n private apiKeyManager: ApiKeyManager | null = null\n private scopedTokenManager: ScopedTokenManager | null = null\n\n constructor() { super({ jwtSecret: '', adminUsername: '', adminPassword: '' }) }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n // Read auth section from the global settings store (config.yaml + env\n // overrides + SQL). Addon-level config (`this.config`) is kept as a\n // fallback for isolated/test environments where ctx.settings is absent.\n const authSection = (await this.ctx.settings?.getSection('auth')) ?? {}\n const resolvedJwtSecret = typeof authSection['jwtSecret'] === 'string'\n ? authSection['jwtSecret']\n : (this.config.jwtSecret ?? '')\n const resolvedAdminUser = typeof authSection['adminUsername'] === 'string' && authSection['adminUsername']\n ? authSection['adminUsername']\n : (this.config.adminUsername ?? '')\n const resolvedAdminPass = typeof authSection['adminPassword'] === 'string' && authSection['adminPassword']\n ? authSection['adminPassword']\n : (this.config.adminPassword ?? '')\n\n const reader = {\n get<T>(path: string): T {\n if (path === 'auth.jwtSecret') return resolvedJwtSecret as unknown as T\n if (path === 'auth.adminUsername') return resolvedAdminUser as unknown as T\n if (path === 'auth.adminPassword') return resolvedAdminPass as unknown as T\n return undefined as unknown as T\n },\n update: (_section: string, data: Record<string, unknown>): void => {\n if (typeof data['jwtSecret'] === 'string') {\n void this.ctx.settings?.setSection('auth', { jwtSecret: data['jwtSecret'] })\n }\n },\n }\n\n this.authManager = new AuthManager(reader, this.ctx.logger)\n\n const store = this.ctx.api?.settingsStore\n if (store) {\n // Own the schema. Same pattern as `pipeline-analytics` — each\n // addon declares its typed collections in `onInitialize`. The\n // backend just exposes the `declareCollection` primitive and\n // doesn't carry domain knowledge about auth tables.\n await declareAuthSchema(store)\n\n const storageAccess: UserStorageAccess & ApiKeyStorageAccess = {\n getStore() { return store },\n }\n this.userManager = new UserManager(storageAccess, this.authManager, reader)\n this.apiKeyManager = new ApiKeyManager(storageAccess, this.authManager)\n this.scopedTokenManager = new ScopedTokenManager(store)\n try {\n await this.userManager.ensureAdminExists()\n } catch (err: unknown) {\n // Surface the underlying cause loudly: AddonRegistry catches\n // and skips on throw, leaving auth.login to return the opaque\n // \"User management not available\" message at runtime. The\n // wrap below makes the actual fault (settings-store query\n // shape regression, sqlite migration glitch, …) visible in\n // both the addon error log and the user-facing error chain.\n const detail = err instanceof Error ? err.message : String(err)\n throw new Error(\n 'local-auth bootstrap failed: ensureAdminExists threw before '\n + '`user-management` could be registered. Most likely a '\n + '`users` collection schema mismatch in the settings-store. '\n + `Underlying: ${detail}`,\n { cause: err },\n )\n }\n } else {\n // Hard fail rather than register a no-op cap that throws\n // \"User management not available\" on every call later — the\n // operator sees the boot-time error instead of a confused login\n // panel. Local-auth without a settings store cannot persist\n // anything, so registering the cap would be a lie.\n throw new Error(\n 'local-auth: settings-store API not available — refusing to '\n + 'register `user-management` cap. Check that `sqlite-storage` '\n + 'addon initialized before `local-auth`.',\n )\n }\n\n // ── auth-provider capability (collection) ──────────────────────\n\n const authProvider = {\n validateCredentials: async (input: { username: string; password: string }): Promise<AuthResult | null> => {\n if (!this.userManager) return null\n const user = await this.userManager.validateCredentials(input.username, input.password)\n return user ? toAuthResult(user) : null\n },\n getLoginUrl: async (): Promise<string> => {\n throw new Error('local-auth: URL-based login not supported')\n },\n handleCallback: async (): Promise<AuthResult> => {\n throw new Error('local-auth: URL-based login not supported')\n },\n validateToken: async (input: { token: string }): Promise<AuthResult | null> => {\n if (!this.authManager || !this.userManager) return null\n try {\n const payload = this.authManager.verifyToken(input.token)\n const userId = payload.userId\n if (!userId) return null\n const user = await this.userManager.findById(userId)\n return user ? toAuthResult(user) : null\n } catch {\n return null\n }\n },\n }\n\n // ── user-management capability (singleton) ─────────────────────\n\n const userMgmt: IUserManagementProvider = {\n listUsers: async () => {\n if (!this.userManager) return []\n return this.userManager.listAll()\n },\n createUser: async (input) => {\n if (!this.userManager) throw new Error('User management not available')\n const record = await this.userManager.create(input)\n const { passwordHash: _, ...summary } = record\n return summary\n },\n updateUser: async (input) => {\n if (!this.userManager) throw new Error('User management not available')\n const { id, ...data } = input\n await this.userManager.update(id, data)\n return { success: true as const }\n },\n deleteUser: async (input) => {\n if (!this.userManager) throw new Error('User management not available')\n await this.userManager.delete(input.id)\n return { success: true as const }\n },\n resetPassword: async (input) => {\n if (!this.userManager) throw new Error('User management not available')\n await this.userManager.resetPassword(input.id, input.newPassword)\n return { success: true as const }\n },\n validateCredentials: async (input) => {\n if (!this.userManager) return null\n const user = await this.userManager.validateCredentials(input.username, input.password)\n return user ?? null\n },\n listApiKeys: async () => {\n if (!this.apiKeyManager) return []\n return this.apiKeyManager.listAll()\n },\n createApiKey: async (input) => {\n if (!this.apiKeyManager) throw new Error('API key management not available')\n const { record, token } = await this.apiKeyManager.create(input)\n const { tokenHash: _, ...summary } = record\n return { token, record: summary }\n },\n revokeApiKey: async (input) => {\n if (!this.apiKeyManager) throw new Error('API key management not available')\n await this.apiKeyManager.revoke(input.id)\n return { success: true as const }\n },\n validateApiKey: async (input) => {\n if (!this.apiKeyManager) return null\n const record = await this.apiKeyManager.validateToken(input.token)\n if (!record) return null\n const { tokenHash: _, ...summary } = record\n return summary\n },\n createScopedToken: async (input) => {\n if (!this.scopedTokenManager) throw new Error('Scoped token management not available')\n // userId comes from the tRPC context in production — for now\n // we use a placeholder. The server's login flow sets the real userId.\n const { token, record } = await this.scopedTokenManager.create('system', input.name, input.scopes, input.expiresAt)\n return { token, record }\n },\n revokeScopedToken: async (input) => {\n if (!this.scopedTokenManager) throw new Error('Scoped token management not available')\n await this.scopedTokenManager.revoke(input.id)\n return { success: true as const }\n },\n validateScopedToken: async (input) => {\n if (!this.scopedTokenManager) return null\n return this.scopedTokenManager.validate(input.token)\n },\n listScopedTokens: async (input) => {\n if (!this.scopedTokenManager) return []\n return this.scopedTokenManager.listForUser(input.userId)\n },\n }\n\n this.ctx.logger.info('registered auth-provider + user-management capabilities')\n return [\n { capability: authProviderCapability, provider: authProvider },\n { capability: userManagementCapability, provider: userMgmt },\n ]\n }\n\n protected async onShutdown(): Promise<void> {\n this.authManager = null\n this.userManager = null\n this.apiKeyManager = null\n this.scopedTokenManager = null\n }\n}\n\nexport default LocalAuthAddon\n","import * as jwt from 'jsonwebtoken'\nimport * as bcrypt from 'bcryptjs'\nimport * as crypto from 'node:crypto'\nimport type { ScopedToken, UserRole, TokenPayload, IScopedLogger } from '@camstack/types'\nimport type { ScopedTokenManager } from './scoped-token-manager.js'\n\n/** Minimal no-op logger for default parameter */\nconst noopLogger: IScopedLogger = {\n debug() {},\n info() {},\n warn() {},\n error() {},\n child() { return noopLogger },\n withTags() { return noopLogger },\n}\n\nexport type { UserRole, TokenPayload }\n\nexport type AuthConfigReader = {\n get<T>(path: string): T\n update(section: string, data: Record<string, unknown>): void\n}\n\nexport class AuthManager {\n private readonly jwtSecret: string\n private scopedTokenManager: ScopedTokenManager | null = null\n private readonly logger: IScopedLogger\n\n constructor(private readonly config: AuthConfigReader, logger: IScopedLogger = noopLogger) {\n this.logger = logger\n const configured = this.config.get<string>('auth.jwtSecret')\n if (configured) {\n this.jwtSecret = configured\n } else {\n const secret = crypto.randomBytes(32).toString('hex')\n // Persist directly into config.yaml so it survives restarts\n this.config.update('auth', { jwtSecret: secret })\n this.logger.info('Generated JWT secret and saved to config.yaml (auth.jwtSecret)')\n this.jwtSecret = secret\n }\n }\n\n signToken(payload: Omit<TokenPayload, 'iat' | 'exp'>): string {\n return jwt.sign({ ...payload }, this.jwtSecret, { expiresIn: '24h' })\n }\n\n verifyToken(token: string): TokenPayload {\n return jwt.verify(token, this.jwtSecret) as TokenPayload\n }\n\n async hashPassword(password: string): Promise<string> {\n return bcrypt.hash(password, 10)\n }\n\n async comparePassword(password: string, hash: string): Promise<boolean> {\n return bcrypt.compare(password, hash)\n }\n\n generateApiKey(): { token: string; hash: string; prefix: string } {\n const token = crypto.randomBytes(32).toString('hex')\n const hash = crypto.createHash('sha256').update(token).digest('hex')\n const prefix = token.slice(0, 8)\n return { token, hash, prefix }\n }\n\n validateApiKey(token: string, storedHash: string): boolean {\n const hash = crypto.createHash('sha256').update(token).digest('hex')\n return hash === storedHash\n }\n\n /**\n * Create a service token for agent/worker authentication.\n * Used when forking workers or when agents register.\n */\n createServiceToken(opts: {\n readonly agentId: string\n readonly role?: string\n readonly expiresIn?: string\n }): string {\n const payload: Record<string, unknown> = {\n userId: opts.agentId,\n username: opts.agentId,\n role: opts.role ?? 'agent',\n type: 'service',\n agentId: opts.agentId,\n allowedProviders: '*',\n allowedDevices: {},\n }\n const expiresIn = (opts.expiresIn ?? '24h') as jwt.SignOptions['expiresIn']\n return jwt.sign(payload as object, this.jwtSecret, { expiresIn })\n }\n\n /**\n * Set the scoped token manager for the auth chain.\n */\n setScopedTokenManager(manager: ScopedTokenManager): void {\n this.scopedTokenManager = manager\n }\n\n /**\n * Validate a scoped token string.\n * Returns the token record if valid, null otherwise.\n */\n async validateScopedToken(rawToken: string): Promise<ScopedToken | null> {\n if (!this.scopedTokenManager) {\n return null\n }\n return this.scopedTokenManager.validate(rawToken)\n }\n\n /**\n * Check whether a scoped token grants access to a given addon/route/capability.\n */\n matchesScopedTokenScope(\n token: ScopedToken,\n addonId?: string,\n routePath?: string,\n capability?: string,\n ): boolean {\n if (!this.scopedTokenManager) {\n return false\n }\n return this.scopedTokenManager.matchesScope(token, addonId, routePath, capability)\n }\n}\n","import * as crypto from 'node:crypto'\nimport type { AuthManager } from './auth-manager.js'\nimport { UserRecordSchema } from '@camstack/types'\nimport type { UserRecord, UserRole, SettingsStoreClient } from '@camstack/types'\nimport { parseRecord } from './parse-record.js'\n\nexport type { UserRecord }\n\ninterface CreateUserInput {\n username: string\n password: string\n role: UserRole\n allowedProviders?: string[] | '*'\n allowedDevices?: Record<string, string[] | '*'>\n}\n\ntype UpdatableUserFields = Partial<Pick<UserRecord, 'role' | 'allowedProviders' | 'allowedDevices'>>\n\nconst USERS_COLLECTION = 'users'\n\nexport interface UserStorageAccess {\n getStore(): SettingsStoreClient\n}\n\nexport interface UserConfigReader {\n get<T>(path: string): T\n}\n\nfunction parseUser(data: Record<string, unknown>): UserRecord {\n return parseRecord('user', UserRecordSchema, data)\n}\n\nexport class UserManager {\n constructor(\n private readonly storageAccess: UserStorageAccess,\n private readonly auth: AuthManager,\n private readonly config: UserConfigReader,\n ) {}\n\n private get store(): SettingsStoreClient {\n return this.storageAccess.getStore()\n }\n\n async create(input: CreateUserInput): Promise<UserRecord> {\n const existing = await this.findByUsername(input.username)\n if (existing) throw new Error(`User with username \"${input.username}\" already exists`)\n\n const passwordHash = await this.auth.hashPassword(input.password)\n const now = Date.now()\n const record: UserRecord = {\n id: crypto.randomUUID(),\n username: input.username,\n passwordHash,\n role: input.role,\n allowedProviders: input.allowedProviders ?? '*',\n allowedDevices: input.allowedDevices ?? {},\n createdAt: now,\n updatedAt: now,\n }\n\n await this.store.insert.mutate({ collection: USERS_COLLECTION, record: { id: record.id, data: { ...record } } })\n return record\n }\n\n async findByUsername(username: string): Promise<UserRecord | null> {\n const results = await this.store.query.query({ collection: USERS_COLLECTION, filter: { where: { username } } })\n if (results.length === 0) return null\n return parseUser(results[0]!.data)\n }\n\n async findById(id: string): Promise<UserRecord | null> {\n const results = await this.store.query.query({ collection: USERS_COLLECTION, filter: { where: { id } } })\n if (results.length === 0) return null\n return parseUser(results[0]!.data)\n }\n\n async validateCredentials(username: string, password: string): Promise<UserRecord | null> {\n const user = await this.findByUsername(username)\n if (!user) return null\n const valid = await this.auth.comparePassword(password, user.passwordHash)\n return valid ? user : null\n }\n\n async listAll(): Promise<Omit<UserRecord, 'passwordHash'>[]> {\n const results = await this.store.query.query({ collection: USERS_COLLECTION })\n return results.map((r) => {\n const parsed = parseUser(r.data)\n const { passwordHash: _ph, ...rest } = parsed\n return rest\n })\n }\n\n async update(id: string, data: UpdatableUserFields): Promise<void> {\n const existing = await this.findById(id)\n if (!existing) throw new Error(`User with id \"${id}\" not found`)\n await this.store.update.mutate({ collection: USERS_COLLECTION, id, data: { ...existing, ...data, updatedAt: Date.now() } })\n }\n\n async delete(id: string): Promise<void> {\n await this.store.delete.mutate({ collection: USERS_COLLECTION, key: id })\n }\n\n async resetPassword(id: string, newPassword: string): Promise<void> {\n const existing = await this.findById(id)\n if (!existing) throw new Error(`User with id \"${id}\" not found`)\n const passwordHash = await this.auth.hashPassword(newPassword)\n await this.store.update.mutate({ collection: USERS_COLLECTION, id, data: { ...existing, passwordHash, updatedAt: Date.now() } })\n }\n\n async ensureAdminExists(): Promise<void> {\n const adminUsername = this.config.get<string>('auth.adminUsername')\n const adminPassword = this.config.get<string>('auth.adminPassword')\n if (!adminUsername || !adminPassword) return\n const existing = await this.findByUsername(adminUsername)\n if (existing) {\n // Admin already exists — sync the password if the configured one has\n // changed. Comparison uses bcrypt.compare against the stored hash\n // (bcrypt includes the per-record salt). When they diverge, re-hash\n // and persist so the config.yaml / env-var is the source of truth.\n const matches = await this.auth.comparePassword(adminPassword, existing.passwordHash)\n if (!matches) {\n await this.resetPassword(existing.id, adminPassword)\n }\n return\n }\n await this.create({ username: adminUsername, password: adminPassword, role: 'super_admin', allowedProviders: '*', allowedDevices: {} })\n }\n}\n","/**\n * Wrap a Zod schema parse with an actionable error message. The\n * settings-store regression that broke local-auth in May 2026 surfaced\n * as an opaque Zod error listing every required field as `undefined`\n * — confusing because the data IS in the DB, just exposed through the\n * wrong shape by `queryDeclared`. This helper makes the failure mode\n * obvious: it explicitly mentions the kind, the offending value's top-\n * level keys, and a hint about the most common cause.\n *\n * `schema` is typed loosely (any with a `parse` method) to avoid the\n * generic ZodTypeAny variance error across Zod major versions when this\n * helper is reused by callers that import schemas from `@camstack/types`.\n */\ninterface ZodLikeSchema<T> {\n parse(data: unknown): T\n}\n\nexport function parseRecord<T>(\n kind: string,\n schema: ZodLikeSchema<T>,\n data: unknown,\n): T {\n try {\n return schema.parse(data)\n } catch (err: unknown) {\n const topKeys = data && typeof data === 'object' && !Array.isArray(data)\n ? Object.keys(data as Record<string, unknown>).join(', ') || '(empty)'\n : `(non-object: ${typeof data})`\n const detail = err instanceof Error ? err.message : String(err)\n const looksDoubleWrapped =\n data\n && typeof data === 'object'\n && !Array.isArray(data)\n && Object.keys(data as Record<string, unknown>).length === 1\n && 'data' in (data as Record<string, unknown>)\n const hint = looksDoubleWrapped\n ? ' This shape is the legacy double-wrap from a stale settings-store query path. Restart the server with the latest @camstack/core build.'\n : ''\n throw new Error(\n `Failed to parse ${kind} from settings store. Top-level keys=[${topKeys}].${hint} Underlying: ${detail}`,\n { cause: err },\n )\n }\n}\n","import * as crypto from 'node:crypto'\nimport type { AuthManager } from './auth-manager.js'\nimport { ApiKeyRecordSchema } from '@camstack/types'\nimport type { ApiKeyRecord, UserRole, SettingsStoreClient } from '@camstack/types'\nimport { parseRecord } from './parse-record.js'\n\nexport type { ApiKeyRecord }\n\ninterface CreateApiKeyInput {\n label: string\n role: UserRole\n allowedProviders?: string[] | '*'\n allowedDevices?: Record<string, string[] | '*'>\n}\n\nconst API_KEYS_COLLECTION = 'api_keys'\n\nexport interface ApiKeyStorageAccess {\n getStore(): SettingsStoreClient\n}\n\nfunction parseApiKey(data: Record<string, unknown>): ApiKeyRecord {\n return parseRecord('api-key', ApiKeyRecordSchema, data)\n}\n\nexport class ApiKeyManager {\n constructor(\n private readonly storageAccess: ApiKeyStorageAccess,\n private readonly auth: AuthManager,\n ) {}\n\n private get store(): SettingsStoreClient {\n return this.storageAccess.getStore()\n }\n\n async create(input: CreateApiKeyInput): Promise<{ record: ApiKeyRecord; token: string }> {\n const { token: rawToken, hash, prefix } = this.auth.generateApiKey()\n const now = Date.now()\n const record: ApiKeyRecord = {\n id: crypto.randomUUID(),\n label: input.label,\n role: input.role,\n allowedProviders: input.allowedProviders ?? '*',\n allowedDevices: input.allowedDevices ?? {},\n tokenHash: hash,\n tokenPrefix: prefix,\n createdAt: now,\n }\n\n await this.store.insert.mutate({ collection: API_KEYS_COLLECTION, record: { id: record.id, data: { ...record } } })\n return { record, token: rawToken }\n }\n\n async validateToken(token: string): Promise<ApiKeyRecord | null> {\n const allKeys = await this.store.query.query({ collection: API_KEYS_COLLECTION })\n for (const entry of allKeys) {\n const record = parseApiKey(entry.data)\n if (this.auth.validateApiKey(token, record.tokenHash)) {\n const updatedData: ApiKeyRecord = { ...record, lastUsedAt: Date.now() }\n await this.store.update.mutate({ collection: API_KEYS_COLLECTION, id: record.id, data: { ...updatedData } })\n return updatedData\n }\n }\n return null\n }\n\n async listAll(): Promise<Omit<ApiKeyRecord, 'tokenHash'>[]> {\n const results = await this.store.query.query({ collection: API_KEYS_COLLECTION })\n return results.map((r) => {\n const parsed = parseApiKey(r.data)\n const { tokenHash: _th, ...rest } = parsed\n return rest\n })\n }\n\n async revoke(id: string): Promise<void> {\n await this.store.delete.mutate({ collection: API_KEYS_COLLECTION, key: id })\n }\n\n async findById(id: string): Promise<ApiKeyRecord | null> {\n const results = await this.store.query.query({ collection: API_KEYS_COLLECTION, filter: { where: { id } } })\n if (results.length === 0) return null\n return parseApiKey(results[0]!.data)\n }\n}\n","import * as crypto from 'node:crypto'\nimport { ScopedTokenSchema } from '@camstack/types'\nimport type { ScopedToken, TokenScope, SettingsStoreClient } from '@camstack/types'\nimport { parseRecord } from './parse-record.js'\n\nconst TOKENS_COLLECTION = 'scoped_tokens'\nconst TOKEN_PREFIX = 'cst_'\n\nfunction parseToken(data: Record<string, unknown>): ScopedToken {\n return parseRecord('scoped-token', ScopedTokenSchema, data)\n}\n\n/**\n * Manages scoped API tokens with restricted addon/route/capability access.\n */\nexport class ScopedTokenManager {\n constructor(private readonly store: SettingsStoreClient) {}\n\n async create(\n userId: string,\n name: string,\n scopes: TokenScope[],\n expiresAt?: number,\n ): Promise<{ token: string; record: ScopedToken }> {\n const rawHex = crypto.randomBytes(32).toString('hex')\n const rawToken = `${TOKEN_PREFIX}${rawHex}`\n const tokenHash = crypto.createHash('sha256').update(rawToken).digest('hex')\n const tokenPrefix = rawToken.slice(0, 12)\n\n const record: ScopedToken = {\n id: crypto.randomUUID(),\n userId,\n name,\n tokenHash,\n tokenPrefix,\n scopes: scopes.map((s) => ({ ...s })),\n expiresAt,\n lastUsedAt: undefined,\n createdAt: Date.now(),\n }\n\n await this.store.insert.mutate({ collection: TOKENS_COLLECTION, record: { id: record.id, data: { ...record } } })\n return { token: rawToken, record }\n }\n\n async validate(rawToken: string): Promise<ScopedToken | null> {\n if (!rawToken.startsWith(TOKEN_PREFIX)) return null\n const tokenHash = crypto.createHash('sha256').update(rawToken).digest('hex')\n const results = await this.store.query.query({ collection: TOKENS_COLLECTION, filter: { where: { tokenHash } } })\n if (results.length === 0) return null\n\n const record = parseToken(results[0]!.data)\n if (record.expiresAt !== undefined && record.expiresAt !== null && Date.now() > record.expiresAt) return null\n this.updateLastUsed(record.id).catch(() => {})\n return record\n }\n\n matchesScope(token: ScopedToken, addonId?: string, routePath?: string, capability?: string): boolean {\n for (const scope of token.scopes) {\n switch (scope.type) {\n case 'addon': if (addonId && scope.target === addonId) return true; break\n case 'route-prefix': if (routePath && routePath.startsWith(scope.target)) return true; break\n case 'capability': if (capability && scope.target === capability) return true; break\n }\n }\n return false\n }\n\n async revoke(tokenId: string): Promise<void> {\n await this.store.delete.mutate({ collection: TOKENS_COLLECTION, key: tokenId })\n }\n\n async listForUser(userId: string): Promise<ScopedToken[]> {\n const results = await this.store.query.query({ collection: TOKENS_COLLECTION, filter: { where: { userId } } })\n return results.map((r) => parseToken(r.data))\n }\n\n async updateLastUsed(tokenId: string): Promise<void> {\n const results = await this.store.query.query({ collection: TOKENS_COLLECTION, filter: { where: { id: tokenId } } })\n if (results.length === 0) return\n const existing = parseToken(results[0]!.data)\n await this.store.update.mutate({ collection: TOKENS_COLLECTION, id: tokenId, data: { ...existing, lastUsedAt: Date.now() } })\n }\n}\n","/**\n * Auth-schema — typed SQL schemas for local-auth's three collections.\n *\n * Mirrors the pattern used by pipeline-analytics (`event-store.ts`,\n * `track-store.ts`): each addon owns its own schema, declared once\n * in `onInitialize` via `store.declareCollection.mutate(...)`.\n *\n * Collection names (no namespace — these are global, single-tenant\n * tables backing the auth layer):\n * - users\n * - api_keys\n * - scoped_tokens\n *\n * Schema migration: when the backend receives `declareCollection` for\n * a name that already exists with a legacy `(id, data)` KV shape, the\n * `ensureTable` helper drops the old table and recreates it. Existing\n * data is wiped — `ensureAdminExists` re-seeds the admin from\n * CAMSTACK_ADMIN_USER / CAMSTACK_ADMIN_PASS on the next boot.\n */\nimport type { SettingsStoreClient } from '@camstack/types'\n\nexport const USERS_COLLECTION = 'users'\nexport const API_KEYS_COLLECTION = 'api_keys'\nexport const SCOPED_TOKENS_COLLECTION = 'scoped_tokens'\n\nconst USERS_COLUMNS = [\n { name: 'id', type: 'TEXT' as const, primaryKey: true, notNull: true },\n { name: 'username', type: 'TEXT' as const, notNull: true, unique: true },\n { name: 'passwordHash', type: 'TEXT' as const, notNull: true },\n { name: 'role', type: 'TEXT' as const, notNull: true },\n { name: 'allowedProviders', type: 'JSON' as const },\n { name: 'allowedDevices', type: 'JSON' as const },\n { name: 'createdAt', type: 'INTEGER' as const, notNull: true },\n { name: 'updatedAt', type: 'INTEGER' as const, notNull: true },\n]\n\nconst API_KEYS_COLUMNS = [\n { name: 'id', type: 'TEXT' as const, primaryKey: true, notNull: true },\n { name: 'label', type: 'TEXT' as const, notNull: true },\n { name: 'role', type: 'TEXT' as const, notNull: true },\n { name: 'tokenHash', type: 'TEXT' as const, notNull: true, unique: true },\n { name: 'tokenPrefix', type: 'TEXT' as const, notNull: true },\n { name: 'allowedProviders', type: 'JSON' as const },\n { name: 'allowedDevices', type: 'JSON' as const },\n { name: 'createdAt', type: 'INTEGER' as const, notNull: true },\n { name: 'lastUsedAt', type: 'INTEGER' as const },\n]\n\nconst SCOPED_TOKENS_COLUMNS = [\n { name: 'id', type: 'TEXT' as const, primaryKey: true, notNull: true },\n { name: 'userId', type: 'TEXT' as const, notNull: true },\n { name: 'name', type: 'TEXT' as const, notNull: true },\n { name: 'tokenHash', type: 'TEXT' as const, notNull: true, unique: true },\n { name: 'tokenPrefix', type: 'TEXT' as const, notNull: true },\n { name: 'scopes', type: 'JSON' as const },\n { name: 'expiresAt', type: 'INTEGER' as const },\n { name: 'lastUsedAt', type: 'INTEGER' as const },\n { name: 'createdAt', type: 'INTEGER' as const, notNull: true },\n]\n\n/**\n * Declare every auth collection with the typed schema. Called by\n * `LocalAuthAddon.onInitialize` before constructing the per-collection\n * managers. Idempotent — `declareCollection` is a no-op when the\n * collection has already been declared (same shape).\n */\nexport async function declareAuthSchema(store: SettingsStoreClient): Promise<void> {\n await store.declareCollection.mutate({\n collection: USERS_COLLECTION,\n columns: USERS_COLUMNS,\n })\n await store.declareCollection.mutate({\n collection: API_KEYS_COLLECTION,\n columns: API_KEYS_COLUMNS,\n indexes: [\n { name: 'idx_api_keys_token_prefix', columns: ['tokenPrefix'] },\n ],\n })\n await store.declareCollection.mutate({\n collection: SCOPED_TOKENS_COLLECTION,\n columns: SCOPED_TOKENS_COLUMNS,\n indexes: [\n { name: 'idx_scoped_tokens_user_id', columns: ['userId'] },\n ],\n })\n}\n"],"mappings":"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","names":["hash","crypto","crypto","hash","crypto","USERS_COLLECTION","API_KEYS_COLLECTION"]}
|
package/dist/chunk-4OOHFJHT.mjs
DELETED
|
@@ -1,421 +0,0 @@
|
|
|
1
|
-
// src/builtins/alerts/alerts.addon.ts
|
|
2
|
-
import {
|
|
3
|
-
EventCategory
|
|
4
|
-
} from "@camstack/types";
|
|
5
|
-
import { BaseAddon, AlertSchema, alertsCapability, createEvent, errMsg } from "@camstack/types";
|
|
6
|
-
var CATEGORY_MAPPINGS = {
|
|
7
|
-
// ── Critical — always surface ──────────────────────────────────────
|
|
8
|
-
"addon.crashed": { severity: "error", titleTemplate: "Addon crashed" },
|
|
9
|
-
"addon.error": { severity: "error", titleTemplate: "Addon error" },
|
|
10
|
-
"process.crashed": { severity: "error", titleTemplate: "Process crashed" },
|
|
11
|
-
"recording.error": { severity: "error", titleTemplate: "Recording error" },
|
|
12
|
-
"recording.storage.critical": { severity: "warning", titleTemplate: "Storage critical" },
|
|
13
|
-
"notification.failed": { severity: "error", titleTemplate: "Notification failed" },
|
|
14
|
-
// ── Cluster — agent connect/disconnect ─────────────────────────────
|
|
15
|
-
"agent.online": { severity: "info", titleTemplate: "Agent connected" },
|
|
16
|
-
"agent.offline": { severity: "warning", titleTemplate: "Agent disconnected" },
|
|
17
|
-
// ── System lifecycle ──────────────────────────────────────────────
|
|
18
|
-
"system.boot": { severity: "info", titleTemplate: "System boot" },
|
|
19
|
-
"system.restarting": { severity: "warning", titleTemplate: "System restarting" },
|
|
20
|
-
// ── Device lifecycle (add/remove only, not settings tweaks) ───────
|
|
21
|
-
"device.registered": { severity: "info", titleTemplate: "Device registered" },
|
|
22
|
-
"device.unregistered": { severity: "warning", titleTemplate: "Device unregistered" },
|
|
23
|
-
// ── Package management ────────────────────────────────────────────
|
|
24
|
-
"addon.installed": { severity: "info", titleTemplate: "Addon installed" },
|
|
25
|
-
"addon.updated": { severity: "info", titleTemplate: "Addon updated" },
|
|
26
|
-
"addon.uninstalled": { severity: "info", titleTemplate: "Addon uninstalled" },
|
|
27
|
-
// ── Backup (rare, important) ──────────────────────────────────────
|
|
28
|
-
"backup.completed": { severity: "info", titleTemplate: "Backup completed" },
|
|
29
|
-
"backup.restored": { severity: "info", titleTemplate: "Backup restored" },
|
|
30
|
-
// ── Model downloads (in-progress merging path) ────────────────────
|
|
31
|
-
"model.download.progress": { severity: "info", titleTemplate: "Model download" }
|
|
32
|
-
};
|
|
33
|
-
var TRACKED_CATEGORIES = Object.keys(CATEGORY_MAPPINGS);
|
|
34
|
-
var RATE_LIMIT_WINDOW_MS = 6e4;
|
|
35
|
-
var RATE_LIMIT_MAX_PER_SOURCE = 5;
|
|
36
|
-
function parseAlert(record) {
|
|
37
|
-
return AlertSchema.parse({ id: record.id, ...record.data });
|
|
38
|
-
}
|
|
39
|
-
var DEFAULT_CONFIG = {
|
|
40
|
-
maxAlerts: 500,
|
|
41
|
-
retentionDays: 30
|
|
42
|
-
};
|
|
43
|
-
var ALERTS_COLLECTION = "alerts";
|
|
44
|
-
var EVENT_SOURCE = { type: "addon", id: "alert-center" };
|
|
45
|
-
var AlertCenterAddon = class extends BaseAddon {
|
|
46
|
-
unsubscribers = [];
|
|
47
|
-
constructor() {
|
|
48
|
-
super({ ...DEFAULT_CONFIG });
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Per `(category, source.id)` counter used to rate-limit chatty
|
|
52
|
-
* events. Entries are pruned lazily when they age out of
|
|
53
|
-
* `RATE_LIMIT_WINDOW_MS`; see `shouldSuppressByRate()` below.
|
|
54
|
-
*/
|
|
55
|
-
rateLimitCounters = /* @__PURE__ */ new Map();
|
|
56
|
-
async onInitialize() {
|
|
57
|
-
const alertsProvider = {
|
|
58
|
-
emit: (alert) => this.emitAlert(alert),
|
|
59
|
-
update: (input) => this.updateAlert(input.alertId, input.patch),
|
|
60
|
-
list: (filter) => this.listAlerts(filter),
|
|
61
|
-
getUnreadCount: () => this.getUnreadCount(),
|
|
62
|
-
markRead: (input) => this.markRead(input.alertId),
|
|
63
|
-
markAllRead: () => this.markAllRead(),
|
|
64
|
-
dismiss: (input) => this.dismiss(input.alertId)
|
|
65
|
-
};
|
|
66
|
-
const unsubs = [];
|
|
67
|
-
for (const category of TRACKED_CATEGORIES) {
|
|
68
|
-
const unsub = this.ctx.eventBus.subscribe(
|
|
69
|
-
{ category },
|
|
70
|
-
(event) => {
|
|
71
|
-
void this.handleEvent(category, event);
|
|
72
|
-
}
|
|
73
|
-
);
|
|
74
|
-
unsubs.push(unsub);
|
|
75
|
-
}
|
|
76
|
-
this.unsubscribers = unsubs;
|
|
77
|
-
this.ctx.logger.info("Initialized", { meta: { trackedCategoriesCount: TRACKED_CATEGORIES.length } });
|
|
78
|
-
return [{ capability: alertsCapability, provider: alertsProvider }];
|
|
79
|
-
}
|
|
80
|
-
async onShutdown() {
|
|
81
|
-
for (const unsub of this.unsubscribers) {
|
|
82
|
-
unsub();
|
|
83
|
-
}
|
|
84
|
-
this.unsubscribers = [];
|
|
85
|
-
}
|
|
86
|
-
globalSettingsSchema() {
|
|
87
|
-
return this.schema({
|
|
88
|
-
sections: [{
|
|
89
|
-
id: "alerts",
|
|
90
|
-
title: "Alert Center",
|
|
91
|
-
description: "Configure alert storage and retention.",
|
|
92
|
-
columns: 1,
|
|
93
|
-
fields: [
|
|
94
|
-
this.field({
|
|
95
|
-
type: "number",
|
|
96
|
-
key: "maxAlerts",
|
|
97
|
-
label: "Maximum stored alerts",
|
|
98
|
-
description: "Oldest read alerts are deleted when this limit is exceeded.",
|
|
99
|
-
min: 50,
|
|
100
|
-
max: 5e3,
|
|
101
|
-
step: 50,
|
|
102
|
-
default: 500
|
|
103
|
-
}),
|
|
104
|
-
this.field({
|
|
105
|
-
type: "number",
|
|
106
|
-
key: "retentionDays",
|
|
107
|
-
label: "Alert retention (days)",
|
|
108
|
-
description: "Alerts older than this are automatically removed.",
|
|
109
|
-
min: 1,
|
|
110
|
-
max: 365,
|
|
111
|
-
step: 1,
|
|
112
|
-
default: 30
|
|
113
|
-
})
|
|
114
|
-
]
|
|
115
|
-
}]
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
// ── Public methods (called by the tRPC router) ────────────────────
|
|
119
|
-
async listAlerts(filter) {
|
|
120
|
-
const backend = this.ctx.api.settingsStore;
|
|
121
|
-
if (!backend) return [];
|
|
122
|
-
const whereClause = {};
|
|
123
|
-
if (filter?.unreadOnly) {
|
|
124
|
-
whereClause.read = false;
|
|
125
|
-
}
|
|
126
|
-
const records = await backend.query.query({ collection: ALERTS_COLLECTION, filter: {
|
|
127
|
-
where: Object.keys(whereClause).length > 0 ? whereClause : void 0,
|
|
128
|
-
orderBy: { field: "updatedAt", direction: "desc" },
|
|
129
|
-
limit: filter?.limit ?? 100
|
|
130
|
-
} });
|
|
131
|
-
return records.map(parseAlert);
|
|
132
|
-
}
|
|
133
|
-
async getUnreadCount() {
|
|
134
|
-
const backend = this.ctx.api.settingsStore;
|
|
135
|
-
if (!backend) return 0;
|
|
136
|
-
return backend.count.query({ collection: ALERTS_COLLECTION, filter: { where: { read: false } } });
|
|
137
|
-
}
|
|
138
|
-
async markRead(alertId) {
|
|
139
|
-
await this.mergeUpdate(alertId, { read: true, updatedAt: Date.now() });
|
|
140
|
-
}
|
|
141
|
-
async markAllRead() {
|
|
142
|
-
const backend = this.ctx.api.settingsStore;
|
|
143
|
-
if (!backend) return;
|
|
144
|
-
const unread = await backend.query.query({ collection: ALERTS_COLLECTION, filter: { where: { read: false } } });
|
|
145
|
-
const now = Date.now();
|
|
146
|
-
for (const record of unread) {
|
|
147
|
-
await this.mergeUpdate(record.id, { read: true, updatedAt: now });
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
async dismiss(alertId) {
|
|
151
|
-
await this.mergeUpdate(alertId, {
|
|
152
|
-
status: "dismissed",
|
|
153
|
-
read: true,
|
|
154
|
-
updatedAt: Date.now()
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
// ── Private: event handling ──────────────────────────────────────
|
|
158
|
-
async handleEvent(category, event) {
|
|
159
|
-
try {
|
|
160
|
-
if (category === "model.download.progress") {
|
|
161
|
-
await this.handleModelDownload(event);
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
const mapping = CATEGORY_MAPPINGS[category];
|
|
165
|
-
if (!mapping) return;
|
|
166
|
-
if (this.shouldSuppressByRate(category, event)) return;
|
|
167
|
-
const message = this.buildMessage(category, event.data);
|
|
168
|
-
const alert = {
|
|
169
|
-
id: crypto.randomUUID(),
|
|
170
|
-
category,
|
|
171
|
-
severity: mapping.severity,
|
|
172
|
-
title: mapping.titleTemplate,
|
|
173
|
-
message,
|
|
174
|
-
status: "active",
|
|
175
|
-
read: false,
|
|
176
|
-
createdAt: Date.now(),
|
|
177
|
-
updatedAt: Date.now(),
|
|
178
|
-
source: event.source ? { type: event.source.type, id: String(event.source.id) } : void 0,
|
|
179
|
-
metadata: event.data
|
|
180
|
-
};
|
|
181
|
-
await this.emitAlert(alert);
|
|
182
|
-
} catch (err) {
|
|
183
|
-
this.ctx.logger?.warn(
|
|
184
|
-
"Failed to handle event",
|
|
185
|
-
{ meta: { category, error: errMsg(err) } }
|
|
186
|
-
);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
async handleModelDownload(event) {
|
|
190
|
-
const data = event.data;
|
|
191
|
-
const modelId = data.modelId ?? "unknown";
|
|
192
|
-
const progress = data.progress ?? 0;
|
|
193
|
-
const stableId = `model-download:${modelId}`;
|
|
194
|
-
const backend = this.ctx.api.settingsStore;
|
|
195
|
-
if (!backend) return;
|
|
196
|
-
const existing = await backend.query.query({ collection: ALERTS_COLLECTION, filter: {
|
|
197
|
-
where: { id: stableId }
|
|
198
|
-
} });
|
|
199
|
-
if (existing.length > 0) {
|
|
200
|
-
const now = Date.now();
|
|
201
|
-
if (progress >= 100) {
|
|
202
|
-
await this.mergeUpdate(stableId, {
|
|
203
|
-
status: "completed",
|
|
204
|
-
progress: 100,
|
|
205
|
-
message: `Model "${modelId}" download completed`,
|
|
206
|
-
updatedAt: now
|
|
207
|
-
});
|
|
208
|
-
this.emitAlertUpdatedEvent(stableId, { status: "completed", progress: 100 });
|
|
209
|
-
} else if (progress < 0) {
|
|
210
|
-
await this.mergeUpdate(stableId, {
|
|
211
|
-
status: "failed",
|
|
212
|
-
message: `Model "${modelId}" download failed`,
|
|
213
|
-
updatedAt: now
|
|
214
|
-
});
|
|
215
|
-
this.emitAlertUpdatedEvent(stableId, { status: "failed" });
|
|
216
|
-
} else {
|
|
217
|
-
await this.mergeUpdate(stableId, {
|
|
218
|
-
progress,
|
|
219
|
-
message: `Downloading model "${modelId}" \u2014 ${String(Math.round(progress))}%`,
|
|
220
|
-
updatedAt: now
|
|
221
|
-
});
|
|
222
|
-
this.emitAlertUpdatedEvent(stableId, { progress });
|
|
223
|
-
}
|
|
224
|
-
} else {
|
|
225
|
-
const alert = {
|
|
226
|
-
id: stableId,
|
|
227
|
-
category: EventCategory.ModelDownloadProgress,
|
|
228
|
-
severity: "info",
|
|
229
|
-
title: "Model download",
|
|
230
|
-
message: `Downloading model "${modelId}" \u2014 ${String(Math.round(progress))}%`,
|
|
231
|
-
status: "in-progress",
|
|
232
|
-
progress,
|
|
233
|
-
read: false,
|
|
234
|
-
createdAt: Date.now(),
|
|
235
|
-
updatedAt: Date.now(),
|
|
236
|
-
source: event.source ? { type: event.source.type, id: String(event.source.id) } : void 0,
|
|
237
|
-
metadata: { modelId }
|
|
238
|
-
};
|
|
239
|
-
await this.persistAlert(alert);
|
|
240
|
-
this.emitAlertCreatedEvent(alert);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* `[ALERT-CENTER-EVENTS]` — rate limit a `(category, source.id)`
|
|
245
|
-
* tuple. Returns `true` when the caller should DROP this event
|
|
246
|
-
* without persisting an alert, and `false` when the alert should
|
|
247
|
-
* proceed normally.
|
|
248
|
-
*
|
|
249
|
-
* Heuristic: the first `RATE_LIMIT_MAX_PER_SOURCE` events within a
|
|
250
|
-
* `RATE_LIMIT_WINDOW_MS` window go through. Once the threshold is
|
|
251
|
-
* crossed, subsequent events are suppressed until the window rolls
|
|
252
|
-
* over. When the threshold is first crossed, the suppression is
|
|
253
|
-
* logged once so operators know why they're not seeing the follow-
|
|
254
|
-
* up alerts; after the window rolls over the next event is
|
|
255
|
-
* un-suppressed and starts a new window.
|
|
256
|
-
*/
|
|
257
|
-
shouldSuppressByRate(category, event) {
|
|
258
|
-
const sourceId = event.source?.id ?? "unknown";
|
|
259
|
-
const key = `${category}::${sourceId}`;
|
|
260
|
-
const now = Date.now();
|
|
261
|
-
const entry = this.rateLimitCounters.get(key);
|
|
262
|
-
if (!entry || now - entry.firstAt > RATE_LIMIT_WINDOW_MS) {
|
|
263
|
-
this.rateLimitCounters.set(key, { firstAt: now, count: 1, suppressedLogged: false });
|
|
264
|
-
return false;
|
|
265
|
-
}
|
|
266
|
-
entry.count += 1;
|
|
267
|
-
if (entry.count <= RATE_LIMIT_MAX_PER_SOURCE) return false;
|
|
268
|
-
if (!entry.suppressedLogged) {
|
|
269
|
-
entry.suppressedLogged = true;
|
|
270
|
-
this.ctx.logger?.info(
|
|
271
|
-
"rate-limiting suppressing remainder of window",
|
|
272
|
-
{ meta: { category, sourceId, maxPerSource: RATE_LIMIT_MAX_PER_SOURCE, windowSeconds: RATE_LIMIT_WINDOW_MS / 1e3 } }
|
|
273
|
-
);
|
|
274
|
-
}
|
|
275
|
-
return true;
|
|
276
|
-
}
|
|
277
|
-
buildMessage(category, data) {
|
|
278
|
-
const addonId = data.addonId;
|
|
279
|
-
const deviceId = data.deviceId;
|
|
280
|
-
const error = data.error;
|
|
281
|
-
const processId = data.processId;
|
|
282
|
-
switch (category) {
|
|
283
|
-
case "addon.crashed":
|
|
284
|
-
return `Addon "${addonId ?? "unknown"}" crashed${error ? `: ${error}` : ""}`;
|
|
285
|
-
case "addon.error":
|
|
286
|
-
return `Addon "${addonId ?? "unknown"}" error${error ? `: ${error}` : ""}`;
|
|
287
|
-
case "addon.installed":
|
|
288
|
-
return `Addon "${addonId ?? "unknown"}" installed`;
|
|
289
|
-
case "addon.updated": {
|
|
290
|
-
const from = data.fromVersion;
|
|
291
|
-
const to = data.toVersion;
|
|
292
|
-
return `Addon "${addonId ?? "unknown"}" updated${from && to ? ` from ${from} to ${to}` : ""}`;
|
|
293
|
-
}
|
|
294
|
-
case "addon.uninstalled":
|
|
295
|
-
return `Addon "${addonId ?? "unknown"}" uninstalled`;
|
|
296
|
-
case "device.registered":
|
|
297
|
-
return `Device "${data.name ?? deviceId ?? "unknown"}" registered`;
|
|
298
|
-
case "device.unregistered":
|
|
299
|
-
return `Device "${deviceId ?? "unknown"}" unregistered`;
|
|
300
|
-
case "agent.online":
|
|
301
|
-
return `Agent "${data.agentId ?? data.nodeId ?? "unknown"}" connected`;
|
|
302
|
-
case "agent.offline":
|
|
303
|
-
return `Agent "${data.agentId ?? data.nodeId ?? "unknown"}" disconnected${data.reason ? `: ${String(data.reason)}` : ""}`;
|
|
304
|
-
case "backup.completed":
|
|
305
|
-
return `Backup completed${data.targetId ? ` (${String(data.targetId)})` : ""}`;
|
|
306
|
-
case "backup.restored":
|
|
307
|
-
return `Backup restored${data.source ? ` from ${String(data.source)}` : ""}`;
|
|
308
|
-
case "notification.failed":
|
|
309
|
-
return `Notification failed${error ? `: ${error}` : ""}`;
|
|
310
|
-
case "system.restarting":
|
|
311
|
-
return `System restarting${data.reason ? ` \u2014 ${String(data.reason)}` : ""}`;
|
|
312
|
-
case "recording.error":
|
|
313
|
-
return `Recording error on device "${deviceId ?? "unknown"}"${error ? `: ${error}` : ""}`;
|
|
314
|
-
case "recording.storage.critical":
|
|
315
|
-
return `Storage critical for device "${deviceId ?? "unknown"}"`;
|
|
316
|
-
case "system.boot":
|
|
317
|
-
return `System booted in "${data.mode ?? "unknown"}" mode`;
|
|
318
|
-
case "process.crashed":
|
|
319
|
-
return `Process "${processId ?? "unknown"}" crashed`;
|
|
320
|
-
default:
|
|
321
|
-
return `Event: ${category}`;
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
// ── Private: persistence ─────────────────────────────────────────
|
|
325
|
-
async emitAlert(alert) {
|
|
326
|
-
await this.persistAlert(alert);
|
|
327
|
-
this.emitAlertCreatedEvent(alert);
|
|
328
|
-
await this.enforceMaxAlerts();
|
|
329
|
-
await this.enforceRetention();
|
|
330
|
-
}
|
|
331
|
-
async updateAlert(alertId, patch) {
|
|
332
|
-
await this.mergeUpdate(alertId, { ...patch, updatedAt: Date.now() });
|
|
333
|
-
this.emitAlertUpdatedEvent(alertId, patch);
|
|
334
|
-
}
|
|
335
|
-
/**
|
|
336
|
-
* Read-merge-write: SettingsBackend.update() replaces the entire `data` blob,
|
|
337
|
-
* so we must read the existing record, merge the patch, and write back.
|
|
338
|
-
*/
|
|
339
|
-
async mergeUpdate(id, patch) {
|
|
340
|
-
const backend = this.ctx.api.settingsStore;
|
|
341
|
-
if (!backend) return;
|
|
342
|
-
const raw = await backend.get.query({ collection: ALERTS_COLLECTION, key: id });
|
|
343
|
-
if (raw === null || raw === void 0 || typeof raw !== "object") return;
|
|
344
|
-
const existing = Object.fromEntries(Object.entries(raw));
|
|
345
|
-
await backend.set.mutate({ collection: ALERTS_COLLECTION, key: id, value: { ...existing, ...patch } });
|
|
346
|
-
}
|
|
347
|
-
async persistAlert(alert) {
|
|
348
|
-
const backend = this.ctx.api.settingsStore;
|
|
349
|
-
if (!backend) return;
|
|
350
|
-
const data = {
|
|
351
|
-
id: alert.id,
|
|
352
|
-
category: alert.category,
|
|
353
|
-
severity: alert.severity,
|
|
354
|
-
title: alert.title,
|
|
355
|
-
message: alert.message,
|
|
356
|
-
status: alert.status,
|
|
357
|
-
read: alert.read,
|
|
358
|
-
createdAt: alert.createdAt,
|
|
359
|
-
updatedAt: alert.updatedAt,
|
|
360
|
-
...alert.progress !== void 0 ? { progress: alert.progress } : {},
|
|
361
|
-
...alert.source ? { source: alert.source } : {},
|
|
362
|
-
...alert.metadata ? { metadata: alert.metadata } : {}
|
|
363
|
-
};
|
|
364
|
-
await backend.set.mutate({ collection: ALERTS_COLLECTION, key: alert.id, value: data });
|
|
365
|
-
}
|
|
366
|
-
emitAlertCreatedEvent(alert) {
|
|
367
|
-
this.ctx.eventBus?.emit(createEvent("alert.created", EVENT_SOURCE, {
|
|
368
|
-
id: alert.id,
|
|
369
|
-
category: alert.category,
|
|
370
|
-
severity: alert.severity,
|
|
371
|
-
title: alert.title,
|
|
372
|
-
status: alert.status
|
|
373
|
-
}));
|
|
374
|
-
}
|
|
375
|
-
emitAlertUpdatedEvent(alertId, patch) {
|
|
376
|
-
const patchRecord = {};
|
|
377
|
-
for (const [key, value] of Object.entries(patch)) {
|
|
378
|
-
patchRecord[key] = value;
|
|
379
|
-
}
|
|
380
|
-
this.ctx.eventBus?.emit(createEvent("alert.updated", EVENT_SOURCE, {
|
|
381
|
-
alertId,
|
|
382
|
-
patch: patchRecord
|
|
383
|
-
}));
|
|
384
|
-
}
|
|
385
|
-
async enforceMaxAlerts() {
|
|
386
|
-
const backend = this.ctx.api.settingsStore;
|
|
387
|
-
if (!backend) return;
|
|
388
|
-
const total = await backend.count.query({ collection: ALERTS_COLLECTION });
|
|
389
|
-
if (total <= this.config.maxAlerts) return;
|
|
390
|
-
const excess = total - this.config.maxAlerts;
|
|
391
|
-
const oldest = await backend.query.query({ collection: ALERTS_COLLECTION, filter: {
|
|
392
|
-
where: { read: true },
|
|
393
|
-
orderBy: { field: "createdAt", direction: "asc" },
|
|
394
|
-
limit: excess
|
|
395
|
-
} });
|
|
396
|
-
for (const record of oldest) {
|
|
397
|
-
await backend.delete.mutate({ collection: ALERTS_COLLECTION, key: record.id });
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
async enforceRetention() {
|
|
401
|
-
const backend = this.ctx.api.settingsStore;
|
|
402
|
-
if (!backend) return;
|
|
403
|
-
const cutoff = Date.now() - this.config.retentionDays * 24 * 60 * 60 * 1e3;
|
|
404
|
-
const expired = await backend.query.query({ collection: ALERTS_COLLECTION, filter: {
|
|
405
|
-
where: { read: true },
|
|
406
|
-
orderBy: { field: "createdAt", direction: "asc" }
|
|
407
|
-
} });
|
|
408
|
-
for (const record of expired) {
|
|
409
|
-
if (Number(record.data["createdAt"] ?? 0) < cutoff) {
|
|
410
|
-
await backend.delete.mutate({ collection: ALERTS_COLLECTION, key: record.id });
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
};
|
|
415
|
-
var alerts_addon_default = AlertCenterAddon;
|
|
416
|
-
|
|
417
|
-
export {
|
|
418
|
-
AlertCenterAddon,
|
|
419
|
-
alerts_addon_default
|
|
420
|
-
};
|
|
421
|
-
//# sourceMappingURL=chunk-4OOHFJHT.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/builtins/alerts/alerts.addon.ts"],"sourcesContent":["import {\n EventCategory,\n type KnownEventCategory,\n type SystemEvent,\n type ProviderRegistration,\n} from '@camstack/types'\nimport type { Alert, AlertSeverity, AlertStatus } from '@camstack/types'\nimport { BaseAddon, AlertSchema, alertsCapability, createEvent , errMsg } from '@camstack/types'\n\n// ── Category → severity mapping ─────────────────────────────────────\n\ninterface CategoryMapping {\n readonly severity: AlertSeverity\n readonly titleTemplate: string\n}\n\nconst CATEGORY_MAPPINGS: Readonly<Record<string, CategoryMapping>> = {\n // ── Critical — always surface ──────────────────────────────────────\n 'addon.crashed': { severity: 'error', titleTemplate: 'Addon crashed' },\n 'addon.error': { severity: 'error', titleTemplate: 'Addon error' },\n 'process.crashed': { severity: 'error', titleTemplate: 'Process crashed' },\n 'recording.error': { severity: 'error', titleTemplate: 'Recording error' },\n 'recording.storage.critical': { severity: 'warning', titleTemplate: 'Storage critical' },\n 'notification.failed': { severity: 'error', titleTemplate: 'Notification failed' },\n\n // ── Cluster — agent connect/disconnect ─────────────────────────────\n 'agent.online': { severity: 'info', titleTemplate: 'Agent connected' },\n 'agent.offline': { severity: 'warning', titleTemplate: 'Agent disconnected' },\n\n // ── System lifecycle ──────────────────────────────────────────────\n 'system.boot': { severity: 'info', titleTemplate: 'System boot' },\n 'system.restarting': { severity: 'warning', titleTemplate: 'System restarting' },\n\n // ── Device lifecycle (add/remove only, not settings tweaks) ───────\n 'device.registered': { severity: 'info', titleTemplate: 'Device registered' },\n 'device.unregistered': { severity: 'warning', titleTemplate: 'Device unregistered' },\n\n // ── Package management ────────────────────────────────────────────\n 'addon.installed': { severity: 'info', titleTemplate: 'Addon installed' },\n 'addon.updated': { severity: 'info', titleTemplate: 'Addon updated' },\n 'addon.uninstalled': { severity: 'info', titleTemplate: 'Addon uninstalled' },\n\n // ── Backup (rare, important) ──────────────────────────────────────\n 'backup.completed': { severity: 'info', titleTemplate: 'Backup completed' },\n 'backup.restored': { severity: 'info', titleTemplate: 'Backup restored' },\n\n // ── Model downloads (in-progress merging path) ────────────────────\n 'model.download.progress': { severity: 'info', titleTemplate: 'Model download' },\n}\n\nconst TRACKED_CATEGORIES = Object.keys(CATEGORY_MAPPINGS)\n\n/**\n * `[ALERT-CENTER-EVENTS]` — rate limiting. Events that fire thousands of\n * times a minute (flaky cam reconnecting, chatty integration, …) would\n * flood the alert feed and push genuinely important alerts off the\n * visible page. We collapse bursts into a single throttled summary per\n * `(category, source.id)` tuple: the first N events within the window\n * still surface as individual alerts, but once the source crosses the\n * threshold we stop emitting alerts for it and wait out the window.\n *\n * A standalone category-count map is cleared on every window rollover.\n * Keep the threshold generous enough that legitimate bursts of ~a few\n * per minute still get through, but strict enough that a reconnect loop\n * firing every second gets muted.\n */\nconst RATE_LIMIT_WINDOW_MS = 60_000\nconst RATE_LIMIT_MAX_PER_SOURCE = 5\n\n/** Parse a raw settings record into a validated Alert. */\nfunction parseAlert(record: { id: string; data: Record<string, unknown> }): Alert {\n return AlertSchema.parse({ id: record.id, ...record.data })\n}\n\n// ── Alert Center Addon ─────────────────────────────────────────────\n\ninterface AlertCenterConfig {\n readonly maxAlerts: number\n readonly retentionDays: number\n}\n\nconst DEFAULT_CONFIG: AlertCenterConfig = {\n maxAlerts: 500,\n retentionDays: 30,\n}\n\nconst ALERTS_COLLECTION = 'alerts'\nconst EVENT_SOURCE = { type: 'addon', id: 'alert-center' } as const\n\n/**\n * Alert Center addon — core builtin that persists alerts in a\n * structured SQLite table and serves them to the admin UI.\n *\n * Registers as an `alerts` collection provider and subscribes to\n * important EventBus categories to create/update alerts automatically.\n */\nexport class AlertCenterAddon extends BaseAddon<AlertCenterConfig> {\n private unsubscribers: readonly (() => void)[] = []\n\n constructor() {\n super({ ...DEFAULT_CONFIG })\n }\n\n /**\n * Per `(category, source.id)` counter used to rate-limit chatty\n * events. Entries are pruned lazily when they age out of\n * `RATE_LIMIT_WINDOW_MS`; see `shouldSuppressByRate()` below.\n */\n private readonly rateLimitCounters = new Map<string, { firstAt: number; count: number; suppressedLogged: boolean }>()\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n const alertsProvider = {\n emit: (alert: Alert) => this.emitAlert(alert),\n update: (input: { alertId: string; patch: Partial<Alert> }) =>\n this.updateAlert(input.alertId, input.patch),\n list: (filter?: { unreadOnly?: boolean; limit?: number }) =>\n this.listAlerts(filter),\n getUnreadCount: () => this.getUnreadCount(),\n markRead: (input: { alertId: string }) => this.markRead(input.alertId),\n markAllRead: () => this.markAllRead(),\n dismiss: (input: { alertId: string }) => this.dismiss(input.alertId),\n }\n\n const unsubs: (() => void)[] = []\n for (const category of TRACKED_CATEGORIES) {\n const unsub = this.ctx.eventBus.subscribe(\n { category: category as KnownEventCategory },\n (event: SystemEvent) => { void this.handleEvent(category, event) },\n )\n unsubs.push(unsub)\n }\n this.unsubscribers = unsubs\n\n this.ctx.logger.info('Initialized', { meta: { trackedCategoriesCount: TRACKED_CATEGORIES.length } })\n return [{ capability: alertsCapability, provider: alertsProvider }]\n }\n\n protected async onShutdown(): Promise<void> {\n for (const unsub of this.unsubscribers) {\n unsub()\n }\n this.unsubscribers = []\n }\n\n protected globalSettingsSchema() {\n return this.schema({\n sections: [{\n id: 'alerts',\n title: 'Alert Center',\n description: 'Configure alert storage and retention.',\n columns: 1,\n fields: [\n this.field({\n type: 'number', key: 'maxAlerts', label: 'Maximum stored alerts',\n description: 'Oldest read alerts are deleted when this limit is exceeded.',\n min: 50, max: 5000, step: 50, default: 500,\n }),\n this.field({\n type: 'number', key: 'retentionDays', label: 'Alert retention (days)',\n description: 'Alerts older than this are automatically removed.',\n min: 1, max: 365, step: 1, default: 30,\n }),\n ],\n }],\n })\n }\n\n // ── Public methods (called by the tRPC router) ────────────────────\n\n async listAlerts(filter?: { unreadOnly?: boolean; limit?: number }): Promise<readonly Alert[]> {\n const backend = this.ctx.api.settingsStore\n if (!backend) return []\n\n const whereClause: Record<string, unknown> = {}\n if (filter?.unreadOnly) {\n whereClause.read = false\n }\n\n const records = await backend.query.query({ collection: ALERTS_COLLECTION, filter: {\n where: Object.keys(whereClause).length > 0 ? whereClause : undefined,\n orderBy: { field: 'updatedAt', direction: 'desc' },\n limit: filter?.limit ?? 100,\n } })\n\n return records.map(parseAlert)\n }\n\n async getUnreadCount(): Promise<number> {\n const backend = this.ctx.api.settingsStore\n if (!backend) return 0\n\n return backend.count.query({ collection: ALERTS_COLLECTION, filter: { where: { read: false } } })\n }\n\n async markRead(alertId: string): Promise<void> {\n await this.mergeUpdate(alertId, { read: true, updatedAt: Date.now() })\n }\n\n async markAllRead(): Promise<void> {\n const backend = this.ctx.api.settingsStore\n if (!backend) return\n\n const unread = await backend.query.query({ collection: ALERTS_COLLECTION, filter: { where: { read: false } } })\n const now = Date.now()\n for (const record of unread) {\n await this.mergeUpdate(record.id, { read: true, updatedAt: now })\n }\n }\n\n async dismiss(alertId: string): Promise<void> {\n await this.mergeUpdate(alertId, {\n status: 'dismissed' satisfies AlertStatus,\n read: true,\n updatedAt: Date.now(),\n })\n }\n\n // ── Private: event handling ──────────────────────────────────────\n\n private async handleEvent(category: string, event: SystemEvent): Promise<void> {\n try {\n if (category === 'model.download.progress') {\n // Model download progress has its own in-progress merging path\n // that intentionally overwrites a single alert per model, so\n // rate limiting does not apply here — the merger itself is the\n // collapse mechanism.\n await this.handleModelDownload(event)\n return\n }\n\n const mapping = CATEGORY_MAPPINGS[category]\n if (!mapping) return\n\n if (this.shouldSuppressByRate(category, event)) return\n\n const message = this.buildMessage(category, event.data)\n const alert: Alert = {\n id: crypto.randomUUID(),\n category,\n severity: mapping.severity,\n title: mapping.titleTemplate,\n message,\n status: 'active',\n read: false,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n source: event.source ? { type: event.source.type, id: String(event.source.id) } : undefined,\n metadata: event.data,\n }\n\n await this.emitAlert(alert)\n } catch (err) {\n this.ctx.logger?.warn(\n 'Failed to handle event',\n { meta: { category, error: errMsg(err) } },\n )\n }\n }\n\n private async handleModelDownload(event: SystemEvent): Promise<void> {\n const data = event.data\n const modelId = (data.modelId as string | undefined) ?? 'unknown'\n const progress = (data.progress as number | undefined) ?? 0\n const stableId = `model-download:${modelId}`\n\n const backend = this.ctx.api.settingsStore\n if (!backend) return\n\n // Check if an in-progress alert already exists for this model\n const existing = await backend.query.query({ collection: ALERTS_COLLECTION, filter: {\n where: { id: stableId },\n } })\n\n if (existing.length > 0) {\n // Update existing alert (read-merge-write)\n const now = Date.now()\n if (progress >= 100) {\n await this.mergeUpdate(stableId, {\n status: 'completed' satisfies AlertStatus,\n progress: 100,\n message: `Model \"${modelId}\" download completed`,\n updatedAt: now,\n })\n this.emitAlertUpdatedEvent(stableId, { status: 'completed', progress: 100 })\n } else if (progress < 0) {\n await this.mergeUpdate(stableId, {\n status: 'failed' satisfies AlertStatus,\n message: `Model \"${modelId}\" download failed`,\n updatedAt: now,\n })\n this.emitAlertUpdatedEvent(stableId, { status: 'failed' })\n } else {\n await this.mergeUpdate(stableId, {\n progress,\n message: `Downloading model \"${modelId}\" — ${String(Math.round(progress))}%`,\n updatedAt: now,\n })\n this.emitAlertUpdatedEvent(stableId, { progress })\n }\n } else {\n // Create new in-progress alert\n const alert: Alert = {\n id: stableId,\n category: EventCategory.ModelDownloadProgress,\n severity: 'info',\n title: 'Model download',\n message: `Downloading model \"${modelId}\" — ${String(Math.round(progress))}%`,\n status: 'in-progress',\n progress,\n read: false,\n createdAt: Date.now(),\n updatedAt: Date.now(),\n source: event.source ? { type: event.source.type, id: String(event.source.id) } : undefined,\n metadata: { modelId },\n }\n\n await this.persistAlert(alert)\n this.emitAlertCreatedEvent(alert)\n }\n }\n\n /**\n * `[ALERT-CENTER-EVENTS]` — rate limit a `(category, source.id)`\n * tuple. Returns `true` when the caller should DROP this event\n * without persisting an alert, and `false` when the alert should\n * proceed normally.\n *\n * Heuristic: the first `RATE_LIMIT_MAX_PER_SOURCE` events within a\n * `RATE_LIMIT_WINDOW_MS` window go through. Once the threshold is\n * crossed, subsequent events are suppressed until the window rolls\n * over. When the threshold is first crossed, the suppression is\n * logged once so operators know why they're not seeing the follow-\n * up alerts; after the window rolls over the next event is\n * un-suppressed and starts a new window.\n */\n private shouldSuppressByRate(category: string, event: SystemEvent): boolean {\n const sourceId = event.source?.id ?? 'unknown'\n const key = `${category}::${sourceId}`\n const now = Date.now()\n const entry = this.rateLimitCounters.get(key)\n\n if (!entry || now - entry.firstAt > RATE_LIMIT_WINDOW_MS) {\n // First event of a new window — always allow, start the counter.\n this.rateLimitCounters.set(key, { firstAt: now, count: 1, suppressedLogged: false })\n return false\n }\n\n entry.count += 1\n if (entry.count <= RATE_LIMIT_MAX_PER_SOURCE) return false\n\n // Over threshold — suppress the rest of this window.\n if (!entry.suppressedLogged) {\n entry.suppressedLogged = true\n this.ctx.logger?.info(\n 'rate-limiting suppressing remainder of window',\n { meta: { category, sourceId, maxPerSource: RATE_LIMIT_MAX_PER_SOURCE, windowSeconds: RATE_LIMIT_WINDOW_MS / 1000 } },\n )\n }\n return true\n }\n\n private buildMessage(category: string, data: Record<string, unknown>): string {\n const addonId = data.addonId as string | undefined\n const deviceId = data.deviceId as string | undefined\n const error = data.error as string | undefined\n const processId = data.processId as string | undefined\n\n switch (category) {\n case 'addon.crashed':\n return `Addon \"${addonId ?? 'unknown'}\" crashed${error ? `: ${error}` : ''}`\n case 'addon.error':\n return `Addon \"${addonId ?? 'unknown'}\" error${error ? `: ${error}` : ''}`\n case 'addon.installed':\n return `Addon \"${addonId ?? 'unknown'}\" installed`\n case 'addon.updated': {\n const from = data.fromVersion as string | undefined\n const to = data.toVersion as string | undefined\n return `Addon \"${addonId ?? 'unknown'}\" updated${from && to ? ` from ${from} to ${to}` : ''}`\n }\n case 'addon.uninstalled':\n return `Addon \"${addonId ?? 'unknown'}\" uninstalled`\n case 'device.registered':\n return `Device \"${data.name as string | undefined ?? deviceId ?? 'unknown'}\" registered`\n case 'device.unregistered':\n return `Device \"${deviceId ?? 'unknown'}\" unregistered`\n case 'agent.online':\n return `Agent \"${data.agentId as string | undefined ?? data.nodeId as string | undefined ?? 'unknown'}\" connected`\n case 'agent.offline':\n return `Agent \"${data.agentId as string | undefined ?? data.nodeId as string | undefined ?? 'unknown'}\" disconnected${data.reason ? `: ${String(data.reason)}` : ''}`\n case 'backup.completed':\n return `Backup completed${data.targetId ? ` (${String(data.targetId)})` : ''}`\n case 'backup.restored':\n return `Backup restored${data.source ? ` from ${String(data.source)}` : ''}`\n case 'notification.failed':\n return `Notification failed${error ? `: ${error}` : ''}`\n case 'system.restarting':\n return `System restarting${data.reason ? ` — ${String(data.reason)}` : ''}`\n case 'recording.error':\n return `Recording error on device \"${deviceId ?? 'unknown'}\"${error ? `: ${error}` : ''}`\n case 'recording.storage.critical':\n return `Storage critical for device \"${deviceId ?? 'unknown'}\"`\n case 'system.boot':\n return `System booted in \"${data.mode as string | undefined ?? 'unknown'}\" mode`\n case 'process.crashed':\n return `Process \"${processId ?? 'unknown'}\" crashed`\n default:\n return `Event: ${category}`\n }\n }\n\n // ── Private: persistence ─────────────────────────────────────────\n\n private async emitAlert(alert: Alert): Promise<void> {\n await this.persistAlert(alert)\n this.emitAlertCreatedEvent(alert)\n await this.enforceMaxAlerts()\n await this.enforceRetention()\n }\n\n private async updateAlert(alertId: string, patch: Partial<Alert>): Promise<void> {\n await this.mergeUpdate(alertId, { ...patch, updatedAt: Date.now() })\n this.emitAlertUpdatedEvent(alertId, patch)\n }\n\n /**\n * Read-merge-write: SettingsBackend.update() replaces the entire `data` blob,\n * so we must read the existing record, merge the patch, and write back.\n */\n private async mergeUpdate(id: string, patch: Record<string, unknown>): Promise<void> {\n const backend = this.ctx.api.settingsStore\n if (!backend) return\n\n const raw = await backend.get.query({ collection: ALERTS_COLLECTION, key: id })\n if (raw === null || raw === undefined || typeof raw !== 'object') return\n const existing: Record<string, unknown> = Object.fromEntries(Object.entries(raw))\n await backend.set.mutate({ collection: ALERTS_COLLECTION, key: id, value: { ...existing, ...patch } })\n }\n\n private async persistAlert(alert: Alert): Promise<void> {\n const backend = this.ctx.api.settingsStore\n if (!backend) return\n\n // Serialize alert to a plain Record for SQLite JSON storage\n const data: Record<string, unknown> = {\n id: alert.id,\n category: alert.category,\n severity: alert.severity,\n title: alert.title,\n message: alert.message,\n status: alert.status,\n read: alert.read,\n createdAt: alert.createdAt,\n updatedAt: alert.updatedAt,\n ...(alert.progress !== undefined ? { progress: alert.progress } : {}),\n ...(alert.source ? { source: alert.source } : {}),\n ...(alert.metadata ? { metadata: alert.metadata } : {}),\n }\n await backend.set.mutate({ collection: ALERTS_COLLECTION, key: alert.id, value: data })\n }\n\n private emitAlertCreatedEvent(alert: Alert): void {\n this.ctx.eventBus?.emit(createEvent('alert.created', EVENT_SOURCE, {\n id: alert.id,\n category: alert.category,\n severity: alert.severity,\n title: alert.title,\n status: alert.status,\n }))\n }\n\n private emitAlertUpdatedEvent(alertId: string, patch: Partial<Alert>): void {\n const patchRecord: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(patch)) {\n patchRecord[key] = value\n }\n this.ctx.eventBus?.emit(createEvent('alert.updated', EVENT_SOURCE, {\n alertId,\n patch: patchRecord,\n }))\n }\n\n private async enforceMaxAlerts(): Promise<void> {\n const backend = this.ctx.api.settingsStore\n if (!backend) return\n\n const total = await backend.count.query({ collection: ALERTS_COLLECTION })\n if (total <= this.config.maxAlerts) return\n\n // Delete oldest read alerts\n const excess = total - this.config.maxAlerts\n const oldest = await backend.query.query({ collection: ALERTS_COLLECTION, filter: {\n where: { read: true },\n orderBy: { field: 'createdAt', direction: 'asc' },\n limit: excess,\n } })\n\n for (const record of oldest) {\n await backend.delete.mutate({ collection: ALERTS_COLLECTION, key: record.id })\n }\n }\n\n private async enforceRetention(): Promise<void> {\n const backend = this.ctx.api.settingsStore\n if (!backend) return\n\n const cutoff = Date.now() - this.config.retentionDays * 24 * 60 * 60 * 1000\n const expired = await backend.query.query({ collection: ALERTS_COLLECTION, filter: {\n where: { read: true },\n orderBy: { field: 'createdAt', direction: 'asc' },\n } })\n\n for (const record of expired) {\n if (Number(record.data['createdAt'] ?? 0) < cutoff) {\n await backend.delete.mutate({ collection: ALERTS_COLLECTION, key: record.id })\n }\n }\n }\n}\n\nexport default AlertCenterAddon\n"],"mappings":"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","names":[]}
|