chore: sync submodule state (parent ref update)

Made-with: Cursor
This commit is contained in:
defiQUG
2026-03-02 12:14:09 -08:00
parent 50ab378da9
commit 5efe36b1e0
1100 changed files with 155024 additions and 8674 deletions

View File

@@ -0,0 +1,3 @@
export function cacheMiddleware(_ttl?: number) {
return (req: unknown, res: unknown, next: () => void) => next();
}

View File

@@ -0,0 +1,55 @@
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
const JWT_SECRET = process.env.JWT_SECRET || 'token-aggregation-secret';
export interface AuthUser {
id: number;
username: string;
email?: string;
role: string;
}
export interface AuthRequest extends Request {
userId?: number;
username?: string;
role?: string;
user?: AuthUser;
}
export function authenticateToken(req: AuthRequest, res: Response, next: NextFunction): void {
const authHeader = req.headers.authorization;
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
res.status(401).json({ error: 'Access token required' });
return;
}
try {
const payload = jwt.verify(token, JWT_SECRET) as { userId: number; username: string; role: string };
req.userId = payload.userId;
req.username = payload.username;
req.role = payload.role;
req.user = { id: payload.userId, username: payload.username, role: payload.role };
next();
} catch {
res.status(403).json({ error: 'Invalid or expired token' });
}
}
export function requireRole(...allowed: string[]) {
return (req: AuthRequest, res: Response, next: NextFunction): void => {
if (!req.role || !allowed.includes(req.role)) {
res.status(403).json({ error: 'Insufficient permissions' });
return;
}
next();
};
}
export function generateToken(userId: number, username: string, role: string): string {
return jwt.sign(
{ userId, username, role },
JWT_SECRET,
{ expiresIn: '24h' }
);
}

View File

@@ -0,0 +1,46 @@
import { Request, Response, NextFunction } from 'express';
interface CacheEntry {
data: any;
expiresAt: number;
}
const cache = new Map<string, CacheEntry>();
const DEFAULT_TTL = 60 * 1000; // 1 minute
export function cacheMiddleware(ttl: number = DEFAULT_TTL) {
return (req: Request, res: Response, next: NextFunction) => {
const key = `${req.method}:${req.originalUrl}`;
const cached = cache.get(key);
if (cached && cached.expiresAt > Date.now()) {
return res.json(cached.data);
}
// Store original json method
const originalJson = res.json.bind(res);
// Override json method to cache response
res.json = function (body: any) {
cache.set(key, {
data: body,
expiresAt: Date.now() + ttl,
});
return originalJson(body);
};
next();
};
}
export function clearCache(): void {
cache.clear();
}
export function clearCacheForPattern(pattern: string): void {
for (const key of cache.keys()) {
if (key.includes(pattern)) {
cache.delete(key);
}
}
}

View File

@@ -0,0 +1,20 @@
import rateLimit from 'express-rate-limit';
const windowMs = parseInt(process.env.RATE_LIMIT_WINDOW_MS || '60000', 10);
const maxRequests = parseInt(process.env.RATE_LIMIT_MAX_REQUESTS || '100', 10);
export const apiRateLimiter = rateLimit({
windowMs,
max: maxRequests,
message: 'Too many requests from this IP, please try again later.',
standardHeaders: true,
legacyHeaders: false,
});
export const strictRateLimiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 10,
message: 'Too many requests, please try again later.',
standardHeaders: true,
legacyHeaders: false,
});