2.6 KiB
reinstall-criteria
(no submodules)
Purpose
Decides whether a manifest update from prev to next requires a full
reinstall path (uninstalled → installing → installed → starting → started)
versus a hot-reload (stopped → starting). The criteria mirror design §4
exactly: a schemaVersion bump, new scopes/events/jobs/secrets, or any
dependsOn diff force the full path; a strict version downgrade throws
LIFECYCLE.REINSTALL_REQUIRED_VERSION_DOWNGRADE because the ledger would
then point at a higher schemaVersion than the running code can satisfy.
Features
- Pure
requiresReinstall(prev, next): boolean— no I/O, no global state, no clock dependency. - Per-field detection of added items only (removals are intentionally not a reinstall trigger — the host can drop them in hot-reload).
- Embedded
compareSemver(a, b)implementing loose semver compare (X.Y.Zform, prerelease/build metadata ignored). The manifest validator inapi-manifestalready rejects non-semver values, so this is the only consumer. - Throws
LIFECYCLE.REINSTALL_REQUIRED_VERSION_DOWNGRADEwithprev/nextversions inerror.contextfor downgrade attempts.
Usage: Basic
import { requiresReinstall } from "@suaveplan/api-lifecycle/reinstall-criteria";
if (requiresReinstall(prev, next)) {
// walk the full install path
} else {
// hot reload via stopped → starting
}
Usage: Advanced
Wrapping the call in admin tooling that wants to surface the specific trigger reason:
import { compareSemver, requiresReinstall } from "@suaveplan/api-lifecycle/reinstall-criteria";
function explain(prev: PluginManifest, next: PluginManifest): string {
if (compareSemver(next.version, prev.version) < 0) return "version downgrade";
if ((next.database?.schemaVersion ?? 0) > (prev.database?.schemaVersion ?? 0)) {
return "schemaVersion bumped";
}
return requiresReinstall(prev, next) ? "manifest changed materially" : "hot reload OK";
}
API Reference
requiresReinstall(prev: PluginManifest, next: PluginManifest): booleancompareSemver(a: string, b: string): -1 | 0 | 1
Implementation Notes
The "added-items" detection uses Sets built from prev so the comparison
is O(n) per field. dependsOn is compared via a key-union walk so a
removed-but-then-readded dep with a different version is still caught.
Removing items intentionally does not trigger a reinstall — design §4
defines this as a hot-reload-safe operation; the host driver drops the
corresponding capability registrations in the installed → starting
side-effect chain.