Plugin Architecture
Stratix uses a plugin-based architecture for extensibility and modularity.
Why Plugins?​
- ✅ Modularity - Add only what you need
- ✅ Extensibility - Create custom plugins
- ✅ Dependency Management - Automatic plugin ordering
- ✅ Lifecycle Management - Initialize, start, stop hooks
- ✅ Type Safety - Strongly typed plugin contracts
Plugin Interface​
import { Plugin, PluginContext } from '@stratix/core';
export interface Plugin {
readonly metadata: PluginMetadata;
initialize?(context: PluginContext): Promise<void>;
start?(context: PluginContext): Promise<void>;
stop?(): Promise<void>;
healthCheck?(): Promise<HealthCheckResult>;
}
Plugin Metadata​
export interface PluginMetadata {
name: string;
version: string;
description?: string;
dependencies?: string[];
optionalDependencies?: string[];
}
Basic Plugin Example​
import { Plugin, PluginContext } from '@stratix/core';
export class MyPlugin implements Plugin {
readonly metadata = {
name: 'my-plugin',
version: '1.0.0',
description: 'My custom plugin'
};
async initialize(context: PluginContext): Promise<void> {
console.log('Plugin initializing...');
// Register services in container
context.container.register('myService', () => new MyService());
}
async start(context: PluginContext): Promise<void> {
console.log('Plugin starting...');
}
async stop(): Promise<void> {
console.log('Plugin stopping...');
}
async healthCheck(): Promise<HealthCheckResult> {
return {
status: 'healthy',
details: { uptime: process.uptime() }
};
}
}
Plugin Lifecycle​
1. Register​
const app = await ApplicationBuilder.create()
.usePlugin(new MyPlugin())
.build();
2. Initialize​
Called once during application startup:
async initialize(context: PluginContext): Promise<void> {
// Register services
context.container.register('service', () => new Service());
// Load configuration
const config = context.getConfig<MyConfig>();
// Set up resources
this.connection = await createConnection(config);
}
3. Start​
Called after all plugins are initialized:
async start(context: PluginContext): Promise<void> {
// Start servers
await this.server.listen(3000);
// Subscribe to events
context.eventBus.subscribe('user.created', this.handleUserCreated);
}
4. Stop​
Called during graceful shutdown:
async stop(): Promise<void> {
// Close connections
await this.connection.close();
// Stop servers
await this.server.close();
}
Plugin Dependencies​
Plugins can depend on other plugins:
export class DatabasePlugin implements Plugin {
readonly metadata = {
name: 'database',
version: '1.0.0',
dependencies: ['logger'] // Requires logger plugin
};
}
export class CachePlugin implements Plugin {
readonly metadata = {
name: 'cache',
version: '1.0.0',
dependencies: ['database'], // Requires database plugin
optionalDependencies: ['logger'] // Optional logger
};
}
Initialization order:
logger(no dependencies)database(depends on logger)cache(depends on database)
Plugin Context​
The PluginContext provides access to:
interface PluginContext {
container: Container;
logger: Logger;
eventBus: EventBus;
getConfig<T>(): T;
}
Container​
Register and resolve services:
async initialize(context: PluginContext): Promise<void> {
context.container.register('database', () => new Database());
const db = context.container.resolve('database');
}
Logger​
Log messages:
async start(context: PluginContext): Promise<void> {
context.logger.info('Plugin started');
context.logger.error('Error occurred', error);
}
Event Bus​
Publish and subscribe to events:
async start(context: PluginContext): Promise<void> {
context.eventBus.subscribe('user.created', async (event) => {
context.logger.info('User created', event);
});
}
Configuration​
Get plugin configuration:
async initialize(context: PluginContext): Promise<void> {
const config = context.getConfig<DatabaseConfig>();
this.connection = await connect(config);
}
Real-World Example: HTTP Plugin​
import { Plugin, PluginContext } from '@stratix/core';
import Fastify, { FastifyInstance } from 'fastify';
export interface HTTPPluginConfig {
port: number;
host?: string;
}
export class HTTPPlugin implements Plugin {
readonly metadata = {
name: 'http',
version: '1.0.0',
description: 'HTTP server plugin',
dependencies: ['logger']
};
private server?: FastifyInstance;
async initialize(context: PluginContext): Promise<void> {
const config = context.getConfig<HTTPPluginConfig>();
this.server = Fastify({
logger: false // Use Stratix logger instead
});
// Register routes
this.server.get('/health', async () => ({
status: 'healthy'
}));
context.logger.info('HTTP plugin initialized');
}
async start(context: PluginContext): Promise<void> {
const config = context.getConfig<HTTPPluginConfig>();
await this.server!.listen({
port: config.port,
host: config.host || '0.0.0.0'
});
context.logger.info(`HTTP server listening on port ${config.port}`);
}
async stop(): Promise<void> {
await this.server?.close();
}
async healthCheck(): Promise<HealthCheckResult> {
return {
status: this.server ? 'healthy' : 'unhealthy',
details: {
port: this.server?.server.address()
}
};
}
}
Best Practices​
1. Clear Metadata​
readonly metadata = {
name: 'my-plugin',
version: '1.0.0',
description: 'What this plugin does'
};
2. Declare Dependencies​
readonly metadata = {
name: 'cache',
dependencies: ['database'],
optionalDependencies: ['logger']
};
3. Graceful Shutdown​
async stop(): Promise<void> {
await this.connection?.close();
await this.server?.close();
}
4. Health Checks​
async healthCheck(): Promise<HealthCheckResult> {
try {
await this.connection.ping();
return { status: 'healthy' };
} catch (error) {
return { status: 'unhealthy', error: error.message };
}
}
Next Steps​
- Creating Plugins - Build your own
- Official Plugins - Available plugins
- Plugin Configuration - Configuration guide