Skip to content

Writing Plugins

Plugins let you extend SIMPLICITY-ADMIN by hooking into lifecycle events. A plugin is an object that implements one or more lifecycle hooks.

import type { Plugin } from '@mabulu-inc/simplicity-admin-core';
const myPlugin: Plugin = {
name: 'my-plugin',
onInit(config) { /* ... */ },
onSchemaLoaded(schema) { /* ... */ },
onReady() { /* ... */ },
onRequest(req, res) { /* ... */ },
onShutdown() { /* ... */ },
};

All hooks are optional. Implement only the ones you need.

Fires after configuration is validated, before any database connections. Receives the resolved config object. Use this for early setup or config validation.

Fires after database introspection completes. Receives the SchemaMeta object. You can transform the metadata here — add computed columns, hide tables, modify relations. Return the modified schema to pass it downstream.

onSchemaLoaded(schema) {
// Hide internal tables from the admin UI
schema.tables = schema.tables.filter(t => !t.name.startsWith('_internal'));
return schema;
},

Fires after all providers are initialized and the server is ready to accept requests. Use this for startup notifications, health check registration, or warm-up tasks.

Fires on every incoming HTTP request. Receives the request and response objects. Use this for logging, metrics, or request-level middleware.

Fires on graceful server shutdown. Use this to close external connections, flush buffers, or send shutdown notifications.

import type { Plugin } from '@mabulu-inc/simplicity-admin-core';
export function requestLogger(): Plugin {
return {
name: 'request-logger',
onRequest(req) {
const start = Date.now();
req.on('finish', () => {
const duration = Date.now() - start;
console.log(`${req.method} ${req.url} ${res.statusCode} ${duration}ms`);
});
},
};
}

Add plugins to the plugins array in your config. Plugins execute in array order:

import { defineConfig } from '@mabulu-inc/simplicity-admin-core';
import { requestLogger } from './plugins/request-logger';
import { auditTrail } from './plugins/audit-trail';
export default defineConfig({
database: process.env.DATABASE_URL,
plugins: [
requestLogger(),
auditTrail(),
],
});

When multiple plugins implement the same hook, they execute in the order they appear in the plugins array. For onSchemaLoaded, each plugin receives the schema returned by the previous plugin, forming a transformation pipeline.