XyPriss Plugin Development Guide
Version: 1.0.0
Last Updated: December 12, 2025
Target: XyPriss v4.2.0+
Table of Contents
- Introduction
- Plugin Architecture
- Getting Started
- Plugin API Reference
- Lifecycle Hooks
- Advanced Features
- Best Practices
- Publishing Plugins
- Examples
Introduction
The XyPriss Plugin System provides a powerful and flexible way to extend server functionality. Plugins can intercept requests, add routes, modify responses, handle errors, and integrate deeply with the server lifecycle.
Key Features
- Lifecycle Hooks: Integrate at every stage of server operation
- Imperative API: Register plugins programmatically with
Plugin.exec() - Declarative API: Configure plugins via server options
- Dependency Resolution: Automatic handling of plugin dependencies
- Type Safety: Full TypeScript support with comprehensive type definitions
- Performance: Minimal overhead with intelligent middleware ordering
Use Cases
- Authentication and authorization systems
- Request/response logging and monitoring
- Rate limiting and throttling
- Custom caching strategies
- API versioning
- Error tracking and reporting
- Performance profiling
- Process management (e.g., Prydam)
Plugin Architecture
Plugin Structure
A XyPriss plugin is a TypeScript/JavaScript object that implements the XyPrissPlugin interface:
interface XyPrissPlugin {
// Required metadata
name: string;
version: string;
// Optional metadata
description?: string;
author?: string;
dependencies?: string[];
// Lifecycle hooks
onServerStart?: (server: UltraFastApp) => void | Promise<void>;
onServerReady?: (server: UltraFastApp) => void | Promise<void>;
onServerStop?: (server: UltraFastApp) => void | Promise<void>;
// Request/Response hooks
onRequest?: (req: Request, res: Response, next: NextFunction) => void;
onResponse?: (req: Request, res: Response) => void;
onError?: (
error: Error,
req: Request,
res: Response,
next: NextFunction
) => void;
// Route registration
registerRoutes?: (app: UltraFastApp) => void;
// Middleware
middleware?: RequestHandler | RequestHandler[];
middlewarePriority?: "first" | "normal" | "last";
}
Plugin Lifecycle
1. Plugin Registration
└─> Plugin.create() or Plugin.register()
2. Server Creation
└─> createServer()
3. Plugin Initialization
└─> Dependency resolution
└─> onServerStart() [BLOCKING]
4. Route Registration
└─> registerRoutes()
5. Middleware Application
└─> middleware / onRequest / onResponse
6. Server Start
└─> app.start()
└─> onServerReady()
7. Request Handling
└─> onRequest -> Route Handler -> onResponse
└─> onError (if error occurs)
8. Server Shutdown
└─> onServerStop()
Getting Started
Creating Your First Plugin
Step 1: Install Dependencies
npm install xypriss
# or
bun add xypriss
Step 2: Create Plugin File
// plugins/my-plugin.ts
import { Plugin } from "xypriss";
export const MyPlugin = Plugin.create({
name: "my-plugin",
version: "1.0.0",
description: "My awesome XyPriss plugin",
onServerStart(server) {
console.log("[MyPlugin] Server starting...");
},
onServerReady(server) {
console.log("[MyPlugin] Server ready!");
},
registerRoutes(app) {
app.get("/plugin/status", (req, res) => {
res.json({ status: "active", plugin: "my-plugin" });
});
},
});
Step 3: Register Plugin
Option A: Imperative API (Recommended)
import { createServer, Plugin } from "xypriss";
import { MyPlugin } from "./plugins/my-plugin";
// Register before server creation
Plugin.exec(MyPlugin);
const app = createServer({
server: { port: 3000 },
});
app.start();
Option B: Declarative API
import { createServer } from "xypriss";
import { MyPlugin } from "./plugins/my-plugin";
const app = createServer({
server: { port: 3000 },
plugins: {
register: [MyPlugin],
},
});
app.start();
Plugin API Reference
Plugin.create()
Creates a new plugin instance.
Plugin.create(config: XyPrissPlugin): XyPrissPlugin
Parameters:
config: Plugin configuration object implementingXyPrissPlugininterface
Returns:
- Plugin instance ready for registration
Example:
const authPlugin = Plugin.create({
name: "auth-plugin",
version: "1.0.0",
onRequest(req, res, next) {
const token = req.headers.authorization;
if (!token) {
return res.status(401).json({ error: "Unauthorized" });
}
next();
},
});
Plugin.register()
Registers a plugin with the global plugin manager.
Plugin.register(
plugin: XyPrissPlugin | PluginCreator,
config?: any
): void
Parameters:
plugin: Plugin instance or creator functionconfig: Optional configuration object
Example:
Plugin.register(authPlugin);
// With configuration
Plugin.register(authPlugin, {
secretKey: process.env.JWT_SECRET,
});
Plugin.exec()
Alias for Plugin.register(). Preferred for imperative plugin registration.
Plugin.exec(
plugin: XyPrissPlugin | PluginCreator,
config?: any
): void
Example:
Plugin.exec(
Plugin.create({
name: "logger",
version: "1.0.0",
onRequest(req, res, next) {
console.log(`${req.method} ${req.url}`);
next();
},
})
);
Plugin.get()
Retrieves a registered plugin by name.
Plugin.get(name: string): XyPrissPlugin | undefined
Parameters:
name: Plugin name
Returns:
- Plugin instance or
undefinedif not found
Example:
const authPlugin = Plugin.get("auth-plugin");
if (authPlugin) {
console.log("Auth plugin is registered");
}
Plugin.factory()
Creates a plugin factory function for configurable plugins.
Plugin.factory<T = any>(
creator: (config: T) => XyPrissPlugin
): PluginCreator<T>
Parameters:
creator: Function that receives configuration and returns a plugin
Returns:
- Plugin creator function
Example:
const createRateLimiter = Plugin.factory(
(config: { maxRequests: number; windowMs: number }) => ({
name: "rate-limiter",
version: "1.0.0",
onRequest(req, res, next) {
// Rate limiting logic using config
next();
},
})
);
// Use the factory
Plugin.exec(
createRateLimiter({
maxRequests: 100,
windowMs: 60000,
})
);
Lifecycle Hooks
onServerStart
Signature:
onServerStart?: (server: UltraFastApp) => void | Promise<void>
Description: Called during server initialization, BEFORE the HTTP server starts listening. This hook BLOCKS server startup until completion.
Use Cases:
- Database connection initialization
- External service authentication
- Configuration validation
- Resource allocation
Important:
- This hook is BLOCKING - server will not start until it completes
- Async operations are fully supported
- Errors will prevent server startup
Example:
{
onServerStart: async (server) => {
// Connect to database
await database.connect();
// Initialize cache
await cache.initialize();
console.log("Plugin initialized successfully");
};
}
onServerReady
Signature:
onServerReady?: (server: UltraFastApp) => void | Promise<void>
Description: Called AFTER the HTTP server has started and is ready to accept connections.
Use Cases:
- Start background jobs
- Register with service discovery
- Send startup notifications
- Begin health checks
Example:
{
onServerReady: async (server) => {
// Start background job
setInterval(() => {
performCleanup();
}, 60000);
// Register with service discovery
await serviceRegistry.register({
name: "my-service",
port: server.getPort(),
});
};
}
onServerStop
Signature:
onServerStop?: (server: UltraFastApp) => void | Promise<void>
Description: Called when the server is shutting down.
Use Cases:
- Close database connections
- Flush logs
- Cleanup resources
- Deregister from service discovery
Example:
{
onServerStop: async (server) => {
// Close connections
await database.disconnect();
// Flush logs
await logger.flush();
console.log("Plugin shutdown complete");
};
}
onRequest
Signature:
onRequest?: (req: Request, res: Response, next: NextFunction) => void
Description: Called for EVERY incoming request, before route handlers.
Use Cases:
- Request logging
- Authentication
- Request modification
- Metrics collection
Example:
{
onRequest(req, res, next) {
// Add request ID
req.id = generateId();
// Log request
console.log(`[${req.id}] ${req.method} ${req.url}`);
// Add timing
req.startTime = Date.now();
next();
}
}
onResponse
Signature:
onResponse?: (req: Request, res: Response) => void
Description: Called AFTER the response has been sent to the client.
Use Cases:
- Response logging
- Metrics collection
- Cleanup operations
- Audit logging
Example:
{
onResponse(req, res) {
const duration = Date.now() - req.startTime;
console.log(`[${req.id}] ${res.statusCode} ${duration}ms`);
// Send metrics
metrics.record({
method: req.method,
path: req.url,
status: res.statusCode,
duration
});
}
}
onError
Signature:
onError?: (error: Error, req: Request, res: Response, next: NextFunction) => void
Description: Called when an error occurs during request processing.
Use Cases:
- Error logging
- Error reporting to external services
- Custom error responses
- Error recovery
Example:
{
onError(error, req, res, next) {
// Log error
console.error(`[${req.id}] Error:`, error);
// Send to error tracking service
errorTracker.captureException(error, {
request: {
method: req.method,
url: req.url,
headers: req.headers
}
});
// Send custom error response
if (!res.headersSent) {
res.status(500).json({
error: 'Internal Server Error',
requestId: req.id
});
}
}
}
registerRoutes
Signature:
registerRoutes?: (app: UltraFastApp) => void
Description: Called during server initialization to register plugin routes.
Use Cases:
- Add API endpoints
- Health check endpoints
- Admin interfaces
- Webhook handlers
Example:
{
registerRoutes(app) {
// Health check
app.get('/health', (req, res) => {
res.json({ status: 'healthy' });
});
// Plugin API
app.get('/api/plugin/stats', (req, res) => {
res.json(getStats());
});
// Admin endpoint
app.post('/api/plugin/config', (req, res) => {
updateConfig(req.body);
res.json({ success: true });
});
}
}
Advanced Features
Plugin Dependencies
Plugins can declare dependencies on other plugins. The plugin manager will automatically resolve dependencies and ensure correct initialization order.
const databasePlugin = Plugin.create({
name: "database",
version: "1.0.0",
onServerStart: async () => {
await database.connect();
},
});
const authPlugin = Plugin.create({
name: "auth",
version: "1.0.0",
dependencies: ["database"], // Requires database plugin
onServerStart: async () => {
// Database is guaranteed to be connected
await loadUsers();
},
});
Plugin.exec(authPlugin);
Plugin.exec(databasePlugin); // Order doesn't matter
Middleware Priority
Control when your middleware executes relative to other plugins.
{
middleware: (req, res, next) => {
// Your middleware logic
next();
},
middlewarePriority: 'first' // 'first' | 'normal' | 'last'
}
Priority Levels:
first: Executes before all other middlewarenormal: Default priority (default)last: Executes after all other middleware
Multiple Middleware
Plugins can register multiple middleware functions.
{
middleware: [
(req, res, next) => {
// First middleware
next();
},
(req, res, next) => {
// Second middleware
next();
},
];
}
Configuration Management
Use Plugin.factory() to create configurable plugins.
interface CacheConfig {
ttl: number;
maxSize: number;
strategy: "lru" | "lfu";
}
export const createCachePlugin = Plugin.factory<CacheConfig>((config) => ({
name: "cache-plugin",
version: "1.0.0",
onServerStart: async () => {
await cache.initialize({
ttl: config.ttl,
maxSize: config.maxSize,
strategy: config.strategy,
});
},
onRequest(req, res, next) {
const cached = cache.get(req.url);
if (cached) {
return res.json(cached);
}
next();
},
}));
// Usage
Plugin.exec(
createCachePlugin({
ttl: 3600,
maxSize: 1000,
strategy: "lru",
})
);
Best Practices
1. Error Handling
Always handle errors gracefully in your plugins.
{
onServerStart: async (server) => {
try {
await externalService.connect();
} catch (error) {
console.error("Failed to connect to external service:", error);
// Decide: fail fast or continue with degraded functionality
throw error; // Prevents server startup
}
};
}
2. Resource Cleanup
Always clean up resources in onServerStop.
{
onServerStart: async () => {
this.connection = await database.connect();
},
onServerStop: async () => {
if (this.connection) {
await this.connection.close();
}
}
}
3. Performance
Minimize overhead in onRequest and onResponse hooks.
// Bad: Synchronous heavy operation
{
onRequest(req, res, next) {
const data = heavyComputation(); // Blocks request
req.data = data;
next();
}
}
// Good: Async or lazy loading
{
onRequest(req, res, next) {
req.getData = () => heavyComputation(); // Lazy
next();
}
}
4. Naming Conventions
Use descriptive, unique names for your plugins.
// Bad
{
name: "plugin";
}
// Good
{
name: "xypriss-auth-jwt";
}
{
name: "xypriss-logger-winston";
}
{
name: "xypriss-cache-redis";
}
5. Versioning
Follow semantic versioning for your plugins.
{
name: 'my-plugin',
version: '1.2.3', // MAJOR.MINOR.PATCH
}
6. Documentation
Document your plugin's configuration and usage.
/**
* JWT Authentication Plugin
*
* Provides JWT-based authentication for XyPriss applications.
*
* @example
* ```typescript
* Plugin.exec(createJWTAuth({
* secret: process.env.JWT_SECRET,
* expiresIn: '1h'
* }));
* ```
*/
export const createJWTAuth = Plugin.factory<JWTConfig>((config) => ({
// Plugin implementation
}));
Publishing Plugins
Package Structure
my-xypriss-plugin/
├── src/
│ └── index.ts
├── dist/
│ └── index.js
├── package.json
├── tsconfig.json
├── README.md
└── LICENSE
package.json
{
"name": "@yourorg/xypriss-plugin-name",
"version": "1.0.0",
"description": "Description of your plugin",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"keywords": ["xypriss", "plugin", "your-keywords"],
"peerDependencies": {
"xypriss": "^4.5.0"
},
"devDependencies": {
"xypriss": "^4.5.11",
"typescript": "^5.0.0"
}
}
README.md Template
# @yourorg/xypriss-plugin-name
Description of what your plugin does.
## Installation
\`\`\`bash
npm install @yourorg/xypriss-plugin-name
\`\`\`
## Usage
\`\`\`typescript
import { Plugin } from 'xypriss';
import { MyPlugin } from '@yourorg/xypriss-plugin-name';
Plugin.exec(MyPlugin);
\`\`\`
## Configuration
| Option | Type | Default | Description |
| ------- | ------ | --------- | ----------- |
| option1 | string | 'default' | Description |
## License
MIT
Publishing to npm
# Build
npm run build
# Test
npm test
# Publish
npm publish --access public
Examples
Example 1: Request Logger
import { Plugin } from "xypriss";
export const RequestLogger = Plugin.create({
name: "request-logger",
version: "1.0.0",
description: "Logs all incoming requests",
onRequest(req, res, next) {
const start = Date.now();
req.startTime = start;
console.log(`--> ${req.method} ${req.url}`);
next();
},
onResponse(req, res) {
const duration = Date.now() - req.startTime;
console.log(
`<-- ${req.method} ${req.url} ${res.statusCode} ${duration}ms`
);
},
});
Example 2: API Key Authentication
import { Plugin } from "xypriss";
interface AuthConfig {
apiKeys: string[];
headerName?: string;
}
export const createAPIKeyAuth = Plugin.factory<AuthConfig>((config) => ({
name: "api-key-auth",
version: "1.0.0",
onRequest(req, res, next) {
const headerName = config.headerName || "x-api-key";
const apiKey = req.headers[headerName];
if (!apiKey || !config.apiKeys.includes(apiKey as string)) {
return res.status(401).json({
error: "Unauthorized",
message: "Invalid or missing API key",
});
}
next();
},
}));
// Usage
Plugin.exec(
createAPIKeyAuth({
apiKeys: ["key1", "key2", "key3"],
headerName: "x-api-key",
})
);
Example 3: Rate Limiter
import { Plugin } from "xypriss";
interface RateLimitConfig {
maxRequests: number;
windowMs: number;
}
export const createRateLimiter = Plugin.factory<RateLimitConfig>((config) => {
const requests = new Map<string, number[]>();
return {
name: "rate-limiter",
version: "1.0.0",
onRequest(req, res, next) {
const ip = req.ip || req.connection.remoteAddress;
const now = Date.now();
if (!requests.has(ip)) {
requests.set(ip, []);
}
const timestamps = requests.get(ip)!;
const validTimestamps = timestamps.filter(
(t) => now - t < config.windowMs
);
if (validTimestamps.length >= config.maxRequests) {
return res.status(429).json({
error: "Too Many Requests",
retryAfter: Math.ceil(config.windowMs / 1000),
});
}
validTimestamps.push(now);
requests.set(ip, validTimestamps);
next();
},
};
});
// Usage
Plugin.exec(
createRateLimiter({
maxRequests: 100,
windowMs: 60000, // 1 minute
})
);
Example 4: Health Check
import { Plugin } from "xypriss";
export const HealthCheckPlugin = Plugin.create({
name: "health-check",
version: "1.0.0",
registerRoutes(app) {
app.get("/health", (req, res) => {
res.json({
status: "healthy",
uptime: process.uptime(),
memory: process.memoryUsage(),
timestamp: new Date().toISOString(),
});
});
app.get("/ready", (req, res) => {
// Check if all dependencies are ready
const ready = checkDependencies();
res.status(ready ? 200 : 503).json({
ready,
timestamp: new Date().toISOString(),
});
});
},
});
Example 5: Error Tracker
import { Plugin } from "xypriss";
interface ErrorTrackerConfig {
apiKey: string;
environment: string;
}
export const createErrorTracker = Plugin.factory<ErrorTrackerConfig>(
(config) => ({
name: "error-tracker",
version: "1.0.0",
onError: async (error, req, res, next) => {
// Send error to tracking service
await fetch("https://error-tracker.example.com/api/errors", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": config.apiKey,
},
body: JSON.stringify({
error: {
message: error.message,
stack: error.stack,
name: error.name,
},
request: {
method: req.method,
url: req.url,
headers: req.headers,
ip: req.ip,
},
environment: config.environment,
timestamp: new Date().toISOString(),
}),
});
// Continue error handling
next();
},
})
);
Support and Resources
- Documentation: https://docs.xypriss.nehonix.com
- GitHub: https://github.com/Nehonix-Team/xypriss
- Issues: https://github.com/Nehonix-Team/xypriss/issues
Copyright 2025 Nehonix Team
License: MIT