diff --git a/apps/api/lib/helpers/customPrisma.ts b/apps/api/lib/helpers/customPrisma.ts index 926c7979cf..db3ffe0c2f 100644 --- a/apps/api/lib/helpers/customPrisma.ts +++ b/apps/api/lib/helpers/customPrisma.ts @@ -1,7 +1,7 @@ import type { NextMiddleware } from "next-api-middleware"; import { CONSOLE_URL } from "@calcom/lib/constants"; -import { customPrisma } from "@calcom/prisma"; +import prisma, { customPrisma } from "@calcom/prisma"; const LOCAL_CONSOLE_URL = process.env.NEXT_PUBLIC_CONSOLE_URL || CONSOLE_URL; @@ -12,32 +12,41 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { } = req; // If no custom api Id is provided, attach to request the regular cal.com prisma client. if (!key) { - req.prisma = customPrisma(); + req.prisma = prisma; await next(); return; } - // If we have a key, we check if the deployment matching the key, has a databaseUrl value set. - const databaseUrl = await fetch(`${LOCAL_CONSOLE_URL}/api/deployments/database?key=${key}`) - .then((res) => res.json()) - .then((res) => res.databaseUrl); + try { + // If we have a key, we check if the deployment matching the key, has a databaseUrl value set. + const databaseUrl = await fetch(`${LOCAL_CONSOLE_URL}/api/deployments/database?key=${key}`) + .then((res) => res.json()) + .then((res) => res.databaseUrl); - if (!databaseUrl) { - res.status(400).json({ error: "no databaseUrl set up at your instance yet" }); - return; - } - req.prisma = customPrisma({ datasources: { db: { url: databaseUrl } } }); - /* @note: + if (!databaseUrl) { + res.status(400).json({ error: "no databaseUrl set up at your instance yet" }); + return; + } + req.prisma = customPrisma({ datasources: { db: { url: databaseUrl } } }); + /* @note: In order to skip verifyApiKey for customPrisma requests, we pass isAdmin true, and userId 0, if we detect them later, we skip verifyApiKey logic and pass onto next middleware instead. */ - req.isAdmin = true; - req.isCustomPrisma = true; - // We don't need the key from here and on. Prevents unrecognized key errors. - delete req.query.key; - await next(); - await req.prisma.$disconnect(); - // @ts-expect-error testing - delete req.prisma; + req.isAdmin = true; + req.isCustomPrisma = true; + // We don't need the key from here and on. Prevents unrecognized key errors. + delete req.query.key; + await next(); + await req.prisma.$disconnect(); + // @ts-expect-error testing + delete req.prisma; + } catch (err) { + if (req.prisma) { + await req.prisma.$disconnect(); + // @ts-expect-error testing + delete req.prisma; + } + throw err; + } }; diff --git a/packages/prisma/index.ts b/packages/prisma/index.ts index b045ff8fb6..eec5d2c34f 100644 --- a/packages/prisma/index.ts +++ b/packages/prisma/index.ts @@ -6,66 +6,54 @@ import { bookingReferenceMiddleware } from "./middleware"; const prismaOptions: Prisma.PrismaClientOptions = {}; -const globalForPrisma = global as unknown as { - prismaWithoutClientExtensions: PrismaClientWithoutExtension; - prismaWithClientExtensions: PrismaClientWithExtensions; -}; - if (!!process.env.NEXT_PUBLIC_DEBUG) prismaOptions.log = ["query", "error", "warn"]; -// Prevents flooding with idle connections -const prismaWithoutClientExtensions = - globalForPrisma.prismaWithoutClientExtensions || new PrismaClientWithoutExtension(prismaOptions); - export const customPrisma = (options?: Prisma.PrismaClientOptions) => new PrismaClientWithoutExtension({ ...prismaOptions, ...options }).$extends(withAccelerate()); -// If any changed on middleware server restart is required -// TODO: Migrate it to $extends -bookingReferenceMiddleware(prismaWithoutClientExtensions); +export const prisma = (function () { + // Prevents flooding with idle connections + const prismaWithoutClientExtensions = new PrismaClientWithoutExtension(prismaOptions); + // If any changed on middleware server restart is required + // TODO: Migrate it to $extends + bookingReferenceMiddleware(prismaWithoutClientExtensions); -// FIXME: Due to some reason, there are types failing in certain places due to the $extends. Fix it and then enable it -// Specifically we get errors like `Type 'string | Date | null | undefined' is not assignable to type 'Exact'` -const prismaWithClientExtensions = prismaWithoutClientExtensions - // - .$extends(withAccelerate()); -// .$extends({ -// query: { -// $allModels: { -// async $allOperations({ model, operation, args, query }) { -// const start = performance.now(); -// /* your custom logic here */ -// const res = await query(args); -// const end = performance.now(); -// logger.debug("Query Perf: ", `${model}.${operation} took ${(end - start).toFixed(2)}ms\n`); -// return res; -// }, -// }, -// }, -// }); -// .$extends({ -// name: "teamUpdateWithMetadata", -// query: { -// team: { -// async update({ model, operation, args, query }) { -// if (args.data.metadata) { -// // Prepare args.data with merged metadata -// } -// return query(args); -// }, -// }, -// }, -// }) + // FIXME: Due to some reason, there are types failing in certain places due to the $extends. Fix it and then enable it + // Specifically we get errors like `Type 'string | Date | null | undefined' is not assignable to type 'Exact'` + const prismaWithClientExtensions = prismaWithoutClientExtensions + // + .$extends(withAccelerate()); + // .$extends({ + // query: { + // $allModels: { + // async $allOperations({ model, operation, args, query }) { + // const start = performance.now(); + // /* your custom logic here */ + // const res = await query(args); + // const end = performance.now(); + // logger.debug("Query Perf: ", `${model}.${operation} took ${(end - start).toFixed(2)}ms\n`); + // return res; + // }, + // }, + // }, + // }); + // .$extends({ + // name: "teamUpdateWithMetadata", + // query: { + // team: { + // async update({ model, operation, args, query }) { + // if (args.data.metadata) { + // // Prepare args.data with merged metadata + // } + // return query(args); + // }, + // }, + // }, + // }) + return prismaWithClientExtensions; +})(); -export const prisma = globalForPrisma.prismaWithClientExtensions || prismaWithClientExtensions; - -if (process.env.NODE_ENV !== "production") { - globalForPrisma.prismaWithoutClientExtensions = prismaWithoutClientExtensions; - globalForPrisma.prismaWithClientExtensions = prisma; -} - -type PrismaClientWithExtensions = typeof prismaWithClientExtensions; -export type PrismaClient = PrismaClientWithExtensions; +export type PrismaClient = typeof prisma; export default prisma; export * from "./selects";