Lets simplify tRPC

This commit is contained in:
Atridad Lahiji 2023-08-01 12:58:14 -06:00
parent 78aa16cded
commit 96565d573b
No known key found for this signature in database
GPG key ID: 7CB8245F56BC3880
5 changed files with 32 additions and 44 deletions

View file

@ -1,16 +1,16 @@
import { z } from "zod"; import { z } from "zod";
import { publishToChannel } from "~/server/ably"; import { publishToChannel } from "~/server/ably";
import { import {
adminRateLimitedProcedure,
createTRPCRouter, createTRPCRouter,
protectedRateLimitedProcedure, protectedProcedure,
adminProcedure,
} from "~/server/api/trpc"; } from "~/server/api/trpc";
import { fetchCache, invalidateCache, setCache } from "~/server/redis"; import { fetchCache, invalidateCache, setCache } from "~/server/redis";
export const roomRouter = createTRPCRouter({ export const roomRouter = createTRPCRouter({
// Create // Create
create: protectedRateLimitedProcedure create: protectedProcedure
.input( .input(
z.object({ z.object({
name: z.string(), name: z.string(),
@ -46,7 +46,7 @@ export const roomRouter = createTRPCRouter({
}), }),
// Get One // Get One
get: protectedRateLimitedProcedure get: protectedProcedure
.input(z.object({ id: z.string() })) .input(z.object({ id: z.string() }))
.query(({ ctx, input }) => { .query(({ ctx, input }) => {
return ctx.prisma.room.findUnique({ return ctx.prisma.room.findUnique({
@ -67,7 +67,7 @@ export const roomRouter = createTRPCRouter({
}), }),
// Get All // Get All
getAll: protectedRateLimitedProcedure.query(async ({ ctx }) => { getAll: protectedProcedure.query(async ({ ctx }) => {
const cachedResult = await fetchCache< const cachedResult = await fetchCache<
{ {
id: string; id: string;
@ -96,7 +96,7 @@ export const roomRouter = createTRPCRouter({
} }
}), }),
countAll: adminRateLimitedProcedure.query(async ({ ctx }) => { countAll: adminProcedure.query(async ({ ctx }) => {
const cachedResult = await fetchCache<number>(`kv_roomcount_admin`); const cachedResult = await fetchCache<number>(`kv_roomcount_admin`);
if (cachedResult) { if (cachedResult) {
@ -111,7 +111,7 @@ export const roomRouter = createTRPCRouter({
}), }),
// Update One // Update One
set: protectedRateLimitedProcedure set: protectedProcedure
.input( .input(
z.object({ z.object({
name: z.string(), name: z.string(),
@ -212,7 +212,7 @@ export const roomRouter = createTRPCRouter({
}), }),
// Delete One // Delete One
delete: protectedRateLimitedProcedure delete: protectedProcedure
.input(z.object({ id: z.string() })) .input(z.object({ id: z.string() }))
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const deletedRoom = await ctx.prisma.room.delete({ const deletedRoom = await ctx.prisma.room.delete({

View file

@ -1,9 +1,9 @@
import { z } from "zod"; import { z } from "zod";
import { adminRateLimitedProcedure, createTRPCRouter } from "~/server/api/trpc"; import { adminProcedure, createTRPCRouter } from "~/server/api/trpc";
import { invalidateCache } from "~/server/redis"; import { invalidateCache } from "~/server/redis";
export const sessionRouter = createTRPCRouter({ export const sessionRouter = createTRPCRouter({
deleteAllByUserId: adminRateLimitedProcedure deleteAllByUserId: adminProcedure
.input( .input(
z.object({ z.object({
userId: z.string(), userId: z.string(),
@ -22,7 +22,7 @@ export const sessionRouter = createTRPCRouter({
return !!sessions; return !!sessions;
}), }),
deleteAll: adminRateLimitedProcedure.mutation(async ({ ctx }) => { deleteAll: adminProcedure.mutation(async ({ ctx }) => {
const sessions = await ctx.prisma.session.deleteMany(); const sessions = await ctx.prisma.session.deleteMany();
if (!!sessions) { if (!!sessions) {

View file

@ -4,9 +4,9 @@ import { z } from "zod";
import { Goodbye } from "~/components/templates/Goodbye"; import { Goodbye } from "~/components/templates/Goodbye";
import { env } from "~/env.mjs"; import { env } from "~/env.mjs";
import { import {
adminRateLimitedProcedure, adminProcedure,
createTRPCRouter, createTRPCRouter,
protectedRateLimitedProcedure, protectedProcedure,
} from "~/server/api/trpc"; } from "~/server/api/trpc";
import { fetchCache, invalidateCache, setCache } from "~/server/redis"; import { fetchCache, invalidateCache, setCache } from "~/server/redis";
@ -14,7 +14,7 @@ import { fetchCache, invalidateCache, setCache } from "~/server/redis";
const resend = new Resend(process.env.RESEND_API_KEY); const resend = new Resend(process.env.RESEND_API_KEY);
export const userRouter = createTRPCRouter({ export const userRouter = createTRPCRouter({
countAll: adminRateLimitedProcedure.query(async ({ ctx }) => { countAll: adminProcedure.query(async ({ ctx }) => {
const cachedResult = await fetchCache<number>(`kv_usercount_admin`); const cachedResult = await fetchCache<number>(`kv_usercount_admin`);
if (cachedResult) { if (cachedResult) {
@ -28,7 +28,7 @@ export const userRouter = createTRPCRouter({
} }
}), }),
getProviders: protectedRateLimitedProcedure.query(async ({ ctx }) => { getProviders: protectedProcedure.query(async ({ ctx }) => {
const providers = await ctx.prisma.user.findUnique({ const providers = await ctx.prisma.user.findUnique({
where: { where: {
id: ctx.session.user.id, id: ctx.session.user.id,
@ -46,7 +46,7 @@ export const userRouter = createTRPCRouter({
return account.provider; return account.provider;
}); });
}), }),
getAll: protectedRateLimitedProcedure.query(async ({ ctx }) => { getAll: protectedProcedure.query(async ({ ctx }) => {
const cachedResult = await fetchCache< const cachedResult = await fetchCache<
{ {
accounts: { accounts: {
@ -98,7 +98,7 @@ export const userRouter = createTRPCRouter({
return users; return users;
} }
}), }),
delete: protectedRateLimitedProcedure delete: protectedProcedure
.input( .input(
z z
.object({ .object({
@ -136,7 +136,7 @@ export const userRouter = createTRPCRouter({
return !!user; return !!user;
}), }),
save: protectedRateLimitedProcedure save: protectedProcedure
.input( .input(
z.object({ z.object({
name: z.string(), name: z.string(),
@ -154,7 +154,7 @@ export const userRouter = createTRPCRouter({
return !!user; return !!user;
}), }),
setAdmin: adminRateLimitedProcedure setAdmin: adminProcedure
.input( .input(
z.object({ z.object({
userId: z.string(), userId: z.string(),
@ -176,7 +176,7 @@ export const userRouter = createTRPCRouter({
return !!user; return !!user;
}), }),
setVIP: adminRateLimitedProcedure setVIP: adminProcedure
.input( .input(
z.object({ z.object({
userId: z.string(), userId: z.string(),

View file

@ -3,14 +3,14 @@ import { publishToChannel } from "~/server/ably";
import type { Room } from "@prisma/client"; import type { Room } from "@prisma/client";
import { import {
adminRateLimitedProcedure, adminProcedure,
createTRPCRouter, createTRPCRouter,
protectedRateLimitedProcedure, protectedProcedure,
} from "~/server/api/trpc"; } from "~/server/api/trpc";
import { fetchCache, invalidateCache, setCache } from "~/server/redis"; import { fetchCache, invalidateCache, setCache } from "~/server/redis";
export const voteRouter = createTRPCRouter({ export const voteRouter = createTRPCRouter({
countAll: adminRateLimitedProcedure countAll: adminProcedure
.input(z.void()) .input(z.void())
.output(z.number()) .output(z.number())
.meta({ openapi: { method: "GET", path: "/votes/count" } }) .meta({ openapi: { method: "GET", path: "/votes/count" } })
@ -27,7 +27,7 @@ export const voteRouter = createTRPCRouter({
return votesCount; return votesCount;
} }
}), }),
getAllByRoomId: protectedRateLimitedProcedure getAllByRoomId: protectedProcedure
.input(z.object({ roomId: z.string() })) .input(z.object({ roomId: z.string() }))
.query(async ({ ctx, input }) => { .query(async ({ ctx, input }) => {
const cachedResult = await fetchCache< const cachedResult = await fetchCache<
@ -71,7 +71,7 @@ export const voteRouter = createTRPCRouter({
return votesByRoomId; return votesByRoomId;
} }
}), }),
set: protectedRateLimitedProcedure set: protectedProcedure
.input(z.object({ value: z.string(), roomId: z.string() })) .input(z.object({ value: z.string(), roomId: z.string() }))
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const vote = await ctx.prisma.vote.upsert({ const vote = await ctx.prisma.vote.upsert({

View file

@ -113,14 +113,6 @@ const enforceUserIsAuthed = t.middleware(async ({ ctx, next }) => {
throw new TRPCError({ code: "UNAUTHORIZED" }); throw new TRPCError({ code: "UNAUTHORIZED" });
} }
return next({
ctx: {
session: { ...ctx.session, user: ctx.session.user },
},
});
});
const enforceRateLimit = t.middleware(async ({ ctx, next }) => {
const rateLimit = new Ratelimit({ const rateLimit = new Ratelimit({
redis: Redis.fromEnv(), redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow( limiter: Ratelimit.slidingWindow(
@ -129,15 +121,18 @@ const enforceRateLimit = t.middleware(async ({ ctx, next }) => {
), ),
analytics: true, analytics: true,
}); });
console.log(`${env.APP_ENV}_${ctx.session?.user.id || ctx.ip}`);
console.log(ctx.ip);
const { success } = await rateLimit.limit( const { success } = await rateLimit.limit(
`${env.APP_ENV}_${ctx.session?.user.id || ctx.ip}` `${env.APP_ENV}_${ctx.session?.user.id}`
); );
if (!success) throw new TRPCError({ code: "TOO_MANY_REQUESTS" }); if (!success) throw new TRPCError({ code: "TOO_MANY_REQUESTS" });
return next(); return next({
ctx: {
session: { ...ctx.session, user: ctx.session.user },
},
});
}); });
const enforceAdminRole = t.middleware(async ({ ctx, next }) => { const enforceAdminRole = t.middleware(async ({ ctx, next }) => {
@ -161,11 +156,4 @@ const enforceAdminRole = t.middleware(async ({ ctx, next }) => {
*/ */
export const protectedProcedure = t.procedure.use(enforceUserIsAuthed); export const protectedProcedure = t.procedure.use(enforceUserIsAuthed);
export const protectedRateLimitedProcedure =
protectedProcedure.use(enforceRateLimit);
export const publicRateLimitedProcedure = publicProcedure.use(enforceRateLimit);
export const adminProcedure = t.procedure.use(enforceAdminRole); export const adminProcedure = t.procedure.use(enforceAdminRole);
export const adminRateLimitedProcedure = adminProcedure.use(enforceAdminRole);