73 lines
2.6 KiB
Markdown
73 lines
2.6 KiB
Markdown
# `reinstall-criteria`
|
|
|
|
<!-- begin:auto-docs -->
|
|
_(no submodules)_
|
|
<!-- end:auto-docs -->
|
|
|
|
## 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.Z` form, prerelease/build metadata ignored). The manifest
|
|
validator in `api-manifest` already rejects non-semver values, so this
|
|
is the only consumer.
|
|
- Throws `LIFECYCLE.REINSTALL_REQUIRED_VERSION_DOWNGRADE` with `prev` /
|
|
`next` versions in `error.context` for downgrade attempts.
|
|
|
|
## Usage: Basic
|
|
|
|
```ts
|
|
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:
|
|
|
|
```ts
|
|
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): boolean`
|
|
- `compareSemver(a: string, b: string): -1 | 0 | 1`
|
|
|
|
## Implementation Notes
|
|
|
|
The "added-items" detection uses `Set`s 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.
|