diff --git a/package.json b/package.json index ff7437c..679b9d1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sprintpadawan", - "version": "1.0.2", + "version": "1.0.3", "description": "Plan. Sprint. Repeat.", "private": true, "scripts": { @@ -25,8 +25,7 @@ "ably": "^1.2.39", "autoprefixer": "^10.4.14", "daisyui": "^2.51.6", - "fms-ts": "^0.1.6", - "ioredis": "^5.3.2", + "fms-ts": "^0.1.7", "json2csv": "6.0.0-alpha.2", "next": "^13.4.3", "next-auth": "^4.22.1", @@ -35,13 +34,14 @@ "react": "18.2.0", "react-dom": "18.2.0", "react-icons": "^4.8.0", + "redicache-ts": "^0.1.1", "superjson": "1.12.3", "tailwindcss": "^3.3.2", "zod": "^3.21.4" }, "devDependencies": { "@types/eslint": "^8.37.0", - "@types/node": "^20.2.1", + "@types/node": "^20.2.3", "@types/react": "^18.2.6", "@types/react-dom": "^18.2.4", "@typescript-eslint/eslint-plugin": "^5.59.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a73111e..5e96d14 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,11 +44,8 @@ dependencies: specifier: ^2.51.6 version: 2.51.6(autoprefixer@10.4.14)(postcss@8.4.23) fms-ts: - specifier: ^0.1.6 - version: 0.1.6 - ioredis: - specifier: ^5.3.2 - version: 5.3.2 + specifier: ^0.1.7 + version: 0.1.7 json2csv: specifier: 6.0.0-alpha.2 version: 6.0.0-alpha.2 @@ -73,6 +70,9 @@ dependencies: react-icons: specifier: ^4.8.0 version: 4.8.0(react@18.2.0) + redicache-ts: + specifier: ^0.1.1 + version: 0.1.1 superjson: specifier: 1.12.3 version: 1.12.3 @@ -88,8 +88,8 @@ devDependencies: specifier: ^8.37.0 version: 8.37.0 '@types/node': - specifier: ^20.2.1 - version: 20.2.1 + specifier: ^20.2.3 + version: 20.2.3 '@types/react': specifier: ^18.2.6 version: 18.2.6 @@ -1747,7 +1747,7 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.1 '@types/keyv': 3.1.4 - '@types/node': 20.2.1 + '@types/node': 20.2.3 '@types/responselike': 1.0.0 dev: false @@ -1775,7 +1775,7 @@ packages: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: false /@types/http-cache-semantics@4.0.1: @@ -1788,7 +1788,7 @@ packages: /@types/json2csv@5.0.3: resolution: {integrity: sha512-ZJEv6SzhPhgpBpxZU4n/TZekbZqI4EcyXXRwms1lAITG2kIAtj85PfNYafUOY1zy8bWs5ujaub0GU4copaA0sw==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: false /@types/json5@0.0.29: @@ -1798,7 +1798,7 @@ packages: /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: false /@types/minimatch@5.1.2: @@ -1824,8 +1824,8 @@ packages: - supports-color dev: false - /@types/node@20.2.1: - resolution: {integrity: sha512-DqJociPbZP1lbZ5SQPk4oag6W7AyaGMO6gSfRwq3PWl4PXTwJpRQJhDq4W0kzrg3w6tJ1SwlvGZ5uKFHY13LIg==} + /@types/node@20.2.3: + resolution: {integrity: sha512-pg9d0yC4rVNWQzX8U7xb4olIOFuuVL9za3bzMT2pu2SU0SNEi66i2qrvhE2qt0HvkhuCaWJu7pLNOt/Pj8BIrw==} /@types/prop-types@15.7.5: resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} @@ -1846,13 +1846,13 @@ packages: /@types/resolve@1.17.1: resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: false /@types/responselike@1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 dev: false /@types/scheduler@0.16.3: @@ -3369,8 +3369,8 @@ packages: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true - /fms-ts@0.1.6: - resolution: {integrity: sha512-udJ0KwyFEIF27DQDl0PUptyTYrWczBr8P9g/b4j+Zri4cxQZcKCqcLfHUeDaD8usoThpk4WO0jVjftcjs9fYRw==} + /fms-ts@0.1.7: + resolution: {integrity: sha512-OLmulPKywj1ETsAGeNTaxOmrFdffLFr97Gc/Bfmwu80mS1ToyvTDGNcMa16rCScBabd7M+UlCDSgpafjrTyCJw==} dev: false /for-each@0.3.3: @@ -3941,7 +3941,7 @@ packages: resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 merge-stream: 2.0.0 supports-color: 7.2.0 dev: false @@ -3950,7 +3950,7 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 20.2.1 + '@types/node': 20.2.3 merge-stream: 2.0.0 supports-color: 8.1.1 dev: false @@ -4302,8 +4302,8 @@ packages: next: 13.4.3(@babel/core@7.21.8)(react-dom@18.2.0)(react@18.2.0) oauth: 0.9.15 openid-client: 5.4.2 - preact: 10.14.1 - preact-render-to-string: 5.2.6(preact@10.14.1) + preact: 10.15.0 + preact-render-to-string: 5.2.6(preact@10.15.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) uuid: 8.3.2 @@ -4747,17 +4747,17 @@ packages: source-map-js: 1.0.2 dev: false - /preact-render-to-string@5.2.6(preact@10.14.1): + /preact-render-to-string@5.2.6(preact@10.15.0): resolution: {integrity: sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==} peerDependencies: preact: '>=10' dependencies: - preact: 10.14.1 + preact: 10.15.0 pretty-format: 3.8.0 dev: false - /preact@10.14.1: - resolution: {integrity: sha512-4XDSnUisk3YFBb3p9WeKeH1mKoxdFUsaXcvxs9wlpYR1wax/TWJVqhwmIWbByX0h7jMEJH6Zc5J6jqc58FKaNQ==} + /preact@10.15.0: + resolution: {integrity: sha512-nZSa8M2R2m1n7nJSBlzDpxRJaIsejrTO1vlFbdpFvyC8qM1iU+On2y0otfoUm6SRB5o0lF0CKDFxg6grEFU0iQ==} dev: false /prelude-ls@1.2.1: @@ -4865,6 +4865,14 @@ packages: picomatch: 2.3.1 dev: false + /redicache-ts@0.1.1: + resolution: {integrity: sha512-z6edrqsRlayBhI91eA8/N+AGJeFAdU+tvnmP3LzAyQ5pqXEM9Ww1+bHTKd0pWRRcZMWKLaaAHx9SOWj/IEfpuw==} + dependencies: + ioredis: 5.3.2 + transitivePeerDependencies: + - supports-color + dev: false + /redis-errors@1.2.0: resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} engines: {node: '>=4'} diff --git a/src/server/api/routers/room.ts b/src/server/api/routers/room.ts index 543466f..299f669 100644 --- a/src/server/api/routers/room.ts +++ b/src/server/api/routers/room.ts @@ -7,7 +7,15 @@ import { protectedProcedure, } from "~/server/api/trpc"; -import { writeToCache, fetchFromCache, deleteFromCache } from "~/server/redis"; +import { + cacheClient, + writeToCache, + fetchFromCache, + deleteFromCache, +} from "redicache-ts"; +import { env } from "~/env.mjs"; + +const client = cacheClient(env.REDIS_URL); export const roomRouter = createTRPCRouter({ // Create @@ -29,8 +37,12 @@ export const roomRouter = createTRPCRouter({ }, }); if (room) { - await deleteFromCache(`kv_roomcount_admin`); - await deleteFromCache(`kv_roomlist_${ctx.session.user.id}`); + await deleteFromCache(client, env.APP_ENV, `kv_roomcount_admin`); + await deleteFromCache( + client, + env.APP_ENV, + `kv_roomlist_${ctx.session.user.id}` + ); await publishToChannel( `${ctx.session.user.id}`, @@ -92,7 +104,7 @@ export const roomRouter = createTRPCRouter({ createdAt: Date; roomName: string; }[] - >(`kv_roomlist_${ctx.session.user.id}`); + >(client, env.APP_ENV, `kv_roomlist_${ctx.session.user.id}`); if (cachedResult) { return cachedResult; @@ -109,6 +121,8 @@ export const roomRouter = createTRPCRouter({ }); await writeToCache( + client, + env.APP_ENV, `kv_roomlist_${ctx.session.user.id}`, JSON.stringify(roomList), 69 @@ -119,14 +133,24 @@ export const roomRouter = createTRPCRouter({ }), countAll: protectedProcedure.query(async ({ ctx }) => { - const cachedResult = await fetchFromCache(`kv_roomcount_admin`); + const cachedResult = await fetchFromCache( + client, + env.APP_ENV, + `kv_roomcount_admin` + ); if (cachedResult) { return cachedResult; } else { const roomsCount = await ctx.prisma.room.count(); - await writeToCache(`kv_roomcount_admin`, roomsCount, 69); + await writeToCache( + client, + env.APP_ENV, + `kv_roomcount_admin`, + roomsCount, + 69 + ); return roomsCount; } @@ -242,9 +266,13 @@ export const roomRouter = createTRPCRouter({ }); if (deletedRoom) { - await deleteFromCache(`kv_roomcount_admin`); - await deleteFromCache(`kv_votecount_admin`); - await deleteFromCache(`kv_roomlist_${ctx.session.user.id}`); + await deleteFromCache(client, env.APP_ENV, `kv_roomcount_admin`); + await deleteFromCache(client, env.APP_ENV, `kv_votecount_admin`); + await deleteFromCache( + client, + env.APP_ENV, + `kv_roomlist_${ctx.session.user.id}` + ); await publishToChannel( `${ctx.session.user.id}`, diff --git a/src/server/api/routers/session.ts b/src/server/api/routers/session.ts index e15423c..66f2e8c 100644 --- a/src/server/api/routers/session.ts +++ b/src/server/api/routers/session.ts @@ -1,6 +1,9 @@ import { z } from "zod"; import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc"; -import { deleteFromCache } from "~/server/redis"; +import { cacheClient, deleteFromCache } from "redicache-ts"; +import { env } from "~/env.mjs"; + +const client = cacheClient(env.REDIS_URL); export const sessionRouter = createTRPCRouter({ deleteAll: protectedProcedure @@ -17,7 +20,7 @@ export const sessionRouter = createTRPCRouter({ }); if (!!sessions) { - await deleteFromCache(`kv_userlist_admin`); + await deleteFromCache(client, env.APP_ENV, `kv_userlist_admin`); } return !!sessions; diff --git a/src/server/api/routers/user.ts b/src/server/api/routers/user.ts index 7c71292..cf6300b 100644 --- a/src/server/api/routers/user.ts +++ b/src/server/api/routers/user.ts @@ -3,19 +3,37 @@ import { z } from "zod"; import { env } from "~/env.mjs"; import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc"; import { sendMail } from "fms-ts"; -import { fetchFromCache, writeToCache, deleteFromCache } from "~/server/redis"; import type { Role } from "~/utils/types"; +import { + cacheClient, + writeToCache, + fetchFromCache, + deleteFromCache, +} from "redicache-ts"; + +const client = cacheClient(env.REDIS_URL); + export const userRouter = createTRPCRouter({ countAll: protectedProcedure.query(async ({ ctx }) => { - const cachedResult = await fetchFromCache(`kv_usercount_admin`); + const cachedResult = await fetchFromCache( + client, + env.APP_ENV, + `kv_usercount_admin` + ); if (cachedResult) { return cachedResult; } else { const usersCount = await ctx.prisma.user.count(); - await writeToCache(`kv_usercount_admin`, usersCount, 69); + await writeToCache( + client, + env.APP_ENV, + `kv_usercount_admin`, + usersCount, + 69 + ); return usersCount; } @@ -50,7 +68,7 @@ export const userRouter = createTRPCRouter({ name: string | null; email: string | null; }[] - >(`kv_userlist_admin`); + >(client, env.APP_ENV, `kv_userlist_admin`); if (cachedResult) { return cachedResult.map((user) => { @@ -75,7 +93,13 @@ export const userRouter = createTRPCRouter({ }, }); - await writeToCache(`kv_userlist_admin`, JSON.stringify(users), 69); + await writeToCache( + client, + env.APP_ENV, + `kv_userlist_admin`, + JSON.stringify(users), + 69 + ); return users; } @@ -121,8 +145,8 @@ export const userRouter = createTRPCRouter({ body, user.email ); - await deleteFromCache(`kv_usercount_admin`); - await deleteFromCache(`kv_userlist_admin`); + await deleteFromCache(client, env.APP_ENV, `kv_usercount_admin`); + await deleteFromCache(client, env.APP_ENV, `kv_userlist_admin`); } return !!user; @@ -162,7 +186,7 @@ export const userRouter = createTRPCRouter({ }, }); - await deleteFromCache(`kv_userlist_admin`); + await deleteFromCache(client, env.APP_ENV, `kv_userlist_admin`); return !!user; }), diff --git a/src/server/api/routers/vote.ts b/src/server/api/routers/vote.ts index 7548794..3c49f60 100644 --- a/src/server/api/routers/vote.ts +++ b/src/server/api/routers/vote.ts @@ -2,18 +2,36 @@ import { z } from "zod"; import { publishToChannel } from "~/server/ably"; import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc"; -import { deleteFromCache, fetchFromCache, writeToCache } from "~/server/redis"; +import { + cacheClient, + writeToCache, + fetchFromCache, + deleteFromCache, +} from "redicache-ts"; +import { env } from "~/env.mjs"; + +const client = cacheClient(env.REDIS_URL); export const voteRouter = createTRPCRouter({ countAll: protectedProcedure.query(async ({ ctx }) => { - const cachedResult = await fetchFromCache(`kv_votecount_admin`); + const cachedResult = await fetchFromCache( + client, + env.APP_ENV, + `kv_votecount_admin` + ); if (cachedResult) { return cachedResult; } else { const votesCount = await ctx.prisma.vote.count(); - await writeToCache(`kv_votecount_admin`, votesCount, 69); + await writeToCache( + client, + env.APP_ENV, + `kv_votecount_admin`, + votesCount, + 69 + ); return votesCount; } @@ -52,7 +70,7 @@ export const voteRouter = createTRPCRouter({ }); if (vote) { - await deleteFromCache(`kv_votecount_admin`); + await deleteFromCache(client, env.APP_ENV, `kv_votecount_admin`); await publishToChannel(`${vote.roomId}`, "VOTE_UPDATE", "UPDATE"); } diff --git a/src/server/auth.ts b/src/server/auth.ts index 8ae7a6a..4422904 100644 --- a/src/server/auth.ts +++ b/src/server/auth.ts @@ -11,7 +11,9 @@ import { env } from "~/env.mjs"; import { prisma } from "~/server/db"; import type { Role } from "~/utils/types"; import { sendMail } from "fms-ts"; -import { deleteFromCache } from "./redis"; +import { cacheClient, deleteFromCache } from "redicache-ts"; + +const client = cacheClient(env.REDIS_URL); /** * Module augmentation for `next-auth` types. Allows us to add custom properties to the `session` @@ -66,15 +68,15 @@ export const authOptions: NextAuthOptions = { body, user.email ); - await deleteFromCache(`kv_userlist_admin`); - await deleteFromCache(`kv_usercount_admin`); + await deleteFromCache(client, env.APP_ENV, `kv_userlist_admin`); + await deleteFromCache(client, env.APP_ENV, `kv_usercount_admin`); } }, async signIn({}) { - await deleteFromCache(`kv_userlist_admin`); + await deleteFromCache(client, env.APP_ENV, `kv_userlist_admin`); }, async signOut({}) { - await deleteFromCache(`kv_userlist_admin`); + await deleteFromCache(client, env.APP_ENV, `kv_userlist_admin`); }, }, adapter: PrismaAdapter(prisma), diff --git a/src/server/redis.ts b/src/server/redis.ts deleted file mode 100644 index 28b6ce3..0000000 --- a/src/server/redis.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Redis } from "ioredis"; -import { env } from "~/env.mjs"; - -export const redis = new Redis(env.REDIS_URL); - -export const writeToCache = async ( - key: string, - value: string | number | Buffer, - timeout?: number -): Promise => { - try { - if (!!timeout) { - await redis.set(`${env.APP_ENV}_${key}`, value, "EX", timeout); - } else { - await redis.set(`${env.APP_ENV}_${key}`, value); - } - return true; - } catch { - return false; - } -}; - -export const fetchFromCache = async (key: string): Promise => { - try { - // This is bad please don't ever do this. - const cachedValue: Awaited | null = JSON.parse( - (await redis.get(`${env.APP_ENV}_${key}`)) || "" - ) as Awaited | null; - if (!cachedValue && cachedValue !== 0) { - throw new Error("Cache Miss"); - } - console.log(`CACHE HIT FOR KEY ${key}: `, cachedValue); - return cachedValue; - } catch { - console.log(`CACHE MISS FOR KEY ${key}!`); - return null; - } -}; - -export const deleteFromCache = async (key: string) => { - try { - await redis.del(`${env.APP_ENV}_${key}`); - return true; - } catch { - return false; - } -};