Skip to content

L3 — + App (plugin lifecycle)

L2 + @nwire/app for the plugin lifecycle: provide / on / boot / shutdown. This is the layer where the framework starts being a framework.

What you add

bash
pnpm add @nwire/app

The shape

ts
import { httpInterface, endpoint } from "@nwire/http"
import { createApp, definePlugin } from "@nwire/app"
import { token } from "@nwire/container"
import { z } from "zod"

const Db = token<{ query(sql: string): Promise<unknown[]>; close(): Promise<void> }>("Db")

const dbPlugin = definePlugin("db", ({ provide, on, boot, shutdown }) => {
  let connection: { query: typeof Db.T["query"]; close: () => Promise<void> }

  provide(Db, () => connection)

  boot(async () => {
    connection = await openDb()
  })

  shutdown(async () => {
    await connection.close()
  })

  on("AppBooted", () => console.log("db ready"))
})

const app = await createApp({ plugins: [dbPlugin] })

const api = httpInterface({ container: app.container })
api.get("/users", ({ resolve }) => resolve(Db).query("select * from users"))

await endpoint("api", { port: 3000 }).serve(api).run({ app })

What's new vs L2

  • definePlugin(name, closure) packages bindings + lifecycle hooks together.
  • boot(fn) runs once at startup. Plugins boot in dependency order.
  • shutdown(fn) runs once at shutdown — in reverse boot order, so resources unwind in the correct sequence.
  • on("AppBooted", fn) subscribes to framework events. See the full list in framework events.
  • provide(Token, factory) registers a binding without the imperative container.provideX calls.

When to stay at L3

  • Your domain is shaped like REST + a database.
  • You don't need state machines, event sourcing, projections, or workflows.
  • You're happy hand-rolling cross-cutting concerns (audit log, multi-tenancy, retries).

When to climb to L4

When the domain has rich state (a submission goes through submitted → graded → reviewed), or when you want one event to fan out to multiple consumers, or when you want a step to run two days after another step, climb to L4 and pull in @nwire/forge.

Next

MIT licensed.