refactor: convert to bun workspaces monorepo
- Move web app into apps/web/ - Create packages/shared/ with shared types - Create plugins/decky-vault/ scaffold - Root package.json manages workspaces only
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
import { betterAuth } from 'better-auth'
|
||||
import { admin, captcha, emailOTP, lastLoginMethod } from 'better-auth/plugins'
|
||||
import { passkey } from '@better-auth/passkey'
|
||||
import { expo } from '@better-auth/expo'
|
||||
import { drizzleAdapter } from '@better-auth/drizzle-adapter'
|
||||
import { db } from '@/lib/db/index'
|
||||
import { ac, admin as adminRole, moderator, contributor, user } from '@/lib/auth/permissions'
|
||||
import { sendOTP, OTP_EXPIRY_SECONDS } from '@/lib/auth/email'
|
||||
|
||||
// ── Origin setup ───────────────────────────────────────
|
||||
// Web + mobile passkey origins
|
||||
const webOrigin = process.env.BETTER_AUTH_URL ?? 'https://localhost:3000'
|
||||
const appScheme = 'deckyvault://'
|
||||
|
||||
// Build trusted origins: web URL + app scheme + optional expo dev
|
||||
const trustedOrigins = [
|
||||
webOrigin,
|
||||
appScheme,
|
||||
]
|
||||
|
||||
// Add Expo dev URLs in development
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
trustedOrigins.push('exp://*')
|
||||
trustedOrigins.push('exp://192.168.*.*:*')
|
||||
}
|
||||
|
||||
// Passkey origins: web URL + optional Android APK key hash
|
||||
const passkeyOrigins = [
|
||||
webOrigin,
|
||||
...(process.env.ANDROID_APK_KEY_HASH
|
||||
? [`android:apk-key-hash:${process.env.ANDROID_APK_KEY_HASH}`]
|
||||
: []),
|
||||
]
|
||||
|
||||
export const auth = betterAuth({
|
||||
experimental: { joins: true },
|
||||
database: drizzleAdapter(db, {
|
||||
provider: 'pg'
|
||||
}),
|
||||
plugins: [
|
||||
captcha({
|
||||
provider: 'cloudflare-turnstile',
|
||||
secretKey: process.env.TURNSTILE_SECRET_KEY!,
|
||||
}),
|
||||
emailOTP({
|
||||
async sendVerificationOTP({ email, otp, type }) {
|
||||
await sendOTP({ email, otp, type })
|
||||
},
|
||||
otpLength: 6,
|
||||
expiresIn: OTP_EXPIRY_SECONDS,
|
||||
allowedAttempts: 5,
|
||||
}),
|
||||
passkey({
|
||||
rpID: process.env.RP_ID ?? 'localhost',
|
||||
rpName: 'DeckyVault',
|
||||
origin: passkeyOrigins,
|
||||
advanced: {
|
||||
webAuthnChallengeCookie: 'better-auth-passkey',
|
||||
},
|
||||
}),
|
||||
lastLoginMethod({
|
||||
storeInDatabase: true,
|
||||
}),
|
||||
admin({
|
||||
ac,
|
||||
roles: {
|
||||
admin: adminRole,
|
||||
moderator,
|
||||
contributor,
|
||||
user,
|
||||
},
|
||||
defaultRole: 'user',
|
||||
adminRoles: ['admin'],
|
||||
}),
|
||||
expo(),
|
||||
],
|
||||
socialProviders: {
|
||||
google: {
|
||||
clientId: process.env.GOOGLE_CLIENT_ID || "",
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET || "",
|
||||
},
|
||||
discord: {
|
||||
clientId: process.env.DISCORD_CLIENT_ID || "",
|
||||
clientSecret: process.env.DISCORD_CLIENT_SECRET || "",
|
||||
},
|
||||
},
|
||||
trustedOrigins,
|
||||
rateLimit: {
|
||||
enabled: false,
|
||||
},
|
||||
session: {
|
||||
expiresIn: 60 * 60 * 24 * 7,
|
||||
updateAge: 60 * 60 * 24,
|
||||
cookieCache: {
|
||||
enabled: true,
|
||||
maxAge: 15 * 60,
|
||||
},
|
||||
},
|
||||
account: {
|
||||
accountLinking: {
|
||||
enabled: true,
|
||||
trustedProviders: ['google', 'discord'],
|
||||
allowDifferentEmails: true
|
||||
}
|
||||
},
|
||||
emailAndPassword: {
|
||||
enabled: true,
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user