feat(backend): add fastify api, auth, prisma schema and jobs

This commit is contained in:
Anton
2026-04-23 16:04:44 +03:00
parent 5f6a551b6c
commit 2972090c48
34 changed files with 1313 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
import fp from 'fastify-plugin';
import fastifyJwt from '@fastify/jwt';
import fastifyCookie from '@fastify/cookie';
import { env } from '../config/env.js';
import { UnauthorizedError } from '../utils/errors.js';
export const AUTH_COOKIE = 'fw_auth';
const AUTH_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; // 7 days
export default fp(async (app) => {
await app.register(fastifyCookie, {
secret: env.COOKIE_SECRET,
parseOptions: {},
});
await app.register(fastifyJwt, {
secret: env.JWT_SECRET,
cookie: { cookieName: AUTH_COOKIE, signed: false },
sign: { expiresIn: `${AUTH_COOKIE_MAX_AGE}s` },
});
app.decorate('authenticate', async (request) => {
try {
await request.jwtVerify({ onlyCookie: true });
} catch {
throw new UnauthorizedError();
}
});
// helpers for routes
app.decorate('setAuthCookie', ((reply, token) => {
reply.setCookie(AUTH_COOKIE, token, {
httpOnly: true,
secure: env.NODE_ENV === 'production',
sameSite: 'lax',
path: '/',
maxAge: AUTH_COOKIE_MAX_AGE,
});
}) as never);
app.decorate('clearAuthCookie', ((reply) => {
reply.clearCookie(AUTH_COOKIE, { path: '/' });
}) as never);
});
declare module 'fastify' {
interface FastifyInstance {
setAuthCookie: (reply: import('fastify').FastifyReply, token: string) => void;
clearAuthCookie: (reply: import('fastify').FastifyReply) => void;
}
}