Plugins Overview
Extend services and resources with modular plugins, typed APIs, and scoped routes.
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():
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.
// 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.dbat 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
| Field | Type | Description |
|---|---|---|
id | text | Page identifier. PK |