import "server-only"; import { and, eq } from "drizzle-orm"; import { db } from "@/db"; import { accounts, users } from "@/db/schema"; import { discordAccountUpdate, reconcileDiscordUser, type DiscordIdentity, } from "@/lib/auth/discord-user-core"; export type { DiscordIdentity } from "@/lib/auth/discord-user-core"; export async function ensureDiscordUser( identity: DiscordIdentity ): Promise { return db.transaction(async (tx) => { const findLinkedUserId = async (discordId: string) => { const [linked] = await tx .select({ userId: accounts.userId }) .from(accounts) .where( and( eq(accounts.provider, "discord"), eq(accounts.providerAccountId, discordId), ), ) .limit(1); return linked?.userId ?? null; }; return reconcileDiscordUser(identity, { findLinkedUserId, async upsertUser({ discordId, displayName, avatarUrl, email }) { const [user] = await tx .insert(users) .values({ discordId, name: displayName, image: avatarUrl, ...(email !== undefined ? { email } : {}), }) .onConflictDoUpdate({ target: users.discordId, set: { name: displayName, image: avatarUrl, ...(email !== undefined ? { email } : {}), }, }) .returning({ id: users.id }); return user.id; }, async insertAccount(userId, discordId, account) { await tx .insert(accounts) .values({ userId, provider: "discord", providerAccountId: discordId, type: account?.type ?? "oauth", ...discordAccountUpdate(account), }) .onConflictDoNothing({ target: [accounts.provider, accounts.providerAccountId], }); }, async updateUser(userId, { discordId, displayName, avatarUrl, email }) { const [user] = await tx .update(users) .set({ discordId, name: displayName, image: avatarUrl, ...(email !== undefined ? { email } : {}), }) .where(eq(users.id, userId)) .returning(); return user ?? null; }, async updateAccount(discordId, update) { await tx .update(accounts) .set(update) .where( and( eq(accounts.provider, "discord"), eq(accounts.providerAccountId, discordId), ), ); }, }); }); }