server/middlewares/rate-limit.ts
Jesse Wierzbinski 3d3e64edab
Some checks failed
CodeQL Scan / Analyze (javascript-typescript) (push) Failing after 42s
Build Docker Images / lint (push) Successful in 31s
Build Docker Images / check (push) Successful in 1m3s
Build Docker Images / tests (push) Failing after 6s
Build Docker Images / build (server, Dockerfile, ${{ github.repository_owner }}/server) (push) Has been skipped
Build Docker Images / build (worker, Worker.Dockerfile, ${{ github.repository_owner }}/worker) (push) Has been skipped
Deploy Docs to GitHub Pages / build (push) Failing after 13s
Mirror to Codeberg / Mirror (push) Failing after 0s
Deploy Docs to GitHub Pages / Deploy (push) Has been skipped
Nix Build / check (push) Failing after 33m18s
feat(api): Implement rate limiting
2025-03-27 20:12:00 +01:00

41 lines
1.3 KiB
TypeScript

import type { z } from "@hono/zod-openapi";
import { env } from "bun";
import type { MiddlewareHandler } from "hono";
import { rateLimiter } from "hono-rate-limiter";
import type { ApiError } from "~/classes/errors/api-error";
import type { HonoEnv } from "~/types/api";
// Not exported by hono-rate-limiter
// So we define it ourselves
type RateLimitEnv = HonoEnv & {
Variables: {
rateLimit: {
limit: number;
remaining: number;
resetTime: Date;
};
};
};
export const rateLimit = (
limit: number,
windowMs = 60 * 1000,
): MiddlewareHandler<RateLimitEnv> =>
env.DISABLE_RATE_LIMIT === "true"
? (_, next): Promise<void> => next()
: rateLimiter<RateLimitEnv>({
keyGenerator: (c): string => c.req.path,
message: (c): z.infer<typeof ApiError.zodSchema> => ({
error: "Too many requests, please try again later.",
details: {
limit: c.get("rateLimit").limit,
remaining: c.get("rateLimit").remaining,
reset: c.get("rateLimit").resetTime.toISOString(),
resetInMs:
c.get("rateLimit").resetTime.getTime() - Date.now(),
},
}),
windowMs,
limit,
});