Rate limits return!
This commit is contained in:
parent
27ce857b1a
commit
69fb13dd16
5 changed files with 314 additions and 273 deletions
|
@ -5,6 +5,8 @@ DATABASE_URL=""
|
||||||
UPSTASH_REDIS_REST_URL=""
|
UPSTASH_REDIS_REST_URL=""
|
||||||
UPSTASH_REDIS_REST_TOKEN=""
|
UPSTASH_REDIS_REST_TOKEN=""
|
||||||
UPSTASH_REDIS_EXPIRY_SECONDS=""
|
UPSTASH_REDIS_EXPIRY_SECONDS=""
|
||||||
|
UPSTASH_RATELIMIT_REQUESTS=""
|
||||||
|
UPSTASH_RATELIMIT_SECONDS=""
|
||||||
|
|
||||||
#Next Auth Core
|
#Next Auth Core
|
||||||
NEXTAUTH_SECRET=""
|
NEXTAUTH_SECRET=""
|
||||||
|
|
31
package.json
31
package.json
|
@ -16,37 +16,38 @@
|
||||||
"@auth/prisma-adapter": "^1.0.1",
|
"@auth/prisma-adapter": "^1.0.1",
|
||||||
"@prisma/client": "5.0.0",
|
"@prisma/client": "5.0.0",
|
||||||
"@react-email/components": "^0.0.7",
|
"@react-email/components": "^0.0.7",
|
||||||
"@tanstack/react-query": "^4.29.25",
|
"@tanstack/react-query": "^4.32.0",
|
||||||
"@trpc/client": "10.34.0",
|
"@trpc/client": "10.35.0",
|
||||||
"@trpc/next": "10.34.0",
|
"@trpc/next": "10.35.0",
|
||||||
"@trpc/react-query": "10.34.0",
|
"@trpc/react-query": "10.35.0",
|
||||||
"@trpc/server": "10.34.0",
|
"@trpc/server": "10.35.0",
|
||||||
|
"@upstash/ratelimit": "^0.4.3",
|
||||||
"@upstash/redis": "^1.22.0",
|
"@upstash/redis": "^1.22.0",
|
||||||
"ably": "^1.2.41",
|
"ably": "^1.2.41",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"json2csv": "6.0.0-alpha.2",
|
"json2csv": "6.0.0-alpha.2",
|
||||||
"next": "^13.4.10",
|
"next": "^13.4.12",
|
||||||
"next-auth": "^4.22.1",
|
"next-auth": "^4.22.3",
|
||||||
"postcss": "^8.4.26",
|
"postcss": "^8.4.27",
|
||||||
"preact": "^10.16.0",
|
"preact": "^10.16.0",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-email": "^1.9.4",
|
"react-email": "^1.9.4",
|
||||||
"react-icons": "^4.10.1",
|
"react-icons": "^4.10.1",
|
||||||
"resend": "^0.17.1",
|
"resend": "^0.17.1",
|
||||||
"sharp": "^0.32.3",
|
"sharp": "^0.32.4",
|
||||||
"superjson": "1.13.1",
|
"superjson": "1.13.1",
|
||||||
"zod": "^3.21.4"
|
"zod": "^3.21.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/eslint": "^8.44.0",
|
"@types/eslint": "^8.44.0",
|
||||||
"@types/json2csv": "^5.0.3",
|
"@types/json2csv": "^5.0.3",
|
||||||
"@types/node": "^20.4.2",
|
"@types/node": "^20.4.4",
|
||||||
"@types/react": "^18.2.15",
|
"@types/react": "^18.2.16",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.1.0",
|
"@typescript-eslint/eslint-plugin": "^6.2.0",
|
||||||
"@typescript-eslint/parser": "^6.1.0",
|
"@typescript-eslint/parser": "^6.2.0",
|
||||||
"daisyui": "^3.2.1",
|
"daisyui": "^3.4.0",
|
||||||
"eslint": "^8.45.0",
|
"eslint": "^8.45.0",
|
||||||
"eslint-config-next": "^13.4.10",
|
"eslint-config-next": "^13.4.12",
|
||||||
"prisma": "5.0.0",
|
"prisma": "5.0.0",
|
||||||
"tailwindcss": "^3.3.3",
|
"tailwindcss": "^3.3.3",
|
||||||
"typescript": "^5.1.6"
|
"typescript": "^5.1.6"
|
||||||
|
|
516
pnpm-lock.yaml
generated
516
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
@ -9,6 +9,8 @@ const server = z.object({
|
||||||
UPSTASH_REDIS_REST_URL: z.string().url(),
|
UPSTASH_REDIS_REST_URL: z.string().url(),
|
||||||
UPSTASH_REDIS_REST_TOKEN: z.string(),
|
UPSTASH_REDIS_REST_TOKEN: z.string(),
|
||||||
UPSTASH_REDIS_EXPIRY_SECONDS: z.string(),
|
UPSTASH_REDIS_EXPIRY_SECONDS: z.string(),
|
||||||
|
UPSTASH_RATELIMIT_REQUESTS: z.string(),
|
||||||
|
UPSTASH_RATELIMIT_SECONDS: z.string(),
|
||||||
NODE_ENV: z.enum(["development", "test", "production"]),
|
NODE_ENV: z.enum(["development", "test", "production"]),
|
||||||
NEXTAUTH_SECRET:
|
NEXTAUTH_SECRET:
|
||||||
process.env.NODE_ENV === "production"
|
process.env.NODE_ENV === "production"
|
||||||
|
@ -50,6 +52,8 @@ const processEnv = {
|
||||||
UPSTASH_REDIS_REST_URL: process.env.UPSTASH_REDIS_REST_URL,
|
UPSTASH_REDIS_REST_URL: process.env.UPSTASH_REDIS_REST_URL,
|
||||||
UPSTASH_REDIS_REST_TOKEN: process.env.UPSTASH_REDIS_REST_TOKEN,
|
UPSTASH_REDIS_REST_TOKEN: process.env.UPSTASH_REDIS_REST_TOKEN,
|
||||||
UPSTASH_REDIS_EXPIRY_SECONDS: process.env.UPSTASH_REDIS_EXPIRY_SECONDS,
|
UPSTASH_REDIS_EXPIRY_SECONDS: process.env.UPSTASH_REDIS_EXPIRY_SECONDS,
|
||||||
|
UPSTASH_RATELIMIT_REQUESTS: process.env.UPSTASH_RATELIMIT_REQUESTS,
|
||||||
|
UPSTASH_RATELIMIT_SECONDS: process.env.UPSTASH_RATELIMIT_SECONDS,
|
||||||
NODE_ENV: process.env.NODE_ENV,
|
NODE_ENV: process.env.NODE_ENV,
|
||||||
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
|
NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
|
||||||
NEXTAUTH_URL: process.env.NEXTAUTH_URL,
|
NEXTAUTH_URL: process.env.NEXTAUTH_URL,
|
||||||
|
|
|
@ -66,8 +66,10 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => {
|
||||||
* This is where the tRPC API is initialized, connecting the context and transformer.
|
* This is where the tRPC API is initialized, connecting the context and transformer.
|
||||||
*/
|
*/
|
||||||
import { initTRPC, TRPCError } from "@trpc/server";
|
import { initTRPC, TRPCError } from "@trpc/server";
|
||||||
|
import { Ratelimit } from "@upstash/ratelimit";
|
||||||
import superjson from "superjson";
|
import superjson from "superjson";
|
||||||
import { env } from "~/env.mjs";
|
import { env } from "~/env.mjs";
|
||||||
|
import { Redis } from "@upstash/redis";
|
||||||
|
|
||||||
const t = initTRPC.context<typeof createTRPCContext>().create({
|
const t = initTRPC.context<typeof createTRPCContext>().create({
|
||||||
transformer: superjson,
|
transformer: superjson,
|
||||||
|
@ -106,11 +108,33 @@ const enforceRouteProtection = t.middleware(async ({ ctx, next }) => {
|
||||||
throw new TRPCError({ code: "UNAUTHORIZED" });
|
throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||||
}
|
}
|
||||||
|
|
||||||
return next({
|
try {
|
||||||
ctx: {
|
const rateLimit = new Ratelimit({
|
||||||
session: { ...ctx.session, user: ctx.session.user },
|
redis: Redis.fromEnv(),
|
||||||
},
|
limiter: Ratelimit.slidingWindow(
|
||||||
});
|
Number(env.UPSTASH_RATELIMIT_REQUESTS),
|
||||||
|
`${Number(env.UPSTASH_RATELIMIT_SECONDS)}s`
|
||||||
|
),
|
||||||
|
analytics: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { success } = await rateLimit.limit(
|
||||||
|
`${env.APP_ENV}_${ctx.session.user.id}`
|
||||||
|
);
|
||||||
|
if (!success) throw new TRPCError({ code: "TOO_MANY_REQUESTS" });
|
||||||
|
|
||||||
|
return next({
|
||||||
|
ctx: {
|
||||||
|
session: { ...ctx.session, user: ctx.session.user },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
return next({
|
||||||
|
ctx: {
|
||||||
|
session: { ...ctx.session, user: ctx.session.user },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Reference in a new issue