5ab2acc711
- Fix Authentik button type casting issue in login page * Use exported signIn instead of authClient type assertion * Add proper error handling for OAuth calls - Fix image MIME type handling in import-photo.ts * Convert base64 to data URL format for AI SDK compatibility - Fix type annotations in auth/server.ts changeEmail handler * Add explicit type annotation for destructured parameters These TypeScript errors were preventing 'pnpm build' from completing during Docker image build process.
144 lines
3.8 KiB
TypeScript
144 lines
3.8 KiB
TypeScript
import { betterAuth } from "better-auth";
|
|
import { genericOAuth } from "better-auth/plugins";
|
|
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
|
import { db, users, sessions, accounts, verifications, eq, count } from "@epicure/db";
|
|
import { sendEmail, verifyEmailHtml, resetPasswordHtml, welcomeHtml } from "@/lib/email";
|
|
|
|
export const auth = betterAuth({
|
|
database: drizzleAdapter(db, {
|
|
provider: "pg",
|
|
schema: { user: users, session: sessions, account: accounts, verification: verifications },
|
|
}),
|
|
|
|
emailAndPassword: {
|
|
enabled: true,
|
|
requireEmailVerification: true,
|
|
sendResetPassword: async ({ user, url }) => {
|
|
await sendEmail({
|
|
to: user.email,
|
|
subject: "Reset your Epicure password",
|
|
html: resetPasswordHtml(url),
|
|
});
|
|
},
|
|
},
|
|
|
|
emailVerification: {
|
|
sendOnSignUp: true,
|
|
autoSignInAfterVerification: true,
|
|
sendVerificationEmail: async ({ user, url }) => {
|
|
await sendEmail({
|
|
to: user.email,
|
|
subject: "Verify your Epicure email",
|
|
html: verifyEmailHtml(url),
|
|
});
|
|
},
|
|
},
|
|
|
|
socialProviders: {
|
|
google: {
|
|
clientId: process.env["GOOGLE_CLIENT_ID"] ?? "",
|
|
clientSecret: process.env["GOOGLE_CLIENT_SECRET"] ?? "",
|
|
},
|
|
...(process.env["GITHUB_CLIENT_ID"] && {
|
|
github: {
|
|
clientId: process.env["GITHUB_CLIENT_ID"],
|
|
clientSecret: process.env["GITHUB_CLIENT_SECRET"] ?? "",
|
|
},
|
|
}),
|
|
...(process.env["DISCORD_CLIENT_ID"] && {
|
|
discord: {
|
|
clientId: process.env["DISCORD_CLIENT_ID"],
|
|
clientSecret: process.env["DISCORD_CLIENT_SECRET"] ?? "",
|
|
},
|
|
}),
|
|
},
|
|
|
|
plugins: [
|
|
...(process.env["AUTHENTIK_CLIENT_ID"] && process.env["AUTHENTIK_BASE_URL"] ? [
|
|
genericOAuth({
|
|
config: [
|
|
{
|
|
providerId: "authentik",
|
|
clientId: process.env["AUTHENTIK_CLIENT_ID"],
|
|
clientSecret: process.env["AUTHENTIK_CLIENT_SECRET"] ?? "",
|
|
// Authentik OIDC discovery URL: https://<your-authentik-domain>/application/o/<slug>/
|
|
discoveryUrl: `${process.env["AUTHENTIK_BASE_URL"]}/.well-known/openid-configuration`,
|
|
scopes: ["openid", "email", "profile"],
|
|
},
|
|
],
|
|
}),
|
|
] : []),
|
|
],
|
|
|
|
session: {
|
|
cookieCache: {
|
|
enabled: true,
|
|
maxAge: 60 * 5,
|
|
},
|
|
},
|
|
|
|
databaseHooks: {
|
|
user: {
|
|
create: {
|
|
after: async (user) => {
|
|
// First registered user becomes admin
|
|
const result = await db.select({ total: count() }).from(users);
|
|
if ((result[0]?.total ?? 0) === 1) {
|
|
await db.update(users).set({ role: "admin" }).where(eq(users.id, user.id));
|
|
}
|
|
// Welcome email (fire and forget)
|
|
sendEmail({
|
|
to: user.email,
|
|
subject: "Welcome to Epicure",
|
|
html: welcomeHtml(user.name),
|
|
}).catch(() => {});
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
user: {
|
|
additionalFields: {
|
|
role: {
|
|
type: "string",
|
|
defaultValue: "user",
|
|
input: false,
|
|
},
|
|
tier: {
|
|
type: "string",
|
|
defaultValue: "free",
|
|
input: false,
|
|
},
|
|
username: {
|
|
type: "string",
|
|
required: false,
|
|
},
|
|
bio: {
|
|
type: "string",
|
|
required: false,
|
|
},
|
|
unitPref: {
|
|
type: "string",
|
|
defaultValue: "metric",
|
|
},
|
|
locale: {
|
|
type: "string",
|
|
defaultValue: "en",
|
|
},
|
|
},
|
|
changeEmail: {
|
|
enabled: true,
|
|
sendChangeEmailVerification: async ({ newEmail, url }: { newEmail: string; url: string }) => {
|
|
await sendEmail({
|
|
to: newEmail,
|
|
subject: "Verify your new Epicure email",
|
|
html: verifyEmailHtml(url),
|
|
});
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
export type Session = typeof auth.$Infer.Session;
|
|
export type User = typeof auth.$Infer.Session.user;
|