import fastify, { type FastifyServerOptions } from 'fastify' import fcookie from '@fastify/cookie' import fsession from '@fastify/session' import fstatic from '@fastify/static' import RedisStore from 'fastify-session-redis-store' import { serializerCompiler, validatorCompiler } from 'fastify-type-provider-zod' import { Redis } from 'ioredis' import kysely from './lib/kysely.ts' import StatusError from './lib/status_error.ts' import env from './env.ts' import ErrorHandler from './handlers/error.ts' import authPlugin from './plugins/auth.ts' import dbPlugin from './plugins/db.ts' import vitePlugin from './plugins/vite.ts' import apiRoutes from './routes/api.ts' import templateAdmin from './templates/admin.ts' import templatePublic from './templates/public.ts' export default async (options?: FastifyServerOptions) => { const server = fastify(options) server.setValidatorCompiler(validatorCompiler) server.setSerializerCompiler(serializerCompiler) server.register(fcookie) server.register(fsession, { cookie: { secure: env.NODE_ENV !== 'development', maxAge: 24 * 60 * 60 * 1000, }, cookieName: 'sessionId', secret: env.SESSION_SECRET, store: env.NODE_ENV !== 'testing' ? new RedisStore({ client: new Redis(env.REDIS_HOST) }) : undefined, }) server.register(dbPlugin, { kysely }) server.setNotFoundHandler(() => { throw new StatusError(404) }) server.register(fstatic, { root: new URL('../uploads', import.meta.url), prefix: '/uploads/', }) if (env.NODE_ENV !== 'testing') { server.register(vitePlugin, { mode: env.NODE_ENV, createErrorHandler: ErrorHandler, entries: { public: { path: '/', template: templatePublic, }, admin: { path: '/admin', template: templateAdmin, createPreHandler(route) { return async function preHandler(request, reply) { if (request.session.userId) { return (reply.ctx = { user: await request.user }) } else if (route.auth) { return reply.redirect('/admin/login') } } }, }, }, }) } server.register(authPlugin, { prefix: '/auth' }) server.register(apiRoutes, { prefix: '/api' }) return server }