Initial commit: MOPC platform with Docker deployment setup
Full Next.js 15 platform with tRPC, Prisma, PostgreSQL, NextAuth. Includes production Dockerfile (multi-stage, port 7600), docker-compose with registry-based image pull, Gitea Actions CI workflow, nginx config for portal.monaco-opc.com, deployment scripts, and DEPLOYMENT.md guide. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
59
src/lib/rate-limit.ts
Normal file
59
src/lib/rate-limit.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Simple in-memory rate limiter using fixed window approach.
|
||||
* Tracks request counts per key (typically IP) within time windows.
|
||||
*
|
||||
* For production with multiple instances, replace with Redis-based solution.
|
||||
*/
|
||||
|
||||
type RateLimitEntry = {
|
||||
count: number
|
||||
resetAt: number
|
||||
}
|
||||
|
||||
const store = new Map<string, RateLimitEntry>()
|
||||
|
||||
export type RateLimitResult = {
|
||||
success: boolean
|
||||
remaining: number
|
||||
resetAt: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Check rate limit for a given key.
|
||||
* @param key - Identifier (e.g., IP address)
|
||||
* @param limit - Max requests per window
|
||||
* @param windowMs - Window size in milliseconds
|
||||
*/
|
||||
export function checkRateLimit(
|
||||
key: string,
|
||||
limit: number,
|
||||
windowMs: number
|
||||
): RateLimitResult {
|
||||
const now = Date.now()
|
||||
const entry = store.get(key)
|
||||
|
||||
if (!entry || now > entry.resetAt) {
|
||||
const resetAt = now + windowMs
|
||||
store.set(key, { count: 1, resetAt })
|
||||
return { success: true, remaining: limit - 1, resetAt }
|
||||
}
|
||||
|
||||
if (entry.count >= limit) {
|
||||
return { success: false, remaining: 0, resetAt: entry.resetAt }
|
||||
}
|
||||
|
||||
entry.count++
|
||||
return { success: true, remaining: limit - entry.count, resetAt: entry.resetAt }
|
||||
}
|
||||
|
||||
// Clean up stale entries every 5 minutes to prevent memory leaks
|
||||
if (typeof setInterval !== 'undefined') {
|
||||
setInterval(() => {
|
||||
const now = Date.now()
|
||||
for (const [key, entry] of store) {
|
||||
if (now > entry.resetAt) {
|
||||
store.delete(key)
|
||||
}
|
||||
}
|
||||
}, 5 * 60 * 1000).unref?.()
|
||||
}
|
||||
Reference in New Issue
Block a user