Files
calendar/packages/features/auth/lib/next-auth-custom-adapter.ts
T
devin-ai-integration[bot]GitHubalex@cal.com <me@alexvanandel.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>alex@cal.com <me@alexvanandel.com>
d23d68bf2d fix: add explicit type annotation to CalComAdapter function (#22230)
* fix: add explicit type annotation to CalComAdapter function

Resolves TS7056 error where inferred type exceeded maximum length
the compiler will serialize. Added custom CalComAdapterType type
annotation to provide explicit typing while preserving existing
functionality of the authentication adapter.

The custom type annotation matches the actual implementation structure
and resolves the TypeScript compilation error without breaking the
existing NextAuth adapter functionality.

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

* fix: replace any types with proper NextAuth Adapter typing

- Import Awaitable type from next-auth for proper async typing
- Define CalComAdapter type using Cal.com's actual Prisma types
- Remove all any types following TypeScript best practices
- Maintain compatibility with NextAuth's expected interface
- Resolves TS7056 compilation error with explicit typing

Co-Authored-By: alex@cal.com <me@alexvanandel.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: alex@cal.com <me@alexvanandel.com>
2025-07-03 11:37:15 +01:00

100 lines
4.4 KiB
TypeScript

import type { Account, IdentityProvider, Prisma, User, VerificationToken } from "@prisma/client";
import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library";
import type { Awaitable } from "next-auth";
import type { PrismaClient } from "@calcom/prisma";
import { identityProviderNameMap } from "./identityProviderNameMap";
type CalComAdapter = {
createUser: (data: Prisma.UserCreateInput) => Awaitable<User>;
getUser: (id: string | number) => Awaitable<User | null>;
getUserByEmail: (email: User["email"]) => Awaitable<User | null>;
getUserByAccount: (provider_providerAccountId: {
providerAccountId: Account["providerAccountId"];
provider: User["identityProvider"];
}) => Awaitable<User | null>;
updateUser: (data: Prisma.UserUncheckedCreateInput) => Awaitable<User>;
deleteUser: (id: User["id"]) => Awaitable<User>;
createVerificationToken: (data: VerificationToken) => Awaitable<Omit<VerificationToken, "id">>;
useVerificationToken: (
identifier_token: Prisma.VerificationTokenIdentifierTokenCompoundUniqueInput
) => Awaitable<Omit<VerificationToken, "id"> | null>;
linkAccount: (data: Prisma.AccountCreateInput) => Awaitable<Account>;
unlinkAccount: (
provider_providerAccountId: Prisma.AccountProviderProviderAccountIdCompoundUniqueInput
) => Awaitable<Account>;
};
/** @return { import("next-auth/adapters").Adapter } */
export default function CalComAdapter(prismaClient: PrismaClient): CalComAdapter {
return {
createUser: (data: Prisma.UserCreateInput) => prismaClient.user.create({ data }),
getUser: (id: string | number) =>
prismaClient.user.findUnique({ where: { id: typeof id === "string" ? parseInt(id) : id } }),
getUserByEmail: (email: User["email"]) => prismaClient.user.findUnique({ where: { email } }),
async getUserByAccount(provider_providerAccountId: {
providerAccountId: Account["providerAccountId"];
provider: User["identityProvider"];
}) {
let _account;
const account = await prismaClient.account.findUnique({
where: {
provider_providerAccountId,
},
select: { user: true },
});
if (account) {
return (_account = account === null || account === void 0 ? void 0 : account.user) !== null &&
_account !== void 0
? _account
: null;
}
// NOTE: this code it's our fallback to users without Account but credentials in User Table
// We should remove this code after all googles tokens have expired
const provider = provider_providerAccountId?.provider.toUpperCase() as IdentityProvider;
if (["GOOGLE", "SAML"].indexOf(provider) < 0) {
return null;
}
const obtainProvider = identityProviderNameMap[provider].toUpperCase() as IdentityProvider;
const user = await prismaClient.user.findFirst({
where: {
identityProviderId: provider_providerAccountId?.providerAccountId,
identityProvider: obtainProvider,
},
});
return user || null;
},
updateUser: ({ id, ...data }: Prisma.UserUncheckedCreateInput) =>
prismaClient.user.update({ where: { id }, data }),
deleteUser: (id: User["id"]) => prismaClient.user.delete({ where: { id } }),
async createVerificationToken(data: VerificationToken) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { id: _, ...verificationToken } = await prismaClient.verificationToken.create({
data,
});
return verificationToken;
},
async useVerificationToken(identifier_token: Prisma.VerificationTokenIdentifierTokenCompoundUniqueInput) {
try {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { id: _, ...verificationToken } = await prismaClient.verificationToken.delete({
where: { identifier_token },
});
return verificationToken;
} catch (error) {
// If token already used/deleted, just return null
// https://www.prisma.io/docs/reference/api-reference/error-reference#p2025
if (error instanceof PrismaClientKnownRequestError) {
if (error.code === "P2025") return null;
}
throw error;
}
},
linkAccount: (data: Prisma.AccountCreateInput) => prismaClient.account.create({ data }),
unlinkAccount: (provider_providerAccountId: Prisma.AccountProviderProviderAccountIdCompoundUniqueInput) =>
prismaClient.account.delete({ where: { provider_providerAccountId } }),
};
}