@prism-engineer/router
Version:
Type-safe Express.js router with automatic client generation
128 lines • 6.16 kB
JavaScript
;
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