UNPKG

create-arktos

Version:

🚀 A modern Node.js backend boilerplate with TypeScript, Express, JWT authentication, Prisma ORM, PostgreSQL, and Resend email service. Includes complete authentication flow, security middleware, and database management.

139 lines (119 loc) • 5.47 kB
import { z } from 'zod'; // Environment validation schema export const envSchema = z.object({ NODE_ENV: z.enum(['development', 'production', 'test']).default('development'), PORT: z.string().default('3001'), // Database DATABASE_URL: z.string().min(1, 'Database URL is required'), DIRECT_URL: z.string().optional(), // JWT JWT_SECRET: z.string().min(32, 'JWT Secret must be at least 32 characters'), JWT_REFRESH_SECRET: z.string().min(32, 'JWT Refresh Secret must be at least 32 characters'), JWT_EXPIRES_IN: z.string().default('15m'), JWT_REFRESH_EXPIRES_IN: z.string().default('7d'), // Email RESEND_API_KEY: z.string().optional(), FROM_EMAIL: z.string().email().default('noreply@yourapp.com'), FROM_NAME: z.string().default('Arktos'), // App URLs FRONTEND_URL: z.string().url().default('http://localhost:3000'), BACKEND_URL: z.string().url().default('http://localhost:3001'), APP_NAME: z.string().default('Arktos'), // Security BCRYPT_SALT_ROUNDS: z.string().default('12'), PASSWORD_MIN_LENGTH: z.string().default('8'), MAX_LOGIN_ATTEMPTS: z.string().default('5'), ACCOUNT_LOCK_TIME: z.string().default('900000'), // CORS CORS_ORIGIN: z.string().default('http://localhost:3000'), CORS_CREDENTIALS: z.string().default('true'), // Rate Limiting RATE_LIMIT_WINDOW: z.string().default('900000'), RATE_LIMIT_MAX: z.string().default('100'), // Logging LOG_LEVEL: z.enum(['error', 'warn', 'info', 'debug']).default('info'), LOG_FILE: z.string().default('logs/app.log'), }); // Authentication schemas export const loginSchema = z.object({ email: z.string().email('Invalid email format'), password: z.string().min(1, 'Password is required'), }); export const registerSchema = z.object({ email: z.string().email('Invalid email format'), password: z .string() .min(8, 'Password must be at least 8 characters long') .regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/, 'Password must contain at least one lowercase letter, one uppercase letter, and one number'), firstName: z.string().min(1, 'First name is required').max(50, 'First name too long').optional(), lastName: z.string().min(1, 'Last name is required').max(50, 'Last name too long').optional(), username: z .string() .min(3, 'Username must be at least 3 characters') .max(30, 'Username too long') .regex(/^[a-zA-Z0-9_-]+$/, 'Username can only contain letters, numbers, underscores, and hyphens') .optional(), }); export const refreshTokenSchema = z.object({ refreshToken: z.string().min(1, 'Refresh token is required'), }); export const resendVerificationSchema = z.object({ email: z.string().email('Invalid email format'), }); export const forgotPasswordSchema = z.object({ email: z.string().email('Invalid email format'), }); export const resetPasswordSchema = z.object({ token: z.string().min(1, 'Reset token is required'), newPassword: z .string() .min(8, 'Password must be at least 8 characters long') .regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/, 'Password must contain at least one lowercase letter, one uppercase letter, and one number'), }); export const changePasswordSchema = z.object({ currentPassword: z.string().min(1, 'Current password is required'), newPassword: z .string() .min(8, 'Password must be at least 8 characters long') .regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/, 'Password must contain at least one lowercase letter, one uppercase letter, and one number'), }).refine((data) => { return data.newPassword !== data.currentPassword; }, { message: 'New password must be different from current password', path: ['newPassword'], }); // Profile schemas export const updateProfileSchema = z.object({ firstName: z.string().min(1, 'First name is required').max(50, 'First name too long').optional(), lastName: z.string().min(1, 'Last name is required').max(50, 'Last name too long').optional(), username: z .string() .min(3, 'Username must be at least 3 characters') .max(30, 'Username too long') .regex(/^[a-zA-Z0-9_-]+$/, 'Username can only contain letters, numbers, underscores, and hyphens') .optional(), avatar: z.string().url('Avatar must be a valid URL').optional(), }); // Pagination schema export const paginationSchema = z.object({ page: z.string().default('1'), limit: z.string().default('10'), }); // Contact/Support schemas export const contactSchema = z.object({ name: z.string().min(1, 'Name is required').max(100, 'Name too long'), email: z.string().email('Invalid email format'), subject: z.string().min(1, 'Subject is required').max(200, 'Subject too long'), message: z.string().min(10, 'Message too short').max(2000, 'Message too long'), }); export type EnvSchema = z.infer<typeof envSchema>; export type LoginSchema = z.infer<typeof loginSchema>; export type RegisterSchema = z.infer<typeof registerSchema>; export type RefreshTokenSchema = z.infer<typeof refreshTokenSchema>; export type ResendVerificationSchema = z.infer<typeof resendVerificationSchema>; export type ForgotPasswordSchema = z.infer<typeof forgotPasswordSchema>; export type ResetPasswordSchema = z.infer<typeof resetPasswordSchema>; export type ChangePasswordSchema = z.infer<typeof changePasswordSchema>; export type UpdateProfileSchema = z.infer<typeof updateProfileSchema>; export type PaginationSchema = z.infer<typeof paginationSchema>; export type ContactSchema = z.infer<typeof contactSchema>;