shared: - Add class-filter, error-state, route-error, section-error-boundary, widget-boundary components - Add ui/alert component - Add constants directory - Add breached-password, export-utils, permission-bitmap, rate-limit, resolve-action-error, route-permissions, route-resolver, type-guards lib - Add i18n messages (en, zh-CN) for invitation-codes, parent, questions, rbac tests: - Add integration tests for elective - Add tests/setup/empty-stub scripts: - Add update-md.cjs, tmp_append_en.ps1, tmp_merge_en.ps1 utilities
72 lines
2.3 KiB
TypeScript
72 lines
2.3 KiB
TypeScript
/**
|
||
* 速率限制器门面(audit-P1-6)
|
||
*
|
||
* 公共 API 与原 `rate-limit.ts` 单文件保持一致,差异:
|
||
* - `rateLimit()` 与 `resetRateLimit()` 改为 `Promise` 返回,以支持异步后端
|
||
* - 内部根据 `RATE_LIMIT_DRIVER` 环境变量选择实现:
|
||
* - `memory`(默认):单实例内存滑动窗口
|
||
* - `redis`:基于 @upstash/ratelimit + @upstash/redis 的分布式实现
|
||
* - 调用方需 `await rateLimit(...)` / `await resetRateLimit(...)`
|
||
*
|
||
* `rateLimitKey` / `RATE_LIMIT_RULES` / `rateLimitHeaders` 保持同步纯函数。
|
||
*/
|
||
|
||
import { env } from "@/env.mjs"
|
||
|
||
import type { RateLimiter, RateLimitParams, RateLimitResult } from "./types"
|
||
|
||
export type { RateLimiter, RateLimitParams, RateLimitResult } from "./types"
|
||
export { RATE_LIMIT_RULES, rateLimitHeaders, rateLimitKey } from "./rules"
|
||
|
||
import { MemoryRateLimiter } from "./memory-limiter"
|
||
import { RedisRateLimiter } from "./redis-limiter"
|
||
|
||
/**
|
||
* 单例限流器实例(按 env 选择实现,进程级复用)。
|
||
*
|
||
* RedisRateLimiter 类本身在 import 时不会加载 @upstash/* 依赖——
|
||
* 重依赖通过类方法内的 `await import(...)` 懒加载,
|
||
* 仅当 `RATE_LIMIT_DRIVER=redis` 且实际调用 `limit()` 时才加载。
|
||
*/
|
||
let singleton: RateLimiter | null = null
|
||
|
||
/**
|
||
* 获取当前进程的限流器实例。
|
||
*
|
||
* - 默认返回内存实现
|
||
* - 当 `RATE_LIMIT_DRIVER=redis` 时返回 Redis 实现
|
||
* - Redis 实现懒加载所需依赖,未安装 @upstash/ratelimit/redis 时首次调用抛错
|
||
*/
|
||
export function getRateLimiter(): RateLimiter {
|
||
if (singleton) return singleton
|
||
|
||
if (env.RATE_LIMIT_DRIVER === "redis") {
|
||
singleton = new RedisRateLimiter()
|
||
} else {
|
||
singleton = new MemoryRateLimiter()
|
||
}
|
||
return singleton
|
||
}
|
||
|
||
/**
|
||
* 检查请求是否应被允许。
|
||
*
|
||
* 无论成功失败均累加计数(便于失败次数累计锁定)。
|
||
*
|
||
* **变更**:返回 `Promise<RateLimitResult>`,调用方需 `await`。
|
||
*/
|
||
export function rateLimit(params: RateLimitParams): Promise<RateLimitResult> {
|
||
return getRateLimiter().limit(params)
|
||
}
|
||
|
||
/**
|
||
* 重置指定 key 的计数。
|
||
*
|
||
* 用于成功登录后清除失败计数等场景。
|
||
*
|
||
* **变更**:返回 `Promise<void>`,调用方需 `await`。
|
||
*/
|
||
export function resetRateLimit(key: string): Promise<void> {
|
||
return getRateLimiter().reset(key)
|
||
}
|