UNPKG

better-auth

Version:

The most comprehensive authentication library for TypeScript.

801 lines (786 loc) 27.6 kB
import { checkEndpointConflicts, getEndpoints, router } from '../api/index.mjs'; import { defu } from 'defu'; import { hashToBase64, verifyPassword, hashPassword } from '../crypto/index.mjs'; import { a as getAdapter, c as createInternalAdapter, e as getMigrations } from './better-auth.DV0Lly8-.mjs'; import { g as getAuthTables } from './better-auth.B_PTVODM.mjs'; import 'zod/v4'; import './better-auth.Dcv8PS7T.mjs'; import { g as getCookies, c as createCookieGetter } from './better-auth.UfVWArIB.mjs'; import { a as logger, c as createLogger } from './better-auth.BjBlybv-.mjs'; import { U as socialProviders } from './better-auth.CewjboYP.mjs'; import { g as generateId } from './better-auth.BUPPRXfK.mjs'; import 'better-call'; import '@better-auth/utils/hash'; import '@noble/ciphers/chacha.js'; import '@noble/ciphers/utils.js'; import '@better-auth/utils/base64'; import 'jose'; import './better-auth.B4Qoxdgc.mjs'; import { e as env, g as getEnvVar, i as isTest, c as getBooleanEnvVar, E as ENV, a as isProduction } from './better-auth.CMQ3rA-I.mjs'; import { c as checkPassword } from './better-auth.YwDQhoPc.mjs'; import { a as getBaseURL, g as getOrigin } from './better-auth.CuS_eDdK.mjs'; import { B as BetterAuthError } from './better-auth.DdzSJf-n.mjs'; import '@noble/hashes/scrypt.js'; import '@better-auth/utils'; import '@better-auth/utils/hex'; import '@noble/hashes/utils.js'; import { betterFetch } from '@better-fetch/fetch'; import '@better-auth/utils/random'; import { g as getKyselyDatabaseType } from './better-auth.BduPtJy8.mjs'; import { B as BASE_ERROR_CODES } from './better-auth.DV5EHeYG.mjs'; const DEFAULT_SECRET = "better-auth-secret-123456789"; let packageJSONCache; async function readRootPackageJson() { if (packageJSONCache) return packageJSONCache; try { const cwd = typeof process !== "undefined" && typeof process.cwd === "function" ? process.cwd() : ""; if (!cwd) return void 0; const importRuntime = (m) => Function("mm", "return import(mm)")(m); const [{ default: fs }, { default: path }] = await Promise.all([ importRuntime("fs/promises"), importRuntime("path") ]); const raw = await fs.readFile(path.join(cwd, "package.json"), "utf-8"); packageJSONCache = JSON.parse(raw); return packageJSONCache; } catch { } return void 0; } async function getPackageVersion(pkg) { if (packageJSONCache) { return packageJSONCache.dependencies?.[pkg] || packageJSONCache.devDependencies?.[pkg] || packageJSONCache.peerDependencies?.[pkg]; } try { const cwd = typeof process !== "undefined" && typeof process.cwd === "function" ? process.cwd() : ""; if (!cwd) throw new Error("no-cwd"); const importRuntime = (m) => Function("mm", "return import(mm)")(m); const [{ default: fs }, { default: path }] = await Promise.all([ importRuntime("fs/promises"), importRuntime("path") ]); const pkgJsonPath = path.join(cwd, "node_modules", pkg, "package.json"); const raw = await fs.readFile(pkgJsonPath, "utf-8"); const json = JSON.parse(raw); const resolved = json.version || await getVersionFromLocalPackageJson(pkg) || void 0; return resolved; } catch { } const fromRoot = await getVersionFromLocalPackageJson(pkg); return fromRoot; } async function getVersionFromLocalPackageJson(pkg) { const json = await readRootPackageJson(); if (!json) return void 0; const allDeps = { ...json.dependencies, ...json.devDependencies, ...json.peerDependencies }; return allDeps[pkg]; } async function getNameFromLocalPackageJson() { const json = await readRootPackageJson(); return json?.name; } let projectIdCached = null; async function getProjectId(baseUrl) { if (projectIdCached) return projectIdCached; const projectName = await getNameFromLocalPackageJson(); if (projectName) { projectIdCached = await hashToBase64( baseUrl ? baseUrl + projectName : projectName ); return projectIdCached; } if (baseUrl) { projectIdCached = await hashToBase64(baseUrl); return projectIdCached; } projectIdCached = generateId(32); return projectIdCached; } const importRuntime = (m) => { return Function("mm", "return import(mm)")(m); }; function getVendor() { const hasAny = (...keys) => keys.some((k) => Boolean(env[k])); if (hasAny("CF_PAGES", "CF_PAGES_URL", "CF_ACCOUNT_ID") || typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers") { return "cloudflare"; } if (hasAny("VERCEL", "VERCEL_URL", "VERCEL_ENV")) return "vercel"; if (hasAny("NETLIFY", "NETLIFY_URL")) return "netlify"; if (hasAny( "RENDER", "RENDER_URL", "RENDER_INTERNAL_HOSTNAME", "RENDER_SERVICE_ID" )) { return "render"; } if (hasAny("AWS_LAMBDA_FUNCTION_NAME", "AWS_EXECUTION_ENV", "LAMBDA_TASK_ROOT")) { return "aws"; } if (hasAny( "GOOGLE_CLOUD_FUNCTION_NAME", "GOOGLE_CLOUD_PROJECT", "GCP_PROJECT", "K_SERVICE" )) { return "gcp"; } if (hasAny( "AZURE_FUNCTION_NAME", "FUNCTIONS_WORKER_RUNTIME", "WEBSITE_INSTANCE_ID", "WEBSITE_SITE_NAME" )) { return "azure"; } if (hasAny("DENO_DEPLOYMENT_ID", "DENO_REGION")) return "deno-deploy"; if (hasAny("FLY_APP_NAME", "FLY_REGION", "FLY_ALLOC_ID")) return "fly-io"; if (hasAny("RAILWAY_STATIC_URL", "RAILWAY_ENVIRONMENT_NAME")) return "railway"; if (hasAny("DYNO", "HEROKU_APP_NAME")) return "heroku"; if (hasAny("DO_DEPLOYMENT_ID", "DO_APP_NAME", "DIGITALOCEAN")) return "digitalocean"; if (hasAny("KOYEB", "KOYEB_DEPLOYMENT_ID", "KOYEB_APP_NAME")) return "koyeb"; return null; } async function detectSystemInfo() { try { if (getVendor() === "cloudflare") return "cloudflare"; const os = await importRuntime("os"); const cpus = os.cpus(); return { deploymentVendor: getVendor(), systemPlatform: os.platform(), systemRelease: os.release(), systemArchitecture: os.arch(), cpuCount: cpus.length, cpuModel: cpus.length ? cpus[0].model : null, cpuSpeed: cpus.length ? cpus[0].speed : null, memory: os.totalmem(), isWSL: await isWsl(), isDocker: await isDocker(), isTTY: typeof process !== "undefined" && process.stdout ? process.stdout.isTTY : null }; } catch (e) { return { systemPlatform: null, systemRelease: null, systemArchitecture: null, cpuCount: null, cpuModel: null, cpuSpeed: null, memory: null, isWSL: null, isDocker: null, isTTY: null }; } } let isDockerCached; async function hasDockerEnv() { if (getVendor() === "cloudflare") return false; try { const fs = await importRuntime("fs"); fs.statSync("/.dockerenv"); return true; } catch { return false; } } async function hasDockerCGroup() { if (getVendor() === "cloudflare") return false; try { const fs = await importRuntime("fs"); return fs.readFileSync("/proc/self/cgroup", "utf8").includes("docker"); } catch { return false; } } async function isDocker() { if (getVendor() === "cloudflare") return false; if (isDockerCached === void 0) { isDockerCached = await hasDockerEnv() || await hasDockerCGroup(); } return isDockerCached; } async function isWsl() { try { if (getVendor() === "cloudflare") return false; if (typeof process === "undefined" || process.platform !== "linux") { return false; } const fs = await importRuntime("fs"); const os = await importRuntime("os"); if (os.release().toLowerCase().includes("microsoft")) { if (await isInsideContainer()) { return false; } return true; } return fs.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft") ? !await isInsideContainer() : false; } catch { return false; } } let isInsideContainerCached; const hasContainerEnv = async () => { if (getVendor() === "cloudflare") return false; try { const fs = await importRuntime("fs"); fs.statSync("/run/.containerenv"); return true; } catch { return false; } }; async function isInsideContainer() { if (isInsideContainerCached === void 0) { isInsideContainerCached = await hasContainerEnv() || await isDocker(); } return isInsideContainerCached; } function isCI() { return env.CI !== "false" && ("BUILD_ID" in env || // Jenkins, Cloudbees "BUILD_NUMBER" in env || // Jenkins, TeamCity (fixed typo: extra space removed) "CI" in env || // Travis CI, CircleCI, Cirrus CI, Gitlab CI, Appveyor, CodeShip, dsari, Cloudflare "CI_APP_ID" in env || // Appflow "CI_BUILD_ID" in env || // Appflow "CI_BUILD_NUMBER" in env || // Appflow "CI_NAME" in env || // Codeship and others "CONTINUOUS_INTEGRATION" in env || // Travis CI, Cirrus CI "RUN_ID" in env); } function detectRuntime() { if (typeof Deno !== "undefined") { const denoVersion = Deno?.version?.deno ?? null; return { name: "deno", version: denoVersion }; } if (typeof Bun !== "undefined") { const bunVersion = Bun?.version ?? null; return { name: "bun", version: bunVersion }; } if (typeof process !== "undefined" && process?.versions?.node) { return { name: "node", version: process.versions.node ?? null }; } return { name: "edge", version: null }; } function detectEnvironment() { return getEnvVar("NODE_ENV") === "production" ? "production" : isCI() ? "ci" : isTest() ? "test" : "development"; } const DATABASES = { pg: "postgresql", mysql: "mysql", mariadb: "mariadb", sqlite3: "sqlite", "better-sqlite3": "sqlite", "@prisma/client": "prisma", mongoose: "mongodb", mongodb: "mongodb", "drizzle-orm": "drizzle" }; async function detectDatabase() { for (const [pkg, name] of Object.entries(DATABASES)) { const version = await getPackageVersion(pkg); if (version) return { name, version }; } return void 0; } const FRAMEWORKS = { next: "next", nuxt: "nuxt", "@remix-run/server-runtime": "remix", astro: "astro", "@sveltejs/kit": "sveltekit", "solid-start": "solid-start", "tanstack-start": "tanstack-start", hono: "hono", express: "express", elysia: "elysia", expo: "expo" }; async function detectFramework() { for (const [pkg, name] of Object.entries(FRAMEWORKS)) { const version = await getPackageVersion(pkg); if (version) return { name, version }; } return void 0; } function detectPackageManager() { const userAgent = env.npm_config_user_agent; if (!userAgent) { return void 0; } const pmSpec = userAgent.split(" ")[0]; const separatorPos = pmSpec.lastIndexOf("/"); const name = pmSpec.substring(0, separatorPos); return { name: name === "npminstall" ? "cnpm" : name, version: pmSpec.substring(separatorPos + 1) }; } function getTelemetryAuthConfig(options, context) { return { database: context?.database, adapter: context?.adapter, emailVerification: { sendVerificationEmail: !!options.emailVerification?.sendVerificationEmail, sendOnSignUp: !!options.emailVerification?.sendOnSignUp, sendOnSignIn: !!options.emailVerification?.sendOnSignIn, autoSignInAfterVerification: !!options.emailVerification?.autoSignInAfterVerification, expiresIn: options.emailVerification?.expiresIn, onEmailVerification: !!options.emailVerification?.onEmailVerification, afterEmailVerification: !!options.emailVerification?.afterEmailVerification }, emailAndPassword: { enabled: !!options.emailAndPassword?.enabled, disableSignUp: !!options.emailAndPassword?.disableSignUp, requireEmailVerification: !!options.emailAndPassword?.requireEmailVerification, maxPasswordLength: options.emailAndPassword?.maxPasswordLength, minPasswordLength: options.emailAndPassword?.minPasswordLength, sendResetPassword: !!options.emailAndPassword?.sendResetPassword, resetPasswordTokenExpiresIn: options.emailAndPassword?.resetPasswordTokenExpiresIn, onPasswordReset: !!options.emailAndPassword?.onPasswordReset, password: { hash: !!options.emailAndPassword?.password?.hash, verify: !!options.emailAndPassword?.password?.verify }, autoSignIn: !!options.emailAndPassword?.autoSignIn, revokeSessionsOnPasswordReset: !!options.emailAndPassword?.revokeSessionsOnPasswordReset }, socialProviders: Object.keys(options.socialProviders || {}).map((p) => { const provider = options.socialProviders?.[p]; if (!provider) return {}; return { id: p, mapProfileToUser: !!provider.mapProfileToUser, disableDefaultScope: !!provider.disableDefaultScope, disableIdTokenSignIn: !!provider.disableIdTokenSignIn, disableImplicitSignUp: provider.disableImplicitSignUp, disableSignUp: provider.disableSignUp, getUserInfo: !!provider.getUserInfo, overrideUserInfoOnSignIn: !!provider.overrideUserInfoOnSignIn, prompt: provider.prompt, verifyIdToken: !!provider.verifyIdToken, scope: provider.scope, refreshAccessToken: !!provider.refreshAccessToken }; }), plugins: options.plugins?.map((p) => p.id.toString()), user: { modelName: options.user?.modelName, fields: options.user?.fields, additionalFields: options.user?.additionalFields, changeEmail: { enabled: options.user?.changeEmail?.enabled, sendChangeEmailVerification: !!options.user?.changeEmail?.sendChangeEmailVerification } }, verification: { modelName: options.verification?.modelName, disableCleanup: options.verification?.disableCleanup, fields: options.verification?.fields }, session: { modelName: options.session?.modelName, additionalFields: options.session?.additionalFields, cookieCache: { enabled: options.session?.cookieCache?.enabled, maxAge: options.session?.cookieCache?.maxAge }, disableSessionRefresh: options.session?.disableSessionRefresh, expiresIn: options.session?.expiresIn, fields: options.session?.fields, freshAge: options.session?.freshAge, preserveSessionInDatabase: options.session?.preserveSessionInDatabase, storeSessionInDatabase: options.session?.storeSessionInDatabase, updateAge: options.session?.updateAge }, account: { modelName: options.account?.modelName, fields: options.account?.fields, encryptOAuthTokens: options.account?.encryptOAuthTokens, updateAccountOnSignIn: options.account?.updateAccountOnSignIn, accountLinking: { enabled: options.account?.accountLinking?.enabled, trustedProviders: options.account?.accountLinking?.trustedProviders, updateUserInfoOnLink: options.account?.accountLinking?.updateUserInfoOnLink, allowUnlinkingAll: options.account?.accountLinking?.allowUnlinkingAll } }, hooks: { after: !!options.hooks?.after, before: !!options.hooks?.before }, secondaryStorage: !!options.secondaryStorage, advanced: { cookiePrefix: !!options.advanced?.cookiePrefix, //this shouldn't be tracked cookies: !!options.advanced?.cookies, crossSubDomainCookies: { domain: !!options.advanced?.crossSubDomainCookies?.domain, enabled: options.advanced?.crossSubDomainCookies?.enabled, additionalCookies: options.advanced?.crossSubDomainCookies?.additionalCookies }, database: { useNumberId: !!options.advanced?.database?.useNumberId, generateId: options.advanced?.database?.generateId, defaultFindManyLimit: options.advanced?.database?.defaultFindManyLimit }, useSecureCookies: options.advanced?.useSecureCookies, ipAddress: { disableIpTracking: options.advanced?.ipAddress?.disableIpTracking, ipAddressHeaders: options.advanced?.ipAddress?.ipAddressHeaders }, disableCSRFCheck: options.advanced?.disableCSRFCheck, cookieAttributes: { expires: options.advanced?.defaultCookieAttributes?.expires, secure: options.advanced?.defaultCookieAttributes?.secure, sameSite: options.advanced?.defaultCookieAttributes?.sameSite, domain: !!options.advanced?.defaultCookieAttributes?.domain, path: options.advanced?.defaultCookieAttributes?.path, httpOnly: options.advanced?.defaultCookieAttributes?.httpOnly } }, trustedOrigins: options.trustedOrigins?.length, rateLimit: { storage: options.rateLimit?.storage, modelName: options.rateLimit?.modelName, window: options.rateLimit?.window, customStorage: !!options.rateLimit?.customStorage, enabled: options.rateLimit?.enabled, max: options.rateLimit?.max }, onAPIError: { errorURL: options.onAPIError?.errorURL, onError: !!options.onAPIError?.onError, throw: options.onAPIError?.throw }, logger: { disabled: options.logger?.disabled, level: options.logger?.level, log: !!options.logger?.log }, databaseHooks: { user: { create: { after: !!options.databaseHooks?.user?.create?.after, before: !!options.databaseHooks?.user?.create?.before }, update: { after: !!options.databaseHooks?.user?.update?.after, before: !!options.databaseHooks?.user?.update?.before } }, session: { create: { after: !!options.databaseHooks?.session?.create?.after, before: !!options.databaseHooks?.session?.create?.before }, update: { after: !!options.databaseHooks?.session?.update?.after, before: !!options.databaseHooks?.session?.update?.before } }, account: { create: { after: !!options.databaseHooks?.account?.create?.after, before: !!options.databaseHooks?.account?.create?.before }, update: { after: !!options.databaseHooks?.account?.update?.after, before: !!options.databaseHooks?.account?.update?.before } }, verification: { create: { after: !!options.databaseHooks?.verification?.create?.after, before: !!options.databaseHooks?.verification?.create?.before }, update: { after: !!options.databaseHooks?.verification?.update?.after, before: !!options.databaseHooks?.verification?.update?.before } } } }; } async function createTelemetry(options, context) { const debugEnabled = options.telemetry?.debug || getBooleanEnvVar("BETTER_AUTH_TELEMETRY_DEBUG", false); const TELEMETRY_ENDPOINT = ENV.BETTER_AUTH_TELEMETRY_ENDPOINT; const track = async (event) => { try { if (context?.customTrack) { await context.customTrack(event); } else { if (debugEnabled) { await Promise.resolve( logger.info("telemetry event", JSON.stringify(event, null, 2)) ); } else { await betterFetch(TELEMETRY_ENDPOINT, { method: "POST", body: event }); } } } catch { } }; const isEnabled = async () => { const telemetryEnabled = options.telemetry?.enabled !== void 0 ? options.telemetry.enabled : false; const envEnabled = getBooleanEnvVar("BETTER_AUTH_TELEMETRY", false); return (envEnabled || telemetryEnabled) && (context?.skipTestCheck || !isTest()); }; const enabled = await isEnabled(); let anonymousId; if (enabled) { anonymousId = await getProjectId(options.baseURL); const payload = { config: getTelemetryAuthConfig(options), runtime: detectRuntime(), database: await detectDatabase(), framework: await detectFramework(), environment: detectEnvironment(), systemInfo: await detectSystemInfo(), packageManager: detectPackageManager() }; void track({ type: "init", payload, anonymousId }); } return { publish: async (event) => { if (!enabled) return; if (!anonymousId) { anonymousId = await getProjectId(options.baseURL); } await track({ type: event.type, payload: event.payload, anonymousId }); } }; } const init = async (options) => { const adapter = await getAdapter(options); const plugins = options.plugins || []; const internalPlugins = getInternalPlugins(options); const logger = createLogger(options.logger); const baseURL = getBaseURL(options.baseURL, options.basePath); const secret = options.secret || env.BETTER_AUTH_SECRET || env.AUTH_SECRET || DEFAULT_SECRET; if (secret === DEFAULT_SECRET) { if (isProduction) { logger.error( "You are using the default secret. Please set `BETTER_AUTH_SECRET` in your environment variables or pass `secret` in your auth config." ); } } options = { ...options, secret, baseURL: baseURL ? new URL(baseURL).origin : "", basePath: options.basePath || "/api/auth", plugins: plugins.concat(internalPlugins) }; checkEndpointConflicts(options, logger); const cookies = getCookies(options); const tables = getAuthTables(options); const providers = Object.entries( options.socialProviders || {} ).map(([key, config]) => { if (config == null) { return null; } if (config.enabled === false) { return null; } if (!config.clientId) { logger.warn( `Social provider ${key} is missing clientId or clientSecret` ); } const provider = socialProviders[key](config); provider.disableImplicitSignUp = config.disableImplicitSignUp; return provider; }).filter((x) => x !== null); const generateIdFunc = ({ model, size }) => { if (typeof options.advanced?.generateId === "function") { return options.advanced.generateId({ model, size }); } if (typeof options?.advanced?.database?.generateId === "function") { return options.advanced.database.generateId({ model, size }); } return generateId(size); }; const { publish } = await createTelemetry(options, { adapter: adapter.id, database: typeof options.database === "function" ? "adapter" : getKyselyDatabaseType(options.database) || "unknown" }); let ctx = { appName: options.appName || "Better Auth", socialProviders: providers, options, tables, trustedOrigins: getTrustedOrigins(options), baseURL: baseURL || "", sessionConfig: { updateAge: options.session?.updateAge !== void 0 ? options.session.updateAge : 24 * 60 * 60, // 24 hours expiresIn: options.session?.expiresIn || 60 * 60 * 24 * 7, // 7 days freshAge: options.session?.freshAge === void 0 ? 60 * 60 * 24 : options.session.freshAge }, secret, rateLimit: { ...options.rateLimit, enabled: options.rateLimit?.enabled ?? isProduction, window: options.rateLimit?.window || 10, max: options.rateLimit?.max || 100, storage: options.rateLimit?.storage || (options.secondaryStorage ? "secondary-storage" : "memory") }, authCookies: cookies, logger, generateId: generateIdFunc, session: null, secondaryStorage: options.secondaryStorage, password: { hash: options.emailAndPassword?.password?.hash || hashPassword, verify: options.emailAndPassword?.password?.verify || verifyPassword, config: { minPasswordLength: options.emailAndPassword?.minPasswordLength || 8, maxPasswordLength: options.emailAndPassword?.maxPasswordLength || 128 }, checkPassword }, setNewSession(session) { this.newSession = session; }, newSession: null, adapter, internalAdapter: createInternalAdapter(adapter, { options, logger, hooks: options.databaseHooks ? [options.databaseHooks] : []}), createAuthCookie: createCookieGetter(options), async runMigrations() { if (!options.database || "updateMany" in options.database) { throw new BetterAuthError( "Database is not provided or it's an adapter. Migrations are only supported with a database instance." ); } const { runMigrations } = await getMigrations(options); await runMigrations(); }, publishTelemetry: publish }; let { context } = runPluginInit(ctx); return context; }; function runPluginInit(ctx) { let options = ctx.options; const plugins = options.plugins || []; let context = ctx; const dbHooks = []; for (const plugin of plugins) { if (plugin.init) { const result = plugin.init(context); if (typeof result === "object") { if (result.options) { const { databaseHooks, ...restOpts } = result.options; if (databaseHooks) { dbHooks.push(databaseHooks); } options = defu(options, restOpts); } if (result.context) { context = { ...context, ...result.context }; } } } } dbHooks.push(options.databaseHooks); context.internalAdapter = createInternalAdapter(ctx.adapter, { options, logger: ctx.logger, hooks: dbHooks.filter((u) => u !== void 0), generateId: ctx.generateId }); context.options = options; return { context }; } function getInternalPlugins(options) { const plugins = []; if (options.advanced?.crossSubDomainCookies?.enabled) ; return plugins; } function getTrustedOrigins(options) { const baseURL = getBaseURL(options.baseURL, options.basePath); if (!baseURL) { return []; } const trustedOrigins = [new URL(baseURL).origin]; if (options.trustedOrigins && Array.isArray(options.trustedOrigins)) { trustedOrigins.push(...options.trustedOrigins); } const envTrustedOrigins = env.BETTER_AUTH_TRUSTED_ORIGINS; if (envTrustedOrigins) { trustedOrigins.push(...envTrustedOrigins.split(",")); } if (trustedOrigins.filter((x) => !x).length) { throw new BetterAuthError( "A provided trusted origin is invalid, make sure your trusted origins list is properly defined." ); } return trustedOrigins; } const betterAuth = (options) => { const authContext = init(options); const { api } = getEndpoints(authContext, options); const errorCodes = options.plugins?.reduce((acc, plugin) => { if (plugin.$ERROR_CODES) { return { ...acc, ...plugin.$ERROR_CODES }; } return acc; }, {}); return { handler: async (request) => { const ctx = await authContext; const basePath = ctx.options.basePath || "/api/auth"; if (!ctx.options.baseURL) { const baseURL = getBaseURL(void 0, basePath, request); if (baseURL) { ctx.baseURL = baseURL; ctx.options.baseURL = getOrigin(ctx.baseURL) || void 0; } else { throw new BetterAuthError( "Could not get base URL from request. Please provide a valid base URL." ); } } ctx.trustedOrigins = [ ...options.trustedOrigins ? Array.isArray(options.trustedOrigins) ? options.trustedOrigins : await options.trustedOrigins(request) : [], ctx.options.baseURL ]; const { handler } = router(ctx, options); return handler(request); }, api, options, $context: authContext, $Infer: {}, $ERROR_CODES: { ...errorCodes, ...BASE_ERROR_CODES } }; }; export { betterAuth as b, createTelemetry as c, getTelemetryAuthConfig as g };