Skip to content

Commit fa385d3

Browse files
authored
Merge pull request #1811 from mfts/fix/invocations
feat: introduce ratelimiting to endpoint
2 parents ee35f4d + 1193a58 commit fa385d3

File tree

2 files changed

+25
-4
lines changed

2 files changed

+25
-4
lines changed

lib/swr/use-document.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ import { useRouter } from "next/router";
22

33
import { useTeam } from "@/context/team-context";
44
import { View } from "@prisma/client";
5+
import { toast } from "sonner";
56
import useSWR from "swr";
7+
68
import { DocumentWithVersion, LinkWithViews } from "@/lib/types";
79
import { fetcher } from "@/lib/utils";
8-
import { toast } from "sonner";
910

1011
export function useDocument() {
1112
const router = useRouter();
@@ -27,15 +28,20 @@ export function useDocument() {
2728
)}`,
2829
fetcher,
2930
{
30-
dedupingInterval: 10000,
31+
// Reduce background-driven revalidation to avoid excessive API traffic
32+
dedupingInterval: 30000,
33+
revalidateOnFocus: false,
34+
revalidateOnReconnect: false,
35+
revalidateIfStale: false,
3136
onError: (err) => {
3237
if (err.status === 404) {
3338
toast.error("Document not found", {
34-
description: "The document you're looking for doesn't exist or has been moved.",
39+
description:
40+
"The document you're looking for doesn't exist or has been moved.",
3541
});
3642
router.replace("/documents");
3743
}
38-
}
44+
},
3945
},
4046
);
4147

pages/api/teams/[teamId]/documents/[id]/index.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { getServerSession } from "next-auth/next";
55
import { TeamError, errorhandler } from "@/lib/errorHandler";
66
import { deleteFile } from "@/lib/files/delete-file-server";
77
import prisma from "@/lib/prisma";
8+
import { ratelimit } from "@/lib/redis";
89
import { getTeamWithUsersAndDocument } from "@/lib/team/helper";
910
import { CustomUser } from "@/lib/types";
1011
import { serializeFileSize } from "@/lib/utils";
@@ -27,6 +28,20 @@ export default async function handle(
2728
const userId = (session.user as CustomUser).id;
2829

2930
try {
31+
// Per-user, per-document rate limit to prevent abuse
32+
// Default: 120 requests per minute per user per document
33+
const { success, limit, remaining, reset } = await ratelimit(
34+
120,
35+
"1 m",
36+
).limit(`doc:${docId}:team:${teamId}:user:${userId}`);
37+
38+
res.setHeader("X-RateLimit-Limit", limit.toString());
39+
res.setHeader("X-RateLimit-Remaining", remaining.toString());
40+
res.setHeader("X-RateLimit-Reset", reset.toString());
41+
if (!success) {
42+
return res.status(429).json({ error: "Too many requests" });
43+
}
44+
3045
const { document } = await getTeamWithUsersAndDocument({
3146
teamId,
3247
userId,

0 commit comments

Comments
 (0)