@re-shell/cli
Version:
Full-stack development platform uniting microservices and microfrontends. Build complete applications with .NET (ASP.NET Core Web API, Minimal API), Java (Spring Boot, Quarkus, Micronaut, Vert.x), Rust (Actix-Web, Warp, Rocket, Axum), Python (FastAPI, Dja
1,944 lines (1,645 loc) • 57.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.polkaTemplate = void 0;
exports.polkaTemplate = {
id: 'polka',
name: 'polka',
displayName: 'Polka',
description: 'Micro web server with minimal overhead (5x faster than Express) for high-performance APIs',
language: 'typescript',
framework: 'polka',
version: '1.0.0-next.23',
tags: ['nodejs', 'polka', 'micro', 'api', 'high-performance', 'minimal', 'typescript'],
port: 3000,
dependencies: {},
features: ['minimal-overhead', 'routing', 'middleware', 'static-files', 'websockets', 'sessions', 'cors', 'body-parsing'],
files: {
// TypeScript project configuration
'package.json': `{
"name": "{{projectName}}",
"version": "1.0.0",
"description": "High-performance micro web server built with Polka and TypeScript",
"main": "dist/index.js",
"type": "module",
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsc",
"start": "node dist/index.js",
"lint": "eslint src --ext .ts",
"test": "uvu tests",
"test:coverage": "c8 npm test",
"typecheck": "tsc --noEmit",
"format": "prettier --write .",
"docker:build": "docker build -t {{projectName}} .",
"docker:run": "docker run -p 3000:3000 {{projectName}}"
},
"dependencies": {
"polka": "^1.0.0-next.23",
"@polka/send-type": "^1.0.0-next.12",
"@polka/redirect": "^1.0.0-next.12",
"@polka/compression": "^1.0.0-next.12",
"@polka/url": "^1.0.0-next.23",
"sirv": "^2.0.4",
"trouter": "^3.2.1",
"mrmime": "^2.0.0",
"regexparam": "^3.0.0",
"body-parser": "^1.20.2",
"cookie-parser": "^1.4.6",
"express-session": "^1.18.0",
"connect-redis": "^7.1.1",
"cors": "^2.8.5",
"helmet": "^7.1.0",
"dotenv": "^16.4.5",
"bcryptjs": "^2.4.3",
"jsonwebtoken": "^9.0.2",
"ioredis": "^5.3.2",
"ws": "^8.17.0",
"uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.43.0",
"pino": "^9.0.0",
"pino-pretty": "^11.0.0",
"@prisma/client": "^5.13.0",
"prisma": "^5.13.0",
"zod": "^3.23.5",
"nanoid": "^5.0.7"
},
"devDependencies": {
"@types/node": "^20.12.7",
"@types/body-parser": "^1.19.5",
"@types/cookie-parser": "^1.4.7",
"@types/cors": "^2.8.17",
"@types/express-session": "^1.17.10",
"@types/bcryptjs": "^2.4.6",
"@types/jsonwebtoken": "^9.0.6",
"@types/ws": "^8.5.10",
"@typescript-eslint/eslint-plugin": "^7.7.1",
"@typescript-eslint/parser": "^7.7.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"prettier": "^3.2.5",
"typescript": "^5.4.5",
"tsx": "^4.7.2",
"uvu": "^0.5.6",
"c8": "^9.1.0",
"httpie": "^1.1.2",
"superstruct": "^1.0.4"
}
}`,
// TypeScript configuration
'tsconfig.json': `{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2022"],
"moduleResolution": "bundler",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"removeComments": true,
"noEmitOnError": true,
"allowSyntheticDefaultImports": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@config/*": ["src/config/*"],
"@handlers/*": ["src/handlers/*"],
"@middlewares/*": ["src/middlewares/*"],
"@routes/*": ["src/routes/*"],
"@services/*": ["src/services/*"],
"@utils/*": ["src/utils/*"],
"@types/*": ["src/types/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "coverage", "tests"]
}`,
// Main application entry point
'src/index.ts': `import polka from 'polka';
import sirv from 'sirv';
import { json, urlencoded } from 'body-parser';
import cookieParser from 'cookie-parser';
import cors from 'cors';
import helmet from 'helmet';
import compression from '@polka/compression';
import { config } from 'dotenv';
import { logger, httpLogger } from './utils/logger';
import { errorHandler } from './middlewares/error.middleware';
import { notFound } from './middlewares/notFound.middleware';
import { rateLimiter } from './middlewares/rateLimit.middleware';
import { connectDatabase } from './config/database';
import { redis } from './config/redis';
import { initWebSocketServer } from './config/websocket';
import routes from './routes';
// Load environment variables
config();
const PORT = parseInt(process.env.PORT || '3000', 10);
const isDev = process.env.NODE_ENV !== 'production';
// Create Polka instance
const app = polka({
onError: errorHandler,
onNoMatch: notFound
});
// Initialize WebSocket server
const wss = initWebSocketServer();
// Global middlewares
app
.use(compression())
.use(helmet())
.use(cors({
origin: process.env.CORS_ORIGIN?.split(',') || '*',
credentials: true
}))
.use(json({ limit: '10mb' }))
.use(urlencoded({ extended: true, limit: '10mb' }))
.use(cookieParser())
.use(httpLogger)
.use('/api', rateLimiter);
// Serve static files (if any)
if (!isDev) {
app.use(sirv('public', {
maxAge: 31536000, // 1 year
immutable: true,
gzip: true,
brotli: true
}));
}
// Health check endpoint
app.get('/health', (req, res) => {
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
environment: process.env.NODE_ENV || 'development',
memory: process.memoryUsage(),
version: process.version
}));
});
// API info endpoint
app.get('/api', (req, res) => {
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({
name: '{{projectName}}',
version: '1.0.0',
framework: 'Polka',
performance: '5x faster than Express',
endpoints: {
auth: '/api/v1/auth',
users: '/api/v1/users',
todos: '/api/v1/todos',
websocket: 'ws://localhost:3000',
health: '/health'
}
}));
});
// Mount API routes
app.use('/api/v1', routes);
// Graceful shutdown
const shutdown = async (signal: string) => {
logger.info(\`\${signal} received: closing server gracefully\`);
// Close WebSocket server
wss.close(() => {
logger.info('WebSocket server closed');
});
// Close database connection
await redis.quit();
// Exit process
process.exit(0);
};
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
// Start server
const start = async () => {
try {
// Connect to database
await connectDatabase();
// Connect to Redis
await redis.connect();
// Start HTTP server
app.listen(PORT, () => {
logger.info(\`⚡ Polka server running on port \${PORT}\`);
logger.info(\`📊 Performance: 5x faster than Express.js\`);
logger.info(\`🔧 Environment: \${process.env.NODE_ENV || 'development'}\`);
logger.info(\`💾 Memory: \${Math.round(process.memoryUsage().heapUsed / 1024 / 1024)}MB\`);
});
} catch (error) {
logger.error('Failed to start server:', error);
process.exit(1);
}
};
start();
export { app, wss };`,
// Routes index
'src/routes/index.ts': `import polka from 'polka';
import authRoutes from './auth.routes';
import userRoutes from './user.routes';
import todoRoutes from './todo.routes';
const router = polka();
// Mount routes
router
.use('/auth', authRoutes)
.use('/users', userRoutes)
.use('/todos', todoRoutes);
export default router;`,
// Authentication routes
'src/routes/auth.routes.ts': `import polka from 'polka';
import { z } from 'zod';
import { validate } from '../middlewares/validate.middleware';
import { AuthHandler } from '../handlers/auth.handler';
import { authenticate } from '../middlewares/auth.middleware';
const router = polka();
const authHandler = new AuthHandler();
// Validation schemas
const registerSchema = z.object({
body: z.object({
email: z.string().email(),
password: z.string().min(8),
name: z.string().min(1)
})
});
const loginSchema = z.object({
body: z.object({
email: z.string().email(),
password: z.string()
})
});
const forgotPasswordSchema = z.object({
body: z.object({
email: z.string().email()
})
});
const resetPasswordSchema = z.object({
params: z.object({
token: z.string()
}),
body: z.object({
password: z.string().min(8)
})
});
// Routes
router
.post('/register', validate(registerSchema), authHandler.register)
.post('/login', validate(loginSchema), authHandler.login)
.post('/refresh', authHandler.refreshToken)
.post('/logout', authenticate, authHandler.logout)
.get('/verify/:token', authHandler.verifyEmail)
.post('/forgot-password', validate(forgotPasswordSchema), authHandler.forgotPassword)
.post('/reset-password/:token', validate(resetPasswordSchema), authHandler.resetPassword);
export default router;`,
// User routes
'src/routes/user.routes.ts': `import polka from 'polka';
import { z } from 'zod';
import { validate } from '../middlewares/validate.middleware';
import { authenticate, authorize } from '../middlewares/auth.middleware';
import { UserHandler } from '../handlers/user.handler';
const router = polka();
const userHandler = new UserHandler();
// Validation schemas
const updateUserSchema = z.object({
params: z.object({
id: z.string()
}),
body: z.object({
email: z.string().email().optional(),
name: z.string().min(1).optional()
})
});
const changePasswordSchema = z.object({
body: z.object({
currentPassword: z.string(),
newPassword: z.string().min(8)
})
});
// All routes require authentication
router.use(authenticate);
// Routes
router
.get('/', authorize('admin'), userHandler.getAllUsers)
.get('/me', userHandler.getCurrentUser)
.get('/:id', userHandler.getUserById)
.put('/:id', validate(updateUserSchema), userHandler.updateUser)
.delete('/:id', authorize('admin'), userHandler.deleteUser)
.post('/change-password', validate(changePasswordSchema), userHandler.changePassword)
.post('/avatar', userHandler.uploadAvatar);
export default router;`,
// Todo routes
'src/routes/todo.routes.ts': `import polka from 'polka';
import { z } from 'zod';
import { validate } from '../middlewares/validate.middleware';
import { authenticate } from '../middlewares/auth.middleware';
import { TodoHandler } from '../handlers/todo.handler';
const router = polka();
const todoHandler = new TodoHandler();
// Validation schemas
const createTodoSchema = z.object({
body: z.object({
title: z.string().min(1),
description: z.string().optional(),
priority: z.enum(['low', 'medium', 'high']).optional(),
dueDate: z.string().datetime().optional()
})
});
const updateTodoSchema = z.object({
params: z.object({
id: z.string()
}),
body: z.object({
title: z.string().min(1).optional(),
description: z.string().optional(),
status: z.enum(['pending', 'in_progress', 'completed']).optional(),
priority: z.enum(['low', 'medium', 'high']).optional(),
dueDate: z.string().datetime().optional()
})
});
const querySchema = z.object({
query: z.object({
page: z.coerce.number().min(1).default(1),
limit: z.coerce.number().min(1).max(100).default(10),
status: z.enum(['pending', 'in_progress', 'completed']).optional(),
priority: z.enum(['low', 'medium', 'high']).optional()
})
});
// All routes require authentication
router.use(authenticate);
// Routes
router
.get('/', validate(querySchema), todoHandler.getAllTodos)
.get('/:id', todoHandler.getTodoById)
.post('/', validate(createTodoSchema), todoHandler.createTodo)
.put('/:id', validate(updateTodoSchema), todoHandler.updateTodo)
.delete('/:id', todoHandler.deleteTodo)
.post('/bulk/delete', todoHandler.bulkDelete)
.post('/bulk/update', todoHandler.bulkUpdate);
export default router;`,
// Authentication handler
'src/handlers/auth.handler.ts': `import type { Request, Response } from 'polka';
import { sendJSON } from '@polka/send-type';
import { AuthService } from '../services/auth.service';
import { EmailService } from '../services/email.service';
import { logger } from '../utils/logger';
import { asyncHandler } from '../utils/asyncHandler';
export class AuthHandler {
private authService: AuthService;
private emailService: EmailService;
constructor() {
this.authService = new AuthService();
this.emailService = new EmailService();
}
register = asyncHandler(async (req: Request, res: Response) => {
const { email, password, name } = req.body;
const result = await this.authService.register({ email, password, name });
// Send verification email
await this.emailService.sendVerificationEmail(email, result.verificationToken);
sendJSON(res, 201, {
success: true,
message: 'Registration successful. Please check your email to verify your account.',
data: {
user: result.user,
accessToken: result.accessToken,
refreshToken: result.refreshToken
}
});
});
login = asyncHandler(async (req: Request, res: Response) => {
const { email, password } = req.body;
const result = await this.authService.login(email, password);
// Set refresh token as HTTP-only cookie
res.setHeader('Set-Cookie', \`refreshToken=\${result.refreshToken}; HttpOnly; Secure; SameSite=Strict; Max-Age=604800000; Path=/\`);
sendJSON(res, 200, {
success: true,
message: 'Login successful',
data: {
user: result.user,
accessToken: result.accessToken
}
});
});
refreshToken = asyncHandler(async (req: Request, res: Response) => {
const cookies = this.parseCookies(req.headers.cookie || '');
const refreshToken = cookies.refreshToken || req.body.refreshToken;
if (!refreshToken) {
sendJSON(res, 401, {
success: false,
error: 'Refresh token not provided'
});
return;
}
const result = await this.authService.refreshToken(refreshToken);
sendJSON(res, 200, {
success: true,
data: {
accessToken: result.accessToken
}
});
});
logout = asyncHandler(async (req: Request, res: Response) => {
const userId = req.user?.id;
if (userId) {
await this.authService.logout(userId);
}
// Clear refresh token cookie
res.setHeader('Set-Cookie', 'refreshToken=; HttpOnly; Secure; SameSite=Strict; Max-Age=0; Path=/');
sendJSON(res, 200, {
success: true,
message: 'Logout successful'
});
});
verifyEmail = asyncHandler(async (req: Request, res: Response) => {
const { token } = req.params;
await this.authService.verifyEmail(token);
sendJSON(res, 200, {
success: true,
message: 'Email verified successfully'
});
});
forgotPassword = asyncHandler(async (req: Request, res: Response) => {
const { email } = req.body;
const resetToken = await this.authService.forgotPassword(email);
// Send reset email
await this.emailService.sendPasswordResetEmail(email, resetToken);
sendJSON(res, 200, {
success: true,
message: 'Password reset email sent'
});
});
resetPassword = asyncHandler(async (req: Request, res: Response) => {
const { token } = req.params;
const { password } = req.body;
await this.authService.resetPassword(token, password);
sendJSON(res, 200, {
success: true,
message: 'Password reset successful'
});
});
private parseCookies(cookieHeader: string): Record<string, string> {
return cookieHeader
.split(';')
.map(v => v.split('='))
.reduce((acc, v) => {
acc[decodeURIComponent(v[0].trim())] = decodeURIComponent(v[1].trim());
return acc;
}, {} as Record<string, string>);
}
}`,
// User handler
'src/handlers/user.handler.ts': `import type { Request, Response } from 'polka';
import { sendJSON } from '@polka/send-type';
import { UserService } from '../services/user.service';
import { asyncHandler } from '../utils/asyncHandler';
export class UserHandler {
private userService: UserService;
constructor() {
this.userService = new UserService();
}
getAllUsers = asyncHandler(async (req: Request, res: Response) => {
const { page = 1, limit = 10, search } = req.query as any;
const result = await this.userService.getAllUsers({
page: Number(page),
limit: Number(limit),
search: search as string
});
sendJSON(res, 200, {
success: true,
data: result
});
});
getCurrentUser = asyncHandler(async (req: Request, res: Response) => {
const userId = req.user!.id;
const user = await this.userService.getUserById(userId);
sendJSON(res, 200, {
success: true,
data: user
});
});
getUserById = asyncHandler(async (req: Request, res: Response) => {
const { id } = req.params;
const user = await this.userService.getUserById(id);
sendJSON(res, 200, {
success: true,
data: user
});
});
updateUser = asyncHandler(async (req: Request, res: Response) => {
const { id } = req.params;
const updates = req.body;
// Ensure users can only update their own profile unless admin
if (req.user!.id !== id && req.user!.role !== 'admin') {
sendJSON(res, 403, {
success: false,
error: 'Forbidden'
});
return;
}
const user = await this.userService.updateUser(id, updates);
sendJSON(res, 200, {
success: true,
message: 'User updated successfully',
data: user
});
});
deleteUser = asyncHandler(async (req: Request, res: Response) => {
const { id } = req.params;
await this.userService.deleteUser(id);
sendJSON(res, 200, {
success: true,
message: 'User deleted successfully'
});
});
changePassword = asyncHandler(async (req: Request, res: Response) => {
const userId = req.user!.id;
const { currentPassword, newPassword } = req.body;
await this.userService.changePassword(userId, currentPassword, newPassword);
sendJSON(res, 200, {
success: true,
message: 'Password changed successfully'
});
});
uploadAvatar = asyncHandler(async (req: Request, res: Response) => {
const userId = req.user!.id;
// TODO: Implement file upload with multer or similar
sendJSON(res, 200, {
success: true,
message: 'Avatar upload endpoint - implement with file upload middleware'
});
});
}`,
// Todo handler
'src/handlers/todo.handler.ts': `import type { Request, Response } from 'polka';
import { sendJSON } from '@polka/send-type';
import { TodoService } from '../services/todo.service';
import { asyncHandler } from '../utils/asyncHandler';
export class TodoHandler {
private todoService: TodoService;
constructor() {
this.todoService = new TodoService();
}
getAllTodos = asyncHandler(async (req: Request, res: Response) => {
const userId = req.user!.id;
const { page, limit, status, priority } = req.query as any;
const result = await this.todoService.getAllTodos({
userId,
page,
limit,
status,
priority
});
sendJSON(res, 200, {
success: true,
data: result
});
});
getTodoById = asyncHandler(async (req: Request, res: Response) => {
const { id } = req.params;
const userId = req.user!.id;
const todo = await this.todoService.getTodoById(id, userId);
sendJSON(res, 200, {
success: true,
data: todo
});
});
createTodo = asyncHandler(async (req: Request, res: Response) => {
const userId = req.user!.id;
const todoData = { ...req.body, userId };
const todo = await this.todoService.createTodo(todoData);
sendJSON(res, 201, {
success: true,
message: 'Todo created successfully',
data: todo
});
});
updateTodo = asyncHandler(async (req: Request, res: Response) => {
const { id } = req.params;
const userId = req.user!.id;
const updates = req.body;
const todo = await this.todoService.updateTodo(id, userId, updates);
sendJSON(res, 200, {
success: true,
message: 'Todo updated successfully',
data: todo
});
});
deleteTodo = asyncHandler(async (req: Request, res: Response) => {
const { id } = req.params;
const userId = req.user!.id;
await this.todoService.deleteTodo(id, userId);
sendJSON(res, 200, {
success: true,
message: 'Todo deleted successfully'
});
});
bulkDelete = asyncHandler(async (req: Request, res: Response) => {
const userId = req.user!.id;
const { ids } = req.body;
if (!Array.isArray(ids) || ids.length === 0) {
sendJSON(res, 400, {
success: false,
error: 'Invalid todo IDs'
});
return;
}
const count = await this.todoService.bulkDelete(ids, userId);
sendJSON(res, 200, {
success: true,
message: \`\${count} todos deleted successfully\`
});
});
bulkUpdate = asyncHandler(async (req: Request, res: Response) => {
const userId = req.user!.id;
const { ids, updates } = req.body;
if (!Array.isArray(ids) || ids.length === 0) {
sendJSON(res, 400, {
success: false,
error: 'Invalid todo IDs'
});
return;
}
const count = await this.todoService.bulkUpdate(ids, userId, updates);
sendJSON(res, 200, {
success: true,
message: \`\${count} todos updated successfully\`
});
});
}`,
// Authentication middleware
'src/middlewares/auth.middleware.ts': `import type { Request, Response, NextFunction } from 'polka';
import jwt from 'jsonwebtoken';
import { sendJSON } from '@polka/send-type';
import { UserService } from '../services/user.service';
interface JwtPayload {
id: string;
email: string;
role: string;
}
declare module 'polka' {
interface Request {
user?: JwtPayload;
}
}
const userService = new UserService();
export const authenticate = async (req: Request, res: Response, next: NextFunction) => {
try {
let token: string | undefined;
// Check for token in Authorization header
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer')) {
token = req.headers.authorization.split(' ')[1];
}
if (!token) {
sendJSON(res, 401, {
success: false,
error: 'Not authorized, no token'
});
return;
}
// Verify token
const decoded = jwt.verify(token, process.env.JWT_SECRET!) as JwtPayload;
// Check if user still exists
const user = await userService.getUserById(decoded.id);
if (!user) {
sendJSON(res, 401, {
success: false,
error: 'User no longer exists'
});
return;
}
// Attach user to request
req.user = {
id: decoded.id,
email: decoded.email,
role: decoded.role
};
next();
} catch (error) {
sendJSON(res, 401, {
success: false,
error: 'Not authorized, token failed'
});
}
};
export const authorize = (...roles: string[]) => {
return (req: Request, res: Response, next: NextFunction) => {
if (!req.user) {
sendJSON(res, 401, {
success: false,
error: 'Not authenticated'
});
return;
}
if (!roles.includes(req.user.role)) {
sendJSON(res, 403, {
success: false,
error: 'Not authorized for this resource'
});
return;
}
next();
};
};`,
// Error handling middleware
'src/middlewares/error.middleware.ts': `import type { Request, Response } from 'polka';
import { sendJSON } from '@polka/send-type';
import { logger } from '../utils/logger';
interface ErrorWithStatus extends Error {
status?: number;
code?: string;
}
export const errorHandler = (err: ErrorWithStatus, req: Request, res: Response, next?: Function) => {
let status = err.status || 500;
let message = err.message || 'Internal Server Error';
// Prisma validation error
if (err.code === 'P2002') {
status = 400;
message = 'Duplicate field value';
}
// JWT errors
if (err.name === 'JsonWebTokenError') {
status = 401;
message = 'Invalid token';
}
if (err.name === 'TokenExpiredError') {
status = 401;
message = 'Token expired';
}
// Zod validation errors
if (err.name === 'ZodError') {
status = 400;
message = 'Validation failed';
}
// Log error
logger.error({
message: err.message,
stack: err.stack,
url: req.url,
method: req.method,
status
});
sendJSON(res, status, {
success: false,
error: {
message,
status,
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
}
});
};`,
// Not found middleware
'src/middlewares/notFound.middleware.ts': `import type { Request, Response } from 'polka';
import { sendJSON } from '@polka/send-type';
export const notFound = (req: Request, res: Response) => {
sendJSON(res, 404, {
success: false,
error: {
message: 'Resource not found',
status: 404,
path: req.url
}
});
};`,
// Validation middleware
'src/middlewares/validate.middleware.ts': `import type { Request, Response, NextFunction } from 'polka';
import { sendJSON } from '@polka/send-type';
import { ZodSchema, ZodError } from 'zod';
export const validate = (schema: ZodSchema) => {
return async (req: Request, res: Response, next: NextFunction) => {
try {
const validated = await schema.parseAsync({
body: req.body,
query: req.query,
params: req.params
});
// Replace request properties with validated data
req.body = validated.body || req.body;
req.query = validated.query || req.query;
req.params = validated.params || req.params;
next();
} catch (error) {
if (error instanceof ZodError) {
sendJSON(res, 400, {
success: false,
error: {
message: 'Validation failed',
status: 400,
details: error.errors
}
});
} else {
next(error);
}
}
};
};`,
// Rate limiting middleware
'src/middlewares/rateLimit.middleware.ts': `import type { Request, Response, NextFunction } from 'polka';
import { sendJSON } from '@polka/send-type';
import { redis } from '../config/redis';
import { logger } from '../utils/logger';
interface RateLimitOptions {
windowMs: number;
max: number;
message?: string;
keyPrefix?: string;
}
const createRateLimiter = (options: RateLimitOptions) => {
const {
windowMs,
max,
message = 'Too many requests from this IP, please try again later.',
keyPrefix = 'rate_limit:'
} = options;
return async (req: Request, res: Response, next: NextFunction) => {
const ip = req.headers['x-forwarded-for'] || req.socket.remoteAddress || 'unknown';
const key = \`\${keyPrefix}\${ip}\`;
try {
const current = await redis.incr(key);
if (current === 1) {
await redis.expire(key, Math.ceil(windowMs / 1000));
}
const ttl = await redis.ttl(key);
res.setHeader('X-RateLimit-Limit', max.toString());
res.setHeader('X-RateLimit-Remaining', Math.max(0, max - current).toString());
res.setHeader('X-RateLimit-Reset', new Date(Date.now() + ttl * 1000).toISOString());
if (current > max) {
res.setHeader('Retry-After', ttl.toString());
sendJSON(res, 429, {
success: false,
error: {
message,
status: 429
}
});
return;
}
next();
} catch (error) {
logger.error('Rate limiter error:', error);
next(); // Continue on error
}
};
};
// General API rate limit
export const rateLimiter = createRateLimiter({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100
});
// Strict rate limit for auth endpoints
export const authRateLimiter = createRateLimiter({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5,
message: 'Too many authentication attempts, please try again later.',
keyPrefix: 'auth_limit:'
});
// File upload rate limit
export const uploadRateLimiter = createRateLimiter({
windowMs: 60 * 60 * 1000, // 1 hour
max: 10,
message: 'Upload limit exceeded, please try again later.',
keyPrefix: 'upload_limit:'
});`,
// Database configuration (Prisma)
'src/config/database.ts': `import { PrismaClient } from '@prisma/client';
import { logger } from '../utils/logger';
const prisma = new PrismaClient({
log: process.env.NODE_ENV === 'development'
? ['query', 'info', 'warn', 'error']
: ['error'],
});
// Log database events in development
if (process.env.NODE_ENV === 'development') {
prisma.$on('query' as any, (e: any) => {
logger.debug(\`Query: \${e.query}\`);
logger.debug(\`Duration: \${e.duration}ms\`);
});
}
export const connectDatabase = async () => {
try {
await prisma.$connect();
logger.info('✅ Database connected successfully');
} catch (error) {
logger.error('❌ Database connection failed:', error);
throw error;
}
};
export { prisma };`,
// Redis configuration
'src/config/redis.ts': `import { Redis } from 'ioredis';
import { logger } from '../utils/logger';
const redisUrl = process.env.REDIS_URL || 'redis://localhost:6379';
export const redis = new Redis(redisUrl, {
maxRetriesPerRequest: 3,
retryStrategy: (times) => {
if (times > 3) {
logger.error('Redis: Maximum reconnection attempts reached');
return null;
}
const delay = Math.min(times * 100, 3000);
logger.info(\`Redis: Reconnecting in \${delay}ms...\`);
return delay;
},
reconnectOnError: (err) => {
const targetErrors = ['READONLY', 'ETIMEDOUT', 'ECONNRESET', 'ECONNREFUSED'];
if (targetErrors.some(e => err.message.includes(e))) {
return true;
}
return false;
}
});
redis.on('error', (err) => {
logger.error('Redis Client Error:', err);
});
redis.on('connect', () => {
logger.info('🔌 Redis Client Connected');
});
redis.on('ready', () => {
logger.info('✅ Redis Client Ready');
});
redis.on('reconnecting', () => {
logger.warn('🔄 Redis Client Reconnecting');
});`,
// WebSocket configuration (using uWebSockets.js)
'src/config/websocket.ts': `import { WebSocketServer } from 'ws';
import jwt from 'jsonwebtoken';
import { logger } from '../utils/logger';
interface ExtendedWebSocket {
userId?: string;
isAlive?: boolean;
}
export const initWebSocketServer = () => {
const wss = new WebSocketServer({
port: parseInt(process.env.WS_PORT || '3001', 10),
perMessageDeflate: {
zlibDeflateOptions: {
chunkSize: 1024,
memLevel: 7,
level: 3
},
zlibInflateOptions: {
chunkSize: 10 * 1024
},
clientNoContextTakeover: true,
serverNoContextTakeover: true,
serverMaxWindowBits: 10,
concurrencyLimit: 10,
threshold: 1024
}
});
// Heartbeat to detect broken connections
const interval = setInterval(() => {
wss.clients.forEach((ws: any) => {
if (ws.isAlive === false) {
return ws.terminate();
}
ws.isAlive = false;
ws.ping();
});
}, 30000);
wss.on('listening', () => {
logger.info(\`🔌 WebSocket server listening on port \${process.env.WS_PORT || '3001'}\`);
});
wss.on('connection', (ws: ExtendedWebSocket, req) => {
ws.isAlive = true;
// Parse token from query string
const url = new URL(req.url!, \`http://\${req.headers.host}\`);
const token = url.searchParams.get('token');
if (!token) {
ws.close(1008, 'No token provided');
return;
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET!) as any;
ws.userId = decoded.id;
logger.info(\`User \${ws.userId} connected via WebSocket\`);
ws.on('pong', () => {
ws.isAlive = true;
});
ws.on('message', (data) => {
try {
const message = JSON.parse(data.toString());
handleMessage(ws, message, wss);
} catch (error) {
logger.error('Invalid WebSocket message:', error);
}
});
ws.on('close', () => {
logger.info(\`User \${ws.userId} disconnected from WebSocket\`);
});
ws.on('error', (error) => {
logger.error(\`WebSocket error for user \${ws.userId}:\`, error);
});
// Send welcome message
ws.send(JSON.stringify({
type: 'connection',
data: { message: 'Connected to WebSocket server' }
}));
} catch (error) {
ws.close(1008, 'Invalid token');
}
});
wss.on('close', () => {
clearInterval(interval);
});
return wss;
};
const handleMessage = (ws: ExtendedWebSocket, message: any, wss: WebSocketServer) => {
const { type, data } = message;
switch (type) {
case 'ping':
ws.send(JSON.stringify({ type: 'pong', data: { timestamp: Date.now() } }));
break;
case 'broadcast':
// Broadcast to all connected clients
wss.clients.forEach((client: any) => {
if (client.readyState === 1 && client.userId !== ws.userId) {
client.send(JSON.stringify({
type: 'broadcast',
data: {
...data,
from: ws.userId,
timestamp: Date.now()
}
}));
}
});
break;
case 'todo:update':
// Broadcast todo updates to all authenticated users
wss.clients.forEach((client: any) => {
if (client.readyState === 1) {
client.send(JSON.stringify({
type: 'todo:updated',
data: {
...data,
timestamp: Date.now()
}
}));
}
});
break;
default:
logger.warn(\`Unknown message type: \${type}\`);
}
};
export const broadcastToUser = (wss: WebSocketServer, userId: string, type: string, data: any) => {
wss.clients.forEach((client: any) => {
if (client.readyState === 1 && client.userId === userId) {
client.send(JSON.stringify({ type, data, timestamp: Date.now() }));
}
});
};`,
// Logger utility using Pino (faster than Winston)
'src/utils/logger.ts': `import pino from 'pino';
const isDev = process.env.NODE_ENV !== 'production';
export const logger = pino({
level: process.env.LOG_LEVEL || (isDev ? 'debug' : 'info'),
transport: isDev ? {
target: 'pino-pretty',
options: {
colorize: true,
translateTime: 'yyyy-mm-dd HH:MM:ss',
ignore: 'pid,hostname'
}
} : undefined,
formatters: {
level: (label) => {
return { level: label.toUpperCase() };
}
},
timestamp: pino.stdTimeFunctions.isoTime,
serializers: {
req: pino.stdSerializers.req,
res: pino.stdSerializers.res,
err: pino.stdSerializers.err
}
});
// HTTP request logger middleware
export const httpLogger = (req: any, res: any, next: any) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
logger.info({
method: req.method,
url: req.url,
status: res.statusCode,
duration: \`\${duration}ms\`,
ip: req.headers['x-forwarded-for'] || req.socket.remoteAddress
});
});
next();
};`,
// Async handler utility
'src/utils/asyncHandler.ts': `import type { Request, Response, NextFunction } from 'polka';
type AsyncRequestHandler = (
req: Request,
res: Response,
next?: NextFunction
) => Promise<void>;
export const asyncHandler = (fn: AsyncRequestHandler) => {
return (req: Request, res: Response, next: NextFunction) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
};`,
// Auth service
'src/services/auth.service.ts': `import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import { nanoid } from 'nanoid';
import { prisma } from '../config/database';
import { redis } from '../config/redis';
import { logger } from '../utils/logger';
interface RegisterData {
email: string;
password: string;
name: string;
}
export class AuthService {
async register(data: RegisterData) {
const { email, password, name } = data;
// Check if user exists
const existingUser = await prisma.user.findUnique({ where: { email } });
if (existingUser) {
throw new Error('User already exists');
}
// Hash password
const hashedPassword = await bcrypt.hash(password, 10);
// Create verification token
const verificationToken = nanoid();
// Create user
const user = await prisma.user.create({
data: {
email,
password: hashedPassword,
name,
verificationToken
},
select: {
id: true,
email: true,
name: true,
role: true
}
});
// Generate tokens
const accessToken = this.generateAccessToken(user);
const refreshToken = this.generateRefreshToken(user.id);
// Store refresh token
await prisma.user.update({
where: { id: user.id },
data: {
refreshTokens: {
push: refreshToken
}
}
});
return { user, accessToken, refreshToken, verificationToken };
}
async login(email: string, password: string) {
// Find user
const user = await prisma.user.findUnique({ where: { email } });
if (!user) {
throw new Error('Invalid credentials');
}
// Check password
const isValidPassword = await bcrypt.compare(password, user.password);
if (!isValidPassword) {
throw new Error('Invalid credentials');
}
// Check if email is verified
if (!user.isEmailVerified) {
throw new Error('Please verify your email first');
}
// Generate tokens
const accessToken = this.generateAccessToken(user);
const refreshToken = this.generateRefreshToken(user.id);
// Store refresh token
await prisma.user.update({
where: { id: user.id },
data: {
refreshTokens: {
push: refreshToken
}
}
});
return {
user: {
id: user.id,
email: user.email,
name: user.name,
role: user.role
},
accessToken,
refreshToken
};
}
async refreshToken(refreshToken: string) {
try {
const decoded = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET!) as any;
// Check if token exists in database
const user = await prisma.user.findFirst({
where: {
id: decoded.userId,
refreshTokens: {
has: refreshToken
}
}
});
if (!user) {
throw new Error('Invalid refresh token');
}
// Generate new access token
const accessToken = this.generateAccessToken(user);
return { accessToken };
} catch (error) {
throw new Error('Invalid refresh token');
}
}
async logout(userId: string) {
// Clear all refresh tokens
await prisma.user.update({
where: { id: userId },
data: { refreshTokens: [] }
});
// Clear any cached sessions
await redis.del(\`session:\${userId}\`);
}
async verifyEmail(token: string) {
const user = await prisma.user.findFirst({
where: { verificationToken: token }
});
if (!user) {
throw new Error('Invalid verification token');
}
await prisma.user.update({
where: { id: user.id },
data: {
isEmailVerified: true,
verificationToken: null
}
});
}
async forgotPassword(email: string) {
const user = await prisma.user.findUnique({ where: { email } });
if (!user) {
throw new Error('User not found');
}
const resetToken = nanoid();
const resetTokenExpiry = new Date(Date.now() + 3600000); // 1 hour
await prisma.user.update({
where: { id: user.id },
data: {
resetToken,
resetTokenExpiry
}
});
return resetToken;
}
async resetPassword(token: string, newPassword: string) {
const user = await prisma.user.findFirst({
where: {
resetToken: token,
resetTokenExpiry: {
gt: new Date()
}
}
});
if (!user) {
throw new Error('Invalid or expired reset token');
}
const hashedPassword = await bcrypt.hash(newPassword, 10);
await prisma.user.update({
where: { id: user.id },
data: {
password: hashedPassword,
resetToken: null,
resetTokenExpiry: null
}
});
}
private generateAccessToken(user: any) {
return jwt.sign(
{
id: user.id,
email: user.email,
role: user.role
},
process.env.JWT_SECRET!,
{ expiresIn: '15m' }
);
}
private generateRefreshToken(userId: string) {
return jwt.sign(
{ userId },
process.env.JWT_REFRESH_SECRET!,
{ expiresIn: '7d' }
);
}
}`,
// User service
'src/services/user.service.ts': `import { prisma } from '../config/database';
import { redis } from '../config/redis';
import bcrypt from 'bcryptjs';
interface GetUsersParams {
page: number;
limit: number;
search?: string;
}
export class UserService {
async getAllUsers(params: GetUsersParams) {
const { page, limit, search } = params;
const skip = (page - 1) * limit;
const where = search ? {
OR: [
{ name: { contains: search, mode: 'insensitive' as const } },
{ email: { contains: search, mode: 'insensitive' as const } }
]
} : {};
const [users, total] = await Promise.all([
prisma.user.findMany({
where,
skip,
take: limit,
select: {
id: true,
email: true,
name: true,
role: true,
createdAt: true
},
orderBy: { createdAt: 'desc' }
}),
prisma.user.count({ where })
]);
return {
users,
pagination: {
page,
limit,
total,
pages: Math.ceil(total / limit)
}
};
}
async getUserById(id: string) {
// Try cache first
const cached = await redis.get(\`user:\${id}\`);
if (cached) {
return JSON.parse(cached);
}
const user = await prisma.user.findUnique({
where: { id },
select: {
id: true,
email: true,
name: true,
role: true,
avatar: true,
isEmailVerified: true,
createdAt: true,
updatedAt: true
}
});
if (!user) {
throw new Error('User not found');
}
// Cache for 5 minutes
await redis.setex(\`user:\${id}\`, 300, JSON.stringify(user));
return user;
}
async updateUser(id: string, updates: any) {
const user = await prisma.user.update({
where: { id },
data: updates,
select: {
id: true,
email: true,
name: true,
role: true,
avatar: true
}
});
// Invalidate cache
await redis.del(\`user:\${id}\`);
return user;
}
async deleteUser(id: string) {
await prisma.user.delete({ where: { id } });
// Invalidate cache
await redis.del(\`user:\${id}\`);
}
async changePassword(userId: string, currentPassword: string, newPassword: string) {
const user = await prisma.user.findUnique({ where: { id: userId } });
if (!user) {
throw new Error('User not found');
}
const isValidPassword = await bcrypt.compare(currentPassword, user.password);
if (!isValidPassword) {
throw new Error('Current password is incorrect');
}
const hashedPassword = await bcrypt.hash(newPassword, 10);
await prisma.user.update({
where: { id: userId },
data: { password: hashedPassword }
});
}
async updateAvatar(userId: string, file: any) {
// TODO: Implement file upload to S3 or similar
const avatarUrl = \`/uploads/avatars/\${userId}-\${Date.now()}.png\`;
await prisma.user.update({
where: { id: userId },
data: { avatar: avatarUrl }
});
// Invalidate cache
await redis.del(\`user:\${userId}\`);
return avatarUrl;
}
}`,
// Todo service
'src/services/todo.service.ts': `import { prisma } from '../config/database';
import { redis } from '../config/redis';
interface GetTodosParams {
userId: string;
page: number;
limit: number;
status?: string;
priority?: string;
}
export class TodoService {
async getAllTodos(params: GetTodosParams) {
const { userId, page, limit, status, priority } = params;
const skip = (page - 1) * limit;
const where: any = { userId };
if (status) where.status = status;
if (priority) where.priority = priority;
const [todos, total] = await Promise.all([
prisma.todo.findMany({
where,
skip,
take: limit,
orderBy: { createdAt: 'desc' }
}),
prisma.todo.count({ where })
]);
return {
todos,
pagination: {
page,
limit,
total,
pages: Math.ceil(total / limit)
}
};
}
async getTodoById(id: string, userId: string) {
const todo = await prisma.todo.findFirst({
where: { id, userId }
});
if (!todo) {
throw new Error('Todo not found');
}
return todo;
}
async createTodo(data: any) {
const todo = await prisma.todo.create({ data });
// Invalidate user's todo list cache
await redis.del(\`todos:\${data.userId}\`);
return todo;
}
async updateTodo(id: string, userId: string, updates: any) {
const todo = await prisma.todo.updateMany({
where: { id, userId },
data: updates
});
if (todo.count === 0) {
throw new Error('Todo not found');
}
// Invalidate cache
await redis.del(\`todos:\${userId}\`);
return prisma.todo.findFirst({ where: { id, userId } });
}
async deleteTodo(id: string, userId: string) {
const result = await prisma.todo.deleteMany({
where: { id, userId }
});
if (result.count === 0) {
throw new Error('Todo not found');
}
// Invalidate cache
await redis.del(\`todos:\${userId}\`);
}
async bulkDelete(ids: string[], userId: string) {
const result = await prisma.todo.deleteMany({
where: {
id: { in: ids },
userId
}
});
// Invalidate cache
await redis.del(\`todos:\${userId}\`);
return result.count;
}
async bulkUpdate(ids: string[], userId: string, updates: any) {
const result = await prisma.todo.updateMany({
where: {
id: { in: ids },
userId
},
data: updates
});
// Invalidate cache
await redis.del(\`todos:\${userId}\`);
return result.count;
}
}`,
// Email service stub
'src/services/email.service.ts': `import { logger } from '../utils/logger';
export class EmailService {
async sendVerificationEmail(email: string, token: string) {
// TODO: Implement actual email sending
logger.info(\`Sending verification email to \${email} with token: \${token}\`);
const verificationUrl = \`\${process.env.CLIENT_URL}/verify-email?token=\${token}\`;
// In production, use a service like SendGrid, SES, or Postmark
return Promise.resolve();
}
async sendPasswordResetEmail(email: string, token: string) {
// TODO: Implement actual email sending
logger.info(\`Sending password reset email to \${email} with token: \${token}\`);
const resetUrl = \`\${process.env.CLIENT_URL}/reset-password?token=\${token}\`;
// In production, use a service like SendGrid, SES, or Postmark
return Promise.resolve();
}
async sendWelcomeEmail(email: string, name: string) {
// TODO: Implement actual email sending
logger.info(\`Sending welcome email to \${name} at \${email}\`);
// In production, use a service like SendGrid, SES, or Postmark
return Promise.resolve();
}
}`,
// Prisma schema
'prisma/schema.prisma': `generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(cuid())
email String @unique
password String
name String
role Role @default(USER)
avatar String?
isEmailVerified Boolean @default(false)
verificationToken String?
resetToken String?
resetTokenExpiry DateTime?
refreshTokens String[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
todos Todo[]
@@index([email])
}
model Todo {
id String @id @default(cuid())
title String
description String?
status TodoStatus @default(PENDING)
priority TodoPriority @default(MEDIUM)
dueDate DateTime?
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([userId])
@@index([status])
@@index([priority])
}
enum Role {
USER
ADMIN
}
enum TodoStatus {
PENDING
IN_PROGRESS
COMPLETED
}
enum TodoPriority {
LOW
MEDIUM
HIGH
}`,
// Environment variables
'.env.example': `# Application
NODE_ENV=development
PORT=3000
WS_PORT=3001
# Database
DATABASE_URL="postgresql://user:password@localhost:5432/dbname"
# Redis
REDIS_URL=redis://localhost:6379
# JWT
JWT_SECRET=your-super-secret-jwt-key
JWT_REFRESH_SECRET=your-super-secret-refresh-key
#