Files
qipai/backend/src/app.ts
T

76 lines
2.2 KiB
TypeScript

import { randomUUID } from 'node:crypto';
import cors from '@fastify/cors';
import rateLimit from '@fastify/rate-limit';
import Fastify, { type FastifyInstance } from 'fastify';
import { loadConfig, type AppConfig } from './config.js';
import { registerHealthRoutes } from './routes/health.js';
import {
registerPlatformBootstrapRoutes,
type PlatformConfigResolver
} from './routes/platform-bootstrap.js';
import { registerAuthRoutes, type AuthRouteOptions } from './routes/auth.js';
import {
registerUserManagementRoutes,
type UserManagementRouteOptions
} from './routes/user-management.js';
export interface BuildAppOptions {
config?: AppConfig;
platformConfigRepository?: PlatformConfigResolver;
auth?: AuthRouteOptions;
userManagement?: UserManagementRouteOptions;
}
declare module 'fastify' {
interface FastifyRequest {
traceId: string;
}
}
export async function buildApp(options: BuildAppOptions = {}): Promise<FastifyInstance> {
const config = options.config ?? loadConfig();
const app = Fastify({
logger: {
level: config.nodeEnv === 'test' ? 'silent' : 'info'
},
genReqId: () => randomUUID()
});
app.decorateRequest('traceId', '');
app.addHook('onRequest', async (request, reply) => {
const traceHeader = request.headers['x-trace-id'];
request.traceId = Array.isArray(traceHeader) ? traceHeader[0] : traceHeader || request.id;
reply.header('x-trace-id', request.traceId);
});
await app.register(cors, {
origin: config.corsOrigins
});
await app.register(rateLimit, {
max: 120,
timeWindow: '1 minute'
});
app.setErrorHandler((error, request, reply) => {
request.log.error({ err: error, traceId: request.traceId }, 'request failed');
reply.status(500).send({
code: 'INTERNAL_ERROR',
message: 'Internal server error',
traceId: request.traceId
});
});
await registerHealthRoutes(app, config);
if (options.platformConfigRepository) {
await registerPlatformBootstrapRoutes(app, options.platformConfigRepository);
}
if (options.auth) {
await registerAuthRoutes(app, options.auth);
}
if (options.userManagement) {
await registerUserManagementRoutes(app, options.userManagement);
}
return app;
}