Skip to content

Adding a plugin

The closure form of definePlugin is the shortest path from "I need a cross-cutting concern" to "it's wired in". This recipe walks through a minimal audit-log plugin that binds a service, reacts to a framework event, runs on boot, and flushes on shutdown.

Define the plugin

ts
// app/plugins/audit-log.plugin.ts
import { definePlugin } from "@nwire/app"

interface AuditLog {
  entries: string[];
  record(line: string): void;
  flush(): Promise<void>;
}

export const auditLogPlugin = () =>
  definePlugin("audit-log", ({ bind, container, boot, dispose }) => {
    const log: AuditLog = {
      entries: [],
      record(line) { this.entries.push(line) },
      async flush() { /* ship to durable store */ },
    }
    bind("auditLog", log)

    boot(async () => {
      log.record("booting")
    })

    dispose(async () => {
      await log.flush()
    })
  })

Register it

ts
// app/app.ts
import { createApp } from "@nwire/app"
import { auditLogPlugin } from "./plugins/audit-log.plugin"

export const app = createApp({
  appName: "demo",
  plugins: [auditLogPlugin()],
})

To react to framework events, observe them inside the plugin via on — the payload is typed from the named hook:

ts
const auditLogPlugin = () =>
  definePlugin("audit-log", ({ bind, on }) => {
    const log = new AuditLog()
    bind("auditLog", () => log)
    on("AppBooted", ({ appName }) => log.record(`app booted: ${appName}`))
  })

Verify

bash
nwire ls plugins

You should see audit-log listed with its contributed surfaces (provides: auditLog, on: AppReady, boot, shutdown). If you don't, check that the plugin is in the plugins array and that nwire cache ran against the right topology.

See also

MIT licensed.