@camstack/system 1.2.179 → 1.2.181
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-runner.js +2 -2
- package/dist/addon-runner.mjs +2 -2
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.d.ts +56 -10
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +657 -62
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +658 -63
- package/dist/builtins/backup-orchestrator/run-queue.d.ts +103 -0
- package/dist/builtins/backup-orchestrator/staging-paths.d.ts +36 -0
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
- package/dist/builtins/device-manager/device-manager.addon.js +349 -65
- package/dist/builtins/device-manager/device-manager.addon.mjs +349 -65
- package/dist/builtins/device-manager/device-meta-actions.d.ts +8 -19
- package/dist/builtins/device-manager/device-provider-context.d.ts +4 -0
- package/dist/builtins/device-manager/migrate-device.d.ts +47 -3
- package/dist/builtins/device-manager/migrate-guard.d.ts +39 -0
- package/dist/builtins/device-manager/migrate-hardware-state.d.ts +24 -0
- package/dist/builtins/device-manager/migrate-reload.d.ts +8 -0
- package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
- package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
- package/dist/builtins/local-network/local-network.addon.js +1 -1
- package/dist/builtins/local-network/local-network.addon.mjs +1 -1
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/dist/builtins/system-backup/system-backup.service.d.ts +55 -2
- package/dist/builtins/system-config/system-config.addon.js +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{dist-L_39vRmH.mjs → dist-DbnNk4Lw.mjs} +211 -2
- package/dist/{dist-C7qWwrK1.js → dist-whe0b4_3.js} +211 -2
- package/dist/index.js +530 -2
- package/dist/index.mjs +533 -5
- package/dist/kernel/addon-installer.d.ts +69 -0
- package/dist/kernel/deps/closure-dedupe.d.ts +105 -0
- package/dist/{manifest-system-deps-CMOGc5nC.mjs → manifest-system-deps-DOcMuUWK.mjs} +1 -1
- package/dist/{manifest-system-deps-PAIfmNun.js → manifest-system-deps-y5vZBO6q.js} +1 -1
- package/dist/{retired-settings-keys-3soU9pfP.js → retired-settings-keys-BdvmiaK7.js} +1 -1
- package/dist/{retired-settings-keys-CnbKAxmX.mjs → retired-settings-keys-CyQG8b-A.mjs} +1 -1
- package/package.json +1 -1
|
@@ -57,8 +57,25 @@ export interface AddonInstallerConfig {
|
|
|
57
57
|
* unreachable in a process where that package always resolves.
|
|
58
58
|
*/
|
|
59
59
|
readonly isPackageResolvable?: (packageName: string) => boolean;
|
|
60
|
+
/**
|
|
61
|
+
* The server closure's node_modules to dedupe addon trees against.
|
|
62
|
+
* Production leaves it unset (derived from `CAMSTACK_FRAMEWORK_DIR`);
|
|
63
|
+
* specs point it at a fabricated closure dir.
|
|
64
|
+
*/
|
|
65
|
+
readonly closureNodeModulesDir?: string;
|
|
60
66
|
}
|
|
61
67
|
export type { InstalledPackage };
|
|
68
|
+
/** Outcome of {@link AddonInstaller.ensureAddonRuntimeDeps}. */
|
|
69
|
+
export interface EnsureAddonDepsResult {
|
|
70
|
+
/** Installed addon packages examined. */
|
|
71
|
+
readonly checked: number;
|
|
72
|
+
/** `"<package>:<dep>"` entries satisfied by a new closure link — no npm. */
|
|
73
|
+
readonly linked: readonly string[];
|
|
74
|
+
/** Packages whose deps required an in-place npm install. */
|
|
75
|
+
readonly reinstalled: readonly string[];
|
|
76
|
+
/** Packages whose deps could not be ensured (logged loudly, boot continues). */
|
|
77
|
+
readonly failed: readonly string[];
|
|
78
|
+
}
|
|
62
79
|
/** Outcome of {@link AddonInstaller.sweepBackups}. Absolute paths. */
|
|
63
80
|
export interface BackupSweepResult {
|
|
64
81
|
/** Backup dirs reclaimed by the sweep. */
|
|
@@ -104,6 +121,8 @@ export declare class AddonInstaller {
|
|
|
104
121
|
readonly installSource: InstallSource;
|
|
105
122
|
private readonly logger;
|
|
106
123
|
private readonly isPackageResolvable?;
|
|
124
|
+
/** Test seam — production resolves via `CAMSTACK_FRAMEWORK_DIR`. */
|
|
125
|
+
private readonly closureNodeModulesDir;
|
|
107
126
|
/**
|
|
108
127
|
* Central manifest of installed addons. Tracks version + source +
|
|
109
128
|
* timestamps + last-backup pointer per package, written atomically
|
|
@@ -209,6 +228,42 @@ export declare class AddonInstaller {
|
|
|
209
228
|
* Returns the number of changes.
|
|
210
229
|
*/
|
|
211
230
|
reconcileManifest(): number;
|
|
231
|
+
/**
|
|
232
|
+
* Make every INSTALLED addon's runtime dependencies resolvable — doing the
|
|
233
|
+
* least work that achieves it. Runs at boot on hub and agent, which is what
|
|
234
|
+
* turns a restore back into a working node: a system backup archives no
|
|
235
|
+
* node_modules (D338), so before this pass every restored non-bootstrap
|
|
236
|
+
* addon failed its first import until someone redeployed it by hand.
|
|
237
|
+
*
|
|
238
|
+
* Per addon, in order:
|
|
239
|
+
* 1. drop closure links that no longer hold (dangling, or the closure
|
|
240
|
+
* moved to a version the addon tree's recorded ranges refuse) — those
|
|
241
|
+
* addons get a reinstall;
|
|
242
|
+
* 2. a declared dep that already resolves in the addon tree costs nothing;
|
|
243
|
+
* 3. a missing declared dep the closure provides at a COMPATIBLE version
|
|
244
|
+
* becomes a link — no npm, no network;
|
|
245
|
+
* 4. only an addon left with a genuinely unresolvable dep gets an npm
|
|
246
|
+
* install (then dedupe + native ensure, same tail as a fresh install).
|
|
247
|
+
*
|
|
248
|
+
* "Only when necessary" is the contract: an addon whose deps are all
|
|
249
|
+
* satisfied is not touched at all. Failures are per-addon and non-fatal —
|
|
250
|
+
* a dep that cannot be re-fetched leaves that addon exactly as broken as
|
|
251
|
+
* it already was, but LOUDLY, and never blocks the rest of the boot.
|
|
252
|
+
*/
|
|
253
|
+
ensureAddonRuntimeDeps(): Promise<EnsureAddonDepsResult>;
|
|
254
|
+
/**
|
|
255
|
+
* One addon's dependency audit (steps 1–3 of `ensureAddonRuntimeDeps`).
|
|
256
|
+
* Pure decision + link creation; the npm fallback is the caller's.
|
|
257
|
+
*/
|
|
258
|
+
private ensureOneAddonDeps;
|
|
259
|
+
/**
|
|
260
|
+
* npm-install an installed addon's runtime deps IN PLACE (the restore /
|
|
261
|
+
* repair path — the tree is not yet running at boot), then the same tail
|
|
262
|
+
* every fresh install gets: closure dedupe + native deps + prebuild ensure.
|
|
263
|
+
* Closure links are stripped first so npm reifies against plain missing
|
|
264
|
+
* dirs instead of symlinks it does not own.
|
|
265
|
+
*/
|
|
266
|
+
private reinstallAddonDeps;
|
|
212
267
|
/**
|
|
213
268
|
* Install a single addon — on-demand installer used by AddonPackageService
|
|
214
269
|
* (admin UI "Install addon" / "Reinstall" buttons).
|
|
@@ -382,6 +437,20 @@ export declare class AddonInstaller {
|
|
|
382
437
|
* declares no natives.
|
|
383
438
|
*/
|
|
384
439
|
private installNativeDependencies;
|
|
440
|
+
/**
|
|
441
|
+
* Stop copying what the server closure already provides: replace each
|
|
442
|
+
* top-level `node_modules` entry the closure serves at a COMPATIBLE version
|
|
443
|
+
* with a symlink into the closure (see `deps/closure-dedupe.ts` for the
|
|
444
|
+
* plan rules and the live measurements). Runs LAST in tree
|
|
445
|
+
* materialisation — after the runtime-dep npm install AND the native-dep
|
|
446
|
+
* steps — so no later npm invocation can fight the links.
|
|
447
|
+
*
|
|
448
|
+
* Non-fatal by design: dedupe is an optimisation, and its failure mode is
|
|
449
|
+
* "the addon keeps its own copies", which is exactly today's behaviour. A
|
|
450
|
+
* refusal on version grounds is logged loudly — that line is the answer to
|
|
451
|
+
* "why does this addon still carry its own zod".
|
|
452
|
+
*/
|
|
453
|
+
private dedupeTreeAgainstClosure;
|
|
385
454
|
/** Install addon from a tgz file (uploaded or downloaded) */
|
|
386
455
|
installFromTgz(tgzPath: string): Promise<{
|
|
387
456
|
name: string;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { IScopedLogger } from '@camstack/types';
|
|
2
|
+
/**
|
|
3
|
+
* Does `version` satisfy `range`, for the range forms this module is willing
|
|
4
|
+
* to vouch for?
|
|
5
|
+
*
|
|
6
|
+
* Supported: exact (`1.2.3`, `=1.2.3`), caret (`^1.2.3`, incl. the 0.x rules)
|
|
7
|
+
* and tilde (`~1.2.3`). EVERYTHING else — `*`, `>=`, unions, hyphen ranges,
|
|
8
|
+
* dist-tags, bases with prereleases — returns false: an unprovable range must
|
|
9
|
+
* keep the addon's own copy, never borrow the closure's.
|
|
10
|
+
*
|
|
11
|
+
* A prerelease `version` satisfies only an exact string match — semver range
|
|
12
|
+
* semantics around prereleases are precisely the kind of subtlety a
|
|
13
|
+
* hand-rolled parser must refuse rather than approximate.
|
|
14
|
+
*/
|
|
15
|
+
export declare function closureSatisfiesRange(range: string, version: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Belt over the range check: the closure copy must live in the same major
|
|
18
|
+
* line as the copy npm actually materialised (same minor while major is 0).
|
|
19
|
+
* The range check should already guarantee this; if the two ever disagree
|
|
20
|
+
* the safe answer is "do not link".
|
|
21
|
+
*/
|
|
22
|
+
export declare function sameCompatLine(a: string, b: string): boolean;
|
|
23
|
+
/** A real (non-symlink) top-level entry of an addon's node_modules. */
|
|
24
|
+
export interface DedupeCandidate {
|
|
25
|
+
readonly name: string;
|
|
26
|
+
readonly version: string;
|
|
27
|
+
}
|
|
28
|
+
export type ClosureKeepReason = 'camstack-package' | 'never-link' | 'not-in-closure' | 'version-incompatible';
|
|
29
|
+
export interface ClosureLink {
|
|
30
|
+
readonly name: string;
|
|
31
|
+
readonly closureVersion: string;
|
|
32
|
+
}
|
|
33
|
+
export interface ClosureKeep {
|
|
34
|
+
readonly name: string;
|
|
35
|
+
readonly reason: ClosureKeepReason;
|
|
36
|
+
}
|
|
37
|
+
export interface ClosureDedupePlan {
|
|
38
|
+
readonly links: readonly ClosureLink[];
|
|
39
|
+
readonly keeps: readonly ClosureKeep[];
|
|
40
|
+
}
|
|
41
|
+
export interface ClosureDedupeInput {
|
|
42
|
+
readonly candidates: readonly DedupeCandidate[];
|
|
43
|
+
/** name → version installed in the server closure's node_modules. */
|
|
44
|
+
readonly closureVersions: ReadonlyMap<string, string>;
|
|
45
|
+
/**
|
|
46
|
+
* name → every requirement range the addon tree records for it (the addon's
|
|
47
|
+
* own manifest + every dependent that resolves to the top-level copy).
|
|
48
|
+
*/
|
|
49
|
+
readonly requirements: ReadonlyMap<string, readonly string[]>;
|
|
50
|
+
/** Names that must never be linked (e.g. `camstack.nativeDependencies`). */
|
|
51
|
+
readonly neverLink: ReadonlySet<string>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Decide, per top-level entry, whether the closure's copy can serve in place
|
|
55
|
+
* of the addon's own. Identical versions always link; otherwise every
|
|
56
|
+
* recorded requirement range must accept the closure version, and the two
|
|
57
|
+
* copies must share a compat line. Anything unprovable keeps the local copy.
|
|
58
|
+
*/
|
|
59
|
+
export declare function planClosureDedupe(input: ClosureDedupeInput): ClosureDedupePlan;
|
|
60
|
+
export interface AddonTreeState {
|
|
61
|
+
/** Real directories eligible for linking (symlinks are excluded). */
|
|
62
|
+
readonly candidates: readonly DedupeCandidate[];
|
|
63
|
+
/** name → requirement ranges collected across the tree. */
|
|
64
|
+
readonly requirements: ReadonlyMap<string, readonly string[]>;
|
|
65
|
+
/** Top-level entries that are already symlinks (with their targets). */
|
|
66
|
+
readonly existingLinks: readonly {
|
|
67
|
+
readonly name: string;
|
|
68
|
+
readonly target: string;
|
|
69
|
+
}[];
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Read an addon tree's dedupe-relevant state: which top-level packages exist
|
|
73
|
+
* (and their versions), and which requirement ranges apply to each. A
|
|
74
|
+
* dependent's range for `X` is recorded only when that dependent resolves to
|
|
75
|
+
* the TOP-LEVEL `X` — a nested override copy (`dep/node_modules/X`) means the
|
|
76
|
+
* flat copy is not what that dependent loads, so its range must not block the
|
|
77
|
+
* flat copy's dedupe.
|
|
78
|
+
*/
|
|
79
|
+
export declare function collectAddonTreeState(addonDir: string): AddonTreeState;
|
|
80
|
+
/** Read `name → version` from a closure node_modules for the given names. */
|
|
81
|
+
export declare function readClosureVersions(closureNodeModulesDir: string, names: Iterable<string>): Map<string, string>;
|
|
82
|
+
/**
|
|
83
|
+
* Where the running node's server closure keeps its node_modules, or null
|
|
84
|
+
* when there is none to dedupe against (dev workspace, tests without a
|
|
85
|
+
* closure). `CAMSTACK_FRAMEWORK_DIR` is set by the starter/launcher on every
|
|
86
|
+
* deployed node — the same directory the framework resolver hook and
|
|
87
|
+
* NODE_PATH extension already point at.
|
|
88
|
+
*/
|
|
89
|
+
export declare function resolveClosureNodeModulesDir(explicitDir: string | undefined): string | null;
|
|
90
|
+
/**
|
|
91
|
+
* Replace each planned entry with a symlink into the closure. Probes symlink
|
|
92
|
+
* support once (Windows without developer mode cannot create them — in that
|
|
93
|
+
* case every copy is kept, which is exactly today's behaviour). Each link
|
|
94
|
+
* re-verifies the closure version right before the swap so a closure updated
|
|
95
|
+
* mid-flight can only cause a KEEP, never a wrong link.
|
|
96
|
+
*
|
|
97
|
+
* Returns the names actually linked.
|
|
98
|
+
*/
|
|
99
|
+
export declare function executeClosureDedupe(addonDir: string, closureNodeModulesDir: string, plan: ClosureDedupePlan, logger: IScopedLogger): readonly string[];
|
|
100
|
+
/**
|
|
101
|
+
* Is `linkTarget` (as read from `readlink`) a path inside the closure's
|
|
102
|
+
* node_modules? Only such links belong to this mechanism — workspace/npm
|
|
103
|
+
* `file:` links must never be touched by dedupe maintenance.
|
|
104
|
+
*/
|
|
105
|
+
export declare function isClosureLinkTarget(linkTarget: string, closureNodeModulesDir: string): boolean;
|