76 lines
2.2 KiB
TypeScript
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;
|
|
}
|