Plugins#

Extend BunTok apps with isolated, named plugins. Plugins can add middleware, routes, context properties, or any other functionality to the app.

Imports#

typescript
import { createPlugin } from "@buntok/core";
import type { Plugin } from "@buntok/core";

Plugin Interface#

typescript
interface Plugin<DI extends Record<string, unknown> = Record<string, unknown>> {
  name: string;
  install: (app: App<DI>) => void | Promise<void>;
}
  • name — unique identifier, used for dedup (same name = install once only)
  • install(app) — receives the app instance, can be async
  • DI generic — constrains the app's dependency injection type

Creating a Plugin#

Simple plugin — add middleware#

typescript
const loggerPlugin = createPlugin({
  name: "logger",
  install: (app) => {
    app.use(async (ctx, next) => {
      const start = Date.now();
      await next();
      const ms = Date.now() - start;
      console.log(`${ctx.request.method} ${ctx.request.url} - ${ms}ms`);
    });
  },
});

Plugin with routes#

typescript
const healthPlugin = createPlugin({
  name: "health",
  install: (app) => {
    app.get("/health", () => ({ status: "ok", timestamp: Date.now() }));
    app.get("/health/ready", () => ({ ready: true }));
  },
});

Plugin with async dependencies (lazy import)#

typescript
const authPlugin = createPlugin({
  name: "@buntok/auth",
  install: async (app) => {
    // Lazy import — zero startup cost if plugin not installed
    const { JwtService } = await import("@buntok/core");
    const jwt = new JwtService(process.env.JWT_SECRET!);
    app.use(requireAuth(jwt));
  },
});

Installing Plugins#

typescript
app.plugin(loggerPlugin);
app.plugin(healthPlugin);
Info
  • Dedup by name — installing same plugin twice is a no-op
  • install() runs immediately when app.plugin() is called
  • Async install() is awaited — server won't start until all plugins finish
  • Installed names tracked in app.installedPlugins (Set)

Checking Installed Plugins#

typescript
if (app.installedPlugins.has("logger")) {
  console.log("Logger plugin is installed");
}

Plugin Order Matters#

Plugins run in order of app.plugin() calls. Middleware added by earlier plugins runs before later ones:

typescript
app.plugin(corsPlugin);    // CORS runs first
app.plugin(authPlugin);    // Auth runs second
app.plugin(loggerPlugin);  // Logger runs third