Custom Plugins
Build and integrate custom plugins for the LegionEdge Platform
The LegionEdge Platform plugin system lets you extend platform functionality by hooking into the request lifecycle, adding custom endpoints, and integrating with third-party services.
Plugin Structure
A plugin is a JavaScript/TypeScript module that exports a definePlugin function:
import { definePlugin } from "@legionedge/sdk/plugins";
export default definePlugin({
name: "my-custom-plugin",
version: "1.0.0",
description: "Adds custom logging and validation",
hooks: {
beforeRequest: async (context) => {
console.log(`[${context.method}] ${context.url}`);
return context;
},
afterResponse: async (context, response) => {
console.log(`Response: ${response.status} in ${response.duration}ms`);
return response;
},
onError: async (context, error) => {
console.error(`Request failed: ${error.message}`);
// Return undefined to re-throw, or return a response to recover
},
},
});Registering Plugins
Register plugins when creating the SDK client:
import { LegionEdge } from "@legionedge/sdk";
import loggingPlugin from "./plugins/logging";
import validationPlugin from "./plugins/validation";
const client = new LegionEdge({
apiKey: process.env.LEGIONEDGE_API_KEY!,
plugins: [loggingPlugin, validationPlugin],
});Plugins execute in the order they are registered.
Lifecycle Hooks
Plugins can hook into these lifecycle events:
| Hook | Timing | Use Case |
|---|---|---|
beforeRequest | Before the HTTP request is sent | Add headers, transform body, validate input |
afterResponse | After a successful response | Transform response, log metrics |
onError | When an error occurs | Error reporting, fallback logic |
onRetry | Before a retry attempt | Adjust retry strategy, log retries |
onInit | When the client is initialized | Validate configuration, register resources |
onDestroy | When the client is destroyed | Clean up connections, flush buffers |
Example: Custom Header Plugin
export default definePlugin({
name: "custom-headers",
version: "1.0.0",
hooks: {
beforeRequest: async (context) => {
context.headers.set("X-Custom-Trace-Id", generateTraceId());
context.headers.set("X-Client-Version", "2.1.0");
return context;
},
},
});Example: Caching Plugin
const cache = new Map<string, { data: unknown; expiresAt: number }>();
export default definePlugin({
name: "simple-cache",
version: "1.0.0",
hooks: {
beforeRequest: async (context) => {
if (context.method !== "GET") return context;
const cached = cache.get(context.url);
if (cached && cached.expiresAt > Date.now()) {
return { ...context, cachedResponse: cached.data };
}
return context;
},
afterResponse: async (context, response) => {
if (context.method === "GET") {
cache.set(context.url, {
data: response.data,
expiresAt: Date.now() + 60_000,
});
}
return response;
},
},
});Plugin API
Plugins receive a PluginContext object with access to:
interface PluginContext {
method: string;
url: string;
headers: Headers;
body: unknown;
params: Record<string, string>;
config: LegionEdgeConfig;
logger: Logger;
metadata: Map<string, unknown>; // share data between hooks
}Publishing Plugins
Share plugins with the community by publishing to npm:
npm publish --access publicUse the legionedge-plugin keyword in your package.json so others can discover it:
{
"name": "@acme/legionedge-plugin-audit",
"keywords": ["legionedge-plugin"],
"main": "dist/index.js",
"types": "dist/index.d.ts"
}Next Steps
- Set up webhooks for event-driven integrations.
- Review best practices for plugin development.