@lamstack/initializer
v0.1.0
Published
Framework-agnostic app-startup orchestrator core — run async init steps (with parallel batching, abort, and retry) before your app renders.
Maintainers
Readme
@lamstack/initializer
Framework-agnostic core of the lamstack app-startup orchestrator: createInitializer
runs a sequence of stages — a task, or several running concurrently via parallel([...])
— with retry, timeout, and critical/non-critical failure handling, and no dependency on
React or any other UI framework. Safe to import anywhere, including a Next.js Server
Component.
For a React app, use @lamstack/react-initializer instead — it
depends on this package and adds <Initializer>/useInitializer(), re-exporting
everything here from its own root so you only need one import.
Install
pnpm add @lamstack/initializerUsage
import { createInitializer, parallel } from '@lamstack/initializer';
import type { InitializationTask } from '@lamstack/initializer';
const initializeConfig: InitializationTask = {
id: 'config',
run: async ({ state }) => {
state.set('config', await loadConfig());
},
};
const initializer = createInitializer({ tasks: [initializeConfig] });
initializer.subscribe(() => console.log(initializer.getSnapshot()));
await initializer.run();
console.log(initializer.getState().get('config'));
// later, e.g. on unmount or navigation away:
initializer.abort();Concepts
- Stages run in order —
tasksis a list of stages, each either one task or aparallel([...])group; the run waits for a stage to fully settle before starting the next one. There's no dependency graph and nodependsOn— that's the whole ordering model. parallel(tasks, { concurrency? })— runs its tasks concurrently as a single stage.concurrencycaps how many run at once (e.g. to avoid firing 50 simultaneous requests) — omit it for no cap.critical— defaults totrue: a failing task aborts the whole run. Setcritical: falsefor work that must be attempted before render but can survive failing — the run continues to the next stage regardless.retry/retryDelay— total attempts (default 1, no retry), with an optional delay (a number, or(attempt) => msfor backoff) between them.timeout— max time in ms per attempt before it's treated as a failure — tripscontext.signalfor that specific attempt.condition— an optional async predicate; returningfalseskips the task.onStart/onSuccess/onError— optional per-task lifecycle callbacks, in addition to the run-wideonTaskStart/onTaskComplete/onTaskFailedevents passed tocreateInitializer.state— a shared key/value bag passed to every task via context ({ signal, state }), for passing data between tasks. ParameterizeInitializationTask<{ user: User }>(andcreateInitializer<{ user: User }>()) forstate.get/.setchecked and inferred per key instead ofunknown.
Debugging
Outside NODE_ENV=production, createInitializer logs a console.warn for a task with
retry set but no timeout, and for a critical: false task placed in its own
sequential stage. Call checkTasks(tasks) to get these as a plain string[] yourself.
License
MIT
