Plugins Guide
Plugins Guide
Section titled “Plugins Guide”Learn how to use and create plugins for Veloce.
Table of Contents
Section titled “Table of Contents”Introduction
Section titled “Introduction”Veloce’s plugin system allows you to extend the framework with additional functionality. Plugins can add routes, middleware, modify the application, and integrate with external services.
Plugin Interface
Section titled “Plugin Interface”interface Plugin { name: string; version?: string; dependencies?: string[]; install(app: Veloce): void | Promise<void>;}Built-in Plugins
Section titled “Built-in Plugins”Veloce-TS v0.2.6 includes several powerful built-in plugins:
1. Authentication Plugin
Section titled “1. Authentication Plugin”JWT-based authentication with refresh tokens and user management.
import { VeloceTS, AuthPlugin } from 'veloce-ts';
const app = new VeloceTS();
app.install('auth', { jwt: { secret: 'your-secret-key', accessTokenTTL: 3600, // 1 hour refreshTokenTTL: 86400, // 24 hours }, userProvider: { findByCredentials: async (username: string, password: string) => { // Your user lookup logic }, findById: async (id: string) => { // Your user lookup logic }, hashPassword: async (password: string) => { // Your password hashing logic }, verifyPassword: async (password: string, hash: string) => { // Your password verification logic } }});2. RBAC Plugin
Section titled “2. RBAC Plugin”Role-Based Access Control with hierarchical roles and permissions.
import { VeloceTS, RBACPlugin } from 'veloce-ts';
const app = new VeloceTS();
app.install('rbac', { roles: [ { name: 'admin', level: 100 }, { name: 'manager', level: 80 }, { name: 'developer', level: 60 }, { name: 'viewer', level: 20 } ], permissions: [ 'users.create', 'users.read', 'users.update', 'users.delete', 'tasks.create', 'tasks.read', 'tasks.update', 'tasks.delete' ]});3. GraphQL Plugin
Section titled “3. GraphQL Plugin”Full GraphQL support with schema generation and introspection.
import { VeloceTS } from 'veloce-ts';
const app = new VeloceTS();
app.install('graphql', { path: '/graphql', playground: true, introspection: true});4. WebSocket Plugin
Section titled “4. WebSocket Plugin”Real-time communication with WebSocket support.
import { VeloceTS } from 'veloce-ts';
const app = new VeloceTS();
app.install('websocket', { path: '/ws'});5. OpenAPI Plugin
Section titled “5. OpenAPI Plugin”Generates OpenAPI documentation automatically from your routes.
import { VeloceTS } from 'veloce-ts';
const app = new VeloceTS();
app.install('openapi', { path: '/openapi.json', docsPath: '/docs', title: 'My API', version: '1.0.0', description: 'API description',}));Using Authentication & RBAC Decorators
Section titled “Using Authentication & RBAC Decorators”Once you’ve installed the auth and RBAC plugins, you can use the decorators:
import { Controller, Get, Post, Auth, CurrentUser, MinimumRole, Permissions} from 'veloce-ts';
@Controller('/api/users')export class UserController {
// Require authentication @Get('/profile') @Auth() async getProfile(@CurrentUser() user: any) { return user; }
// Require specific role level @Get('/admin-only') @MinimumRole('admin') async adminOnly() { return { message: 'Admin access granted' }; }
// Require specific permissions @Post('/') @Permissions('users.create') async createUser(@Body() userData: any) { return { message: 'User created', user: userData }; }
// Multiple permissions (user needs ALL) @Put('/:id') @Permissions('users.update', 'users.read') async updateUser(@Param('id') id: string, @Body() userData: any) { return { message: 'User updated', id, user: userData }; }}Available Decorators:
@Auth()- Requires valid JWT token@CurrentUser()- Injects current authenticated user@MinimumRole(roleName)- Requires minimum role level@Permissions(...perms)- Requires specific permissions
Options:
path: Path to serve OpenAPI JSON spec (default:/openapi.json)docsPath: Path to serve Swagger UI (default:/docs)title: API titleversion: API versiondescription: API description
Access:
- Swagger UI:
http://localhost:3000/docs - OpenAPI Spec:
http://localhost:3000/openapi.json
GraphQLPlugin
Section titled “GraphQLPlugin”Enables GraphQL support with automatic schema generation.
import { Veloce, GraphQLPlugin } from 'veloce-ts';
const app = new Veloce();
app.usePlugin(new GraphQLPlugin({ path: '/graphql', playground: true, introspection: true,}));Options:
path: GraphQL endpoint path (default:/graphql)playground: Enable GraphQL Playground (default:true)introspection: Enable schema introspection (default:true)
Access:
- GraphQL Endpoint:
http://localhost:3000/graphql - GraphQL Playground:
http://localhost:3000/graphql(in browser)
WebSocketPlugin
Section titled “WebSocketPlugin”Enables WebSocket support (automatically included).
import { Veloce, WebSocketPlugin } from 'veloce-ts';
const app = new Veloce();
app.usePlugin(new WebSocketPlugin({ path: '/ws', maxConnections: 1000,}));Using Plugins
Section titled “Using Plugins”Basic Usage
Section titled “Basic Usage”import { Veloce, OpenAPIPlugin } from 'veloce-ts';
const app = new Veloce();
// Use a single pluginapp.usePlugin(new OpenAPIPlugin());
// Use multiple pluginsapp.usePlugin(new OpenAPIPlugin());app.usePlugin(new GraphQLPlugin());Plugin Configuration
Section titled “Plugin Configuration”const app = new Veloce({ plugins: [ new OpenAPIPlugin({ path: '/api-docs.json', docsPath: '/api-docs', }), new GraphQLPlugin({ path: '/gql', playground: process.env.NODE_ENV !== 'production', }), ],});Creating Custom Plugins
Section titled “Creating Custom Plugins”Simple Plugin
Section titled “Simple Plugin”import { Plugin, Veloce } from 'veloce-ts';
class HelloPlugin implements Plugin { name = 'hello-plugin'; version = '1.0.0';
install(app: Veloce) { // Add a route app.get('/hello', { handler: async (c) => { return { message: 'Hello from plugin!' }; }, });
console.log('HelloPlugin installed'); }}
// Use the pluginconst app = new Veloce();app.usePlugin(new HelloPlugin());Plugin with Configuration
Section titled “Plugin with Configuration”interface LoggerPluginConfig { level: 'debug' | 'info' | 'warn' | 'error'; format: 'json' | 'text';}
class LoggerPlugin implements Plugin { name = 'logger-plugin'; version = '1.0.0';
constructor(private config: LoggerPluginConfig) {}
install(app: Veloce) { // Add logging middleware app.use(async (c, next) => { const start = Date.now();
await next();
const duration = Date.now() - start; const log = { method: c.req.method, url: c.req.url, status: c.res.status, duration: `${duration}ms`, };
if (this.config.format === 'json') { console.log(JSON.stringify(log)); } else { console.log(`${log.method} ${log.url} - ${log.status} (${log.duration})`); } }); }}
// Use with configurationapp.usePlugin(new LoggerPlugin({ level: 'info', format: 'json',}));Async Plugin
Section titled “Async Plugin”class DatabasePlugin implements Plugin { name = 'database-plugin';
async install(app: Veloce) { // Async initialization const db = await this.connectDatabase();
// Register as singleton app.getContainer().register(DatabaseService, { scope: 'singleton', factory: () => db, });
console.log('Database connected'); }
private async connectDatabase() { // Connect to database return new DatabaseService(); }}Plugin with Dependencies
Section titled “Plugin with Dependencies”class AnalyticsPlugin implements Plugin { name = 'analytics-plugin'; version = '1.0.0'; dependencies = ['logger-plugin'];
install(app: Veloce) { // This plugin requires logger-plugin to be installed first app.use(async (c, next) => { // Track request await next(); // Send analytics }); }}Plugin Examples
Section titled “Plugin Examples”Authentication Plugin
Section titled “Authentication Plugin”interface AuthPluginConfig { secret: string; expiresIn: string;}
class AuthPlugin implements Plugin { name = 'auth-plugin';
constructor(private config: AuthPluginConfig) {}
install(app: Veloce) { // Add auth service class AuthService { generateToken(userId: string) { // Generate JWT token return 'token'; }
verifyToken(token: string) { // Verify JWT token return { userId: '1' }; } }
app.getContainer().register(AuthService, { scope: 'singleton' });
// Add auth routes app.post('/auth/login', { handler: async (c) => { const { email, password } = await c.req.json(); // Validate credentials const token = 'generated-token'; return { token }; }, });
app.post('/auth/logout', { handler: async (c) => { return { success: true }; }, }); }}Rate Limiting Plugin
Section titled “Rate Limiting Plugin”interface RateLimitConfig { windowMs: number; max: number;}
class RateLimitPlugin implements Plugin { name = 'rate-limit-plugin'; private requests = new Map<string, number[]>();
constructor(private config: RateLimitConfig) {}
install(app: Veloce) { app.use(async (c, next) => { const ip = c.req.header('x-forwarded-for') || 'unknown'; const now = Date.now();
// Get request timestamps for this IP const timestamps = this.requests.get(ip) || [];
// Remove old timestamps const validTimestamps = timestamps.filter( t => now - t < this.config.windowMs );
// Check if limit exceeded if (validTimestamps.length >= this.config.max) { return c.json({ error: 'Too many requests' }, 429); }
// Add current timestamp validTimestamps.push(now); this.requests.set(ip, validTimestamps);
await next(); }); }}
app.usePlugin(new RateLimitPlugin({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // 100 requests per window}));Caching Plugin
Section titled “Caching Plugin”interface CachePluginConfig { ttl: number; // Time to live in seconds maxSize: number; // Maximum cache size}
class CachePlugin implements Plugin { name = 'cache-plugin'; private cache = new Map<string, { data: any; expires: number }>();
constructor(private config: CachePluginConfig) {}
install(app: Veloce) { class CacheService { constructor(private cache: Map<string, any>) {}
get(key: string) { const item = this.cache.get(key); if (!item) return null;
if (Date.now() > item.expires) { this.cache.delete(key); return null; }
return item.data; }
set(key: string, data: any, ttl?: number) { const expires = Date.now() + (ttl || this.config.ttl) * 1000; this.cache.set(key, { data, expires }); }
delete(key: string) { this.cache.delete(key); }
clear() { this.cache.clear(); } }
app.getContainer().register(CacheService, { scope: 'singleton', factory: () => new CacheService(this.cache), }); }}Monitoring Plugin
Section titled “Monitoring Plugin”class MonitoringPlugin implements Plugin { name = 'monitoring-plugin'; private metrics = { requests: 0, errors: 0, totalDuration: 0, };
install(app: Veloce) { // Track metrics app.use(async (c, next) => { this.metrics.requests++; const start = Date.now();
try { await next(); } catch (error) { this.metrics.errors++; throw error; } finally { this.metrics.totalDuration += Date.now() - start; } });
// Expose metrics endpoint app.get('/metrics', { handler: async (c) => { return { ...this.metrics, averageDuration: this.metrics.totalDuration / this.metrics.requests, errorRate: this.metrics.errors / this.metrics.requests, }; }, }); }}Best Practices
Section titled “Best Practices”1. Use Descriptive Names
Section titled “1. Use Descriptive Names”// ✓ Goodclass AuthenticationPlugin implements Plugin { name = 'authentication-plugin';}
// ✗ Badclass MyPlugin implements Plugin { name = 'plugin1';}2. Version Your Plugins
Section titled “2. Version Your Plugins”class MyPlugin implements Plugin { name = 'my-plugin'; version = '1.0.0';}3. Document Configuration Options
Section titled “3. Document Configuration Options”/** * Configuration options for CachePlugin */interface CachePluginConfig { /** Time to live in seconds */ ttl: number; /** Maximum number of items in cache */ maxSize: number; /** Cache key prefix */ prefix?: string;}
class CachePlugin implements Plugin { constructor(private config: CachePluginConfig) {}}4. Handle Errors Gracefully
Section titled “4. Handle Errors Gracefully”class MyPlugin implements Plugin { name = 'my-plugin';
async install(app: Veloce) { try { await this.initialize(); } catch (error) { console.error(`Failed to initialize ${this.name}:`, error); throw error; } }
private async initialize() { // Initialization logic }}5. Clean Up Resources
Section titled “5. Clean Up Resources”class DatabasePlugin implements Plugin { name = 'database-plugin'; private connection: any;
async install(app: Veloce) { this.connection = await this.connect();
// Register cleanup handler process.on('SIGTERM', () => this.cleanup()); process.on('SIGINT', () => this.cleanup()); }
private async cleanup() { if (this.connection) { await this.connection.close(); } }}6. Make Plugins Configurable
Section titled “6. Make Plugins Configurable”// ✓ Good - Configurableclass LoggerPlugin implements Plugin { constructor(private config: LoggerConfig) {}}
// ✗ Bad - Hardcodedclass LoggerPlugin implements Plugin { private level = 'info'; // Hardcoded}7. Test Your Plugins
Section titled “7. Test Your Plugins”import { describe, it, expect } from 'bun:test';import { createTestApp } from 'veloce/testing';
describe('MyPlugin', () => { it('should add route', async () => { const app = createTestApp(); app.usePlugin(new MyPlugin());
const response = await app.request('/plugin-route'); expect(response.status).toBe(200); });});Plugin Distribution
Section titled “Plugin Distribution”Publishing to NPM
Section titled “Publishing to NPM”{ "name": "veloce-plugin-myfeature", "version": "1.0.0", "main": "dist/index.js", "types": "dist/index.d.ts", "peerDependencies": { "veloce-ts": "^0.1.0" }}npm install veloce-plugin-myfeatureimport { Veloce } from 'veloce-ts';import { MyFeaturePlugin } from 'veloce-plugin-myfeature';
const app = new Veloce();app.usePlugin(new MyFeaturePlugin());Next Steps
Section titled “Next Steps”- Read the Testing Guide
- Check out the Getting Started Guide
- Learn about Dependency Injection