(
options: BuildAppOptions = {},
)
| 78 | } |
| 79 | |
| 80 | export async function buildApp( |
| 81 | options: BuildAppOptions = {}, |
| 82 | ): Promise<FastifyInstance> { |
| 83 | const { testing = false } = options; |
| 84 | |
| 85 | const fastify = Fastify({ |
| 86 | maxParamLength: 15_000, |
| 87 | bodyLimit: 1_048_576 * 500, |
| 88 | disableRequestLogging: true, |
| 89 | genReqId: (req) => |
| 90 | req.headers['request-id'] |
| 91 | ? String(req.headers['request-id']) |
| 92 | : generateId(), |
| 93 | ...(testing |
| 94 | ? { logger: false } |
| 95 | : { loggerInstance: logger as FastifyBaseLogger }), |
| 96 | }); |
| 97 | |
| 98 | fastify.setValidatorCompiler(validatorCompiler); |
| 99 | fastify.setSerializerCompiler(serializerCompiler); |
| 100 | |
| 101 | // Env is read once at startup — changing CORS origins requires a |
| 102 | // restart, which is already true for every other env-driven piece |
| 103 | // of the server. |
| 104 | const dashboardOrigins = [ |
| 105 | process.env.DASHBOARD_URL || process.env.NEXT_PUBLIC_DASHBOARD_URL, |
| 106 | ...(process.env.API_CORS_ORIGINS?.split(',') ?? []), |
| 107 | ].filter(Boolean) as string[]; |
| 108 | const corsPaths = ['/trpc', '/live', '/webhook', '/oauth', '/misc', '/ai']; |
| 109 | |
| 110 | fastify.register(cors, () => { |
| 111 | return ( |
| 112 | req: FastifyRequest, |
| 113 | callback: (error: Error | null, options: FastifyCorsOptions) => void, |
| 114 | ) => { |
| 115 | const isPrivatePath = corsPaths.some((p) => req.url.startsWith(p)); |
| 116 | |
| 117 | if (isPrivatePath) { |
| 118 | const origin = req.headers.origin; |
| 119 | const isAllowed = origin && dashboardOrigins.includes(origin); |
| 120 | return callback(null, { origin: isAllowed ? origin : false, credentials: true }); |
| 121 | } |
| 122 | |
| 123 | return callback(null, { origin: '*', maxAge: 86_400 * 7 }); |
| 124 | }; |
| 125 | }); |
| 126 | |
| 127 | await fastify.register(import('fastify-raw-body'), { global: false }); |
| 128 | |
| 129 | fastify.addHook('onRequest', requestIdHook); |
| 130 | fastify.addHook('onRequest', timestampHook); |
| 131 | fastify.addHook('onRequest', ipHook); |
| 132 | fastify.addHook('onResponse', requestLoggingHook); |
| 133 | |
| 134 | fastify.register(compress, { global: false, encodings: ['gzip', 'deflate'] }); |
| 135 | |
| 136 | // Dashboard API |
| 137 | fastify.register(async (instance) => { |
no test coverage detected