chore: server-and-serverless template

This commit is contained in:
e2e
2026-06-28 12:36:05 +02:00
commit b21fe5a987
202 changed files with 9063 additions and 0 deletions

85
apps/app/src/lib/auth.ts Normal file
View File

@@ -0,0 +1,85 @@
import { createAuthClient } from 'better-auth/client'
import { apiUrl } from './env'
// Better Auth browser client. It targets the worker's catch-all `/api/auth/**`
// routes (generated from src/auth.ts in the functions package). Pass the FULL
// auth base (`<apiUrl>/auth`): better-auth's withPath only appends its default
// `/api/auth` when baseURL has no path, and apiUrl() already carries `/api`, so
// a bare apiUrl() would leave the client calling `/api/get-session` (404) and
// the app would loop back to /login. Cookies ride every request so the session
// round-trips across origins.
export const authClient = createAuthClient({ baseURL: `${apiUrl()}/auth` })
export type AuthSession = {
user?: {
email?: string | null
name?: string | null
image?: string | null
} | null
expires?: string
}
// Thrown by signInWithPassword when the email/password pair is wrong.
export const INVALID_CREDENTIALS = 'INVALID_CREDENTIALS'
// Thrown by registerWithPassword when the email is already taken.
export const EMAIL_IN_USE = 'EMAIL_IN_USE'
export async function getAuthSession(): Promise<AuthSession> {
const { data } = await authClient.getSession()
if (!data?.user) {
return {}
}
return {
user: {
email: data.user.email,
name: data.user.name ?? null,
image: data.user.image ?? null,
},
expires: data.session?.expiresAt
? new Date(data.session.expiresAt).toISOString()
: undefined,
}
}
// Sign in with an email and password. On success Better Auth sets the session
// cookie; on bad credentials this throws INVALID_CREDENTIALS.
export async function signInWithPassword(
email: string,
password: string,
_redirectPath = '/app',
) {
const { error } = await authClient.signIn.email({ email, password })
if (error) {
throw new Error(INVALID_CREDENTIALS)
}
}
// Create a new account. Better Auth signs the user in on success (sets the
// session cookie), so they land logged in.
export async function registerWithPassword(
email: string,
password: string,
options: { name?: string; redirectPath?: string } = {},
) {
const { error } = await authClient.signUp.email({
email,
password,
// Better Auth requires a name; fall back to the local-part of the email.
name: options.name?.trim() || email.split('@')[0],
})
if (error) {
// Better Auth returns 422 (UNPROCESSABLE_ENTITY) when the email is taken.
if (error.status === 422 || /exist|taken/i.test(error.message ?? '')) {
throw new Error(EMAIL_IN_USE)
}
throw new Error('Unable to create account')
}
}
export async function signOut() {
const { error } = await authClient.signOut()
if (error) {
throw new Error('Unable to sign out')
}
}