better-auth
Version:
The most comprehensive authentication library for TypeScript.
801 lines (786 loc) • 27.6 kB
JavaScript
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 };