Files
erika/lib/auth/discord-user.ts

95 lines
2.6 KiB
TypeScript

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<typeof users.$inferSelect> {
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),
),
);
},
});
});
}