exisjs/plugin
The exisjs/plugin module provides tools and interfaces for authoring, typing, and distributing reusable ExisJS plugins, middleware packages, and third-party integrations.
Module Exports
import { definePlugin } from 'exisjs/plugin'import type { ExisPlugin, ExisPluginInstance, HookReady, HookClose, HookRequest, HookResponse, HookError, HookRoute,} from 'exisjs/plugin'1. definePlugin(plugin)
The definePlugin helper wraps a plugin definition object and returns a hybrid callable object. This allows developers to register the plugin directly without options (app.register(myPlugin)) or invoke it as a factory function to pass configuration parameters (app.register(myPlugin({ apiKey: '...' }))).
function definePlugin<TOptions = Record<string, unknown>>( plugin: ExisPlugin<TOptions>): ExisPlugin<TOptions> & ((options?: TOptions) => ExisPluginInstance)Parameters
| Parameter | Type | Description |
|---|---|---|
plugin | ExisPlugin<TOptions> | Object conforming to the ExisPlugin specification. |
2. ExisPlugin<TOptions> Interface
The core specification contract for all plugins:
| Property | Type | Default | Description |
|---|---|---|---|
name | string | (Required) | Unique identifier for the plugin. Used to detect duplicate registrations. |
register | (app: App, options?: TOptions) => void | Promise<void> | (Required) | Lifecycle method executed during app.register(). |
version | string | undefined | Semantic version string of the plugin package. |
dependencies | string[] | [] | List of required plugin names that must be registered before this plugin boots. |
encapsulate | boolean | false | When true, creates an isolated sub-router and dependency scope. |
3. Authoring Plugins
Basic Plugin
src/plugins/request-logger.plugin.ts
import { definePlugin } from 'exisjs/plugin'
export const requestLoggerPlugin = definePlugin({ name: 'custom-request-logger', version: '1.0.0',
async register(app) { app.use((req, res, next) => { app.log.info({ method: req.method, url: req.url }, 'Incoming request') next() }) },})Configurable Generic Plugin with Lifecycle Teardown
src/plugins/database.plugin.ts
import { definePlugin } from 'exisjs/plugin'import { Pool } from 'pg'
export interface DatabasePluginOptions { connectionString: string maxConnections?: number}
export const databasePlugin = definePlugin<DatabasePluginOptions>({ name: 'postgres-database-plugin', version: '1.2.0',
async register(app, options) { if (!options?.connectionString) { throw new Error('[databasePlugin] "connectionString" is required') }
const pool = new Pool({ connectionString: options.connectionString, max: options.maxConnections ?? 10, })
await pool.connect()
// Provide database pool to the DI container app.provide('DB_POOL', { useValue: pool })
// Register graceful shutdown hook app.onClose(async () => { await pool.end() }) },})Plugin with Dependencies
src/plugins/auth.plugin.ts
import { definePlugin } from 'exisjs/plugin'
export const authPlugin = definePlugin({ name: 'auth-plugin', dependencies: ['postgres-database-plugin'], // Guarantees DB is registered first
async register(app) { const db = app.resolve('DB_POOL') app.provide('AuthService', { useFactory: () => new AuthService(db), }) },})4. Registering Plugins in Applications
Plugins can be registered in src/http/server.ts using app.register() or statically declared in exis.config.ts:
In src/http/server.ts
src/http/server.ts
import { exis } from 'exisjs'import { databasePlugin } from '../plugins/database.plugin'import { authPlugin } from '../plugins/auth.plugin'
export default exis({ async onStart(app) { await app.register( databasePlugin({ connectionString: process.env.DATABASE_URL!, maxConnections: 20, }) ) await app.register(authPlugin) },})In exis.config.ts
exis.config.ts
import { defineConfig } from 'exisjs/config'import { databasePlugin } from './src/plugins/database.plugin'import { authPlugin } from './src/plugins/auth.plugin'
export default defineConfig({ plugins: [ databasePlugin({ connectionString: process.env.DATABASE_URL!, }), authPlugin, ],})