Skip to content
Moku LabsDocs
Concepts pages

Lifecycle

init, start, stop. Order, async model, failures.

lifecycle.mdllms.txt

Three phases

PhaseMethodDirectionWhenContext
initonInitforwardinside createApp(), synchronousfull ctx
startonStartforwardawait app.start()full ctx
stoponStopreverseawait app.stop()own global, config, state

Before the lifecycle, each plugin's factories run in this order:

  1. createState
  2. hooks
  3. api
  4. onInit
  5. onStart
  6. onStop

Async model

One plugin at a time, fully awaited. There is no parallelism inside or across phases: plugin A resolves before plugin B begins. createApp() is synchronous; start() and stop() return promises.

src/server.ts
import { createApp, createPlugin } from "@moku-labs/web";

const timerPlugin = createPlugin("timer", {
  createState: (): { handle?: ReturnType<typeof setInterval> } => ({}),
  onStart: ctx => {
    ctx.state.handle = setInterval(() => ctx.log.info("timer:tick"), 1000);
  },
  onStop: ctx => {
    clearInterval(ctx.state.handle);
  }
});

const app = createApp({
  plugins: [timerPlugin],
  pluginConfigs: { site: { name: "Demo", url: "https://example.com" } }
});

await app.start(); // onStart, forward, one plugin at a time
await app.stop(); // onStop, reverse: infrastructure outlives the plugins that use it
  1. Open a resource when the app starts.
  2. onStop gets its own state back, nothing else.

onStart and onStop are optional. Add them only when a plugin opens something it must close: a socket, a listener, a timer.

Failures

Lifecycle is not transactional. Errors propagate to the caller. The kernel does not roll back, retry or compensate. After a failure, discard the app and create a new one.

start() throws when called twice, and stop() throws when start() never ran. The exact messages are on What the kernel checks.

Core plugins

Core plugins have their own timeline: they init and start before regular plugins, and stop after them. ctx.log therefore works in every onStop of a regular plugin's teardown chain, and the logger is the last thing to go.

In @moku-labs/web

Most web plugins only use onInit: router compiles its table, site and i18n validate their config. spa is the one default with onStart and onStop, because it owns browser listeners.