@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/native-metrics/native-metrics.addon.ts","../src/builtins/native-metrics/native-metrics-provider.ts"],"sourcesContent":["import type {\n AddonInstance,\n IMetricsProvider,\n KillProcessInput,\n KillProcessResult,\n NodeProcess,\n ProviderRegistration,\n} from '@camstack/types'\nimport { BaseAddon, EventCategory, createEvent, metricsProviderCapability } from '@camstack/types'\nimport { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport { NativeMetricsProvider } from './native-metrics-provider.js'\n\nconst execFileAsync = promisify(execFile)\n\n/**\n * Regex matching camstack-related command lines. We surface anything with\n * an obvious camstack fingerprint so operators can spot stray inference\n * pools, leaked tsx watchers, and zombie node workers in the Cluster →\n * Agent → Processes tab.\n *\n * Patterns mirror `scripts/hunt-zombies.sh` — keep them in sync when\n * adding a new long-lived subprocess.\n */\nconst CAMSTACK_CMD_RE = /(camstack|tsx\\s+watch\\s.*launcher\\.ts|packages\\/agent\\/dist\\/cli\\.js|inference_pool\\.py|bench-(inference-pool|nodeav)|node .*\\/packages\\/)/\n\n/**\n * Boundary patterns: ancestry walks that pass through a process whose\n * command line matches one of these are considered to be inside an\n * \"intentional camstack tree\". Anything reachable by walking up the\n * pid tree from such a boundary is `system` — not a ghost.\n *\n * The boundaries are:\n * - `tsx watch .../launcher.ts` — hub launcher (npm run dev:server)\n * - `node .../packages/agent/dist/cli.js` — agent CLI (dev-cluster, npm run dev:agent)\n * - `concurrently` — dev-cluster orchestrator that runs hub + admin-ui + agents\n * - `npm exec ` / `npm-cli.js` — npm wrappers driving the above\n * - `vite` — admin-ui dev server (sibling of hub under concurrently)\n *\n * The classification logic (`classifyByAncestry`) walks each candidate\n * pid up to ppid=1; if any ancestor matches this regex, the candidate\n * is `system`. Reaching ppid=1 without crossing a boundary = `ghost`.\n */\nconst SUPERVISOR_BOUNDARY_RE = /(tsx\\s+watch\\s.*launcher\\.ts|packages\\/agent\\/dist\\/cli\\.js|\\.bin\\/concurrently|\\/concurrently\\/dist|\\bnpm-cli\\.js\\b|npm exec |\\.bin\\/vite|\\/vite\\/bin\\/vite\\.js|node_modules\\/\\.bin\\/(vite|concurrently|tsup|rollup|esbuild|tsx)(\\s|$))/\n\ninterface NativeMetricsConfig {\n readonly samplingIntervalMs: number\n}\n\n/**\n * Cadence for the per-node metric snapshot bus events. ~5 s matches\n * the existing UI polling cadence (ProcessesTab, ProcessResources)\n * and stays within the sampling interval so consumers always see a\n * fresh-from-OS payload.\n */\nconst METRICS_SNAPSHOT_INTERVAL_MS = 5_000\n/**\n * Force a metrics-snapshot emit at least every 60s even when the\n * coarsened payload looks unchanged. Without this an idle node\n * (steady CPU within ±5%, no process churn) goes silent on the\n * bus and the UI's \"node alive\" chip can stale out.\n */\nconst METRICS_SNAPSHOT_HEARTBEAT_MS = 60_000\n\n/**\n * Coarsen CPU/mem percentages to integer buckets before deduping.\n * Without this every 5s tick differs by ±0.3% and the equality check\n * always fails, so the snapshot fans out unconditionally.\n */\nfunction coarsenResourcesSnapshot(snapshot: unknown): string {\n if (!snapshot || typeof snapshot !== 'object') return JSON.stringify(snapshot)\n // Walk the object and round any value that looks like a percent.\n const round = (v: unknown): unknown => {\n if (typeof v === 'number') {\n // CPU% / mem% / disk% all sit in 0..100. Bucket to nearest 5%.\n // Anything outside (uptime, byte counts) gets rounded to 100k\n // so byte deltas under that don't fire emits.\n if (v >= 0 && v <= 100) return Math.round(v / 5) * 5\n return Math.round(v / 100_000) * 100_000\n }\n if (Array.isArray(v)) return v.map(round)\n if (v && typeof v === 'object') {\n const out: Record<string, unknown> = {}\n for (const [k, val] of Object.entries(v as Record<string, unknown>)) {\n out[k] = round(val)\n }\n return out\n }\n return v\n }\n return JSON.stringify(round(snapshot))\n}\n\n/**\n * Coarsen a process list before deduping — pid, addonId, state +\n * bucketed cpu%. Drops cmdline / cwd / start time / uptime which\n * change every tick on a process that's just running. The result\n * is \"process X has the same role and roughly the same load\" =\n * skip emit.\n */\nfunction coarsenProcessList(processes: readonly unknown[]): string {\n const summary = processes\n .filter((p): p is Record<string, unknown> => !!p && typeof p === 'object')\n .map((p) => {\n const pid = p['pid']\n const addonId = p['addonId']\n const state = p['state']\n const cpu = typeof p['cpuPercent'] === 'number' ? Math.round((p['cpuPercent'] as number) / 5) * 5 : null\n const mem = typeof p['memoryRss'] === 'number' ? Math.round((p['memoryRss'] as number) / (50 * 1024 * 1024)) : null\n return [pid, addonId, state, cpu, mem]\n })\n return JSON.stringify(summary)\n}\n\n// Shape of the ProcessInfo returned by the kernel `$process.list` Moleculer action.\n// Not imported from @camstack/kernel — core cannot depend on kernel. Keep the shape\n// minimal + narrow the state field at the boundary.\ninterface KernelProcessInfo {\n readonly pid: number\n readonly nodeId: string\n readonly addonId: string\n readonly state: string\n readonly cpuPercent: number\n readonly memoryRss: number\n readonly uptimeSeconds: number\n}\n\ntype WorkerState = 'starting' | 'running' | 'stopping' | 'stopped' | 'crashed'\n\nfunction narrowWorkerState(state: string): WorkerState {\n switch (state) {\n case 'starting':\n case 'running':\n case 'stopping':\n case 'stopped':\n case 'crashed':\n return state\n default:\n return 'running'\n }\n}\n\n/**\n * Native metrics — CPU, memory, disk usage sampling.\n * Settings appear under Cluster → NodeDetail → Settings.\n */\nexport default class NativeMetricsAddon extends BaseAddon<NativeMetricsConfig> {\n private provider: NativeMetricsProvider | null = null\n private startedAtMs: number = Date.now()\n private snapshotTimer: ReturnType<typeof setInterval> | null = null\n /**\n * Snapshot-equality cache for the resources + processes emit.\n * Stores the coarsened JSON and timestamp; a tick where the\n * coarsened payload matches the cache (and the heartbeat hasn't\n * elapsed) is skipped.\n */\n private lastResourcesEmit: { coarse: string; emittedAt: number } | null = null\n private lastProcessesEmit: { coarse: string; emittedAt: number } | null = null\n\n constructor() {\n super({ samplingIntervalMs: 5000 })\n }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n const provider = new NativeMetricsProvider()\n provider.setDiagnostics({\n warn: (message, meta) => this.ctx.logger.warn(message, { meta: meta ?? {} }),\n })\n provider.startSampling(this.config.samplingIntervalMs)\n this.provider = provider\n this.startedAtMs = Date.now()\n this.ctx.logger.info('Native metrics provider started', { meta: { intervalMs: this.config.samplingIntervalMs } })\n\n const composed: IMetricsProvider = {\n collectSnapshot: () => provider.collectSnapshot(),\n getCached: () => provider.getCached(),\n getCurrent: () => provider.getCurrent(),\n getDiskSpace: (params) => provider.getDiskSpace(params),\n getGpuInfo: () => provider.getGpuInfo(),\n getCpuTemperature: () => provider.getCpuTemperature(),\n getProcessStats: (params) => provider.getProcessStats(params),\n listAddonInstances: () => this.listAddonInstances(),\n getAddonStats: (params) => this.getAddonStats(params.addonId),\n listNodeProcesses: () => this.listNodeProcesses(),\n killProcess: (params) => this.killProcess(params),\n }\n\n // Periodic snapshot emission — UI dashboards subscribe to these\n // categories instead of polling `getCached` /\n // `listNodeProcesses`. One full SystemResourceSnapshot + one\n // NodeProcess[] per node per tick.\n this.snapshotTimer = setInterval(\n () => this.emitMetricsSnapshots(),\n METRICS_SNAPSHOT_INTERVAL_MS,\n )\n\n return [{ capability: metricsProviderCapability, provider: composed }]\n }\n\n protected async onShutdown(): Promise<void> {\n if (this.snapshotTimer) {\n clearInterval(this.snapshotTimer)\n this.snapshotTimer = null\n }\n this.provider?.stopSampling()\n this.provider = null\n }\n\n /**\n * Emit one `metrics.node-resources-snapshot` + one\n * `metrics.node-processes-snapshot` for this node. UI consumers\n * subscribe and read state directly from the payload.\n */\n private async emitMetricsSnapshots(): Promise<void> {\n const provider = this.provider\n const eventBus = this.ctx.eventBus\n if (!provider || !eventBus) return\n const rawNodeId = this.ctx.kernel.localNodeId ?? this.ctx.id\n const nodeId = rawNodeId.includes('/') ? rawNodeId.split('/')[0]! : rawNodeId\n const timestamp = Date.now()\n\n // Resources snapshot — uses the cached sample (the provider's\n // background sampler already runs at samplingIntervalMs).\n try {\n const cached = await provider.getCached()\n const snapshot = cached ?? (await provider.collectSnapshot())\n const coarse = coarsenResourcesSnapshot(snapshot)\n const prev = this.lastResourcesEmit\n const heartbeatDue = !prev || timestamp - prev.emittedAt >= METRICS_SNAPSHOT_HEARTBEAT_MS\n if (!prev || prev.coarse !== coarse || heartbeatDue) {\n this.lastResourcesEmit = { coarse, emittedAt: timestamp }\n eventBus.emit(createEvent(\n EventCategory.MetricsNodeResourcesSnapshot,\n { type: 'node', id: nodeId, nodeId },\n { nodeId, snapshot, timestamp },\n ))\n }\n } catch {\n // Soft-fail: dashboards tolerate a missing tick.\n }\n\n // Process tree snapshot — heavier (`ps -eo`) but still well under\n // the snapshot interval. Skip on failure rather than block the\n // resources event above.\n try {\n const processes = await this.listNodeProcesses()\n const coarse = coarsenProcessList(processes)\n const prev = this.lastProcessesEmit\n const heartbeatDue = !prev || timestamp - prev.emittedAt >= METRICS_SNAPSHOT_HEARTBEAT_MS\n if (!prev || prev.coarse !== coarse || heartbeatDue) {\n this.lastProcessesEmit = { coarse, emittedAt: timestamp }\n eventBus.emit(createEvent(\n EventCategory.MetricsNodeProcessesSnapshot,\n { type: 'node', id: nodeId, nodeId },\n { nodeId, processes, timestamp },\n ))\n }\n } catch {\n // Soft-fail.\n }\n }\n\n protected async onConfigChanged(): Promise<void> {\n this.provider?.stopSampling()\n this.provider?.startSampling(this.config.samplingIntervalMs)\n }\n\n private async listWorkerInstances(): Promise<readonly KernelProcessInfo[]> {\n const broker = this.ctx.kernel.cluster?.broker\n if (!broker) return []\n try {\n return await broker.call<void, readonly KernelProcessInfo[]>('$process.list')\n } catch {\n // $process service not running on this node (workers, remote agents) —\n // a benign empty list.\n return []\n }\n }\n\n private async listAddonInstances() {\n const broker = this.ctx.kernel.cluster?.broker\n const hubNodeId = broker?.nodeID ?? 'hub'\n const uptimeSec = Math.max(0, Math.floor((Date.now() - this.startedAtMs) / 1000))\n const instances: AddonInstance[] = [{\n addonId: '$hub',\n nodeId: hubNodeId,\n role: 'hub',\n pid: process.pid,\n state: 'running',\n uptimeSec,\n }]\n const workers = await this.listWorkerInstances()\n for (const w of workers) {\n instances.push({\n addonId: w.addonId,\n nodeId: w.nodeId,\n role: 'worker',\n pid: w.pid,\n state: narrowWorkerState(w.state),\n uptimeSec: w.uptimeSeconds,\n })\n }\n return instances\n }\n\n private async getAddonStats(addonId: string) {\n const provider = this.provider\n if (!provider) return null\n if (addonId === '$hub') {\n const stats = await provider.getProcessStats({ pids: [process.pid] })\n return stats[0] ?? null\n }\n const workers = await this.listWorkerInstances()\n const target = workers.find((w) => w.addonId === addonId)\n if (!target) return null\n const stats = await provider.getProcessStats({ pids: [target.pid] })\n return stats[0] ?? null\n }\n\n /**\n * Walk the OS process table and classify each camstack-shaped process.\n *\n * Classification (ancestry-driven, NOT pattern-driven):\n * - root — the current node's own pid (`process.pid`).\n * - managed — pid is registered in the kernel's `$process.list`\n * (forked addon worker spawned by this hub).\n * - system — ancestry walk crosses a SUPERVISOR_BOUNDARY_RE match\n * (tsx-watch launcher, agent CLI, concurrently, vite,\n * npm exec wrapper). The process belongs to the dev\n * tree even if not in `$process.list`. NEVER killable.\n * - ghost — ancestry walk reaches `ppid=1` without crossing any\n * supervisor boundary AND the parent isn't visible in\n * `ps`. A truly orphaned camstack-shaped process. The\n * ONLY classification that's eligible for kill.\n *\n * Old pattern-only ghost detection produced false positives: every\n * monorepo-path process matched CAMSTACK_CMD_RE, ancestry walk\n * stopping at ppid=hub returned false-positive ghosts whenever a\n * concurrently sibling sat above hub. Ancestry-driven classification\n * fixes that.\n */\n private async listNodeProcesses(): Promise<readonly NodeProcess[]> {\n const ps = await this.runPs()\n if (ps.length === 0) return []\n\n const managedPids = new Map<number, { addonId: string; nodeId: string }>()\n const workers = await this.listWorkerInstances()\n for (const w of workers) {\n managedPids.set(w.pid, { addonId: w.addonId, nodeId: w.nodeId })\n }\n\n const hubNodeId = this.ctx.kernel.cluster?.broker?.nodeID ?? 'hub'\n const selfPid = process.pid\n\n // pid→{ppid, command} map for the ancestry walk. Indexes every visible\n // ps row regardless of CAMSTACK_CMD_RE match — we need command lines\n // for non-camstack ancestors (concurrently, npm exec) that act as\n // boundaries.\n const psIndex = new Map<number, { ppid: number; command: string }>()\n for (const p of ps) psIndex.set(p.pid, { ppid: p.ppid, command: p.command })\n\n /**\n * Walk ancestry from `pid` up to ppid=1 (or until we leave the ps\n * snapshot). Returns:\n * - 'system' — crossed a SUPERVISOR_BOUNDARY_RE ancestor\n * - 'ghost' — reached ppid=1 OR the parent isn't visible in ps\n * without crossing a boundary\n *\n * `selfPid` itself is treated as a boundary (this node's own root).\n */\n const classifyByAncestry = (startPid: number): 'system' | 'ghost' => {\n let cur = startPid\n for (let depth = 0; depth < 32; depth++) {\n const node = psIndex.get(cur)\n if (!node) return 'ghost' // parent left the scan — treat as orphan\n if (cur === selfPid) return 'system'\n if (SUPERVISOR_BOUNDARY_RE.test(node.command)) return 'system'\n if (node.ppid === 1) return 'ghost'\n if (node.ppid === selfPid) return 'system'\n cur = node.ppid\n }\n return 'system' // 32-deep ancestry = something weird, default safe\n }\n\n const out: NodeProcess[] = []\n for (const p of ps) {\n if (!CAMSTACK_CMD_RE.test(p.command)) continue\n const managed = managedPids.get(p.pid)\n let classification: NodeProcess['classification']\n if (p.pid === selfPid) {\n classification = 'root'\n } else if (managed) {\n classification = 'managed'\n } else {\n classification = classifyByAncestry(p.pid)\n }\n const orphaned = classification === 'ghost'\n\n out.push({\n pid: p.pid,\n ppid: p.ppid,\n pgid: p.pgid,\n classification,\n addonId: managed?.addonId ?? null,\n nodeId: managed?.nodeId ?? (p.pid === selfPid ? hubNodeId : null),\n command: p.command,\n cpuPercent: p.cpuPercent,\n memoryRssBytes: p.memoryRssBytes,\n uptimeSec: p.uptimeSec,\n orphaned,\n })\n }\n return out\n }\n\n /**\n * Send SIGTERM / SIGKILL to a pid. Refuses pids that don't appear in\n * `listNodeProcesses()` to prevent arbitrary system kills — a dedicated\n * admin-path for resurrected zombies, not a generic shell replacement.\n *\n * `root`-classified pids (the running launcher / agent CLI / hub itself)\n * are also refused: killing them tears down the whole node and the\n * operator's intent is almost always to nuke a leaked child, not the\n * supervisor that keeps the rest alive. Process restart goes through\n * the dedicated `$process.restart` action, not this kill API.\n */\n private async killProcess(input: KillProcessInput): Promise<KillProcessResult> {\n const visible = await this.listNodeProcesses()\n const match = visible.find((p) => p.pid === input.pid)\n if (!match) {\n return { success: false, reason: 'pid not in node process table' }\n }\n if (match.classification === 'root' || match.classification === 'system') {\n this.ctx.logger.warn('Refused to kill protected process', {\n meta: { pid: input.pid, classification: match.classification, addonId: match.addonId, command: match.command },\n })\n const reason = match.classification === 'root'\n ? 'cannot kill root (current node supervisor)'\n : 'cannot kill system (intentional dev-tree ancestor — vite, concurrently, npm, etc.)'\n return { success: false, reason }\n }\n const signal: 'SIGTERM' | 'SIGKILL' = input.force ? 'SIGKILL' : 'SIGTERM'\n try {\n process.kill(input.pid, signal)\n this.ctx.logger.info('Killed node process', { meta: { pid: input.pid, signal, classification: match.classification, addonId: match.addonId } })\n return { success: true, signal }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n return { success: false, reason: msg, signal }\n }\n }\n\n /** Raw `ps` scan returning every pid + command + resource stats. */\n private async runPs(): Promise<readonly {\n pid: number\n ppid: number\n pgid: number\n cpuPercent: number\n memoryRssBytes: number\n uptimeSec: number\n command: string\n }[]> {\n try {\n const { stdout } = await execFileAsync(\n 'ps',\n ['-eo', 'pid=,ppid=,pgid=,pcpu=,rss=,etime=,command='],\n { timeout: 5_000, maxBuffer: 8 * 1024 * 1024 },\n )\n const lines = stdout.split('\\n')\n const rows: {\n pid: number\n ppid: number\n pgid: number\n cpuPercent: number\n memoryRssBytes: number\n uptimeSec: number\n command: string\n }[] = []\n for (const line of lines) {\n const trimmed = line.trim()\n if (!trimmed) continue\n const match = trimmed.match(/^(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+([\\d.]+)\\s+(\\d+)\\s+(\\S+)\\s+(.+)$/)\n if (!match) continue\n const [, pidS, ppidS, pgidS, cpuS, rssS, etimeS, command] = match\n rows.push({\n pid: parseInt(pidS!, 10),\n ppid: parseInt(ppidS!, 10),\n pgid: parseInt(pgidS!, 10),\n cpuPercent: Math.round(parseFloat(cpuS!) * 10) / 10,\n memoryRssBytes: parseInt(rssS!, 10) * 1024,\n uptimeSec: parseEtime(etimeS!),\n command: command!,\n })\n }\n return rows\n } catch (err) {\n this.ctx.logger.warn('ps scan failed', { meta: { error: err instanceof Error ? err.message : String(err) } })\n return []\n }\n }\n\n protected globalSettingsSchema() {\n return this.schema({\n sections: [{\n id: 'native-metrics-settings',\n title: 'System Metrics',\n fields: [\n this.field({\n type: 'number',\n key: 'samplingIntervalMs',\n label: 'Sampling Interval',\n description: 'How often to collect system metrics',\n min: 1000,\n max: 60000,\n step: 1000,\n default: 5000,\n unit: 'ms',\n }),\n ],\n }],\n })\n }\n}\n\n/**\n * Parse `ps etime` format → seconds.\n *\n * Formats we handle:\n * `MM:SS` (< 1h)\n * `HH:MM:SS` (< 1d)\n * `DD-HH:MM:SS` (>= 1d)\n */\nfunction parseEtime(etime: string): number {\n const dashParts = etime.split('-')\n let days = 0\n let hms = etime\n if (dashParts.length === 2) {\n days = parseInt(dashParts[0]!, 10) || 0\n hms = dashParts[1]!\n }\n const parts = hms.split(':').map((p) => parseInt(p, 10) || 0)\n let hours = 0, minutes = 0, seconds = 0\n if (parts.length === 3) [hours, minutes, seconds] = parts as [number, number, number]\n else if (parts.length === 2) [minutes, seconds] = parts as [number, number]\n else if (parts.length === 1) [seconds] = parts as [number]\n return days * 86400 + hours * 3600 + minutes * 60 + seconds\n}\n","import * as os from 'node:os'\nimport * as fs from 'node:fs'\nimport { execFile, execFileSync } from 'node:child_process'\nimport type {\n SystemResourceSnapshot,\n CpuBreakdown,\n MemoryInfo,\n DiskSpaceInfo,\n DiskIoSnapshot,\n NetworkIoSnapshot,\n MetricsGpuInfo,\n ProcessResourceInfo,\n PressureInfo,\n PidResourceStats,\n} from '@camstack/types'\n\nconst IS_DARWIN = os.platform() === 'darwin'\nconst IS_LINUX = os.platform() === 'linux'\n\n// Node.js internal API — no public type declarations exist.\n// _getActiveHandles and _getActiveRequests are undocumented but stable across all LTS versions.\ninterface NodeProcessInternals {\n _getActiveHandles?: () => unknown[]\n _getActiveRequests?: () => unknown[]\n}\n\n// ===========================================================================\n// NativeMetricsProvider — implements the metrics-provider capability using\n// OS-level APIs. Zero external dependencies. Works on macOS and Linux.\n//\n// Lifecycle methods (startSampling/stopSampling) and the `id` field are\n// NOT part of the capability contract — they live on the class for addon\n// lifecycle use. Only the async methods declared on IMetricsProvider cross\n// the tRPC/Moleculer boundary.\n// ===========================================================================\n\ninterface SamplingDiagnostics {\n warn(message: string, meta?: Record<string, unknown>): void\n}\n\nexport class NativeMetricsProvider {\n readonly id = 'native'\n\n private cachedSnapshot: SystemResourceSnapshot | null = null\n private samplingTimer: ReturnType<typeof setInterval> | null = null\n private macMemTimer: ReturnType<typeof setInterval> | null = null\n private prevCpu: CpuTimes\n private diagnostics: SamplingDiagnostics | null = null\n private consecutiveSampleErrors = 0\n\n constructor() {\n this.prevCpu = aggregateCpuTimes()\n }\n\n /**\n * Optional diagnostics sink for sampling errors. The first failure and\n * every Nth failure thereafter are reported so a permanently-broken\n * collector doesn't spam logs but is still observable.\n */\n setDiagnostics(diag: SamplingDiagnostics): void {\n this.diagnostics = diag\n }\n\n // ─── Lifecycle (not on the cap contract) ────────────────────────────\n\n startSampling(intervalMs: number): void {\n // Seed macOS vm_stat cache immediately\n if (IS_DARWIN) {\n sampleMacMemory(this)\n this.macMemTimer = setInterval(() => sampleMacMemory(this), 5000)\n if (this.macMemTimer.unref) this.macMemTimer.unref()\n }\n\n // First sample immediately\n this.collectSnapshot()\n .then((s) => { this.cachedSnapshot = s; this.consecutiveSampleErrors = 0 })\n .catch((err: unknown) => this.reportSampleError(err))\n\n this.samplingTimer = setInterval(() => {\n this.collectSnapshot()\n .then((s) => { this.cachedSnapshot = s; this.consecutiveSampleErrors = 0 })\n .catch((err: unknown) => this.reportSampleError(err))\n }, intervalMs)\n if (this.samplingTimer.unref) this.samplingTimer.unref()\n }\n\n private reportSampleError(err: unknown): void {\n this.consecutiveSampleErrors++\n if (!this.diagnostics) return\n // First failure + every 60th sample (~1/min at 1s interval)\n const shouldLog = this.consecutiveSampleErrors === 1 || this.consecutiveSampleErrors % 60 === 0\n if (!shouldLog) return\n this.diagnostics.warn('metrics-provider sample failed', {\n consecutiveErrors: this.consecutiveSampleErrors,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n\n stopSampling(): void {\n if (this.samplingTimer) { clearInterval(this.samplingTimer); this.samplingTimer = null }\n if (this.macMemTimer) { clearInterval(this.macMemTimer); this.macMemTimer = null }\n }\n\n // ─── Cap contract — async methods ───────────────────────────────────\n\n async collectSnapshot(): Promise<SystemResourceSnapshot> {\n const cpu = this.sampleCpu()\n const memory = this.getMemoryInfo()\n const processInfo = getProcessResources()\n\n const [gpu, network, disk, cpuTemp] = await Promise.all([\n getGpuInfoInternal().catch(() => null),\n takeNetworkIoSnapshot(),\n takeDiskIoSnapshot(),\n getCpuTemperatureInternal().catch(() => null),\n ])\n\n const snapshot: SystemResourceSnapshot = {\n cpu,\n memory,\n gpu,\n network,\n disk,\n pressure: {\n cpu: getPressure('cpu'),\n memory: getPressure('memory'),\n io: getPressure('io'),\n },\n process: processInfo,\n cpuTemperature: cpuTemp,\n timestampMs: Date.now(),\n }\n\n this.cachedSnapshot = snapshot\n return snapshot\n }\n\n async getCached(): Promise<SystemResourceSnapshot | null> {\n return this.cachedSnapshot\n }\n\n async getCurrent(): Promise<{\n cpuPercent: number\n memoryPercent: number\n memoryUsedMB: number\n memoryTotalMB: number\n diskPercent?: number\n temperature?: number\n gpuPercent?: number\n gpuMemoryPercent?: number\n }> {\n const s = this.cachedSnapshot ?? await this.collectSnapshot()\n const mb = (bytes: number) => Math.round(bytes / 1024 / 1024)\n return {\n cpuPercent: s.cpu.total,\n memoryPercent: s.memory.percent,\n memoryUsedMB: mb(s.memory.usedBytes),\n memoryTotalMB: mb(s.memory.totalBytes),\n temperature: s.cpuTemperature ?? undefined,\n gpuPercent: s.gpu?.utilization,\n gpuMemoryPercent:\n s.gpu && s.gpu.memoryTotalBytes > 0\n ? Math.round((s.gpu.memoryUsedBytes / s.gpu.memoryTotalBytes) * 1000) / 10\n : undefined,\n }\n }\n\n async getDiskSpace(input: { dirPath: string }): Promise<DiskSpaceInfo> {\n return getDiskSpaceInternal(input.dirPath)\n }\n\n async getGpuInfo(): Promise<MetricsGpuInfo | null> {\n return getGpuInfoInternal()\n }\n\n async getCpuTemperature(): Promise<number | null> {\n return getCpuTemperatureInternal()\n }\n\n async getProcessStats(input: { pids: number[] }): Promise<PidResourceStats[]> {\n const { getPidStats } = await import('../../process/resource-monitor.js')\n const raw = await getPidStats(input.pids)\n const result: PidResourceStats[] = []\n for (const [pid, s] of raw) {\n result.push({ pid, cpu: s.cpu, memory: s.memory })\n }\n return result\n }\n\n // ─── Internal: CPU sampling ─────────────────────────────────────────\n\n private sampleCpu(): CpuBreakdown {\n const curr = aggregateCpuTimes()\n const prev = this.prevCpu\n this.prevCpu = curr\n\n const dUser = curr.user - prev.user\n const dNice = curr.nice - prev.nice\n const dSys = curr.sys - prev.sys\n const dIrq = curr.irq - prev.irq\n const dIdle = curr.idle - prev.idle\n const dTotal = dUser + dNice + dSys + dIrq + dIdle\n\n const pct = (v: number) => dTotal === 0 ? 0 : Math.round((v / dTotal) * 1000) / 10\n\n return {\n total: pct(dUser + dNice + dSys + dIrq),\n user: pct(dUser),\n system: pct(dSys),\n irq: pct(dIrq),\n nice: pct(dNice),\n loadAvg: os.loadavg() as [number, number, number],\n cores: os.cpus().length,\n }\n }\n\n // ─── Internal: Memory ───────────────────────────────────────────────\n\n /** Cached macOS memory (set by sampleMacMemory timer). */\n _cachedMacMem: MemoryInfo | null = null\n\n private getMemoryInfo(): MemoryInfo {\n const total = os.totalmem()\n if (total === 0) {\n return { percent: 0, totalBytes: 0, usedBytes: 0, availableBytes: 0, swapUsedBytes: 0, swapTotalBytes: 0 }\n }\n\n if (IS_DARWIN && this._cachedMacMem !== null) {\n return this._cachedMacMem\n }\n\n const free = os.freemem()\n const used = total - free\n let swapUsedBytes = 0\n let swapTotalBytes = 0\n\n if (IS_LINUX) {\n try {\n const meminfo = fs.readFileSync('/proc/meminfo', 'utf-8')\n const swapTotal = parseInt(meminfo.match(/SwapTotal:\\s+(\\d+)/)?.[1] ?? '0', 10) * 1024\n const swapFree = parseInt(meminfo.match(/SwapFree:\\s+(\\d+)/)?.[1] ?? '0', 10) * 1024\n swapTotalBytes = swapTotal\n swapUsedBytes = swapTotal - swapFree\n } catch { /* ignore */ }\n }\n\n return {\n percent: Math.round(((total - free) / total) * 1000) / 10,\n totalBytes: total,\n usedBytes: used,\n availableBytes: free,\n swapUsedBytes,\n swapTotalBytes,\n }\n }\n}\n\n// ===========================================================================\n// Internal helpers (module-private, no side effects at import time)\n// ===========================================================================\n\ninterface CpuTimes {\n user: number\n nice: number\n sys: number\n irq: number\n idle: number\n}\n\nfunction aggregateCpuTimes(): CpuTimes {\n const cpus = os.cpus()\n let user = 0, nice = 0, sys = 0, irq = 0, idle = 0\n for (const cpu of cpus) {\n user += cpu.times.user\n nice += cpu.times.nice\n sys += cpu.times.sys\n irq += cpu.times.irq\n idle += cpu.times.idle\n }\n return { user, nice, sys, irq, idle }\n}\n\n// ─── macOS vm_stat memory sampling ─────────────────────────────────────────\n\nfunction sampleMacMemory(provider: NativeMetricsProvider): void {\n try {\n const output = execFileSync('vm_stat', { timeout: 2000, encoding: 'utf-8' })\n const pageSize = 16384 // macOS ARM64\n const parse = (label: string): number => {\n const match = output.match(new RegExp(`${label}:\\\\s+(\\\\d+)`))\n return match ? parseInt(match[1]!, 10) * pageSize : 0\n }\n\n const free = parse('Pages free')\n const inactive = parse('Pages inactive')\n const purgeable = parse('Pages purgeable')\n const speculative = parse('Pages speculative')\n const available = free + inactive + purgeable + speculative\n const total = os.totalmem()\n const used = total - available\n\n let swapUsedBytes = 0\n let swapTotalBytes = 0\n try {\n const swapOut = execFileSync('sysctl', ['-n', 'vm.swapusage'], { timeout: 2000, encoding: 'utf-8' })\n const totalMatch = swapOut.match(/total\\s*=\\s*([\\d.]+)M/)\n const usedMatch = swapOut.match(/used\\s*=\\s*([\\d.]+)M/)\n if (totalMatch) swapTotalBytes = parseFloat(totalMatch[1]!) * 1024 * 1024\n if (usedMatch) swapUsedBytes = parseFloat(usedMatch[1]!) * 1024 * 1024\n } catch { /* ignore */ }\n\n provider._cachedMacMem = {\n percent: Math.round((used / total) * 1000) / 10,\n totalBytes: total,\n usedBytes: used,\n availableBytes: available,\n swapUsedBytes,\n swapTotalBytes,\n }\n } catch {\n provider._cachedMacMem = null\n }\n}\n\n// ─── Disk space ────────────────────────────────────────────────────────────\n\nfunction getDiskSpaceInternal(dirPath: string): Promise<DiskSpaceInfo> {\n return new Promise((resolve, reject) => {\n fs.statfs(dirPath, (err, stats) => {\n if (err) return reject(err)\n const totalBytes = stats.blocks * stats.bsize\n const availableBytes = stats.bavail * stats.bsize\n const usedBytes = totalBytes - (stats.bfree * stats.bsize)\n resolve({\n path: dirPath,\n totalBytes,\n usedBytes,\n availableBytes,\n percent: totalBytes > 0 ? Math.round((usedBytes / totalBytes) * 1000) / 10 : 0,\n })\n })\n })\n}\n\n// ─── Disk I/O ──────────────────────────────────────────────────────────────\n\nasync function takeDiskIoSnapshot(): Promise<DiskIoSnapshot> {\n const now = Date.now()\n\n if (IS_LINUX) {\n try {\n const data = fs.readFileSync('/proc/diskstats', 'utf-8')\n let readOps = 0, readBytes = 0, writeOps = 0, writeBytes = 0\n for (const line of data.split('\\n')) {\n const parts = line.trim().split(/\\s+/)\n if (parts.length < 14) continue\n const devName = parts[2]!\n if (/\\d+$/.test(devName) && !/^nvme\\d+n\\d+$/.test(devName)) continue\n readOps += parseInt(parts[3]!, 10) || 0\n readBytes += (parseInt(parts[5]!, 10) || 0) * 512\n writeOps += parseInt(parts[7]!, 10) || 0\n writeBytes += (parseInt(parts[9]!, 10) || 0) * 512\n }\n return { readBytes, writeBytes, readOps, writeOps, timestampMs: now }\n } catch { /* fallback */ }\n }\n\n return { readBytes: 0, writeBytes: 0, readOps: 0, writeOps: 0, timestampMs: now }\n}\n\n// ─── Network I/O ───────────────────────────────────────────────────────────\n\nasync function takeNetworkIoSnapshot(): Promise<NetworkIoSnapshot> {\n const now = Date.now()\n\n if (IS_LINUX) {\n try {\n const data = fs.readFileSync('/proc/net/dev', 'utf-8')\n let rxBytes = 0, txBytes = 0, rxPackets = 0, txPackets = 0, rxErrors = 0, txErrors = 0\n for (const line of data.split('\\n')) {\n const match = line.match(/^\\s*(\\w+):\\s+(.+)$/)\n if (!match) continue\n if (match[1] === 'lo') continue\n const cols = match[2]!.trim().split(/\\s+/)\n rxBytes += parseInt(cols[0]!, 10) || 0\n rxPackets += parseInt(cols[1]!, 10) || 0\n rxErrors += parseInt(cols[2]!, 10) || 0\n txBytes += parseInt(cols[8]!, 10) || 0\n txPackets += parseInt(cols[9]!, 10) || 0\n txErrors += parseInt(cols[10]!, 10) || 0\n }\n return { rxBytes, txBytes, rxPackets, txPackets, rxErrors, txErrors, timestampMs: now }\n } catch { /* fallback */ }\n }\n\n if (IS_DARWIN) {\n try {\n const stdout = await execAsync('netstat', ['-ib'])\n let rxBytes = 0, txBytes = 0, rxPackets = 0, txPackets = 0, rxErrors = 0, txErrors = 0\n for (const line of stdout.split('\\n')) {\n const parts = line.trim().split(/\\s+/)\n if (parts.length < 11) continue\n if (parts[0] === 'lo0' || parts[0] === 'Name') continue\n if (!parts[2]?.startsWith('Link#')) continue\n rxPackets += parseInt(parts[4]!, 10) || 0\n rxErrors += parseInt(parts[5]!, 10) || 0\n rxBytes += parseInt(parts[6]!, 10) || 0\n txPackets += parseInt(parts[7]!, 10) || 0\n txErrors += parseInt(parts[8]!, 10) || 0\n txBytes += parseInt(parts[9]!, 10) || 0\n }\n return { rxBytes, txBytes, rxPackets, txPackets, rxErrors, txErrors, timestampMs: now }\n } catch { /* fallback */ }\n }\n\n return { rxBytes: 0, txBytes: 0, rxPackets: 0, txPackets: 0, rxErrors: 0, txErrors: 0, timestampMs: now }\n}\n\n// ─── CPU temperature ───────────────────────────────────────────────────────\n\nasync function getCpuTemperatureInternal(): Promise<number | null> {\n if (IS_LINUX) {\n const paths = ['/sys/class/thermal/thermal_zone0/temp', '/sys/class/hwmon/hwmon0/temp1_input']\n for (const p of paths) {\n try {\n const raw = fs.readFileSync(p, 'utf-8').trim()\n const millideg = parseInt(raw, 10)\n if (!isNaN(millideg)) return Math.round(millideg / 100) / 10\n } catch { continue }\n }\n }\n\n if (IS_DARWIN) {\n try {\n const stdout = await execAsync('sudo', ['-n', 'powermetrics', '--samplers', 'smc', '-i', '1', '-n', '1'], 3000)\n const match = stdout.match(/CPU die temperature:\\s+([\\d.]+)\\s*C/)\n if (match) return Math.round(parseFloat(match[1]!) * 10) / 10\n } catch { /* no root */ }\n }\n\n return null\n}\n\n// ─── GPU info ──────────────────────────────────────────────────────────────\n\nasync function getGpuInfoInternal(): Promise<MetricsGpuInfo | null> {\n if (IS_DARWIN) {\n try {\n const stdout = await execAsync('ioreg', ['-r', '-d', '1', '-c', 'IOAccelerator'])\n const utilMatch = stdout.match(/\"GPU Core Utilization\"\\s*=\\s*(\\d+)/)\n const util = utilMatch ? parseInt(utilMatch[1]!, 10) : 0\n const utilPct = util > 1000 ? Math.round(util / 10000000) : util\n return {\n utilization: Math.min(100, utilPct),\n model: 'Apple Silicon GPU',\n memoryUsedBytes: 0,\n memoryTotalBytes: 0,\n temperature: null,\n }\n } catch { /* ignore */ }\n }\n\n if (IS_LINUX) {\n try {\n const stdout = await execAsync('nvidia-smi', [\n '--query-gpu=utilization.gpu,name,memory.used,memory.total,temperature.gpu',\n '--format=csv,noheader,nounits',\n ])\n const parts = stdout.trim().split(',').map(s => s.trim())\n if (parts.length >= 5) {\n return {\n utilization: parseInt(parts[0]!, 10) || 0,\n model: parts[1] ?? 'Unknown GPU',\n memoryUsedBytes: (parseInt(parts[2]!, 10) || 0) * 1024 * 1024,\n memoryTotalBytes: (parseInt(parts[3]!, 10) || 0) * 1024 * 1024,\n temperature: parseInt(parts[4]!, 10) || null,\n }\n }\n } catch { /* no nvidia-smi */ }\n }\n\n return null\n}\n\n// ─── Process resources ─────────────────────────────────────────────────────\n\nfunction getProcessResources(): ProcessResourceInfo {\n let openFds = 0\n let threadCount = 0\n\n if (IS_LINUX) {\n try { openFds = fs.readdirSync(`/proc/${process.pid}/fd`).length } catch { /* ignore */ }\n try {\n const status = fs.readFileSync(`/proc/${process.pid}/status`, 'utf-8')\n const match = status.match(/Threads:\\s+(\\d+)/)\n if (match) threadCount = parseInt(match[1]!, 10)\n } catch { /* ignore */ }\n }\n\n const nodeProcess = process as typeof process & NodeProcessInternals\n return {\n openFds,\n threadCount,\n activeHandles: (nodeProcess._getActiveHandles?.() ?? []).length,\n activeRequests: (nodeProcess._getActiveRequests?.() ?? []).length,\n }\n}\n\n// ─── Linux PSI ─────────────────────────────────────────────────────────────\n\nfunction getPressure(resource: 'cpu' | 'memory' | 'io'): PressureInfo | null {\n if (!IS_LINUX) return null\n try {\n const data = fs.readFileSync(`/proc/pressure/${resource}`, 'utf-8')\n const parseLine = (prefix: string) => {\n const match = data.match(new RegExp(`${prefix} avg10=(\\\\d+\\\\.\\\\d+) avg60=(\\\\d+\\\\.\\\\d+) avg300=(\\\\d+\\\\.\\\\d+)`))\n if (!match) return null\n return { avg10: parseFloat(match[1]!), avg60: parseFloat(match[2]!), avg300: parseFloat(match[3]!) }\n }\n const some = parseLine('some')\n if (!some) return null\n return { some, full: parseLine('full') }\n } catch {\n return null\n }\n}\n\n// ─── Util ──────────────────────────────────────────────────────────────────\n\nfunction execAsync(cmd: string, args: string[], timeoutMs = 5000): Promise<string> {\n return new Promise((resolve, reject) => {\n execFile(cmd, args, { timeout: timeoutMs }, (err, stdout) => {\n if (err) return reject(err)\n resolve(stdout)\n })\n })\n}\n"],"mappings":"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","names":["execFile","cpus","execFile","stats"]}
|
package/dist/chunk-6M2HSSTQ.mjs
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
// src/storage/storage-location-manager.ts
|
|
2
|
-
import { join as join2, isAbsolute as isAbsolute2 } from "path";
|
|
3
|
-
|
|
4
|
-
// src/storage/fs-storage-backend.ts
|
|
5
|
-
import { existsSync, accessSync, constants } from "fs";
|
|
6
|
-
import { join, resolve, dirname, isAbsolute } from "path";
|
|
7
|
-
var FsStorageBackend = class {
|
|
8
|
-
type = "local";
|
|
9
|
-
basePath;
|
|
10
|
-
constructor(basePath) {
|
|
11
|
-
this.basePath = resolve(basePath);
|
|
12
|
-
}
|
|
13
|
-
resolve(subpath) {
|
|
14
|
-
if (isAbsolute(subpath)) return subpath;
|
|
15
|
-
return join(this.basePath, subpath);
|
|
16
|
-
}
|
|
17
|
-
isAvailable() {
|
|
18
|
-
try {
|
|
19
|
-
if (existsSync(this.basePath)) {
|
|
20
|
-
accessSync(this.basePath, constants.W_OK);
|
|
21
|
-
return true;
|
|
22
|
-
}
|
|
23
|
-
let parent = dirname(this.basePath);
|
|
24
|
-
while (parent && parent !== dirname(parent)) {
|
|
25
|
-
if (existsSync(parent)) {
|
|
26
|
-
accessSync(parent, constants.W_OK);
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
29
|
-
parent = dirname(parent);
|
|
30
|
-
}
|
|
31
|
-
return false;
|
|
32
|
-
} catch {
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
async initialize() {
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
// src/storage/storage-location-manager.ts
|
|
41
|
-
var StorageLocationManager = class {
|
|
42
|
-
backends = /* @__PURE__ */ new Map();
|
|
43
|
-
dataPath;
|
|
44
|
-
constructor(dataPath) {
|
|
45
|
-
this.dataPath = dataPath;
|
|
46
|
-
}
|
|
47
|
-
/** Initialize all locations with default paths */
|
|
48
|
-
async initializeDefaults() {
|
|
49
|
-
const defaults = {
|
|
50
|
-
data: join2(this.dataPath, "db"),
|
|
51
|
-
media: join2(this.dataPath, "media"),
|
|
52
|
-
recordings: join2(this.dataPath, "recordings"),
|
|
53
|
-
models: join2(this.dataPath, "models"),
|
|
54
|
-
cache: "/tmp/camstack-cache",
|
|
55
|
-
logs: join2(this.dataPath, "logs")
|
|
56
|
-
};
|
|
57
|
-
for (const [name, path] of Object.entries(defaults)) {
|
|
58
|
-
const backend = new FsStorageBackend(path);
|
|
59
|
-
await backend.initialize();
|
|
60
|
-
this.backends.set(name, backend);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
/** Override a specific location's backend path */
|
|
64
|
-
async setLocationPath(name, basePath) {
|
|
65
|
-
const resolved = isAbsolute2(basePath) ? basePath : join2(this.dataPath, basePath);
|
|
66
|
-
const backend = new FsStorageBackend(resolved);
|
|
67
|
-
await backend.initialize();
|
|
68
|
-
this.backends.set(name, backend);
|
|
69
|
-
}
|
|
70
|
-
/** Get the backend for a location */
|
|
71
|
-
getBackend(name) {
|
|
72
|
-
const backend = this.backends.get(name);
|
|
73
|
-
if (!backend) throw new Error(`Storage location "${name}" not initialized`);
|
|
74
|
-
return backend;
|
|
75
|
-
}
|
|
76
|
-
/** Resolve a path within a location */
|
|
77
|
-
resolve(location, subpath) {
|
|
78
|
-
return this.getBackend(location).resolve(subpath);
|
|
79
|
-
}
|
|
80
|
-
/** Check if all locations are available */
|
|
81
|
-
getStatus() {
|
|
82
|
-
return Array.from(this.backends.entries()).map(([name, backend]) => ({
|
|
83
|
-
name,
|
|
84
|
-
available: backend.isAvailable(),
|
|
85
|
-
path: backend.basePath
|
|
86
|
-
}));
|
|
87
|
-
}
|
|
88
|
-
/** All location names */
|
|
89
|
-
getLocationNames() {
|
|
90
|
-
return Array.from(this.backends.keys());
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
export {
|
|
95
|
-
FsStorageBackend,
|
|
96
|
-
StorageLocationManager
|
|
97
|
-
};
|
|
98
|
-
//# sourceMappingURL=chunk-6M2HSSTQ.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/storage/storage-location-manager.ts","../src/storage/fs-storage-backend.ts"],"sourcesContent":["import { join, isAbsolute } from 'node:path'\nimport { FsStorageBackend, type IStorageBackend } from './fs-storage-backend.js'\n\nexport type StorageLocationName = 'data' | 'media' | 'recordings' | 'models' | 'cache' | 'logs'\n\nexport class StorageLocationManager {\n private readonly backends: Map<StorageLocationName, IStorageBackend> = new Map()\n private readonly dataPath: string\n\n constructor(dataPath: string) {\n this.dataPath = dataPath\n }\n\n /** Initialize all locations with default paths */\n async initializeDefaults(): Promise<void> {\n const defaults: Record<StorageLocationName, string> = {\n data: join(this.dataPath, 'db'),\n media: join(this.dataPath, 'media'),\n recordings: join(this.dataPath, 'recordings'),\n models: join(this.dataPath, 'models'),\n cache: '/tmp/camstack-cache',\n logs: join(this.dataPath, 'logs'),\n }\n\n for (const [name, path] of Object.entries(defaults)) {\n const backend = new FsStorageBackend(path)\n await backend.initialize()\n this.backends.set(name as StorageLocationName, backend)\n }\n }\n\n /** Override a specific location's backend path */\n async setLocationPath(name: StorageLocationName, basePath: string): Promise<void> {\n const resolved = isAbsolute(basePath) ? basePath : join(this.dataPath, basePath)\n const backend = new FsStorageBackend(resolved)\n await backend.initialize()\n this.backends.set(name, backend)\n }\n\n /** Get the backend for a location */\n getBackend(name: StorageLocationName): IStorageBackend {\n const backend = this.backends.get(name)\n if (!backend) throw new Error(`Storage location \"${name}\" not initialized`)\n return backend\n }\n\n /** Resolve a path within a location */\n resolve(location: StorageLocationName, subpath: string): string {\n return this.getBackend(location).resolve(subpath)\n }\n\n /** Check if all locations are available */\n getStatus(): Array<{ name: StorageLocationName; available: boolean; path: string }> {\n return Array.from(this.backends.entries()).map(([name, backend]) => ({\n name,\n available: backend.isAvailable(),\n path: backend.basePath,\n }))\n }\n\n /** All location names */\n getLocationNames(): StorageLocationName[] {\n return Array.from(this.backends.keys())\n }\n}\n","import { existsSync, accessSync, constants } from 'node:fs'\nimport { join, resolve, dirname, isAbsolute } from 'node:path'\n\nexport interface IStorageBackend {\n /** Backend type identifier */\n readonly type: string\n /** Base path of this backend */\n readonly basePath: string\n /** Resolve a subpath to an absolute path */\n resolve(subpath: string): string\n /**\n * Check whether the backend is usable: either the base directory\n * already exists and is writable, OR we can create it on first\n * write (i.e. the nearest existing ancestor is writable).\n */\n isAvailable(): boolean\n /** No-op for lazy backends. Kept for API compatibility. */\n initialize(): Promise<void>\n}\n\n/**\n * Filesystem storage backend — lazy by design.\n *\n * `initialize()` does NOT create the base directory eagerly. Instead,\n * consumers that write via `FilesystemStorageProvider` (and other write\n * helpers in storage-manager.ts) run `fs.mkdir(dirname(filePath), { recursive: true })`\n * right before every `writeFile`, so the directory tree appears on demand.\n *\n * The previous behaviour eagerly mkdir'd every location declared in\n * `StorageLocationManager.initializeDefaults()` — six directories (`db`,\n * `media`, `recordings`, `models`, `cache`, `logs`) got created at boot\n * even if the installation had no cameras, no recording addon, no\n * analytics addon, etc. That meant every fresh install looked like it\n * was producing data when it had nothing to write. Laziness fixes that:\n * a directory only exists once an addon decides to put a file there.\n */\nexport class FsStorageBackend implements IStorageBackend {\n readonly type = 'local'\n readonly basePath: string\n\n constructor(basePath: string) {\n this.basePath = resolve(basePath)\n }\n\n resolve(subpath: string): string {\n if (isAbsolute(subpath)) return subpath\n return join(this.basePath, subpath)\n }\n\n isAvailable(): boolean {\n // If the base dir already exists, check write permission directly.\n // Otherwise walk up to the first existing ancestor (guaranteed to\n // terminate at the filesystem root) and check it is writable — we\n // can then mkdir the missing segments on first write.\n try {\n if (existsSync(this.basePath)) {\n accessSync(this.basePath, constants.W_OK)\n return true\n }\n let parent = dirname(this.basePath)\n while (parent && parent !== dirname(parent)) {\n if (existsSync(parent)) {\n accessSync(parent, constants.W_OK)\n return true\n }\n parent = dirname(parent)\n }\n return false\n } catch {\n return false\n }\n }\n\n async initialize(): Promise<void> {\n // No-op: base directory is created lazily on first write. See the\n // class docstring for the rationale.\n }\n}\n"],"mappings":";AAAA,SAAS,QAAAA,OAAM,cAAAC,mBAAkB;;;ACAjC,SAAS,YAAY,YAAY,iBAAiB;AAClD,SAAS,MAAM,SAAS,SAAS,kBAAkB;AAmC5C,IAAM,mBAAN,MAAkD;AAAA,EAC9C,OAAO;AAAA,EACP;AAAA,EAET,YAAY,UAAkB;AAC5B,SAAK,WAAW,QAAQ,QAAQ;AAAA,EAClC;AAAA,EAEA,QAAQ,SAAyB;AAC/B,QAAI,WAAW,OAAO,EAAG,QAAO;AAChC,WAAO,KAAK,KAAK,UAAU,OAAO;AAAA,EACpC;AAAA,EAEA,cAAuB;AAKrB,QAAI;AACF,UAAI,WAAW,KAAK,QAAQ,GAAG;AAC7B,mBAAW,KAAK,UAAU,UAAU,IAAI;AACxC,eAAO;AAAA,MACT;AACA,UAAI,SAAS,QAAQ,KAAK,QAAQ;AAClC,aAAO,UAAU,WAAW,QAAQ,MAAM,GAAG;AAC3C,YAAI,WAAW,MAAM,GAAG;AACtB,qBAAW,QAAQ,UAAU,IAAI;AACjC,iBAAO;AAAA,QACT;AACA,iBAAS,QAAQ,MAAM;AAAA,MACzB;AACA,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,aAA4B;AAAA,EAGlC;AACF;;;ADxEO,IAAM,yBAAN,MAA6B;AAAA,EACjB,WAAsD,oBAAI,IAAI;AAAA,EAC9D;AAAA,EAEjB,YAAY,UAAkB;AAC5B,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA,EAGA,MAAM,qBAAoC;AACxC,UAAM,WAAgD;AAAA,MACpD,MAAMC,MAAK,KAAK,UAAU,IAAI;AAAA,MAC9B,OAAOA,MAAK,KAAK,UAAU,OAAO;AAAA,MAClC,YAAYA,MAAK,KAAK,UAAU,YAAY;AAAA,MAC5C,QAAQA,MAAK,KAAK,UAAU,QAAQ;AAAA,MACpC,OAAO;AAAA,MACP,MAAMA,MAAK,KAAK,UAAU,MAAM;AAAA,IAClC;AAEA,eAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACnD,YAAM,UAAU,IAAI,iBAAiB,IAAI;AACzC,YAAM,QAAQ,WAAW;AACzB,WAAK,SAAS,IAAI,MAA6B,OAAO;AAAA,IACxD;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,gBAAgB,MAA2B,UAAiC;AAChF,UAAM,WAAWC,YAAW,QAAQ,IAAI,WAAWD,MAAK,KAAK,UAAU,QAAQ;AAC/E,UAAM,UAAU,IAAI,iBAAiB,QAAQ;AAC7C,UAAM,QAAQ,WAAW;AACzB,SAAK,SAAS,IAAI,MAAM,OAAO;AAAA,EACjC;AAAA;AAAA,EAGA,WAAW,MAA4C;AACrD,UAAM,UAAU,KAAK,SAAS,IAAI,IAAI;AACtC,QAAI,CAAC,QAAS,OAAM,IAAI,MAAM,qBAAqB,IAAI,mBAAmB;AAC1E,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,QAAQ,UAA+B,SAAyB;AAC9D,WAAO,KAAK,WAAW,QAAQ,EAAE,QAAQ,OAAO;AAAA,EAClD;AAAA;AAAA,EAGA,YAAoF;AAClF,WAAO,MAAM,KAAK,KAAK,SAAS,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,OAAO,OAAO;AAAA,MACnE;AAAA,MACA,WAAW,QAAQ,YAAY;AAAA,MAC/B,MAAM,QAAQ;AAAA,IAChB,EAAE;AAAA,EACJ;AAAA;AAAA,EAGA,mBAA0C;AACxC,WAAO,MAAM,KAAK,KAAK,SAAS,KAAK,CAAC;AAAA,EACxC;AACF;","names":["join","isAbsolute","join","isAbsolute"]}
|
package/dist/chunk-7FI7SQS7.mjs
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
// src/builtins/local-backup/local-backup.ts
|
|
2
|
-
import { randomUUID } from "crypto";
|
|
3
|
-
import { EventCategory } from "@camstack/types";
|
|
4
|
-
var LocalBackupService = class {
|
|
5
|
-
constructor(config, logger, eventBus) {
|
|
6
|
-
this.config = config;
|
|
7
|
-
this.logger = logger;
|
|
8
|
-
this.eventBus = eventBus;
|
|
9
|
-
}
|
|
10
|
-
config;
|
|
11
|
-
logger;
|
|
12
|
-
eventBus;
|
|
13
|
-
manifests = [];
|
|
14
|
-
/** Create a backup of specified locations */
|
|
15
|
-
async backup(options) {
|
|
16
|
-
const id = randomUUID();
|
|
17
|
-
const timestamp = Date.now();
|
|
18
|
-
const locations = options?.locations ?? ["config", "events", "logs"];
|
|
19
|
-
this.logger.info("Starting backup", { meta: { backupId: id, locations } });
|
|
20
|
-
const manifest = {
|
|
21
|
-
id,
|
|
22
|
-
timestamp,
|
|
23
|
-
label: options?.label,
|
|
24
|
-
locations,
|
|
25
|
-
sizeMB: 0,
|
|
26
|
-
path: `${this.config.backupDir}/${id}`
|
|
27
|
-
};
|
|
28
|
-
const updated = [...this.manifests, manifest];
|
|
29
|
-
this.manifests = updated;
|
|
30
|
-
await this.pruneOldBackups();
|
|
31
|
-
this.eventBus.emit({
|
|
32
|
-
id: randomUUID(),
|
|
33
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
34
|
-
source: { type: "addon", id: "local-backup" },
|
|
35
|
-
category: EventCategory.BackupCompleted,
|
|
36
|
-
data: { backupId: id, locations: [...locations], sizeMB: manifest.sizeMB }
|
|
37
|
-
});
|
|
38
|
-
this.logger.info("Backup completed", { meta: { backupId: id } });
|
|
39
|
-
return manifest;
|
|
40
|
-
}
|
|
41
|
-
/** Restore from a backup */
|
|
42
|
-
async restore(backupId) {
|
|
43
|
-
const manifest = this.manifests.find((m) => m.id === backupId);
|
|
44
|
-
if (!manifest) throw new Error(`Backup ${backupId} not found`);
|
|
45
|
-
this.logger.info("Restoring from backup", { meta: { backupId } });
|
|
46
|
-
this.eventBus.emit({
|
|
47
|
-
id: randomUUID(),
|
|
48
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
49
|
-
source: { type: "addon", id: "local-backup" },
|
|
50
|
-
category: EventCategory.BackupRestored,
|
|
51
|
-
data: { backupId }
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
/** List all backups sorted by timestamp descending */
|
|
55
|
-
list() {
|
|
56
|
-
return [...this.manifests].sort((a, b) => b.timestamp - a.timestamp);
|
|
57
|
-
}
|
|
58
|
-
/** Delete a specific backup */
|
|
59
|
-
async delete(backupId) {
|
|
60
|
-
this.manifests = this.manifests.filter((m) => m.id !== backupId);
|
|
61
|
-
}
|
|
62
|
-
async pruneOldBackups() {
|
|
63
|
-
const sorted = [...this.manifests].sort((a, b) => a.timestamp - b.timestamp);
|
|
64
|
-
while (sorted.length > this.config.retentionCount) {
|
|
65
|
-
const oldest = sorted.shift();
|
|
66
|
-
if (oldest) {
|
|
67
|
-
this.logger.info("Pruning old backup", { meta: { backupId: oldest.id } });
|
|
68
|
-
this.manifests = this.manifests.filter((m) => m.id !== oldest.id);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
// src/builtins/local-backup/local-backup.addon.ts
|
|
75
|
-
import * as path from "path";
|
|
76
|
-
import { BaseAddon, backupCapability } from "@camstack/types";
|
|
77
|
-
var LocalBackupAddon = class extends BaseAddon {
|
|
78
|
-
service = null;
|
|
79
|
-
constructor() {
|
|
80
|
-
super({ retentionCount: 7 });
|
|
81
|
-
}
|
|
82
|
-
async onInitialize() {
|
|
83
|
-
const backupConfig = {
|
|
84
|
-
backupDir: path.join(
|
|
85
|
-
await this.ctx.api.storage.resolve.query({ location: "data", relativePath: "" }).catch(() => "camstack-data"),
|
|
86
|
-
"backups"
|
|
87
|
-
),
|
|
88
|
-
retentionCount: this.config.retentionCount
|
|
89
|
-
};
|
|
90
|
-
this.service = new LocalBackupService(backupConfig, this.ctx.logger, this.ctx.eventBus);
|
|
91
|
-
const backupProvider = {
|
|
92
|
-
trigger: (input) => this.service.backup(input),
|
|
93
|
-
list: () => this.service.list(),
|
|
94
|
-
restore: (input) => this.service.restore(input.backupId),
|
|
95
|
-
delete: (input) => this.service.delete(input.backupId)
|
|
96
|
-
};
|
|
97
|
-
this.ctx.logger.info("Local Backup initialized");
|
|
98
|
-
return [{ capability: backupCapability, provider: backupProvider }];
|
|
99
|
-
}
|
|
100
|
-
async onShutdown() {
|
|
101
|
-
this.service = null;
|
|
102
|
-
}
|
|
103
|
-
getService() {
|
|
104
|
-
if (!this.service) throw new Error("Local Backup not initialized");
|
|
105
|
-
return this.service;
|
|
106
|
-
}
|
|
107
|
-
globalSettingsSchema() {
|
|
108
|
-
return this.schema({
|
|
109
|
-
sections: [{
|
|
110
|
-
id: "backup-retention",
|
|
111
|
-
title: "Backup Retention",
|
|
112
|
-
description: "How many local backup snapshots to keep on disk.",
|
|
113
|
-
columns: 1,
|
|
114
|
-
fields: [
|
|
115
|
-
this.field({
|
|
116
|
-
type: "number",
|
|
117
|
-
key: "retentionCount",
|
|
118
|
-
label: "Retention Count",
|
|
119
|
-
description: "Number of backup snapshots to keep before deleting the oldest",
|
|
120
|
-
min: 1,
|
|
121
|
-
max: 100,
|
|
122
|
-
step: 1,
|
|
123
|
-
default: 7
|
|
124
|
-
})
|
|
125
|
-
]
|
|
126
|
-
}]
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
export {
|
|
132
|
-
LocalBackupService,
|
|
133
|
-
LocalBackupAddon
|
|
134
|
-
};
|
|
135
|
-
//# sourceMappingURL=chunk-7FI7SQS7.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/builtins/local-backup/local-backup.ts","../src/builtins/local-backup/local-backup.addon.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto'\nimport { EventCategory } from '@camstack/types'\nimport type { IScopedLogger, IEventBus, BackupManifest } from '@camstack/types'\n\nexport type { BackupManifest }\n\nexport interface BackupConfig {\n readonly backupDir: string\n readonly retentionCount: number\n}\n\nexport class LocalBackupService {\n private manifests: BackupManifest[] = []\n\n constructor(\n private readonly config: BackupConfig,\n private readonly logger: IScopedLogger,\n private readonly eventBus: IEventBus,\n ) {}\n\n /** Create a backup of specified locations */\n async backup(options?: {\n locations?: string[]\n label?: string\n }): Promise<BackupManifest> {\n const id = randomUUID()\n const timestamp = Date.now()\n const locations = options?.locations ?? ['config', 'events', 'logs']\n\n this.logger.info('Starting backup', { meta: { backupId: id, locations } })\n\n const manifest: BackupManifest = {\n id,\n timestamp,\n label: options?.label,\n locations,\n sizeMB: 0,\n path: `${this.config.backupDir}/${id}`,\n }\n\n const updated = [...this.manifests, manifest]\n this.manifests = updated\n\n await this.pruneOldBackups()\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'local-backup' },\n category: EventCategory.BackupCompleted,\n data: { backupId: id, locations: [...locations], sizeMB: manifest.sizeMB },\n })\n\n this.logger.info('Backup completed', { meta: { backupId: id } })\n return manifest\n }\n\n /** Restore from a backup */\n async restore(backupId: string): Promise<void> {\n const manifest = this.manifests.find((m) => m.id === backupId)\n if (!manifest) throw new Error(`Backup ${backupId} not found`)\n\n this.logger.info('Restoring from backup', { meta: { backupId } })\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: 'local-backup' },\n category: EventCategory.BackupRestored,\n data: { backupId },\n })\n }\n\n /** List all backups sorted by timestamp descending */\n list(): readonly BackupManifest[] {\n return [...this.manifests].sort((a, b) => b.timestamp - a.timestamp)\n }\n\n /** Delete a specific backup */\n async delete(backupId: string): Promise<void> {\n this.manifests = this.manifests.filter((m) => m.id !== backupId)\n }\n\n private async pruneOldBackups(): Promise<void> {\n const sorted = [...this.manifests].sort((a, b) => a.timestamp - b.timestamp)\n\n while (sorted.length > this.config.retentionCount) {\n const oldest = sorted.shift()\n if (oldest) {\n this.logger.info('Pruning old backup', { meta: { backupId: oldest.id } })\n this.manifests = this.manifests.filter((m) => m.id !== oldest.id)\n }\n }\n }\n}\n","import * as path from 'node:path'\nimport type { ProviderRegistration } from '@camstack/types'\nimport { BaseAddon, backupCapability } from '@camstack/types'\nimport { LocalBackupService } from './local-backup.js'\nimport type { BackupConfig } from './local-backup.js'\n\ninterface LocalBackupAddonConfig {\n readonly retentionCount: number\n}\n\n/**\n * Local backup addon — snapshot-based backup/restore of camstack data.\n * Settings appear under Cluster → NodeDetail → Settings.\n */\nexport class LocalBackupAddon extends BaseAddon<LocalBackupAddonConfig> {\n private service: LocalBackupService | null = null\n\n constructor() {\n super({ retentionCount: 7 })\n }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n const backupConfig: BackupConfig = {\n backupDir: path.join(\n await this.ctx.api.storage.resolve.query({ location: 'data', relativePath: '' }).catch(() => 'camstack-data'),\n 'backups',\n ),\n retentionCount: this.config.retentionCount,\n }\n this.service = new LocalBackupService(backupConfig, this.ctx.logger, this.ctx.eventBus)\n const backupProvider = {\n trigger: (input?: { locations?: string[]; label?: string }) => this.service!.backup(input),\n list: () => this.service!.list(),\n restore: (input: { backupId: string }) => this.service!.restore(input.backupId),\n delete: (input: { backupId: string }) => this.service!.delete(input.backupId),\n }\n this.ctx.logger.info('Local Backup initialized')\n return [{ capability: backupCapability, provider: backupProvider }]\n }\n\n protected async onShutdown(): Promise<void> {\n this.service = null\n }\n\n getService(): LocalBackupService {\n if (!this.service) throw new Error('Local Backup not initialized')\n return this.service\n }\n\n protected globalSettingsSchema() {\n return this.schema({\n sections: [{\n id: 'backup-retention',\n title: 'Backup Retention',\n description: 'How many local backup snapshots to keep on disk.',\n columns: 1,\n fields: [\n this.field({\n type: 'number',\n key: 'retentionCount',\n label: 'Retention Count',\n description: 'Number of backup snapshots to keep before deleting the oldest',\n min: 1, max: 100, step: 1, default: 7,\n }),\n ],\n }],\n })\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/chunk-ED57RCQE.mjs
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
// src/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.ts
|
|
2
|
-
import * as path from "path";
|
|
3
|
-
import * as fs from "fs";
|
|
4
|
-
import { randomUUID } from "crypto";
|
|
5
|
-
import {
|
|
6
|
-
BaseAddon,
|
|
7
|
-
EventCategory,
|
|
8
|
-
addonWidgetsCapability,
|
|
9
|
-
errMsg
|
|
10
|
-
} from "@camstack/types";
|
|
11
|
-
var RETRY_BACKOFF_MS = [500, 1500, 4e3];
|
|
12
|
-
var AddonWidgetsAggregatorAddon = class extends BaseAddon {
|
|
13
|
-
id = "addon-widgets-aggregator";
|
|
14
|
-
resolvedPaths = null;
|
|
15
|
-
/**
|
|
16
|
-
* Last successful `listWidgets()` snapshot per source. Used as the
|
|
17
|
-
* "stale-but-valid" fallback when a source transiently fails — drops
|
|
18
|
-
* happen often enough during boot (Moleculer service-discovery
|
|
19
|
-
* window) that swallowing the error and returning empty would leave
|
|
20
|
-
* the dashboard with nothing for several seconds. Keeping the
|
|
21
|
-
* previous good entry means a flake is invisible to the operator.
|
|
22
|
-
*/
|
|
23
|
-
lastGood = /* @__PURE__ */ new Map();
|
|
24
|
-
/** In-flight retry guards keyed by sourceAddonId. Avoids double-scheduling. */
|
|
25
|
-
retryTimers = /* @__PURE__ */ new Map();
|
|
26
|
-
constructor() {
|
|
27
|
-
super({});
|
|
28
|
-
}
|
|
29
|
-
async onInitialize() {
|
|
30
|
-
this.resolvedPaths = await this.resolvePaths();
|
|
31
|
-
const provider = {
|
|
32
|
-
listWidgets: async () => this.aggregate()
|
|
33
|
-
};
|
|
34
|
-
this.ctx.logger.info("Initialized \u2014 aggregating addon-widgets-source providers");
|
|
35
|
-
return [{ capability: addonWidgetsCapability, provider }];
|
|
36
|
-
}
|
|
37
|
-
async onShutdown() {
|
|
38
|
-
for (const t of this.retryTimers.values()) clearTimeout(t);
|
|
39
|
-
this.retryTimers.clear();
|
|
40
|
-
this.lastGood.clear();
|
|
41
|
-
}
|
|
42
|
-
// ── Aggregation ───────────────────────────────────────────────────
|
|
43
|
-
async aggregate() {
|
|
44
|
-
const entries = this.capabilities?.getCollectionEntries("addon-widgets-source") ?? [];
|
|
45
|
-
const out = [];
|
|
46
|
-
const seenIds = /* @__PURE__ */ new Set();
|
|
47
|
-
for (const [addonId, source] of entries) {
|
|
48
|
-
seenIds.add(addonId);
|
|
49
|
-
try {
|
|
50
|
-
const widgets = await Promise.resolve(source.listWidgets());
|
|
51
|
-
const enriched = widgets.map((w) => ({
|
|
52
|
-
...w,
|
|
53
|
-
addonId,
|
|
54
|
-
bundleUrl: this.makeBundleUrl(addonId, w.bundle)
|
|
55
|
-
}));
|
|
56
|
-
for (const item of enriched) out.push(item);
|
|
57
|
-
this.lastGood.set(addonId, enriched);
|
|
58
|
-
} catch (err) {
|
|
59
|
-
const message = errMsg(err);
|
|
60
|
-
this.ctx.logger.warn("addon-widgets-source provider failed", {
|
|
61
|
-
meta: { sourceId: addonId, error: message }
|
|
62
|
-
});
|
|
63
|
-
const cached = this.lastGood.get(addonId);
|
|
64
|
-
if (cached !== void 0) {
|
|
65
|
-
for (const item of cached) out.push(item);
|
|
66
|
-
this.ctx.logger.info("addon-widgets-source falling back to cached snapshot", {
|
|
67
|
-
meta: { sourceId: addonId, cachedWidgets: cached.length }
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
this.scheduleRetry(addonId);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
for (const cachedId of this.lastGood.keys()) {
|
|
74
|
-
if (!seenIds.has(cachedId)) this.lastGood.delete(cachedId);
|
|
75
|
-
}
|
|
76
|
-
return out;
|
|
77
|
-
}
|
|
78
|
-
// ── Retry on transient Moleculer race ─────────────────────────────
|
|
79
|
-
scheduleRetry(sourceId, attempt = 0) {
|
|
80
|
-
if (attempt >= RETRY_BACKOFF_MS.length) return;
|
|
81
|
-
if (this.retryTimers.has(sourceId)) return;
|
|
82
|
-
const delayMs = RETRY_BACKOFF_MS[attempt] ?? RETRY_BACKOFF_MS[RETRY_BACKOFF_MS.length - 1];
|
|
83
|
-
const timer = setTimeout(() => {
|
|
84
|
-
this.retryTimers.delete(sourceId);
|
|
85
|
-
void this.retrySource(sourceId, attempt);
|
|
86
|
-
}, delayMs);
|
|
87
|
-
this.retryTimers.set(sourceId, timer);
|
|
88
|
-
}
|
|
89
|
-
async retrySource(sourceId, attempt) {
|
|
90
|
-
const entries = this.capabilities?.getCollectionEntries("addon-widgets-source") ?? [];
|
|
91
|
-
const found = entries.find(([id]) => id === sourceId);
|
|
92
|
-
if (!found) return;
|
|
93
|
-
const [addonId, source] = found;
|
|
94
|
-
try {
|
|
95
|
-
const widgets = await Promise.resolve(source.listWidgets());
|
|
96
|
-
const enriched = widgets.map((w) => ({
|
|
97
|
-
...w,
|
|
98
|
-
addonId,
|
|
99
|
-
bundleUrl: this.makeBundleUrl(addonId, w.bundle)
|
|
100
|
-
}));
|
|
101
|
-
this.lastGood.set(addonId, enriched);
|
|
102
|
-
this.ctx.logger.info("addon-widgets-source recovered after retry", {
|
|
103
|
-
meta: { sourceId: addonId, attempt: attempt + 1, widgets: enriched.length }
|
|
104
|
-
});
|
|
105
|
-
this.ctx.eventBus.emit({
|
|
106
|
-
id: randomUUID(),
|
|
107
|
-
timestamp: /* @__PURE__ */ new Date(),
|
|
108
|
-
source: { type: "addon", id: this.id },
|
|
109
|
-
category: EventCategory.AddonWidgetReady,
|
|
110
|
-
data: { addonId, recovered: true }
|
|
111
|
-
});
|
|
112
|
-
} catch (err) {
|
|
113
|
-
this.ctx.logger.debug("addon-widgets-source retry failed", {
|
|
114
|
-
meta: { sourceId, attempt: attempt + 1, error: errMsg(err) }
|
|
115
|
-
});
|
|
116
|
-
this.scheduleRetry(sourceId, attempt + 1);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
// ── Bundle URL stamping ──────────────────────────────────────────
|
|
120
|
-
/**
|
|
121
|
-
* Build `/api/addon-widgets/<addonId>/<bundle>?v=<mtime>`. Falls back
|
|
122
|
-
* to `Date.now()` when the bundle path can't be stat'd (remote addon
|
|
123
|
-
* with no local file, addon not yet on disk, etc.) — the browser
|
|
124
|
-
* just gets a fresh URL on each call instead of cache-friendly mtime.
|
|
125
|
-
*/
|
|
126
|
-
makeBundleUrl(addonId, bundle) {
|
|
127
|
-
const bundlePath = this.resolveBundlePath(addonId, bundle);
|
|
128
|
-
let mtime = Date.now();
|
|
129
|
-
if (bundlePath !== null) {
|
|
130
|
-
try {
|
|
131
|
-
mtime = fs.statSync(bundlePath).mtimeMs;
|
|
132
|
-
} catch {
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
const v = Math.floor(mtime);
|
|
136
|
-
return `/api/addon-widgets/${addonId}/${bundle}?v=${v}`;
|
|
137
|
-
}
|
|
138
|
-
resolveBundlePath(addonId, bundle) {
|
|
139
|
-
const paths = this.resolvedPaths;
|
|
140
|
-
if (!paths) return null;
|
|
141
|
-
const addonDistPath = path.join(paths.addonsDir, "@camstack", `addon-${addonId}`, "dist");
|
|
142
|
-
const resolvedBase = path.resolve(addonDistPath);
|
|
143
|
-
const resolvedFile = path.resolve(addonDistPath, bundle);
|
|
144
|
-
if (!resolvedFile.startsWith(resolvedBase + path.sep) && resolvedFile !== resolvedBase) {
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
return resolvedFile;
|
|
148
|
-
}
|
|
149
|
-
// ── Path resolution ──────────────────────────────────────────────
|
|
150
|
-
async resolvePaths() {
|
|
151
|
-
const fallback = { addonsDir: path.resolve("camstack-data", "addons") };
|
|
152
|
-
if (!this.ctx.settings) return fallback;
|
|
153
|
-
try {
|
|
154
|
-
const server = await this.ctx.settings.getSection("server");
|
|
155
|
-
const dataPath = typeof server["dataPath"] === "string" && server["dataPath"] ? server["dataPath"] : "camstack-data";
|
|
156
|
-
return { addonsDir: path.resolve(dataPath, "addons") };
|
|
157
|
-
} catch (err) {
|
|
158
|
-
this.ctx.logger.debug("Failed to read server.dataPath \u2014 falling back", {
|
|
159
|
-
meta: { error: errMsg(err) }
|
|
160
|
-
});
|
|
161
|
-
return fallback;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
var addon_widgets_aggregator_addon_default = AddonWidgetsAggregatorAddon;
|
|
166
|
-
|
|
167
|
-
export {
|
|
168
|
-
AddonWidgetsAggregatorAddon,
|
|
169
|
-
addon_widgets_aggregator_addon_default
|
|
170
|
-
};
|
|
171
|
-
//# sourceMappingURL=chunk-ED57RCQE.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.ts"],"sourcesContent":["/**\n * Addon Widgets Aggregator — hub-local builtin that owns the singleton\n * `addon-widgets` cap.\n *\n * Mirrors `addon-pages-aggregator` exactly: walks every registered\n * `addon-widgets-source` (collection) provider and emits an enriched\n * widget metadata list with versioned `bundleUrl`s pointing at\n * `/api/addon-widgets/<addonId>/<bundle>?v=<mtime>`. The filesystem\n * `mtime` cache-buster lets the browser pick up addon rebuilds without\n * manual reload.\n *\n * The static file endpoint (`/api/addon-widgets/:addonId/*`) is served\n * by `AddonWidgetsService.resolveBundle()` on the server side; this\n * addon only owns the listing surface.\n *\n * Why a builtin: same reasoning as `addon-pages-aggregator`. The\n * aggregator is the de-facto \"addon-widgets provider\" — addons own caps,\n * not the server. Living in `@camstack/core/builtins` keeps the surface\n * symmetrical with `system-config`, `local-auth`, etc.\n */\nimport * as path from 'node:path'\nimport * as fs from 'node:fs'\nimport { randomUUID } from 'node:crypto'\nimport {\n BaseAddon,\n EventCategory,\n addonWidgetsCapability,\n errMsg,\n type IAddonWidgetsAggregatorProvider,\n type IAddonWidgetsSourceProvider,\n type ProviderRegistration,\n} from '@camstack/types'\n\ninterface ResolvedPaths {\n readonly addonsDir: string\n}\n\n/**\n * Inferred from the cap definition — equivalent to:\n * `z.infer<typeof EnrichedWidgetMetadataSchema>` but reuses the\n * provider's return type so the aggregator stays in lockstep with the\n * cap if its shape evolves.\n */\ntype EnrichedWidget = Awaited<ReturnType<IAddonWidgetsAggregatorProvider['listWidgets']>>[number]\ntype RawWidget = Awaited<ReturnType<IAddonWidgetsSourceProvider['listWidgets']>>[number]\n\n/**\n * Backoff schedule (ms) used to retry sources that failed during a\n * `listWidgets()` round-trip — typically because the cap was just\n * registered (provider connected via Moleculer) but the worker-side\n * action registration hadn't propagated yet, so `Service '...listWidgets'\n * is not found on '<node>'` raced ahead of the call.\n *\n * On success we re-emit `AddonWidgetReady` so admin-ui invalidates its\n * `addonWidgets.listWidgets` query and the registry populates without a\n * page reload.\n */\nconst RETRY_BACKOFF_MS: readonly number[] = [500, 1500, 4000]\n\nexport class AddonWidgetsAggregatorAddon extends BaseAddon {\n readonly id = 'addon-widgets-aggregator'\n\n private resolvedPaths: ResolvedPaths | null = null\n\n /**\n * Last successful `listWidgets()` snapshot per source. Used as the\n * \"stale-but-valid\" fallback when a source transiently fails — drops\n * happen often enough during boot (Moleculer service-discovery\n * window) that swallowing the error and returning empty would leave\n * the dashboard with nothing for several seconds. Keeping the\n * previous good entry means a flake is invisible to the operator.\n */\n private readonly lastGood = new Map<string, readonly EnrichedWidget[]>()\n\n /** In-flight retry guards keyed by sourceAddonId. Avoids double-scheduling. */\n private readonly retryTimers = new Map<string, NodeJS.Timeout>()\n\n constructor() { super({}) }\n\n protected async onInitialize(): Promise<ProviderRegistration[]> {\n this.resolvedPaths = await this.resolvePaths()\n\n const provider: IAddonWidgetsAggregatorProvider = {\n listWidgets: async (): Promise<readonly EnrichedWidget[]> => this.aggregate(),\n }\n\n this.ctx.logger.info('Initialized — aggregating addon-widgets-source providers')\n return [{ capability: addonWidgetsCapability, provider }]\n }\n\n protected async onShutdown(): Promise<void> {\n for (const t of this.retryTimers.values()) clearTimeout(t)\n this.retryTimers.clear()\n this.lastGood.clear()\n }\n\n // ── Aggregation ───────────────────────────────────────────────────\n\n private async aggregate(): Promise<readonly EnrichedWidget[]> {\n // `getCollectionEntries` returns `[addonId, provider]` tuples — the\n // raw `addon-widgets-source` cap doesn't carry an `id` on the\n // provider (unlike the legacy `IAddonPageProvider`), so we lean on\n // the registry to attribute each contribution back to its addon.\n const entries = this.capabilities?.getCollectionEntries<IAddonWidgetsSourceProvider>('addon-widgets-source') ?? []\n const out: EnrichedWidget[] = []\n const seenIds = new Set<string>()\n\n for (const [addonId, source] of entries) {\n seenIds.add(addonId)\n try {\n const widgets = await Promise.resolve(source.listWidgets())\n const enriched: EnrichedWidget[] = widgets.map((w: RawWidget) => ({\n ...w,\n addonId,\n bundleUrl: this.makeBundleUrl(addonId, w.bundle),\n }))\n for (const item of enriched) out.push(item)\n // Cache successful snapshot — used as fallback on next failure.\n this.lastGood.set(addonId, enriched)\n } catch (err: unknown) {\n const message = errMsg(err)\n this.ctx.logger.warn('addon-widgets-source provider failed', {\n meta: { sourceId: addonId, error: message },\n })\n // Fall back to the last-good snapshot for this source so a\n // transient Moleculer service-discovery race doesn't blank\n // the dashboard.\n const cached = this.lastGood.get(addonId)\n if (cached !== undefined) {\n for (const item of cached) out.push(item)\n this.ctx.logger.info('addon-widgets-source falling back to cached snapshot', {\n meta: { sourceId: addonId, cachedWidgets: cached.length },\n })\n }\n // Schedule a background retry. On success we re-emit\n // `AddonWidgetReady` so admin-ui's queryClient invalidates and\n // any newly-loaded widgets show up without a manual reload.\n this.scheduleRetry(addonId)\n }\n }\n\n // Drop cache entries for sources that have disappeared from the\n // registry — keeps the fallback aligned with the live collection.\n for (const cachedId of this.lastGood.keys()) {\n if (!seenIds.has(cachedId)) this.lastGood.delete(cachedId)\n }\n\n return out\n }\n\n // ── Retry on transient Moleculer race ─────────────────────────────\n\n private scheduleRetry(sourceId: string, attempt = 0): void {\n if (attempt >= RETRY_BACKOFF_MS.length) return\n if (this.retryTimers.has(sourceId)) return // already pending\n\n const delayMs = RETRY_BACKOFF_MS[attempt] ?? RETRY_BACKOFF_MS[RETRY_BACKOFF_MS.length - 1]!\n const timer = setTimeout(() => {\n this.retryTimers.delete(sourceId)\n void this.retrySource(sourceId, attempt)\n }, delayMs)\n this.retryTimers.set(sourceId, timer)\n }\n\n private async retrySource(sourceId: string, attempt: number): Promise<void> {\n const entries = this.capabilities?.getCollectionEntries<IAddonWidgetsSourceProvider>('addon-widgets-source') ?? []\n const found = entries.find(([id]) => id === sourceId)\n if (!found) return // provider went away; nothing to retry\n const [addonId, source] = found\n\n try {\n const widgets = await Promise.resolve(source.listWidgets())\n const enriched: EnrichedWidget[] = widgets.map((w: RawWidget) => ({\n ...w,\n addonId,\n bundleUrl: this.makeBundleUrl(addonId, w.bundle),\n }))\n this.lastGood.set(addonId, enriched)\n this.ctx.logger.info('addon-widgets-source recovered after retry', {\n meta: { sourceId: addonId, attempt: attempt + 1, widgets: enriched.length },\n })\n // Re-emit AddonWidgetReady so admin-ui invalidates and refetches.\n this.ctx.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'addon', id: this.id },\n category: EventCategory.AddonWidgetReady,\n data: { addonId, recovered: true },\n })\n } catch (err: unknown) {\n this.ctx.logger.debug('addon-widgets-source retry failed', {\n meta: { sourceId, attempt: attempt + 1, error: errMsg(err) },\n })\n this.scheduleRetry(sourceId, attempt + 1)\n }\n }\n\n // ── Bundle URL stamping ──────────────────────────────────────────\n\n /**\n * Build `/api/addon-widgets/<addonId>/<bundle>?v=<mtime>`. Falls back\n * to `Date.now()` when the bundle path can't be stat'd (remote addon\n * with no local file, addon not yet on disk, etc.) — the browser\n * just gets a fresh URL on each call instead of cache-friendly mtime.\n */\n private makeBundleUrl(addonId: string, bundle: string): string {\n const bundlePath = this.resolveBundlePath(addonId, bundle)\n let mtime = Date.now()\n if (bundlePath !== null) {\n try { mtime = fs.statSync(bundlePath).mtimeMs }\n catch { /* remote addon — no local file */ }\n }\n const v = Math.floor(mtime)\n return `/api/addon-widgets/${addonId}/${bundle}?v=${v}`\n }\n\n private resolveBundlePath(addonId: string, bundle: string): string | null {\n const paths = this.resolvedPaths\n if (!paths) return null\n const addonDistPath = path.join(paths.addonsDir, '@camstack', `addon-${addonId}`, 'dist')\n const resolvedBase = path.resolve(addonDistPath)\n const resolvedFile = path.resolve(addonDistPath, bundle)\n if (!resolvedFile.startsWith(resolvedBase + path.sep) && resolvedFile !== resolvedBase) {\n return null\n }\n return resolvedFile\n }\n\n // ── Path resolution ──────────────────────────────────────────────\n\n private async resolvePaths(): Promise<ResolvedPaths> {\n const fallback: ResolvedPaths = { addonsDir: path.resolve('camstack-data', 'addons') }\n if (!this.ctx.settings) return fallback\n try {\n const server = await this.ctx.settings.getSection('server')\n const dataPath = typeof server['dataPath'] === 'string' && server['dataPath']\n ? server['dataPath']\n : 'camstack-data'\n return { addonsDir: path.resolve(dataPath, 'addons') }\n } catch (err: unknown) {\n this.ctx.logger.debug('Failed to read server.dataPath — falling back', {\n meta: { error: errMsg(err) },\n })\n return fallback\n }\n }\n}\n\nexport default AddonWidgetsAggregatorAddon\n"],"mappings":"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","names":[]}
|