brick.ts

Plugins Overview

Extend services and resources with modular plugins, typed APIs, and scoped routes.

llms.txt

Brick-TS provides modular plugin primitives—defineServicePlugin and defineResourcePlugin—to package reusable capabilities, custom endpoints, and typed resource extensions.

Minimal Example

Define a reusable service plugin that registers a health check action and install it with service.use():

src/plugins/ping.ts
import { defineServicePlugin, defineService, t } from "@brickkit/core";

// 1. Declare the plugin descriptor
export function pingPlugin(options: { endpointPath?: string } = {}) {
  return defineServicePlugin({
    name: "ping",
    setup({ routes }) {
      const ping = routes.action({
        name: "ping",
        method: "GET",
        path: options.endpointPath ?? "/ping",
        output: t.Object({ status: t.String(), timestamp: t.Number() }),
        execute: () => ({ status: "ok", timestamp: Date.now() }),
      });

      return { ping };
    },
  });
}

// 2. Install the plugin onto a service
const service = defineService("system");
const api = service.use(pingPlugin());

// The returned API is fully typed in TypeScript:
const result = await api.ping({});
console.log(result.status); // "ok"

Two Plugin Kinds

Brick-TS divides plugins into two distinct scopes:

1. Service Plugins (defineServicePlugin)

  • Installed with service.use(plugin).
  • Scope: Service-level capabilities (e.g. rate limiters, health endpoints, event emitters).
  • Returns a typed API object that becomes accessible to callers.

2. Resource Plugins (defineResourcePlugin)

  • Installed with resource.use(plugin).
  • Scope: Table-level capabilities (e.g. @brickkit/crud, comments, audit logs, file attachments).
  • Receives { resource, service, routes } and attaches properties directly onto the host resource.
src/example-resource-plugin.ts
// Attaching CRUD plugin to a resource:
const page = service
  .resource({ name: "page", table: pages, id: pages.id })
  .use(crud({ access: "public", fields: { id: { read: true } } }));

Plugin Lifecycle & Guarantees

All plugins follow strict design rules:

  • Synchronous Registration: The setup() function must be synchronous. Plugins register actions, routes, and hooks before the server compiles.
  • Connection Isolation: Plugins do not open database pools or mutate schemas during setup. Database connections flow through ctx.db at runtime.
  • Namespaced Actions: Actions registered by plugins stay scoped to their host resource or service, preventing naming collisions.

Schema

The ping service plugin requires no database table. The resource-plugin example requires a host table; its CRUD field policy exposes only id.

Table Name: pages

FieldTypeDescription
idtextPage identifier. PK