feat(backend): add fastify api, auth, prisma schema and jobs
This commit is contained in:
86
apps/backend/src/app.ts
Normal file
86
apps/backend/src/app.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import Fastify, { type FastifyInstance } from 'fastify';
|
||||
import helmet from '@fastify/helmet';
|
||||
import sensible from '@fastify/sensible';
|
||||
import { ZodError } from 'zod';
|
||||
import { env } from './config/env.js';
|
||||
import { HttpError } from './utils/errors.js';
|
||||
|
||||
import prismaPlugin from './plugins/prisma.js';
|
||||
import corsPlugin from './plugins/cors.js';
|
||||
import rateLimitPlugin from './plugins/rate-limit.js';
|
||||
import authPlugin from './plugins/auth.js';
|
||||
import guestPlugin from './plugins/guest.js';
|
||||
import staticPlugin from './plugins/static.js';
|
||||
import multipartPlugin from './plugins/multipart.js';
|
||||
|
||||
import authRoutes from './modules/auth/auth.routes.js';
|
||||
import profileRoutes from './modules/profile/profile.routes.js';
|
||||
import wishesRoutes from './modules/wishes/wishes.routes.js';
|
||||
import imagesRoutes from './modules/images/images.routes.js';
|
||||
import publicRoutes from './modules/public/public.routes.js';
|
||||
import metaRoutes from './modules/meta/meta.routes.js';
|
||||
import { registerPurgeTrashJob } from './jobs/purge-trash.js';
|
||||
|
||||
export async function buildApp(): Promise<FastifyInstance> {
|
||||
const app = Fastify({
|
||||
logger: {
|
||||
level: env.LOG_LEVEL,
|
||||
transport:
|
||||
env.NODE_ENV === 'development'
|
||||
? { target: 'pino-pretty', options: { translateTime: 'HH:MM:ss', singleLine: true } }
|
||||
: undefined,
|
||||
redact: {
|
||||
paths: ['req.body.password', 'req.headers.cookie', 'req.headers.authorization'],
|
||||
remove: true,
|
||||
},
|
||||
},
|
||||
trustProxy: true,
|
||||
bodyLimit: 1 * 1024 * 1024,
|
||||
});
|
||||
|
||||
app.setErrorHandler((err, request, reply) => {
|
||||
if (err instanceof HttpError) {
|
||||
return reply.code(err.statusCode).send({
|
||||
error: err.code,
|
||||
message: err.message,
|
||||
details: err.details,
|
||||
});
|
||||
}
|
||||
if (err instanceof ZodError) {
|
||||
return reply.code(400).send({
|
||||
error: 'VALIDATION',
|
||||
message: 'Invalid input',
|
||||
details: err.flatten(),
|
||||
});
|
||||
}
|
||||
if ((err as { statusCode?: number }).statusCode === 429) {
|
||||
return reply.code(429).send({ error: 'RATE_LIMITED', message: err.message });
|
||||
}
|
||||
request.log.error({ err }, 'Unhandled error');
|
||||
return reply.code(500).send({ error: 'INTERNAL', message: 'Internal server error' });
|
||||
});
|
||||
|
||||
await app.register(helmet, {
|
||||
contentSecurityPolicy: false,
|
||||
crossOriginResourcePolicy: { policy: 'cross-origin' },
|
||||
});
|
||||
await app.register(sensible);
|
||||
await app.register(corsPlugin);
|
||||
await app.register(rateLimitPlugin);
|
||||
await app.register(authPlugin);
|
||||
await app.register(guestPlugin);
|
||||
await app.register(staticPlugin);
|
||||
await app.register(multipartPlugin);
|
||||
await app.register(prismaPlugin);
|
||||
|
||||
await app.register(metaRoutes, { prefix: '/api' });
|
||||
await app.register(authRoutes, { prefix: '/api/auth' });
|
||||
await app.register(profileRoutes, { prefix: '/api/profile' });
|
||||
await app.register(wishesRoutes, { prefix: '/api/wishes' });
|
||||
await app.register(imagesRoutes, { prefix: '/api/wishes' });
|
||||
await app.register(publicRoutes, { prefix: '/api/public' });
|
||||
|
||||
registerPurgeTrashJob(app);
|
||||
|
||||
return app;
|
||||
}
|
||||
Reference in New Issue
Block a user