Update Notifier
Check npm for a newer stable version after a command succeeds.
Usage
import { Crust } from "@crustjs/core";
import { updateNotifier } from "@crustjs/extensions";
const app = new Crust("my-cli", { version: "1.2.3" })
.extend(
updateNotifier({
packageName: "my-cli",
updateCommand: { scope: "global" },
}),
)
.action(({ stdout }) => stdout("Done"));
await app.execute();
When the registry reports version 2.0.0, combined stdout and stderr show the completed action followed by this notice:
Done
╭──────────────────────────────────────╮
│ │
│ Update available 1.2.3 → 2.0.0 │
│ Run npm install -g my-cli@latest │
│ │
╰──────────────────────────────────────╯The hook checks only after a completed Command Action. Network, registry, cache, and response failures do not change a successful outcome.
API
const updateNotifier: ExtensionFactory<[options: UpdateNotifierOptions]>;| Option | Type | Default |
|---|---|---|
packageName | string | Required |
currentVersion | string | Root command meta.version |
timeoutMs | number | 5_000 |
registryUrl | string | "https://registry.npmjs.org" |
updateCommand | string | UpdateCommandResolver | { scope: "global" | "local" } | No command |
updateDocsUrl | string | No URL |
cache | false | UpdateNotifierCacheConfig | Built-in cache, 24-hour interval |
The current version must come from currentVersion or root metadata. If neither exists, the hook throws DEFINITION before network or cache work.
The network timeout does not bound cache operations or the whole hook. Version comparison follows SemVer precedence, and notices for the same latest version are suppressed across sequential cached invocations.
Update command
updateNotifier({
packageName: "my-cli",
updateCommand: { scope: "global" },
});A string displays a fixed command. A resolver receives { packageName, packageManager }, while a scope creates the standard command for npm, pnpm, Yarn, or Bun.
updateNotifier({
packageName: "my-cli",
updateCommand: ({ packageName, packageManager }) => `${packageManager} run update-${packageName}`,
});Package-manager detection checks npm_config_user_agent, then npm_execpath, then the runtime executable name, and defaults to npm. Yarn global updates use npm install -g <package>@latest.
Cache
updateNotifier({
packageName: "my-cli",
cache: { intervalMs: 60 * 60 * 1000 },
});The default adapter stores state under the package's platform state directory. Set cache: false to skip all cache reads and writes.
import {
updateNotifier,
type UpdateNotifierCacheAdapter,
type UpdateNotifierState,
} from "@crustjs/extensions";
let state: UpdateNotifierState | undefined;
const adapter: UpdateNotifierCacheAdapter = {
read: async () => state,
write: async (nextState) => {
state = nextState;
},
};
updateNotifier({ packageName: "my-cli", cache: { adapter } });
A custom adapter reads UpdateNotifierState | null | undefined and writes UpdateNotifierState. Adapter failures are treated as soft failures.