Skip to Content
InitializerAPI Reference

API Reference

InitializationTask

A single task — one stage, or one member of a parallel([...]) stage.

interface InitializationTask<S extends StateMap = StateMap> { id: string; label?: string; critical?: boolean; // default true retry?: number; // total attempts, default 1 retryDelay?: number | ((attempt: number) => number); // ms, default 0 timeout?: number; // ms, per attempt condition?: (context: InitializationContext<S>) => boolean | Promise<boolean>; run: (context: InitializationContext<S>) => void | Promise<void>; }
FieldTypeDescription
idstringUniquely identifies the task — used for tracking and error reporting. Must be unique across the whole tasks list.
labelstringHuman-readable name for UI (splash/error screens), surfaced on TaskSnapshot. Falls back to id if unset.
criticalbooleanDefaults to true. false lets the task fail without halting the run — see Concepts.
retrynumberTotal attempts (default 1, no retry).
retryDelaynumber | ((attempt) => number)Delay in ms before each retry (not before the first attempt, not after the last). A function receives the 1-based attempt that just failed. Defaults to 0.
timeoutnumberMax ms per attempt before it’s treated as a failure (InitializerTimeoutError) — trips context.signal for that attempt.
condition(context) => boolean | Promise<boolean>Returning false skips the task — the only source of 'skipped'. A throw is treated as a failure.
run(context) => void | Promise<void>The task’s work. May be synchronous.

InitializationContext

Passed to every run/condition call.

interface InitializationContext<S extends StateMap = StateMap> { signal: AbortSignal; state: InitializationState<S>; }

InitializationState

The shared key/value bag at context.state, one instance per run — also readable after the run completes, via InitializerHandle.getState() / useInitializer().getState() / the onComplete event.

interface InitializationState<S extends StateMap = StateMap> { get<K extends keyof S>(key: K): S[K] | undefined; set<K extends keyof S>(key: K, value: S[K]): void; has(key: keyof S): boolean; }

Parameterize with a StateMap (e.g. InitializationState<{ user: User }>, inferred automatically from InitializationTask<{ user: User }> / createInitializer<{ user: User }>() / <Initializer<{ user: User }>>) to get get/set checked and inferred per key instead of unknown-typed.

parallel()

function parallel<S extends StateMap = StateMap>( tasks: InitializationTask<S>[], options?: { concurrency?: number }, ): ParallelGroup<S>;

Wraps tasks into a single stage that runs them all concurrently — the run waits for the whole stage to settle before starting the next one. concurrency caps how many of the stage’s tasks run at once (e.g. to avoid firing 50 simultaneous requests); omit it for no cap.

<Initializer>

import { Initializer } from '@lamstack/react-initializer'; <Initializer tasks={tasks} splashScreen={MySplashScreen} errorScreen={MyErrorScreen} cancelledScreen={MyCancelledScreen} minSplashDuration={300} onTaskStart={(task) => logger.info(`Starting ${task.id}`)} onTaskFailed={(task, error) => logger.error(task.id, error)} > <App /> </Initializer>;
PropTypeDescription
tasksTaskEntry<S>[]Required. InitializationTasks and/or parallel([...]) stages, run in order. Only read at the moment a run (re)starts — mount, or after retry().
splashScreenComponentType<SplashScreenProps>Shown while any task is pending/running. Defaults to a plain built-in screen.
errorScreenComponentType<ErrorScreenProps>Shown when a critical task fails. Defaults to a plain built-in screen with a “Retry” button.
cancelledScreenComponentType<CancelledScreenProps>Shown when the run was cancelled via abort(). Defaults to a plain built-in screen with a “Retry” button.
minSplashDurationnumberKeeps the splash up for at least this many ms once shown, even if the run settles sooner. Defaults to 0.
childrenReactNodeRendered once every task has settled successfully (status === 'completed').
onTaskStart(task) => voidFires when a task begins running (after its condition check passes).
onTaskComplete(task) => voidFires when a task succeeds.
onTaskFailed(task, error) => voidFires when a task’s final attempt fails (after retries are exhausted).
onComplete(state: InitializationState<S>) => voidFires once, when every task has settled with no critical failure — with the final shared state.
onError(error: InitializationError) => voidFires once, with the first critical failure that halted the run.
onAbort() => voidFires when abort() is called manually (not from a critical failure).

SplashScreenProps

interface SplashScreenProps { progress: number; // 0-100 tasks: TaskSnapshot[]; }

ErrorScreenProps

interface ErrorScreenProps { error: InitializationError; retry: () => void; }

CancelledScreenProps

interface CancelledScreenProps { retry: () => void; }

useInitializer()

Must be called from a component rendered under <Initializer>.

const { status, progress, tasks, error, retry, abort, getState } = useInitializer<S>();
MemberTypeDescription
statusInitializationStatus'idle' | 'running' | 'completed' | 'failed' | 'cancelled'.
progressnumberPercentage of tasks that have settled (0-100).
tasksTaskSnapshot[]Per-task status, in declaration order.
errorInitializationError | nullThe critical failure that halted the run, if any.
retry() => voidRestarts the whole run from the beginning (a fresh run, fresh state, fresh AbortController).
abort() => voidAborts the run in progress.
getState() => InitializationState<S>The shared state bag. Only reliably complete once status is 'completed'.

createInitializer()

The framework-independent core, used by <Initializer> internally and usable directly outside of React — also re-exported from @lamstack/react-initializer for convenience.

import { createInitializer } from '@lamstack/initializer'; const initializer = createInitializer({ tasks, onError: reportToSentry }); const unsubscribe = initializer.subscribe(() => { console.log(initializer.getSnapshot()); }); await initializer.run(); // later: console.log(initializer.getState().get('user')); initializer.abort(); unsubscribe();
MemberSignatureDescription
run() => Promise<void>Starts the run. tasks is validated synchronously inside createInitializer() itself — a duplicate id throws immediately, before run() is ever called. Calling run() more than once is a no-op.
abort() => voidAborts the run in progress.
getSnapshot() => InitializerSnapshotThe current { status, progress, tasks, error }.
getState() => InitializationState<S>The shared state bag. Only reliably complete once getSnapshot().status is 'completed'.
subscribe(listener: () => void) => () => voidRegisters a listener called on every snapshot change; returns an unsubscribe function.

Other types

type InitializationStatus = 'idle' | 'running' | 'completed' | 'failed' | 'cancelled'; type InitializationTaskStatus = | 'pending' | 'running' | 'completed' | 'failed' | 'skipped' | 'cancelled'; interface TaskSnapshot { id: string; label?: string; status: InitializationTaskStatus; critical: boolean; error?: unknown; // set for BOTH critical and non-critical failures durationMs?: number; // set once settled as 'completed' or 'failed' } interface InitializationError { taskId: string; error: unknown; } interface InitializerSnapshot { status: InitializationStatus; progress: number; tasks: TaskSnapshot[]; error: InitializationError | null; }

InitializerTimeoutError (extends Error) is thrown internally when a task exceeds its timeout — check error.error instanceof InitializerTimeoutError in onTaskFailed/ onError to distinguish a timeout from any other failure.

Dev-mode diagnostics

Outside NODE_ENV=production, createInitializer logs a console.warn for a task with retry but no timeout, and for a critical: false task placed in its own sequential stage (its failure won’t block the run, but the next stage still waits for it to settle). Call checkTasks(tasks) yourself to get these as a plain string[] — e.g. to assert on in a test, or run as a lint script — instead of relying on the console.

Last updated on