feat: add Drizzle enums for schema
Made-with: Cursor
This commit is contained in:
33
src/plugins/database.ts
Normal file
33
src/plugins/database.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { FastifyInstance, FastifyPluginAsync } from 'fastify';
|
||||
import { drizzle } from 'drizzle-orm/node-postgres';
|
||||
import pg from 'pg';
|
||||
import fp from 'fastify-plugin';
|
||||
import { env } from '../config/env.js';
|
||||
import * as schema from '../db/schema/index.js';
|
||||
|
||||
const { Pool } = pg;
|
||||
|
||||
declare module 'fastify' {
|
||||
interface FastifyInstance {
|
||||
db: ReturnType<typeof drizzle<typeof schema>>;
|
||||
}
|
||||
}
|
||||
|
||||
const databasePlugin: FastifyPluginAsync = async (app: FastifyInstance) => {
|
||||
const pool = new Pool({
|
||||
connectionString: env.DATABASE_URL,
|
||||
max: 10,
|
||||
idleTimeoutMillis: 30000,
|
||||
connectionTimeoutMillis: 5000,
|
||||
});
|
||||
|
||||
const db = drizzle(pool, { schema });
|
||||
|
||||
app.decorate('db', db);
|
||||
|
||||
app.addHook('onClose', async () => {
|
||||
await pool.end();
|
||||
});
|
||||
};
|
||||
|
||||
export default fp(databasePlugin, { name: 'database' });
|
||||
59
src/plugins/rateLimit.ts
Normal file
59
src/plugins/rateLimit.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { FastifyInstance, FastifyPluginAsync } from 'fastify';
|
||||
import rateLimit from '@fastify/rate-limit';
|
||||
import fp from 'fastify-plugin';
|
||||
import { env } from '../config/env.js';
|
||||
|
||||
declare module 'fastify' {
|
||||
interface FastifyInstance {
|
||||
rateLimitOptions: {
|
||||
login: { max: number; timeWindow: string };
|
||||
register: { max: number; timeWindow: string };
|
||||
forgotPassword: { max: number; timeWindow: string };
|
||||
verifyEmail: { max: number; timeWindow: string };
|
||||
apiAuthed: { max: number; timeWindow: string };
|
||||
apiGuest: { max: number; timeWindow: string };
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const rateLimitPlugin: FastifyPluginAsync = async (app: FastifyInstance) => {
|
||||
const options = {
|
||||
login: { max: env.RATE_LIMIT_LOGIN, timeWindow: '15 minutes' },
|
||||
register: { max: env.RATE_LIMIT_REGISTER, timeWindow: '1 hour' },
|
||||
forgotPassword: { max: env.RATE_LIMIT_FORGOT_PASSWORD, timeWindow: '1 hour' },
|
||||
verifyEmail: { max: env.RATE_LIMIT_VERIFY_EMAIL, timeWindow: '15 minutes' },
|
||||
apiAuthed: { max: env.RATE_LIMIT_API_AUTHED, timeWindow: '1 minute' },
|
||||
apiGuest: { max: env.RATE_LIMIT_API_GUEST, timeWindow: '1 minute' },
|
||||
};
|
||||
|
||||
app.decorate('rateLimitOptions', options);
|
||||
|
||||
await app.register(rateLimit, {
|
||||
max: options.apiGuest.max,
|
||||
timeWindow: options.apiGuest.timeWindow,
|
||||
keyGenerator: (req) => {
|
||||
return (req.ip ?? 'unknown') as string;
|
||||
},
|
||||
redis: app.redis,
|
||||
addHeadersOnExceeding: {
|
||||
'x-ratelimit-limit': true,
|
||||
'x-ratelimit-remaining': true,
|
||||
'x-ratelimit-reset': true,
|
||||
},
|
||||
addHeaders: {
|
||||
'x-ratelimit-limit': true,
|
||||
'x-ratelimit-remaining': true,
|
||||
'x-ratelimit-reset': true,
|
||||
'retry-after': true,
|
||||
},
|
||||
errorResponseBuilder: (_req, context) => ({
|
||||
error: {
|
||||
code: 'RATE_LIMIT_EXCEEDED',
|
||||
message: 'Too many requests, please try again later',
|
||||
retryAfter: context.ttl,
|
||||
},
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
export default fp(rateLimitPlugin, { name: 'rateLimit', dependencies: ['redis'] });
|
||||
21
src/plugins/security.ts
Normal file
21
src/plugins/security.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { FastifyInstance, FastifyPluginAsync } from 'fastify';
|
||||
import helmet from '@fastify/helmet';
|
||||
import cors from '@fastify/cors';
|
||||
import fp from 'fastify-plugin';
|
||||
import { getCorsOrigins } from '../config/env.js';
|
||||
|
||||
const securityPlugin: FastifyPluginAsync = async (app: FastifyInstance) => {
|
||||
await app.register(helmet, {
|
||||
contentSecurityPolicy: false,
|
||||
crossOriginEmbedderPolicy: false,
|
||||
});
|
||||
|
||||
await app.register(cors, {
|
||||
origin: getCorsOrigins(),
|
||||
credentials: true,
|
||||
methods: ['GET', 'POST', 'PATCH', 'DELETE', 'PUT', 'OPTIONS'],
|
||||
allowedHeaders: ['Content-Type', 'Authorization'],
|
||||
});
|
||||
};
|
||||
|
||||
export default fp(securityPlugin, { name: 'security' });
|
||||
Reference in New Issue
Block a user