UNPKG

@prism-engineer/router

Version:

Type-safe Express.js router with automatic client generation

128 lines 6.16 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createAuthScheme = exports.createApiRoute = exports.router = exports.createRouter = void 0; const express_1 = __importDefault(require("express")); const loader_1 = require("./routing/loader"); const compiler_1 = require("./compilation/compiler"); const parser_1 = require("./routing/parser"); const createAuthScheme_1 = require("./createAuthScheme"); const createRouter = () => { const app = (0, express_1.default)(); app.use(express_1.default.json({ verify: (req, res, buf, encoding) => { // buf is a Buffer of the raw request body req.rawBody = buf.toString(encoding || 'utf8'); } })); app.use(express_1.default.urlencoded({ extended: true })); const routes = []; const routeLoader = (0, loader_1.createFileRouteLoader)(); const routeParser = (0, parser_1.createRouteParser)(); const self = { app, async loadRoutes(directory, pattern, options) { if (!directory || !pattern) { throw new Error('Directory and pattern are required'); } try { const files = await routeLoader.loadRoutes(directory, pattern); // Parse each route file and extract route definitions for (const filePath of files) { try { const parsedRoutes = await routeParser.parseRouteFile(filePath); // Add parsed routes to our collection routes.push(...parsedRoutes); // Auto-register each route with Express for (const route of parsedRoutes) { this.registerRoute(route, options?.prefix); } } catch (parseError) { console.warn(`Failed to parse route file ${filePath}: ${parseError}`); // Continue with other files instead of failing completely } } } catch (error) { throw new Error(`Failed to load routes: ${error}`); } }, registerRoute(route, prefix) { // Store the route for client generation routes.push(route); // Convert path params from {param} to :param format for Express const expressPath = (prefix || '') + route.path.replace(/{(\w+)}/g, ':$1'); // Create middleware array const middleware = []; // Add auth middleware if auth is defined if (route.auth) { middleware.push(async (req, res, next) => { const authContext = await (0, createAuthScheme_1.validateAuth)(route.auth, req); req.auth = authContext; next(); }); } // Add main handler middleware.push(async (req, res, next) => { const result = await route.handler({ query: req.query, body: req.body, headers: req.headers, params: req.params, auth: req.auth, rawRequest: req }); const responseSchema = route.response?.[result.status]; if (result && typeof result === 'object' && 'status' in result) { if ('custom' in result && typeof result.custom === 'function') { // Custom content type - user controls response res.status(result.status); if (!responseSchema?.contentType) { return next(new Error('No content type specified for custom response handler')); } res.setHeader('Content-Type', responseSchema?.contentType); await result.custom(res); } else { res.status(result.status); if (!responseSchema?.contentType) { return next(new Error('No content type specified for custom response handler')); } res.setHeader('Content-Type', responseSchema?.contentType); for (const [key, value] of Object.entries(result.headers || {})) { res.setHeader(key, value); } res.json(result.body); } } next(); }); // Register the route with Express app[route.method.toLowerCase()](expressPath, ...middleware); }, async compile(config, loadRoutesOptions) { if (!config) { throw new Error('Configuration is required'); } // Handle both single route config and array of route configs const routeConfigs = Array.isArray(config.routes) ? config.routes : [config.routes]; for (const routeConfig of routeConfigs) { await self.loadRoutes(routeConfig.directory, routeConfig.pattern, routeConfig.options); } const compiler = (0, compiler_1.createCompiler)(); await compiler.compile(config, routes); } }; return self; }; exports.createRouter = createRouter; // Export singleton instance exports.router = (0, exports.createRouter)(); var createApiRoute_1 = require("./createApiRoute"); Object.defineProperty(exports, "createApiRoute", { enumerable: true, get: function () { return createApiRoute_1.createApiRoute; } }); var createAuthScheme_2 = require("./createAuthScheme"); Object.defineProperty(exports, "createAuthScheme", { enumerable: true, get: function () { return createAuthScheme_2.createAuthScheme; } }); //# sourceMappingURL=router.js.map