UNPKG

@pulzar/core

Version:

Next-generation Node.js framework for ultra-fast web applications with zero-reflection DI, GraphQL, WebSockets, events, and edge runtime support

135 lines 4.48 kB
/** * Fastify plugin for request-scoped DI containers */ export async function fastifyDI(fastify, options) { const { container, generateRequestId, onRequestStart, onRequestEnd } = options; // Generate request ID function const getRequestId = generateRequestId || (() => `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`); // Add container to request context fastify.addHook("onRequest", async (request, reply) => { const requestId = getRequestId(); request.container = container.createRequestScope(requestId); // Custom hook if (onRequestStart) { onRequestStart(request, request.container); } }); // Cleanup on request end fastify.addHook("onResponse", async (request, reply) => { if (onRequestEnd && request.container) { onRequestEnd(request, request.container); } }); // Helper methods for dependency injection fastify.decorate("diInject", function (token, request) { if (!request.container) { throw new Error("Request container not available"); } return request.container.resolve(token); }); } /** * Helper decorator for request-scoped services */ export function RequestScoped() { return function (target) { target.__injectable = { ...target.__injectable, scope: "request", }; return target; }; } /** * Helper decorator for injecting request-scoped services */ export function InjectRequest(token) { return function (target, propertyKey, descriptor) { const originalMethod = descriptor.value; descriptor.value = function (request, reply, ...args) { if (!request.container) { throw new Error("Request container not available"); } const service = request.container.resolve(token); return originalMethod.call(this, request, reply, service, ...args); }; return descriptor; }; } /** * Utility to get container from request */ export function getRequestContainer(request) { if (!request.container) { throw new Error("Request container not available"); } return request.container; } /** * Utility to resolve service from request */ export function resolveFromRequest(request, token) { const container = getRequestContainer(request); return container.resolve(token); } /** * Route handler decorator that automatically injects dependencies */ export function Route(options) { return function (target, propertyKey, descriptor) { const originalMethod = descriptor.value; // Store route metadata for registration target.__routes = target.__routes || []; target.__routes.push({ method: options.method, path: options.path, handler: originalMethod, inject: options.inject || [], propertyKey, }); return descriptor; }; } /** * Controller decorator for class-based route handling */ export function Controller(prefix = "") { return function (target) { target.__controller = { prefix, routes: target.__routes || [], }; return target; }; } /** * Register controller with Fastify instance */ export function registerController(fastify, ControllerClass, container) { const metadata = ControllerClass.__controller; if (!metadata) { throw new Error("Class must be decorated with @Controller"); } const controller = container.resolve(ControllerClass); for (const route of metadata.routes) { const fullPath = metadata.prefix + route.path; const handler = async (request, reply) => { try { // Inject dependencies const injectedServices = route.inject.map((token) => request.container.resolve(token)); // Call handler with injected dependencies const result = await route.handler.call(controller, request, reply, ...injectedServices); return result; } catch (error) { reply.code(500).send({ error: "Internal Server Error" }); throw error; } }; // Register route with Fastify fastify[route.method.toLowerCase()](fullPath, handler); } } export default fastifyDI; //# sourceMappingURL=fastify-integration.js.map