@camstack/system 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon/addon-api-factory.d.ts +35 -0
- package/dist/addon-routes/addon-route-registry.d.ts +37 -0
- package/dist/addon-runner.js +599 -0
- package/dist/addon-runner.mjs +597 -0
- package/dist/auth/api-key-manager.d.ts +26 -0
- package/dist/auth/auth-manager.d.ts +109 -0
- package/dist/auth/parse-record.d.ts +18 -0
- package/dist/auth/scope-matcher.d.ts +7 -0
- package/dist/auth/scoped-token-manager.d.ts +40 -0
- package/dist/auth/totp-manager.d.ts +51 -0
- package/dist/auth/user-manager.d.ts +34 -0
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.d.ts +53 -0
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +259 -0
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +251 -0
- package/dist/builtins/addon-pages-aggregator/dedupe-pages.d.ts +6 -0
- package/dist/builtins/addon-pages-aggregator/index.d.ts +1 -0
- package/dist/builtins/addon-pages-aggregator/index.js +8 -0
- package/dist/builtins/addon-pages-aggregator/index.mjs +2 -0
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.d.ts +47 -0
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +228 -0
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +220 -0
- package/dist/builtins/addon-widgets-aggregator/index.d.ts +1 -0
- package/dist/builtins/addon-widgets-aggregator/index.js +8 -0
- package/dist/builtins/addon-widgets-aggregator/index.mjs +2 -0
- package/dist/builtins/alerts/alerts.addon.d.ts +81 -0
- package/dist/builtins/alerts/alerts.addon.js +601 -0
- package/dist/builtins/alerts/alerts.addon.mjs +595 -0
- package/dist/builtins/alerts/index.d.ts +1 -0
- package/dist/builtins/alerts/index.js +4 -0
- package/dist/builtins/alerts/index.mjs +2 -0
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts +147 -0
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2229 -0
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2220 -0
- package/dist/builtins/backup-orchestrator/cron-helpers.d.ts +23 -0
- package/dist/builtins/backup-orchestrator/destination-policy.d.ts +72 -0
- package/dist/builtins/backup-orchestrator/download-helpers.d.ts +12 -0
- package/dist/builtins/backup-orchestrator/index.d.ts +2 -0
- package/dist/builtins/backup-orchestrator/index.js +8 -0
- package/dist/builtins/backup-orchestrator/index.mjs +2 -0
- package/dist/builtins/backup-orchestrator/manifest-store.d.ts +77 -0
- package/dist/builtins/console-logging/console-destination.d.ts +13 -0
- package/dist/builtins/console-logging/console-logging.addon.d.ts +25 -0
- package/dist/builtins/console-logging/index.d.ts +3 -0
- package/dist/builtins/console-logging/index.js +104 -0
- package/dist/builtins/console-logging/index.mjs +95 -0
- package/dist/builtins/device-manager/device-config-contribution.d.ts +32 -0
- package/dist/builtins/device-manager/device-event-propagator.d.ts +26 -0
- package/dist/builtins/device-manager/device-link-overlay.d.ts +23 -0
- package/dist/builtins/device-manager/device-link-resolver.d.ts +15 -0
- package/dist/builtins/device-manager/device-manager.addon.d.ts +452 -0
- package/dist/builtins/device-manager/device-manager.addon.js +3299 -0
- package/dist/builtins/device-manager/device-manager.addon.mjs +3292 -0
- package/dist/builtins/device-manager/index.d.ts +2 -0
- package/dist/builtins/device-manager/index.js +8 -0
- package/dist/builtins/device-manager/index.mjs +2 -0
- package/dist/builtins/hub-forwarder/hub-forwarder-destination.d.ts +44 -0
- package/dist/builtins/hub-forwarder/hub-forwarder.addon.d.ts +15 -0
- package/dist/builtins/hub-forwarder/index.d.ts +3 -0
- package/dist/builtins/hub-forwarder/index.js +154 -0
- package/dist/builtins/hub-forwarder/index.mjs +145 -0
- package/dist/builtins/local-auth/auth-schema.d.ts +26 -0
- package/dist/builtins/local-auth/index.d.ts +1 -0
- package/dist/builtins/local-auth/index.js +4 -0
- package/dist/builtins/local-auth/index.mjs +2 -0
- package/dist/builtins/local-auth/local-auth.addon.d.ts +18 -0
- package/dist/builtins/local-auth/local-auth.addon.js +8094 -0
- package/dist/builtins/local-auth/local-auth.addon.mjs +8063 -0
- package/dist/builtins/local-auth/oauth-grants.d.ts +45 -0
- package/dist/builtins/local-auth/oauth-session-manager.d.ts +50 -0
- package/dist/builtins/local-network/index.d.ts +2 -0
- package/dist/builtins/local-network/index.js +10 -0
- package/dist/builtins/local-network/index.mjs +2 -0
- package/dist/builtins/local-network/local-network.addon.d.ts +150 -0
- package/dist/builtins/local-network/local-network.addon.js +489 -0
- package/dist/builtins/local-network/local-network.addon.mjs +477 -0
- package/dist/builtins/native-metrics/index.d.ts +2 -0
- package/dist/builtins/native-metrics/native-metrics-provider.d.ts +48 -0
- package/dist/builtins/native-metrics/native-metrics.addon.d.ts +73 -0
- package/dist/builtins/native-metrics/native-metrics.addon.js +922 -0
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +914 -0
- package/dist/builtins/platform-probe/hardware-decode-accel-probe.d.ts +37 -0
- package/dist/builtins/platform-probe/hardware-encoder-probe.d.ts +13 -0
- package/dist/builtins/platform-probe/index.d.ts +22 -0
- package/dist/builtins/platform-probe/index.js +834 -0
- package/dist/builtins/platform-probe/index.mjs +822 -0
- package/dist/builtins/platform-probe/inference-config-resolver.d.ts +29 -0
- package/dist/builtins/platform-probe/intel-accelerators.d.ts +11 -0
- package/dist/builtins/platform-probe/platform-scorer.d.ts +30 -0
- package/dist/builtins/platform-probe/runtime-packages.d.ts +6 -0
- package/dist/builtins/remote-access-orchestrator/enabled-providers-reconcile.d.ts +96 -0
- package/dist/builtins/remote-access-orchestrator/index.d.ts +1 -0
- package/dist/builtins/remote-access-orchestrator/index.js +8 -0
- package/dist/builtins/remote-access-orchestrator/index.mjs +2 -0
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.d.ts +40 -0
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +214 -0
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +208 -0
- package/dist/builtins/shared/settle-sources.d.ts +22 -0
- package/dist/builtins/snapshot/index.d.ts +2 -0
- package/dist/builtins/snapshot/index.js +494 -0
- package/dist/builtins/snapshot/index.mjs +488 -0
- package/dist/builtins/snapshot/snapshot.addon.d.ts +120 -0
- package/dist/builtins/sqlite-storage/config-store.d.ts +8 -0
- package/dist/builtins/sqlite-storage/device-store.d.ts +23 -0
- package/dist/builtins/sqlite-storage/filesystem-browse-provider.d.ts +25 -0
- package/dist/builtins/sqlite-storage/filesystem-storage-provider.d.ts +83 -0
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.d.ts +32 -0
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +396 -0
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +388 -0
- package/dist/builtins/sqlite-storage/index.d.ts +8 -0
- package/dist/builtins/sqlite-storage/index.js +62 -0
- package/dist/builtins/sqlite-storage/index.mjs +49 -0
- package/dist/builtins/sqlite-storage/integration-registry.d.ts +27 -0
- package/dist/builtins/sqlite-storage/path-guard.d.ts +4 -0
- package/dist/builtins/sqlite-storage/sqlite-settings-backend.d.ts +102 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.d.ts +14 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +644 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +636 -0
- package/dist/builtins/storage-orchestrator/index.d.ts +6 -0
- package/dist/builtins/storage-orchestrator/index.js +10 -0
- package/dist/builtins/storage-orchestrator/index.mjs +2 -0
- package/dist/builtins/storage-orchestrator/location-store.d.ts +49 -0
- package/dist/builtins/storage-orchestrator/provider-discovery.d.ts +10 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.d.ts +103 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1138 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1128 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.service.d.ts +236 -0
- package/dist/builtins/storage-orchestrator/storage-pressure-manager.d.ts +38 -0
- package/dist/builtins/system-backup/system-backup.service.d.ts +137 -0
- package/dist/builtins/system-config/index.d.ts +1 -0
- package/dist/builtins/system-config/index.js +8 -0
- package/dist/builtins/system-config/index.mjs +2 -0
- package/dist/builtins/system-config/system-config.addon.d.ts +10 -0
- package/dist/builtins/system-config/system-config.addon.js +232 -0
- package/dist/builtins/system-config/system-config.addon.mjs +226 -0
- package/dist/builtins/winston-logging/index.d.ts +3 -0
- package/dist/builtins/winston-logging/index.js +156 -0
- package/dist/builtins/winston-logging/index.mjs +144 -0
- package/dist/builtins/winston-logging/winston-destination.d.ts +21 -0
- package/dist/builtins/winston-logging/winston-logging.addon.d.ts +19 -0
- package/dist/chunk-CNf5ZN-e.mjs +37 -0
- package/dist/chunk-Cek0wNdY.js +64 -0
- package/dist/download/model-download-service.d.ts +41 -0
- package/dist/download/model-downloader.d.ts +31 -0
- package/dist/events/event-bus.d.ts +10 -0
- package/dist/events/system-event-bus.d.ts +14 -0
- package/dist/feature/feature-manager.d.ts +11 -0
- package/dist/formatter-B7qW8bPJ.mjs +162 -0
- package/dist/formatter-DqAKDlvN.js +167 -0
- package/dist/http/authenticated-file-server.d.ts +53 -0
- package/dist/http/data-plane-registry.d.ts +23 -0
- package/dist/http/file-data-plane.d.ts +10 -0
- package/dist/http/reverse-proxy.d.ts +15 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.js +93485 -0
- package/dist/index.mjs +93179 -0
- package/dist/intel-accelerators-Gg0P5mnl.js +20 -0
- package/dist/intel-accelerators-hGgpZ0pX.mjs +19 -0
- package/dist/kernel/addon-class-resolver.d.ts +4 -0
- package/dist/kernel/addon-engine-manager.d.ts +22 -0
- package/dist/kernel/addon-health-monitor.d.ts +154 -0
- package/dist/kernel/addon-installer.d.ts +208 -0
- package/dist/kernel/addon-loader.d.ts +106 -0
- package/dist/kernel/addon-manifest.d.ts +77 -0
- package/dist/kernel/capability-handle.d.ts +46 -0
- package/dist/kernel/capability-registry.d.ts +412 -0
- package/dist/kernel/config-manager.d.ts +212 -0
- package/dist/kernel/config-schema.d.ts +93 -0
- package/dist/kernel/custom-action-registry.d.ts +23 -0
- package/dist/kernel/deps/addon-deps-manager.d.ts +19 -0
- package/dist/kernel/deps/manifest-native-deps.d.ts +25 -0
- package/dist/kernel/deps/manifest-python-deps.d.ts +20 -0
- package/dist/kernel/device-registry.d.ts +29 -0
- package/dist/kernel/fs-utils.d.ts +41 -0
- package/dist/kernel/hwaccel/hwaccel-resolver.d.ts +19 -0
- package/dist/kernel/hwaccel/hwaccel-service.d.ts +4 -0
- package/dist/kernel/index.d.ts +74 -0
- package/dist/kernel/infra-capabilities.d.ts +13 -0
- package/dist/kernel/moleculer/addon-context-factory.d.ts +91 -0
- package/dist/kernel/moleculer/addon-data-plane-facility.d.ts +19 -0
- package/dist/kernel/moleculer/addon-runner.d.ts +1 -0
- package/dist/kernel/moleculer/addon-service-factory.d.ts +50 -0
- package/dist/kernel/moleculer/broker-factory.d.ts +50 -0
- package/dist/kernel/moleculer/cap-usage-registry.d.ts +46 -0
- package/dist/kernel/moleculer/capabilities-access.d.ts +21 -0
- package/dist/kernel/moleculer/child-addon-call-dispatch.d.ts +46 -0
- package/dist/kernel/moleculer/child-cap-dispatch.d.ts +20 -0
- package/dist/kernel/moleculer/cluster-secret.d.ts +15 -0
- package/dist/kernel/moleculer/core-cap-service.d.ts +50 -0
- package/dist/kernel/moleculer/crash-supervisor.d.ts +50 -0
- package/dist/kernel/moleculer/device-cap-proxy.d.ts +79 -0
- package/dist/kernel/moleculer/event-bus-core.d.ts +53 -0
- package/dist/kernel/moleculer/event-bus.d.ts +53 -0
- package/dist/kernel/moleculer/hub-log-forwarder.d.ts +36 -0
- package/dist/kernel/moleculer/hub-service.d.ts +35 -0
- package/dist/kernel/moleculer/node-registry.d.ts +126 -0
- package/dist/kernel/moleculer/process-context.d.ts +4 -0
- package/dist/kernel/moleculer/process-service.d.ts +72 -0
- package/dist/kernel/moleculer/provider-registry.d.ts +28 -0
- package/dist/kernel/moleculer/readiness-context.d.ts +62 -0
- package/dist/kernel/moleculer/readiness-service.d.ts +7 -0
- package/dist/kernel/moleculer/register-node-client.d.ts +35 -0
- package/dist/kernel/moleculer/remote-logger.d.ts +43 -0
- package/dist/kernel/moleculer/resilient-cap-call.d.ts +28 -0
- package/dist/kernel/moleculer/stream-probe-service.d.ts +9 -0
- package/dist/kernel/moleculer/trpc-links.d.ts +189 -0
- package/dist/kernel/moleculer/typed-array-serde.d.ts +25 -0
- package/dist/kernel/moleculer/worker-device-restore.d.ts +10 -0
- package/dist/kernel/provider-kind-drift.d.ts +12 -0
- package/dist/kernel/restart-coordinator.d.ts +90 -0
- package/dist/kernel/storage-location-registry.d.ts +40 -0
- package/dist/kernel/transport/cap-action-name.d.ts +100 -0
- package/dist/kernel/transport/cap-route-resolver.d.ts +148 -0
- package/dist/kernel/transport/cap-route.d.ts +148 -0
- package/dist/kernel/transport/child-cap-protocol.d.ts +136 -0
- package/dist/kernel/transport/create-local-transport.d.ts +7 -0
- package/dist/kernel/transport/frame-codec.d.ts +7 -0
- package/dist/kernel/transport/index.d.ts +27 -0
- package/dist/kernel/transport/local-child-client.d.ts +136 -0
- package/dist/kernel/transport/local-child-registry.d.ts +179 -0
- package/dist/kernel/transport/local-endpoint-path.d.ts +6 -0
- package/dist/kernel/transport/local-transport.d.ts +46 -0
- package/dist/kernel/transport/parent-unowned-call.d.ts +75 -0
- package/dist/kernel/transport/socket-channel.d.ts +27 -0
- package/dist/kernel/transport/uds-event-bridge.d.ts +36 -0
- package/dist/kernel/transport/uds-event-bus.d.ts +22 -0
- package/dist/kernel/transport/uds-local-transport.d.ts +18 -0
- package/dist/kernel/transport/uds-log-ingest.d.ts +28 -0
- package/dist/kernel/transport/uds-logger.d.ts +44 -0
- package/dist/kernel/utils/ring-buffer.d.ts +15 -0
- package/dist/kernel/workspace-detect.d.ts +9 -0
- package/dist/lifecycle/lifecycle-state-machine.d.ts +28 -0
- package/dist/logging/formatter.d.ts +30 -0
- package/dist/logging/log-manager.d.ts +54 -0
- package/dist/logging/log-ring-buffer.d.ts +47 -0
- package/dist/logging/partitioned-log-buffer.d.ts +35 -0
- package/dist/logging/scoped-logger.d.ts +17 -0
- package/dist/main-DNnMW7Z2.js +9983 -0
- package/dist/main-rtjOwPBR.mjs +9976 -0
- package/dist/manifest-python-deps-D1DbAQEv.js +6724 -0
- package/dist/manifest-python-deps-DZsKTbs1.mjs +6315 -0
- package/dist/network/network-quality.d.ts +11 -0
- package/dist/notification/notification-service.d.ts +37 -0
- package/dist/notification/toast-service.d.ts +22 -0
- package/dist/pipeline/engine-manager-resolver.d.ts +15 -0
- package/dist/pipeline/pipeline-runner.d.ts +8 -0
- package/dist/pipeline/pipeline-validator.d.ts +13 -0
- package/dist/process/resource-monitor.d.ts +11 -0
- package/dist/python/python-env-manager.d.ts +12 -0
- package/dist/repl/interfaces.d.ts +31 -0
- package/dist/repl/repl-engine.d.ts +8 -0
- package/dist/resource-monitor-ClDGFyf6.mjs +57 -0
- package/dist/resource-monitor-IIEanuJt.js +74 -0
- package/dist/settle-sources-Bhsy57y-.js +38 -0
- package/dist/settle-sources-CDtNC8ub.mjs +33 -0
- package/dist/storage/fs-storage-backend.d.ts +40 -0
- package/dist/storage/storage-location-manager.d.ts +23 -0
- package/dist/storage/storage-manager.d.ts +83 -0
- package/dist/tar-BgAEMRBR.js +5434 -0
- package/dist/tar-ByMOPNM0.mjs +5429 -0
- package/dist/tls/cert-manager.d.ts +26 -0
- package/dist/tls/index.d.ts +1 -0
- package/package.json +343 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require("./chunk-Cek0wNdY.js");
|
|
2
|
+
//#region src/builtins/platform-probe/intel-accelerators.ts
|
|
3
|
+
var INTEL_VENDOR = "0x8086";
|
|
4
|
+
function classifyIntelAccelerators(fsx) {
|
|
5
|
+
let gpu = null;
|
|
6
|
+
for (const node of fsx.listRenderNodes()) if (fsx.readVendor(node).trim() === INTEL_VENDOR) {
|
|
7
|
+
gpu = {
|
|
8
|
+
type: "intel",
|
|
9
|
+
name: `Intel iGPU (${node.split("/").pop()})`
|
|
10
|
+
};
|
|
11
|
+
break;
|
|
12
|
+
}
|
|
13
|
+
const npu = fsx.exists("/dev/accel/accel0") ? { type: "intel-npu" } : null;
|
|
14
|
+
return {
|
|
15
|
+
gpu,
|
|
16
|
+
npu
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
exports.classifyIntelAccelerators = classifyIntelAccelerators;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/builtins/platform-probe/intel-accelerators.ts
|
|
2
|
+
var INTEL_VENDOR = "0x8086";
|
|
3
|
+
function classifyIntelAccelerators(fsx) {
|
|
4
|
+
let gpu = null;
|
|
5
|
+
for (const node of fsx.listRenderNodes()) if (fsx.readVendor(node).trim() === INTEL_VENDOR) {
|
|
6
|
+
gpu = {
|
|
7
|
+
type: "intel",
|
|
8
|
+
name: `Intel iGPU (${node.split("/").pop()})`
|
|
9
|
+
};
|
|
10
|
+
break;
|
|
11
|
+
}
|
|
12
|
+
const npu = fsx.exists("/dev/accel/accel0") ? { type: "intel-npu" } : null;
|
|
13
|
+
return {
|
|
14
|
+
gpu,
|
|
15
|
+
npu
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { classifyIntelAccelerators };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ICamstackAddon, AddonContext, IEngineManager, IEngineInstance } from '@camstack/types';
|
|
2
|
+
import { AddonLoader } from './addon-loader.js';
|
|
3
|
+
export declare class AddonEngineManager implements IEngineManager {
|
|
4
|
+
private readonly loader;
|
|
5
|
+
private readonly baseContext;
|
|
6
|
+
private engines;
|
|
7
|
+
constructor(loader: AddonLoader, baseContext: Partial<Omit<AddonContext, 'addonConfig'>>);
|
|
8
|
+
/**
|
|
9
|
+
* Get or create an addon engine for the given effective config.
|
|
10
|
+
* Cameras with the same addonId + effective config share the same engine.
|
|
11
|
+
*/
|
|
12
|
+
getOrCreateEngine(addonId: string, globalConfig: Record<string, unknown>, cameraOverride?: Record<string, unknown>): Promise<IEngineInstance>;
|
|
13
|
+
/** Get all active engines */
|
|
14
|
+
getActiveEngines(): Map<string, ICamstackAddon>;
|
|
15
|
+
/** Shutdown a specific engine by its config key */
|
|
16
|
+
shutdownEngine(configKey: string): Promise<void>;
|
|
17
|
+
/** Shutdown all engines */
|
|
18
|
+
shutdownAll(): Promise<void>;
|
|
19
|
+
/** Compute a deterministic config key (visible for tests) */
|
|
20
|
+
computeConfigKey(addonId: string, effectiveConfig: Record<string, unknown>): string;
|
|
21
|
+
private hashConfig;
|
|
22
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { IEventBus, IScopedLogger } from '@camstack/types';
|
|
2
|
+
/**
|
|
3
|
+
* Kernel-level addon health monitor.
|
|
4
|
+
*
|
|
5
|
+
* Tracks load + initialize + crash failures across the addon population
|
|
6
|
+
* and drives an aggressive auto-retry loop independent of any single
|
|
7
|
+
* addon's logic. Mirrors the spec the operator approved:
|
|
8
|
+
*
|
|
9
|
+
* - Boot grace: 5 minutes from `start()`. Failures during this window
|
|
10
|
+
* are silently retried (slow-starting addons must have a chance to
|
|
11
|
+
* come up before alarming).
|
|
12
|
+
* - Retry cadence: 60s after first failure, 120s after second, then
|
|
13
|
+
* 300s for every subsequent attempt — never gives up.
|
|
14
|
+
* - Tick interval: 30s. Faster than the shortest retry interval (60s)
|
|
15
|
+
* so a scheduled retry never waits more than ~30s past its target.
|
|
16
|
+
* - Post-grace alerting: emits `AddonLoadFailed` exactly once per
|
|
17
|
+
* failure-streak; AlertCenter consumes the event to create a
|
|
18
|
+
* persistent operator-visible alert. Recovery emits
|
|
19
|
+
* `AddonLoadRecovered` so the alert can dismiss itself.
|
|
20
|
+
* - In-memory state only. Server restart resets the grace window
|
|
21
|
+
* (operator's call — they want a clean slate after a manual restart).
|
|
22
|
+
*
|
|
23
|
+
* The monitor never restarts addons itself: it knows nothing about
|
|
24
|
+
* tarball install / dist paths / dependency injection. It calls a
|
|
25
|
+
* caller-injected `retryFn(packageName)` which is the AddonRegistry's
|
|
26
|
+
* existing reload path — the monitor is just the scheduler + alert
|
|
27
|
+
* gate. This keeps the kernel package addon-agnostic.
|
|
28
|
+
*
|
|
29
|
+
* Group-runner / fork crashes: `process-service.ts` already respawns
|
|
30
|
+
* crashed children with exponential backoff. The monitor doesn't
|
|
31
|
+
* duplicate that loop — it only marks the addon `failed` when the
|
|
32
|
+
* crash supervisor reports it (via `recordFailure`) and clears it on
|
|
33
|
+
* `READY:<nodeId>` recovery (via `recordSuccess`). The kernel's
|
|
34
|
+
* spawn handler wires both edges.
|
|
35
|
+
*/
|
|
36
|
+
export declare const HEALTH_MONITOR_TICK_MS = 30000;
|
|
37
|
+
export declare const HEALTH_MONITOR_GRACE_PERIOD_MS: number;
|
|
38
|
+
/** Retry intervals after each failure (capped — never stops). */
|
|
39
|
+
export declare const HEALTH_MONITOR_RETRY_INTERVALS_MS: readonly number[];
|
|
40
|
+
export type AddonHealthPhase = 'pending' | 'healthy' | 'failed';
|
|
41
|
+
export interface AddonHealthState {
|
|
42
|
+
readonly packageName: string;
|
|
43
|
+
readonly addonId?: string;
|
|
44
|
+
phase: AddonHealthPhase;
|
|
45
|
+
retryCount: number;
|
|
46
|
+
firstFailureAt: number | null;
|
|
47
|
+
lastAttemptAt: number | null;
|
|
48
|
+
lastError: {
|
|
49
|
+
readonly message: string;
|
|
50
|
+
readonly stack?: string;
|
|
51
|
+
} | null;
|
|
52
|
+
nextRetryAt: number | null;
|
|
53
|
+
/** True once `AddonLoadFailed` has been emitted for the current streak. */
|
|
54
|
+
alertEmitted: boolean;
|
|
55
|
+
/** True if a retry attempt is currently in flight. */
|
|
56
|
+
retrying: boolean;
|
|
57
|
+
}
|
|
58
|
+
export interface AddonHealthSnapshot {
|
|
59
|
+
readonly packageName: string;
|
|
60
|
+
readonly addonId?: string;
|
|
61
|
+
readonly phase: AddonHealthPhase;
|
|
62
|
+
readonly retryCount: number;
|
|
63
|
+
readonly firstFailureAt: number | null;
|
|
64
|
+
readonly lastAttemptAt: number | null;
|
|
65
|
+
readonly lastError: {
|
|
66
|
+
readonly message: string;
|
|
67
|
+
readonly stack?: string;
|
|
68
|
+
} | null;
|
|
69
|
+
readonly nextRetryAt: number | null;
|
|
70
|
+
readonly alertEmitted: boolean;
|
|
71
|
+
readonly retrying: boolean;
|
|
72
|
+
/** Whether the boot grace window is still open (suppresses alerts). */
|
|
73
|
+
readonly inGracePeriod: boolean;
|
|
74
|
+
}
|
|
75
|
+
export interface AddonHealthMonitorOptions {
|
|
76
|
+
readonly eventBus: IEventBus;
|
|
77
|
+
readonly logger: IScopedLogger;
|
|
78
|
+
/**
|
|
79
|
+
* Called by the monitor's tick loop when a failed package is due
|
|
80
|
+
* for a retry attempt. Should perform the actual reload (tarball
|
|
81
|
+
* extract + addon-loader re-import + initialize). Returns true on
|
|
82
|
+
* success; throws on failure (the monitor records the new error).
|
|
83
|
+
*/
|
|
84
|
+
readonly retryFn: (packageName: string) => Promise<void>;
|
|
85
|
+
/** Override for tests. Defaults to `HEALTH_MONITOR_TICK_MS`. */
|
|
86
|
+
readonly tickIntervalMs?: number;
|
|
87
|
+
/** Override for tests. Defaults to `HEALTH_MONITOR_GRACE_PERIOD_MS`. */
|
|
88
|
+
readonly gracePeriodMs?: number;
|
|
89
|
+
/** Override for tests. Defaults to `HEALTH_MONITOR_RETRY_INTERVALS_MS`. */
|
|
90
|
+
readonly retryIntervalsMs?: readonly number[];
|
|
91
|
+
/** Override clock for deterministic tests. */
|
|
92
|
+
readonly now?: () => number;
|
|
93
|
+
}
|
|
94
|
+
export declare class AddonHealthMonitor {
|
|
95
|
+
private readonly state;
|
|
96
|
+
private readonly bootAt;
|
|
97
|
+
private readonly tickIntervalMs;
|
|
98
|
+
private readonly gracePeriodMs;
|
|
99
|
+
private readonly retryIntervalsMs;
|
|
100
|
+
private readonly eventBus;
|
|
101
|
+
private readonly logger;
|
|
102
|
+
private readonly retryFn;
|
|
103
|
+
private readonly now;
|
|
104
|
+
private timer;
|
|
105
|
+
private graceEmittedFor;
|
|
106
|
+
constructor(opts: AddonHealthMonitorOptions);
|
|
107
|
+
/** True while we're still inside the post-boot grace window. */
|
|
108
|
+
inGracePeriod(): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Record a successful load/init/recovery for a package. Clears any
|
|
111
|
+
* existing failure state and emits `AddonLoadRecovered` if the
|
|
112
|
+
* package was previously in `failed` state with an alert emitted.
|
|
113
|
+
*/
|
|
114
|
+
recordSuccess(packageName: string, addonId?: string): void;
|
|
115
|
+
/**
|
|
116
|
+
* Record a load/init/crash failure. Schedules the next retry per
|
|
117
|
+
* `retryIntervalsMs` and (post-grace) emits `AddonLoadFailed` if
|
|
118
|
+
* this is the first alert for the current streak.
|
|
119
|
+
*/
|
|
120
|
+
recordFailure(packageName: string, err: unknown, addonId?: string): void;
|
|
121
|
+
/**
|
|
122
|
+
* Force an immediate retry attempt for a package, resetting the
|
|
123
|
+
* counter back to 0 (next failure goes to the 60s interval again).
|
|
124
|
+
* Used by the user-facing `addons.retryLoad` tRPC procedure and by
|
|
125
|
+
* the explicit reinstall path.
|
|
126
|
+
*/
|
|
127
|
+
retryNow(packageName: string): Promise<void>;
|
|
128
|
+
/** Snapshot of all tracked packages (read-only, for tRPC list / UI). */
|
|
129
|
+
getHealthSnapshot(): readonly AddonHealthSnapshot[];
|
|
130
|
+
/** Get health for a single package (or null if unknown). */
|
|
131
|
+
getHealth(packageName: string): AddonHealthSnapshot | null;
|
|
132
|
+
/**
|
|
133
|
+
* Drop tracking for a package (used on uninstall — we don't want
|
|
134
|
+
* the monitor to keep retrying a package the user explicitly removed).
|
|
135
|
+
*/
|
|
136
|
+
forget(packageName: string): void;
|
|
137
|
+
/** Begin the retry tick loop. Idempotent. */
|
|
138
|
+
start(): void;
|
|
139
|
+
/** Stop the retry loop (cleanup on shutdown). */
|
|
140
|
+
stop(): void;
|
|
141
|
+
/**
|
|
142
|
+
* Public for tests. Production callers go through `start()`.
|
|
143
|
+
*
|
|
144
|
+
* Each tick:
|
|
145
|
+
* 1. If grace JUST ended on this tick, emit `AddonLoadFailed` for
|
|
146
|
+
* every package still in `failed` state that hasn't alerted yet.
|
|
147
|
+
* 2. For every `failed` package whose `nextRetryAt` <= now, run
|
|
148
|
+
* `retryFn`. On success, recordSuccess; on failure, recordFailure
|
|
149
|
+
* (which recomputes the next interval).
|
|
150
|
+
*/
|
|
151
|
+
tick(): Promise<void>;
|
|
152
|
+
private attemptRetry;
|
|
153
|
+
private emit;
|
|
154
|
+
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { InstalledPackage, IScopedLogger } from '@camstack/types';
|
|
2
|
+
import { AddonManifest } from './addon-manifest.js';
|
|
3
|
+
/**
|
|
4
|
+
* Addon install source mode:
|
|
5
|
+
* - 'npm' — download from npm registry (production + dev default).
|
|
6
|
+
* - 'local' — copy dist/ from local workspace `packages/` (used by
|
|
7
|
+
* `installFromWorkspace` + the Electron-packaged bundled
|
|
8
|
+
* addons path).
|
|
9
|
+
* - 'symlink' — point `data/addons/<pkg>` directly at the workspace
|
|
10
|
+
* source dir. Dev-only: workspace edits → next addon
|
|
11
|
+
* load picks them up after a `npm run build` of the
|
|
12
|
+
* package, without re-copying. Costs ~80ms per addon at
|
|
13
|
+
* cold boot instead of the ~200ms-per-package copy.
|
|
14
|
+
* Windows fallback: drops back to `'local'` if symlink
|
|
15
|
+
* creation fails (needs admin / developer-mode on Win10).
|
|
16
|
+
*
|
|
17
|
+
* The previous symlink mode (auto-on when workspace was detected) was
|
|
18
|
+
* removed in `eb96df3c` once addons moved to self-contained bundles —
|
|
19
|
+
* the legacy `symlinkAddonsToNodeModules` / `symlinkPeerDepsIntoAddonsDir`
|
|
20
|
+
* helpers it relied on are GONE. This is the narrower successor: no
|
|
21
|
+
* symlinks into the hub's `node_modules`, no peer-dep planting — just
|
|
22
|
+
* `addonsDir/<pkg>` → `packages/<pkg>`.
|
|
23
|
+
*/
|
|
24
|
+
export type InstallSource = 'npm' | 'local' | 'symlink';
|
|
25
|
+
export interface AddonInstallerConfig {
|
|
26
|
+
/** Directory where addons are stored (e.g., {dataDir}/addons) */
|
|
27
|
+
readonly addonsDir: string;
|
|
28
|
+
/** npm registry URL */
|
|
29
|
+
readonly registry?: string;
|
|
30
|
+
/** Workspace packages directory (e.g., /path/to/camstack-server/packages) */
|
|
31
|
+
readonly workspacePackagesDir?: string;
|
|
32
|
+
/** Install source mode. Default: auto-detect */
|
|
33
|
+
readonly installSource?: InstallSource;
|
|
34
|
+
}
|
|
35
|
+
export type { InstalledPackage };
|
|
36
|
+
export declare class AddonInstaller {
|
|
37
|
+
readonly addonsDir: string;
|
|
38
|
+
private readonly registry;
|
|
39
|
+
readonly workspaceDir: string | undefined;
|
|
40
|
+
readonly installSource: InstallSource;
|
|
41
|
+
private readonly logger;
|
|
42
|
+
/**
|
|
43
|
+
* Central manifest of installed addons. Tracks version + source +
|
|
44
|
+
* timestamps + last-backup pointer per package, written atomically
|
|
45
|
+
* after every install/uninstall. Replaces the legacy per-addon
|
|
46
|
+
* `.install-source` markers (which we still write for backward
|
|
47
|
+
* compatibility with code that reads them directly — see fs-utils
|
|
48
|
+
* `getAddonInstallSource`).
|
|
49
|
+
*/
|
|
50
|
+
readonly manifest: AddonManifest;
|
|
51
|
+
constructor(config: AddonInstallerConfig, logger?: IScopedLogger);
|
|
52
|
+
/**
|
|
53
|
+
* Derive the bootstrap addon list from a meta-package's runtime dependencies.
|
|
54
|
+
* Single source of truth: the meta-package's `package.json` declares which
|
|
55
|
+
* `@camstack/addon-*` packages the deployment needs. Replaces previously
|
|
56
|
+
* hardcoded lists — see design spec
|
|
57
|
+
* docs/superpowers/specs/2026-05-20-docker-install-from-npm-design.md.
|
|
58
|
+
*/
|
|
59
|
+
private static deriveBootstrapList;
|
|
60
|
+
/**
|
|
61
|
+
* Bootstrap packages installed on first boot — derived from the
|
|
62
|
+
* `@camstack/server` meta-package's runtime dependencies. Adding a
|
|
63
|
+
* bootstrap addon = adding it to `server/backend/package.json`.
|
|
64
|
+
* See design spec
|
|
65
|
+
* docs/superpowers/specs/2026-05-20-docker-install-from-npm-design.md.
|
|
66
|
+
*
|
|
67
|
+
* Camera provider drivers are NOT preinstalled with the hub — users
|
|
68
|
+
* pick providers from the admin UI ("Install addon"). Saves ~80MB per
|
|
69
|
+
* hub install and avoids shipping driver code unused on most hubs.
|
|
70
|
+
*/
|
|
71
|
+
static readonly REQUIRED_PACKAGES: readonly string[];
|
|
72
|
+
/**
|
|
73
|
+
* Agent-only bootstrap packages — derived from the `@camstack/agent`
|
|
74
|
+
* meta-package's runtime dependencies. Adding an agent bootstrap addon
|
|
75
|
+
* = adding it to `packages/agent/package.json`.
|
|
76
|
+
*/
|
|
77
|
+
static readonly AGENT_PACKAGES: readonly string[];
|
|
78
|
+
/**
|
|
79
|
+
* Ensure all required packages are installed in the addons directory.
|
|
80
|
+
*
|
|
81
|
+
* Bootstrap-only — prefers the workspace/bundle copy when available
|
|
82
|
+
* (offline-first, faster, container-self-contained). On-demand
|
|
83
|
+
* installs from the admin UI go through `install()` instead, which
|
|
84
|
+
* defaults to npm in production.
|
|
85
|
+
*
|
|
86
|
+
* @param packages — optional custom package list (default: REQUIRED_PACKAGES)
|
|
87
|
+
*/
|
|
88
|
+
ensureRequiredPackages(packages?: readonly string[]): Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Install a single addon — on-demand installer used by AddonPackageService
|
|
91
|
+
* (admin UI "Install addon" / "Reinstall" buttons).
|
|
92
|
+
*
|
|
93
|
+
* Always npm. The legacy "auto-use workspace symlink in dev" branch
|
|
94
|
+
* was removed; local development pushes via `camstack deploy` (CLI
|
|
95
|
+
* tarball upload). Operators wanting to install from workspace use
|
|
96
|
+
* `installFromWorkspace` (explicit `'local'` codepath) instead.
|
|
97
|
+
*/
|
|
98
|
+
install(packageName: string, version?: string): Promise<{
|
|
99
|
+
name: string;
|
|
100
|
+
version: string;
|
|
101
|
+
}>;
|
|
102
|
+
/**
|
|
103
|
+
* Install addon from a local workspace package. Two strategies
|
|
104
|
+
* depending on `installSource`:
|
|
105
|
+
* - `'symlink'` (dev): create a directory symlink
|
|
106
|
+
* `addonsDir/<pkg>` → `<workspace>/packages/<pkg>`. Edits to
|
|
107
|
+
* the workspace are visible at the next addon load after a
|
|
108
|
+
* `npm run build` of that package — no copy step. Falls back
|
|
109
|
+
* to `'local'` if symlink creation fails (Windows w/o
|
|
110
|
+
* developer-mode).
|
|
111
|
+
* - `'local'` (default): copy `package.json` (stripped) + `dist/`
|
|
112
|
+
* into `addonsDir/<pkg>/`. The Electron bundled-addons path
|
|
113
|
+
* uses this so the runtime owns its on-disk copy.
|
|
114
|
+
*/
|
|
115
|
+
private installLocal;
|
|
116
|
+
/**
|
|
117
|
+
* Symlink `addonsDir/<pkg>` at the workspace source dir. Dev-only.
|
|
118
|
+
* After this, the AddonLoader resolves `<addonsDir>/<pkg>/dist/...`
|
|
119
|
+
* through the symlink straight to `packages/<pkg>/dist/...` — a fresh
|
|
120
|
+
* `npm run build` of the package is immediately picked up by the
|
|
121
|
+
* next addon load.
|
|
122
|
+
*
|
|
123
|
+
* Auto-runs `ensureBuilt` so a workspace freshly cloned (with no
|
|
124
|
+
* dist/ yet) still boots — same auto-build hook installCopy uses.
|
|
125
|
+
*
|
|
126
|
+
* Does NOT plant peer-dep symlinks into `<targetDir>/node_modules/`
|
|
127
|
+
* the way the pre-`eb96df3c` symlink mode did. Self-contained
|
|
128
|
+
* addons bundle their own copy of types/zod/sdk — no shared
|
|
129
|
+
* workspace symlinks needed.
|
|
130
|
+
*/
|
|
131
|
+
private installSymlink;
|
|
132
|
+
private installCopy;
|
|
133
|
+
/**
|
|
134
|
+
* Install addon from npm (download tgz, then extract). Tries the
|
|
135
|
+
* registry HTTPS API first (works inside packaged Electron — no need
|
|
136
|
+
* for `npm` on PATH); falls back to `npm pack` for parity with the
|
|
137
|
+
* legacy path when the registry call fails (private registries with
|
|
138
|
+
* unusual auth, offline mode, etc).
|
|
139
|
+
*/
|
|
140
|
+
installFromNpm(packageName: string, version?: string): Promise<{
|
|
141
|
+
name: string;
|
|
142
|
+
version: string;
|
|
143
|
+
}>;
|
|
144
|
+
/**
|
|
145
|
+
* Resolve `{packageName, version?}` against the configured registry
|
|
146
|
+
* over HTTPS and download the tarball into `tmpDir`. Returns the path
|
|
147
|
+
* to the downloaded `.tgz`.
|
|
148
|
+
*
|
|
149
|
+
* Versioning rules (mirrors `npm pack` semantics):
|
|
150
|
+
* - `version === undefined` → uses `dist-tags.latest`
|
|
151
|
+
* - exact semver string → looked up in `versions[version]`
|
|
152
|
+
* - dist-tag name (e.g. `next`, `beta`) → resolved via `dist-tags`
|
|
153
|
+
*
|
|
154
|
+
* Range specs (`^1.0.0`, `~1.2`, `>=2`) are NOT supported here — the
|
|
155
|
+
* caller should resolve those upstream. `npm pack` handles them, so
|
|
156
|
+
* the legacy fallback path remains the right answer for those.
|
|
157
|
+
*/
|
|
158
|
+
private downloadNpmTarball;
|
|
159
|
+
/** Install addon from a tgz file (uploaded or downloaded) */
|
|
160
|
+
installFromTgz(tgzPath: string): Promise<{
|
|
161
|
+
name: string;
|
|
162
|
+
version: string;
|
|
163
|
+
}>;
|
|
164
|
+
/**
|
|
165
|
+
* Apply an update to an installed addon, backing up the current
|
|
166
|
+
* version first so the caller can roll back atomically on failure.
|
|
167
|
+
*
|
|
168
|
+
* Steps:
|
|
169
|
+
* 1. Rename current install dir → {addonsDir}/.backups/{name}/{ts}/
|
|
170
|
+
* 2. Run a fresh install (npm or local depending on installSource)
|
|
171
|
+
* 3. Record `lastBackupDir` in the manifest entry
|
|
172
|
+
*
|
|
173
|
+
* The post-install caller (kernel.restartAddon + health-check) is
|
|
174
|
+
* responsible for verifying the new version actually works and for
|
|
175
|
+
* triggering `rollbackAddon()` if the health check fails.
|
|
176
|
+
*
|
|
177
|
+
* Throws if there is no installed version to update — caller should
|
|
178
|
+
* prefer plain `install()` for first-time installs.
|
|
179
|
+
*/
|
|
180
|
+
applyUpdate(packageName: string, version?: string): Promise<{
|
|
181
|
+
name: string;
|
|
182
|
+
version: string;
|
|
183
|
+
backupDir: string;
|
|
184
|
+
}>;
|
|
185
|
+
/**
|
|
186
|
+
* Roll back an addon to its most recent backup. Used after an update
|
|
187
|
+
* passes installation but fails its post-restart health check.
|
|
188
|
+
*
|
|
189
|
+
* Returns the version that was restored, or `null` if there was no
|
|
190
|
+
* backup to roll back to.
|
|
191
|
+
*/
|
|
192
|
+
rollbackAddon(packageName: string): Promise<string | null>;
|
|
193
|
+
/**
|
|
194
|
+
* Drop the recorded backup for an addon (e.g. after a successful
|
|
195
|
+
* post-update health check confirms the new version is healthy).
|
|
196
|
+
* Frees disk space without affecting the running install.
|
|
197
|
+
*/
|
|
198
|
+
clearBackup(packageName: string): void;
|
|
199
|
+
uninstall(packageName: string): Promise<void>;
|
|
200
|
+
listInstalled(): InstalledPackage[];
|
|
201
|
+
isInstalled(packageName: string): boolean;
|
|
202
|
+
getInstalledPackage(packageName: string): InstalledPackage | null;
|
|
203
|
+
private findLocalPackage;
|
|
204
|
+
/** Ensure a package is built (dist/ exists and page bundles present) */
|
|
205
|
+
private ensureBuilt;
|
|
206
|
+
/** Check if page bundles declared in package.json are missing from dist/ */
|
|
207
|
+
private isDistIncomplete;
|
|
208
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { AddonDeclaration, ICamstackAddon, IScopedLogger, StorageLocationDeclaration } from '@camstack/types';
|
|
2
|
+
export interface RegisteredAddon {
|
|
3
|
+
readonly declaration: AddonDeclaration;
|
|
4
|
+
readonly packageName: string;
|
|
5
|
+
readonly packageVersion: string;
|
|
6
|
+
/** Human-readable package name from camstack.displayName in package.json */
|
|
7
|
+
readonly packageDisplayName?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Optional bundle metadata when the npm package ships multiple addon
|
|
10
|
+
* entries. Mirrors `AddonPackageManifest.bundle`. Drives the
|
|
11
|
+
* collapsible bundle card in the Addons admin UI.
|
|
12
|
+
*/
|
|
13
|
+
readonly bundle?: {
|
|
14
|
+
displayName: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
icon?: string;
|
|
17
|
+
};
|
|
18
|
+
readonly addonClass: new () => ICamstackAddon;
|
|
19
|
+
/**
|
|
20
|
+
* Full raw module namespace. Consumers can read additional named exports
|
|
21
|
+
* (e.g. `customActions`) without instantiating the addon — lets the hub
|
|
22
|
+
* register a forkable addon's custom-action catalog with real zod
|
|
23
|
+
* schemas before the child process is up.
|
|
24
|
+
*/
|
|
25
|
+
readonly module: Readonly<Record<string, unknown>>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Per-package failure record. Surfaced via `listLoadFailures()` so the
|
|
29
|
+
* AddonRegistry can hand the failures to the kernel's
|
|
30
|
+
* `AddonHealthMonitor` after `loadFromDirectory()` completes — the
|
|
31
|
+
* health monitor then schedules the retry loop and emits operator-
|
|
32
|
+
* visible alerts post-grace.
|
|
33
|
+
*
|
|
34
|
+
* Two failure shapes are tracked:
|
|
35
|
+
* - **package-level**: package.json couldn't be read/parsed, or the
|
|
36
|
+
* manifest was malformed. `addonId` undefined.
|
|
37
|
+
* - **declaration-level**: per-addon load failure inside
|
|
38
|
+
* `loadDeclaration` (entry import threw, addon class resolution
|
|
39
|
+
* failed, etc). `addonId` set to `declaration.id`.
|
|
40
|
+
*/
|
|
41
|
+
export interface AddonLoadFailure {
|
|
42
|
+
readonly packageName: string;
|
|
43
|
+
readonly addonDir: string;
|
|
44
|
+
readonly addonId?: string;
|
|
45
|
+
readonly error: Error;
|
|
46
|
+
readonly timestamp: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Pure extraction of per-addon storage-location declarations from a set of
|
|
50
|
+
* registered addons. Each registered addon carries its manifest declaration
|
|
51
|
+
* (`RegisteredAddon.declaration`), whose optional `storageLocations` array is
|
|
52
|
+
* the `camstack.addons[].storageLocations` entry authored in package.json.
|
|
53
|
+
*
|
|
54
|
+
* Returns ONE inner array per addon that declared at least one location;
|
|
55
|
+
* addons declaring nothing are omitted entirely (no empty arrays). The result
|
|
56
|
+
* is the `perAddon` input shape consumed by
|
|
57
|
+
* {@link buildStorageLocationRegistry}.
|
|
58
|
+
*/
|
|
59
|
+
export declare function extractStorageLocationDeclarations(addons: Iterable<RegisteredAddon>): StorageLocationDeclaration[][];
|
|
60
|
+
export declare class AddonLoader {
|
|
61
|
+
private addons;
|
|
62
|
+
private readonly loadFailures;
|
|
63
|
+
private readonly logger;
|
|
64
|
+
constructor(logger?: IScopedLogger);
|
|
65
|
+
/**
|
|
66
|
+
* Failures encountered during the most recent `loadFromDirectory` /
|
|
67
|
+
* `loadFromAddonDir` pass. Cleared (per-package) on a successful
|
|
68
|
+
* subsequent reload so retries don't see stale entries. Cumulative
|
|
69
|
+
* across multiple loads otherwise.
|
|
70
|
+
*/
|
|
71
|
+
listLoadFailures(): readonly AddonLoadFailure[];
|
|
72
|
+
/** Forget any tracked failures for a given package — uninstall path. */
|
|
73
|
+
clearLoadFailures(packageName: string): void;
|
|
74
|
+
/** Scan addons directory and load all addon packages.
|
|
75
|
+
* Supports scoped layout: addons/@scope/package-name/ */
|
|
76
|
+
loadFromDirectory(addonsDir: string): Promise<void>;
|
|
77
|
+
private tryLoadAddon;
|
|
78
|
+
/** Load addon from a specific directory (package.json + dist/) */
|
|
79
|
+
loadFromAddonDir(addonDir: string): Promise<void>;
|
|
80
|
+
private loadDeclaration;
|
|
81
|
+
/** Load addon from a direct path (for development/testing) */
|
|
82
|
+
loadFromPath(addonId: string, modulePath: string, packageName: string, declaration?: Partial<AddonDeclaration>, packageVersion?: string): Promise<void>;
|
|
83
|
+
/** Get a registered addon by ID */
|
|
84
|
+
getAddon(addonId: string): RegisteredAddon | undefined;
|
|
85
|
+
/** List all registered addons */
|
|
86
|
+
listAddons(): RegisteredAddon[];
|
|
87
|
+
/**
|
|
88
|
+
* Per-addon storage-location declarations across every registered addon.
|
|
89
|
+
*
|
|
90
|
+
* Each registered addon's `declaration.storageLocations` (the
|
|
91
|
+
* `camstack.addons[].storageLocations` array from package.json) is surfaced
|
|
92
|
+
* as one inner array; addons declaring nothing are omitted. The result is
|
|
93
|
+
* fed directly to `buildStorageLocationRegistry(perAddon)` so the
|
|
94
|
+
* storage-orchestrator can aggregate declarations and seed `<id>:default`
|
|
95
|
+
* instances.
|
|
96
|
+
*/
|
|
97
|
+
listStorageLocationDeclarations(): StorageLocationDeclaration[][];
|
|
98
|
+
/** Check if an addon is registered */
|
|
99
|
+
hasAddon(addonId: string): boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Create a new instance of an addon (not yet initialized).
|
|
102
|
+
* Injects the manifest from package.json (AddonDeclaration) so the
|
|
103
|
+
* addon class doesn't need to declare it.
|
|
104
|
+
*/
|
|
105
|
+
createInstance(addonId: string): ICamstackAddon;
|
|
106
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export type AddonInstallSource = 'npm' | 'local' | 'upload' | 'bundled' | 'seed';
|
|
2
|
+
export interface AddonManifestEntry {
|
|
3
|
+
/** Full pkg name, e.g. `@camstack/addon-pipeline`. */
|
|
4
|
+
name: string;
|
|
5
|
+
/** Semver currently installed. */
|
|
6
|
+
version: string;
|
|
7
|
+
/** Where this version came from. */
|
|
8
|
+
source: AddonInstallSource;
|
|
9
|
+
/** ISO 8601 of first install. */
|
|
10
|
+
installedAt: string;
|
|
11
|
+
/** ISO 8601 of last update (== installedAt for first install). */
|
|
12
|
+
updatedAt: string;
|
|
13
|
+
/**
|
|
14
|
+
* Path (absolute) of the most recent pre-update backup, if any.
|
|
15
|
+
* Used by `applyUpdate` rollback when an upgrade fails its post-restart
|
|
16
|
+
* health check. Cleared once the new version is confirmed healthy.
|
|
17
|
+
*/
|
|
18
|
+
lastBackupDir?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Free-form, addon-specific metadata. Currently unused but reserved so
|
|
21
|
+
* future fields (e.g. integrity hash, peer-dep checks) don't require a
|
|
22
|
+
* manifest schema bump.
|
|
23
|
+
*/
|
|
24
|
+
meta?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
export interface AddonManifestFile {
|
|
27
|
+
/**
|
|
28
|
+
* Schema version. Increment whenever the on-disk shape changes
|
|
29
|
+
* incompatibly so older readers can refuse to load.
|
|
30
|
+
*/
|
|
31
|
+
version: 1;
|
|
32
|
+
/** Per-package state, keyed by full pkg name. */
|
|
33
|
+
addons: Record<string, AddonManifestEntry>;
|
|
34
|
+
/** ISO 8601 of last manifest write. */
|
|
35
|
+
updatedAt: string;
|
|
36
|
+
}
|
|
37
|
+
export declare class AddonManifest {
|
|
38
|
+
private readonly manifestPath;
|
|
39
|
+
private cache;
|
|
40
|
+
constructor(addonsDir: string);
|
|
41
|
+
/**
|
|
42
|
+
* Read the manifest from disk. Returns an empty manifest if the file is
|
|
43
|
+
* missing or corrupted (logs a warning to stderr in the corrupted case).
|
|
44
|
+
* Cached per instance — call `invalidate()` to force a re-read.
|
|
45
|
+
*/
|
|
46
|
+
read(): AddonManifestFile;
|
|
47
|
+
/**
|
|
48
|
+
* Atomic write — writes to a tmpfile in the same directory, then renames.
|
|
49
|
+
* Rename is atomic on the same filesystem, so readers can never observe
|
|
50
|
+
* a half-written file.
|
|
51
|
+
*/
|
|
52
|
+
write(manifest: AddonManifestFile): void;
|
|
53
|
+
/** Lookup a single addon's manifest entry, or `null` if not tracked. */
|
|
54
|
+
get(name: string): AddonManifestEntry | null;
|
|
55
|
+
/** List every tracked entry. */
|
|
56
|
+
list(): AddonManifestEntry[];
|
|
57
|
+
/**
|
|
58
|
+
* Insert or replace an addon entry. `installedAt` is preserved if the
|
|
59
|
+
* entry already exists; only `updatedAt` advances on subsequent writes.
|
|
60
|
+
*/
|
|
61
|
+
upsert(name: string, fields: Omit<AddonManifestEntry, 'name' | 'installedAt' | 'updatedAt'>): void;
|
|
62
|
+
/** Remove an addon from tracking (e.g. uninstall). */
|
|
63
|
+
remove(name: string): void;
|
|
64
|
+
/**
|
|
65
|
+
* Drop the in-memory cache so the next `read()` re-loads from disk.
|
|
66
|
+
* Useful when an external process may have written the manifest.
|
|
67
|
+
*/
|
|
68
|
+
invalidate(): void;
|
|
69
|
+
/**
|
|
70
|
+
* Migration helper: if the manifest is empty but the addons directory
|
|
71
|
+
* has packages with `.install-source` markers (the legacy per-addon
|
|
72
|
+
* tracking), seed the manifest from those markers. Runs once at boot.
|
|
73
|
+
* Returns the number of entries migrated.
|
|
74
|
+
*/
|
|
75
|
+
migrateFromInstallSourceMarkers(addonsDir: string): number;
|
|
76
|
+
private empty;
|
|
77
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ReadinessRegistry, ReadinessScope, ICapabilityHandle } from '@camstack/types';
|
|
2
|
+
export declare class CapabilityUnavailableError extends Error {
|
|
3
|
+
readonly capName: string;
|
|
4
|
+
readonly scope: ReadinessScope;
|
|
5
|
+
readonly timeoutMs: number;
|
|
6
|
+
constructor(capName: string, scope: ReadinessScope, timeoutMs: number);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A stable reference to a capability that tracks its readiness state and
|
|
10
|
+
* gates calls on that state.
|
|
11
|
+
*
|
|
12
|
+
* Obtained via `ctx.useCapability()` (non-blocking) or `ctx.acquireCapability()`
|
|
13
|
+
* (blocks until the cap is ready). The handle is cached per `(capName, scope)` in
|
|
14
|
+
* AddonContextImpl so repeated calls return the same instance.
|
|
15
|
+
*
|
|
16
|
+
* The generic `T` is a phantom type documenting the expected provider interface;
|
|
17
|
+
* the handle itself does not expose a typed proxy surface in v1.
|
|
18
|
+
*/
|
|
19
|
+
export declare class CapabilityHandle<T = unknown> implements ICapabilityHandle<T> {
|
|
20
|
+
readonly capName: string;
|
|
21
|
+
readonly scope: ReadinessScope;
|
|
22
|
+
private readonly registry;
|
|
23
|
+
readonly defaultTimeoutMs: number;
|
|
24
|
+
private state;
|
|
25
|
+
private readonly unsubscribeReadiness;
|
|
26
|
+
constructor(capName: string, scope: ReadinessScope, registry: ReadinessRegistry, defaultTimeoutMs: number);
|
|
27
|
+
get isReady(): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Block until the capability is ready, or throw `CapabilityUnavailableError`
|
|
30
|
+
* if it does not become ready within `timeoutMs`.
|
|
31
|
+
*/
|
|
32
|
+
awaitReady(timeoutMs?: number): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Execute `fn` with readiness gating: if the cap is not ready, blocks
|
|
35
|
+
* until it becomes ready (or throws CapabilityUnavailableError on timeout),
|
|
36
|
+
* then calls `fn`.
|
|
37
|
+
*
|
|
38
|
+
* Preferred over calling awaitReady() + fn() separately because it
|
|
39
|
+
* re-gates after a down→ready transition that happens between the
|
|
40
|
+
* await and the call.
|
|
41
|
+
*/
|
|
42
|
+
call<R>(fn: () => Promise<R>, timeoutMs?: number): Promise<R>;
|
|
43
|
+
/** Unsubscribe from ReadinessRegistry. Called by AddonContextImpl on shutdown. */
|
|
44
|
+
dispose(): void;
|
|
45
|
+
readonly _provider: T;
|
|
46
|
+
}
|