@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
JavaScript
/**
* 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