import { DBFieldAttribute, ModelNames, SecondaryStorage } from "../db/type.mjs";
import { DBAdapterDebugLogOption, DBAdapterInstance } from "../db/adapter/index.mjs";
import { BaseRateLimit, RateLimit } from "../db/schema/rate-limit.mjs";
import { BaseSession, Session } from "../db/schema/session.mjs";
import { BaseUser, User } from "../db/schema/user.mjs";
import { BaseVerification, Verification } from "../db/schema/verification.mjs";
import { Logger } from "../env/logger.mjs";
import { SocialProviderList, SocialProviders } from "../social-providers/index.mjs";
import { Awaitable, LiteralString, LiteralUnion } from "./helper.mjs";
import { BetterAuthPlugin } from "./plugin.mjs";
import { Account, BaseAccount } from "../db/schema/account.mjs";
import { AuthContext, GenericEndpointContext } from "./context.mjs";
import { AuthMiddleware } from "../api/index.mjs";
import { CookieOptions } from "better-call";
import { Database } from "bun:sqlite";
import { DatabaseSync } from "node:sqlite";
import { D1Database } from "@cloudflare/workers-types";
import { Dialect, Kysely, MysqlPool, PostgresPool, SqliteDatabase } from "kysely";

//#region src/types/init-options.d.ts
type KyselyDatabaseType = "postgres" | "mysql" | "sqlite" | "mssql";
type Optional<T> = { [P in keyof T]?: T[P] | undefined };
type StoreIdentifierOption = "plain" | "hashed" | {
  hash: (identifier: string) => Promise<string>;
};
type GenerateIdFn = (options: {
  model: ModelNames;
  size?: number | undefined;
}) => string | false;
/**
 * Configuration for dynamic base URL resolution.
 * Allows Better Auth to work with multiple domains (e.g., Vercel preview deployments).
 */
type DynamicBaseURLConfig = {
  /**
   * List of allowed hostnames. Supports wildcard patterns.
   *
   * The derived host from the request will be validated against this list.
   * Uses the same wildcard matching as `trustedOrigins`.
   *
   * @example
   * ```ts
   * allowedHosts: [
   *   "myapp.com",           // Exact match
   *   "*.vercel.app",        // Any Vercel preview
   *   "preview-*.myapp.com"  // Pattern match
   * ]
   * ```
   */
  allowedHosts: string[];
  /**
   * Fallback URL to use if the derived host doesn't match any allowed host.
   * If not set, Better Auth will throw an error when the host doesn't match.
   *
   * @example "https://myapp.com"
   */
  fallback?: string | undefined;
  /**
   * Protocol to use when constructing the URL.
   * - `"https"`: Always use HTTPS (recommended for production)
   * - `"http"`: Always use HTTP (for local development)
   * - `"auto"`: Derive from `x-forwarded-proto` header or default to HTTPS
   *
   * @default "auto"
   */
  protocol?: "http" | "https" | "auto" | undefined;
};
/**
 * Base URL configuration.
 * Can be a static string or a dynamic config for multi-domain deployments.
 */
type BaseURLConfig = string | DynamicBaseURLConfig;
interface BetterAuthRateLimitStorage {
  get: (key: string) => Promise<RateLimit | null | undefined>;
  set: (key: string, value: RateLimit, update?: boolean | undefined) => Promise<void>;
}
type BetterAuthRateLimitRule = {
  /**
   * Default window to use for rate limiting. The value
   * should be in seconds.
   *
   * @default 10 seconds
   */
  window: number;
  /**
   * The default maximum number of requests allowed within the window.
   *
   * @default 100 requests
   */
  max: number;
};
type BetterAuthDBOptions<ModelName extends string, Keys extends string = string> = {
  /**
   * The name of the model. Defaults to the model name.
   */
  modelName?: ModelName | LiteralString;
  /**
   * Map fields to database columns
   */
  fields?: Partial<Record<Exclude<Keys, "id">, string>>;
  /**
   * Additional fields for the model
   */
  additionalFields?: { [Key in Exclude<string, Keys | "id">]: DBFieldAttribute };
};
type BetterAuthRateLimitOptions = Optional<BetterAuthRateLimitRule> & Omit<BetterAuthDBOptions<"rateLimit", keyof BaseRateLimit>, "additionalFields"> & {
  /**
   * By default, rate limiting is only
   * enabled on production.
   */
  enabled?: boolean | undefined;
  /**
   * Custom rate limit rules to apply to
   * specific paths.
   */
  customRules?: {
    [key: string]: BetterAuthRateLimitRule | false | ((request: Request, currentRule: BetterAuthRateLimitRule) => Awaitable<false | BetterAuthRateLimitRule>);
  } | undefined;
  /**
   * Storage configuration
   *
   * By default, rate limiting is stored in memory. If you passed a
   * secondary storage, rate limiting will be stored in the secondary
   * storage.
   *
   * @default "memory"
   */
  storage?: ("memory" | "database" | "secondary-storage") | undefined;
  /**
   * custom storage configuration.
   *
   * NOTE: If custom storage is used storage
   * is ignored
   */
  customStorage?: BetterAuthRateLimitStorage;
};
type BetterAuthAdvancedOptions = {
  /**
   * Ip address configuration
   */
  ipAddress?: {
    /**
     * List of headers to use for ip address
     *
     * Ip address is used for rate limiting and session tracking
     *
     * @example ["x-client-ip", "x-forwarded-for", "cf-connecting-ip"]
     *
     * @default
     * @link https://github.com/better-auth/better-auth/blob/main/packages/better-auth/src/utils/get-request-ip.ts#L8
     */
    ipAddressHeaders?: string[];
    /**
     * Disable ip tracking
     *
     * ⚠︎ This is a security risk and it may expose your application to abuse
     */
    disableIpTracking?: boolean;
    /**
     * IPv6 subnet prefix length for rate limiting.
     * IPv6 addresses will be normalized to this subnet.
     *
     * @default 64
     */
    ipv6Subnet?: 128 | 64 | 48 | 32;
  } | undefined;
  /**
   * Force cookies to always use the `Secure` attribute. By default,
   * cookies are secure in production environments. Set this to `true`
   * to enforce secure cookies in all environments.
   *
   * @default false
   */
  useSecureCookies?: boolean | undefined;
  /**
   * Disable all CSRF protection.
   *
   * When enabled, this disables:
   * - Origin header validation when cookies are present
   * - Fetch Metadata checks (Sec-Fetch-Site, Sec-Fetch-Mode, Sec-Fetch-Dest)
   * - Cross-site navigation blocking for first-login scenarios
   *
   * ⚠︎ This is a security risk and it may expose your application to
   * CSRF attacks
   *
   * @default false
   */
  disableCSRFCheck?: boolean | undefined;
  /**
   * Disable URL validation against trustedOrigins.
   *
   * When enabled, this disables validation of:
   * - callbackURL
   * - redirectTo
   * - errorCallbackURL
   * - newUserCallbackURL
   *
   * ⚠︎ This may allow open redirects and could lead to security
   * vulnerabilities.
   *
   * @default false
   */
  disableOriginCheck?: boolean | undefined;
  /**
   * Configure cookies to be cross subdomains
   */
  crossSubDomainCookies?: {
    /**
     * Enable cross subdomain cookies
     */
    enabled: boolean;
    /**
     * Additional cookies to be shared across subdomains
     */
    additionalCookies?: string[];
    /**
     * The domain to use for the cookies
     *
     * By default, the domain will be the root
     * domain from the base URL.
     */
    domain?: string;
  } | undefined;
  cookies?: {
    [key: string]: {
      name?: string;
      attributes?: CookieOptions;
    };
  } | undefined;
  defaultCookieAttributes?: CookieOptions | undefined;
  /**
   * Prefix for cookies. If a cookie name is provided
   * in cookies config, this will be overridden.
   *
   * @default
   * ```txt
   * "appName" -> which defaults to "better-auth"
   * ```
   */
  cookiePrefix?: string | undefined;
  /**
   * Database configuration.
   */
  database?: {
    /**
     * The default number of records to return from the database
     * when using the `findMany` adapter method.
     *
     * @default 100
     */
    defaultFindManyLimit?: number;
    /**
     * Custom generateId function.
     *
     * If not provided, random ids will be generated.
     * If set to false, the database's auto generated id
     * will be used.
     *
     * If set to "serial", the database's auto generated
     * id will be used.
     *
     * If set to "uuid", we generate a random UUID for
     * the id. If postgres, we use the `gen_random_uuid()
     * ` function. If mysql or mssql, we use the `uuid()`
     * function.
     */
    generateId?: GenerateIdFn | false | "serial" | "uuid";
  } | undefined;
  /**
   * Trusted proxy headers
   *
    * - `x-forwarded-host`
   * - `x-forwarded-proto`
   *
   * If set to `true` and no `baseURL` option is provided, we will use the headers to infer the
   * base URL.
   *
   * ⚠︎ This may expose your application to security vulnerabilities if not
   * used correctly. Please use this with caution.
   */
  trustedProxyHeaders?: boolean | undefined;
  /**
   * Configure background task handling for deferred operations.
   *
   * Background tasks allow non-critical operations (like cleanup, analytics,
   * or timing-attack mitigation) to run after the response is sent.
   *
   * Use `waitUntil` from `@vercel/functions` on Vercel,
   * or `ctx.waitUntil` on Cloudflare Workers.
   *
   * @example
   * // Vercel
   * import { waitUntil } from "@vercel/functions";
   * advanced: { backgroundTasks: { handler: waitUntil } }
   *
   * @example
   * // Cloudflare Workers (with AsyncLocalStorage)
   * advanced: {
   *   backgroundTasks: {
   *     handler: (p) => execCtxStorage.getStore()?.waitUntil(p)
   *   }
   * }
   */
  backgroundTasks?: {
    handler: (promise: Promise<unknown>) => void;
  };
  /**
   * Skip trailing slashes in API routes.
   *
   * When enabled, requests with trailing slashes (e.g., `/api/auth/session/`)
   * will be handled the same as requests without (e.g., `/api/auth/session`).
   *
   * @default false
   */
  skipTrailingSlashes?: boolean;
};
type BetterAuthOptions = {
  /**
   * The name of your application. Used as a display name in contexts
   * where your app needs to be identified — for example, as the default
   * issuer name in authenticator apps when users set up 2FA/TOTP.
   *
   * Can also be set via the `APP_NAME` environment variable.
   *
   * @default "Better Auth"
   */
  appName?: string | undefined;
  /**
   * Base URL for the Better Auth. This is typically the
   * root URL where your application server is hosted.
   *
   * Can be configured as:
   * - A static string: `"https://myapp.com"`
   * - A dynamic config with allowed hosts for multi-domain deployments
   *
   * If not explicitly set, the system will check environment variables:
   * `BETTER_AUTH_URL`, `NEXT_PUBLIC_BETTER_AUTH_URL`, etc.
   *
   * @example
   * ```ts
   * // Static URL
   * baseURL: "https://myapp.com"
   *
   * // Dynamic with allowed hosts (for Vercel, multi-domain, etc.)
   * baseURL: {
   *   allowedHosts: ["myapp.com", "*.vercel.app", "preview-*.myapp.com"],
   *   fallback: "https://myapp.com"
   * }
   * ```
   */
  baseURL?: BaseURLConfig | undefined;
  /**
   * Base path for the Better Auth. This is typically
   * the path where the
   * Better Auth routes are mounted.
   *
   * @default "/api/auth"
   */
  basePath?: string | undefined;
  /**
   * The secret to use for encryption,
   * signing and hashing.
   *
   * By default Better Auth will look for
   * the following environment variables:
   * process.env.BETTER_AUTH_SECRET,
   * process.env.AUTH_SECRET
   * If none of these environment
   * variables are set,
   * it will default to
   * "better-auth-secret-123456789".
   *
   * on production if it's not set
   * it will throw an error.
   *
   * you can generate a good secret
   * using the following command:
   * @example
   * ```bash
   * openssl rand -base64 32
   * ```
   */
  secret?: string | undefined;
  /**
   * Versioned secrets for non-destructive secret rotation.
   * When set, encryption uses an envelope format with key IDs.
   * First entry is the current key used for new encryption.
   * Remaining entries are decryption-only (previous rotations).
   *
   * Can also be set via BETTER_AUTH_SECRETS env var:
   * `BETTER_AUTH_SECRETS=2:base64secret,1:base64secret`
   *
   * When set, `secret` is only used as legacy fallback
   * for decrypting bare-hex payloads that predate the envelope format.
   */
  secrets?: Array<{
    version: number;
    value: string;
  }> | undefined;
  /**
   * Database configuration
   */
  database?: (PostgresPool | MysqlPool | SqliteDatabase | Dialect | DBAdapterInstance | Database | DatabaseSync | D1Database | {
    dialect: Dialect;
    type: KyselyDatabaseType;
    /**
     * casing for table names
     *
     * @default "camel"
     */
    casing?: "snake" | "camel";
    /**
     * Enable debug logs for the adapter
     *
     * @default false
     */
    debugLogs?: DBAdapterDebugLogOption;
    /**
     * Whether to execute multiple operations in a transaction.
     * If the database doesn't support transactions,
     * set this to `false` and operations will be executed sequentially.
     *
     * @default false
     */
    transaction?: boolean;
  } | {
    /**
     * Kysely instance
     */
    db: Kysely<any>;
    /**
     * Database type between postgres, mysql and sqlite
     */
    type: KyselyDatabaseType;
    /**
     * casing for table names
     *
     * @default "camel"
     */
    casing?: "snake" | "camel";
    /**
     * Enable debug logs for the adapter
     *
     * @default false
     */
    debugLogs?: DBAdapterDebugLogOption;
    /**
     * Whether to execute multiple operations in a transaction.
     * If the database doesn't support transactions,
     * set this to `false` and operations will be executed sequentially.
     *
     * @default false
     */
    transaction?: boolean;
  }) | undefined;
  /**
   * Secondary storage configuration
   *
   * This is used to store session and rate limit data.
   */
  secondaryStorage?: SecondaryStorage | undefined;
  /**
   * Email verification configuration
   */
  emailVerification?: {
    /**
     * Send a verification email
     * @param data the data object
     * @param request the request object
     */
    sendVerificationEmail?: (
    /**
     * @param user the user to send the
     * verification email to
     * @param url the URL to send the verification email to
     * it contains the token as well
     * @param token the token to send the verification email to
     */
    data: {
      user: User;
      url: string;
      token: string;
    },
    /**
     * The request object
     */
    request?: Request) => Promise<void>;
    /**
     * Send a verification email automatically after sign up.
     *
     * - `true`: Always send verification email on sign up
     * - `false`: Never send verification email on sign up
     * - `undefined`: Follows `requireEmailVerification` behavior
     *
     * @default undefined
     */
    sendOnSignUp?: boolean;
    /**
     * Send a verification email automatically
     * on sign in when the user's email is not verified
     *
     * @default false
     */
    sendOnSignIn?: boolean;
    /**
     * Auto signin the user after they verify their email
     */
    autoSignInAfterVerification?: boolean;
    /**
     * Number of seconds the verification token is
     * valid for.
     * @default 3600 seconds (1 hour)
     */
    expiresIn?: number;
    /**
     * A function that is called before a user verifies their email
     * @param user the user that verified their email
     * @param request the request object
     */
    beforeEmailVerification?: (user: User, request?: Request) => Promise<void>;
    /**
     * A function that is called when a user's email is updated to verified
     * @param user the user that verified their email
     * @param request the request object
     */
    afterEmailVerification?: (user: User, request?: Request) => Promise<void>;
  } | undefined;
  /**
   * Email and password authentication
   */
  emailAndPassword?: {
    /**
     * Enable email and password authentication
     *
     * @default false
     */
    enabled: boolean;
    /**
     * Disable email and password sign up
     *
     * @default false
     */
    disableSignUp?: boolean;
    /**
     * Require email verification before a session
     * can be created for the user.
     *
     * if the user is not verified, the user will not be able to sign in
     * and on sign in attempts, the user will be prompted to verify their email.
     */
    requireEmailVerification?: boolean;
    /**
     * The maximum length of the password.
     *
     * @default 128
     */
    maxPasswordLength?: number;
    /**
     * The minimum length of the password.
     *
     * @default 8
     */
    minPasswordLength?: number;
    /**
     * send reset password
     */
    sendResetPassword?: (
    /**
     * @param user the user to send the
     * reset password email to
     * @param url the URL to send the reset password email to
     * @param token the token to send to the user (could be used instead of sending the url
     * if you need to redirect the user to custom route)
     */
    data: {
      user: User;
      url: string;
      token: string;
    },
    /**
     * The request object
     */
    request?: Request) => Promise<void>;
    /**
     * Number of seconds the reset password token is
     * valid for.
     * @default 1 hour (60 * 60)
     */
    resetPasswordTokenExpiresIn?: number;
    /**
     * A callback function that is triggered
     * when a user's password is changed successfully.
     */
    onPasswordReset?: (data: {
      user: User;
    }, request?: Request) => Promise<void>;
    /**
     * Password hashing and verification
     *
     * By default Scrypt is used for password hashing and
     * verification. You can provide your own hashing and
     * verification function. if you want to use a
     * different algorithm.
     */
    password?: {
      hash?: (password: string) => Promise<string>;
      verify?: (data: {
        hash: string;
        password: string;
      }) => Promise<boolean>;
    };
    /**
     * Automatically sign in the user after sign up
     *
     * @default true
     */
    autoSignIn?: boolean;
    /**
     * Whether to revoke all other sessions when resetting password
     * @default false
     */
    revokeSessionsOnPasswordReset?: boolean;
    /**
     * A callback function that is triggered when a user tries to sign up
     * with an email that already exists. Useful for notifying the existing user
     * that someone attempted to register with their email.
     *
     * This is only called when `requireEmailVerification: true` or `autoSignIn: false`.
     */
    onExistingUserSignUp?: (
    /**
     * @param user the existing user from the database
     */
    data: {
      user: User;
    }, request?: Request) => Promise<void>;
    /**
     * Build a custom synthetic user for email enumeration
     * protection. When a sign-up attempt is made with an
     * email that already exists, this function is called
     * to build the fake user response.
     *
     * Use this when plugins add fields to the user table
     * (e.g. admin plugin adds `role`, `banned`, etc.)
     * to ensure the fake response is indistinguishable
     * from a real sign-up.
     *
     * @example
     * ```ts
     * customSyntheticUser: ({ coreFields, additionalFields, id }) => ({
     *   ...coreFields,
     *   role: "user",
     *   banned: false,
     *   banReason: null,
     *   banExpires: null,
     *   ...additionalFields,
     *   id,
     * })
     * ```
     */
    customSyntheticUser?: (params: {
      /** Core user fields: name, email, emailVerified, image, createdAt, updatedAt */coreFields: {
        name: string;
        email: string;
        emailVerified: boolean;
        image: string | null;
        createdAt: Date;
        updatedAt: Date;
      }; /** Processed additional fields from options.user.additionalFields (with defaults applied) */
      additionalFields: Record<string, unknown>; /** Generated user ID */
      id: string;
    }) => Record<string, unknown>;
  } | undefined;
  /**
   * list of social providers
   */
  socialProviders?: SocialProviders | undefined;
  /**
   * List of Better Auth plugins
   */
  plugins?: ([] | BetterAuthPlugin[]) | undefined;
  /**
   * User configuration
   */
  user?: (BetterAuthDBOptions<"user", keyof BaseUser> & {
    /**
     * Changing email configuration
     */
    changeEmail?: {
      /**
       * Enable changing email
       * @default false
       */
      enabled: boolean;
      /**
       * Send a confirmation email to the old email address when the user changes their email.
       * @param data the data object
       * @param request the request object
       */
      sendChangeEmailConfirmation?: (data: {
        user: User;
        newEmail: string;
        url: string;
        token: string;
      }, request?: Request) => Promise<void>;
      /**
       * Update the email without verification if the user is not verified.
       * @default false
       */
      updateEmailWithoutVerification?: boolean;
    };
    /**
     * User deletion configuration
     */
    deleteUser?: {
      /**
       * Enable user deletion
       */
      enabled?: boolean;
      /**
       * Send a verification email when the user deletes their account.
       *
       * if this is not set, the user will be deleted immediately.
       * @param data the data object
       * @param request the request object
       */
      sendDeleteAccountVerification?: (data: {
        user: User;
        url: string;
        token: string;
      }, request?: Request) => Promise<void>;
      /**
       * A function that is called before a user is deleted.
       *
       * to interrupt with error you can throw `APIError`
       */
      beforeDelete?: (user: User, request?: Request) => Promise<void>;
      /**
       * A function that is called after a user is deleted.
       *
       * This is useful for cleaning up user data
       */
      afterDelete?: (user: User, request?: Request) => Promise<void>;
      /**
       * The expiration time for the delete token.
       *
       * @default 1 day (60 * 60 * 24) in seconds
       */
      deleteTokenExpiresIn?: number;
    };
  }) | undefined;
  session?: (BetterAuthDBOptions<"session", keyof BaseSession> & {
    /**
     * Expiration time for the session token. The value
     * should be in seconds.
     * @default 7 days (60 * 60 * 24 * 7)
     */
    expiresIn?: number;
    /**
     * How often the session should be refreshed. The value
     * should be in seconds.
     * If set 0 the session will be refreshed every time it is used.
     * @default 1 day (60 * 60 * 24)
     */
    updateAge?: number;
    /**
     * Disable session refresh so that the session is not updated
     * regardless of the `updateAge` option.
     *
     * @default false
     */
    disableSessionRefresh?: boolean;
    /**
     * Defer session refresh writes to POST requests.
     * When enabled, GET is read-only and POST performs refresh.
     * Useful for read-replica database setups.
     *
     * @default false
     */
    deferSessionRefresh?: boolean;
    /**
     * By default if secondary storage is provided
     * the session is stored in the secondary storage.
     *
     * Set this to true to store the session in the database
     * as well.
     *
     * Reads are always done from the secondary storage.
     *
     * @default false
     */
    storeSessionInDatabase?: boolean;
    /**
     * By default, sessions are deleted from the database when secondary storage
     * is provided when session is revoked.
     *
     * Set this to true to preserve session records in the database,
     * even if they are deleted from the secondary storage.
     *
     * @default false
     */
    preserveSessionInDatabase?: boolean;
    /**
     * Enable caching session in cookie
     */
    cookieCache?: {
      /**
       * max age of the cookie
       * @default 5 minutes (5 * 60)
       */
      maxAge?: number;
      /**
       * Enable caching session in cookie
       * @default false
       */
      enabled?: boolean;
      /**
       * Strategy for encoding/decoding cookie cache
       *
       * - "compact": Uses base64url encoding with HMAC-SHA256 signature (compact format, no JWT spec overhead)
       * - "jwt": Uses JWT with HMAC signature (no encryption, follows JWT spec)
       * - "jwe": Uses JWE (JSON Web Encryption) with A256CBC-HS512 and HKDF key derivation for secure encrypted tokens
       *
       * @default "compact"
       */
      strategy?: "compact" | "jwt" | "jwe";
      /**
       * Controls stateless cookie cache refresh behavior.
       *
       * When enabled, the cookie cache will be automatically refreshed before expiry
       * WITHOUT querying the database. This is essential for fully stateless or DB-less scenarios.
       *
       * - `false`: Disable automatic refresh. Cache is only invalidated when it reaches maxAge expiry.
       * - `true`: Enable automatic refresh with default settings (refreshes when 80% of maxAge is reached).
       * - `object`: Custom refresh configuration with either `updateAge` or `shouldRefresh` function
       *
       * Note: When the cache expires (reaches maxAge), it will attempt to fetch from database if available.
       * The refreshCache option is specifically for refreshing BEFORE expiry in a stateless manner.
       *
       * @default false
       */
      refreshCache?: boolean | {
        /**
         * Time in seconds before expiry when the cache should be refreshed.
         * For example, if maxAge is 300 (5 minutes) and updateAge is 60,
         * the cache will be refreshed when it has 60 seconds left before expiry.
         *
         * @default 20% of maxAge
         */
        updateAge?: number;
      };
      /**
       * Version of the cookie cache
       *
       * If a cookie cache version is changed, all existing cookie caches with the old version
       * will be invalidated.
       *
       * It can be a string or a function that returns a string or a promise that returns a string.
       * If it's a function, it will be called with the session and user data
       *
       * @default "1"
       */
      version?: string | ((session: Session & Record<string, any>, user: User & Record<string, any>) => string) | ((session: Session & Record<string, any>, user: User & Record<string, any>) => Promise<string>);
    };
    /**
     * The age of the session to consider it fresh.
     *
     * This is used to check if the session is fresh
     * for sensitive operations. (e.g. deleting an account)
     *
     * If the session is not fresh, the user should be prompted
     * to sign in again.
     *
     * If set to 0, the session will be considered fresh every time. (⚠︎ not recommended)
     *
     * @default 1 day (60 * 60 * 24)
     */
    freshAge?: number;
  }) | undefined;
  account?: (BetterAuthDBOptions<"account", keyof BaseAccount> & {
    /**
     * When enabled (true), the user account data (accessToken, idToken, refreshToken, etc.)
     * will be updated on sign in with the latest data from the provider.
     *
     * @default true
     */
    updateAccountOnSignIn?: boolean;
    /**
     * Configuration for account linking.
     */
    accountLinking?: {
      /**
       * Enable account linking
       *
       * @default true
       */
      enabled?: boolean;
      /**
       * Disable implicit account linking on sign-in.
       *
       * When enabled, accounts will not be automatically linked
       * during OAuth sign-in, even if the email is verified or
       * the provider is trusted. Users must explicitly link
       * accounts using `linkSocial()` while authenticated.
       *
       * @default false
       */
      disableImplicitLinking?: boolean;
      /**
       * List of trusted providers. Can be a static array or a function
       * that returns providers dynamically. The function is called
       * during context init (with `request` undefined) and again
       * on each request (with the incoming Request). It must be
       * resilient to `request` being undefined.
       *
       * @example
       * ```ts
       * trustedProviders: ["google", "github"]
       * ```
       *
       * @example
       * ```ts
       * trustedProviders: async (request) => {
       *   if (!request) return [];
       *   const providers = await getTrustedProvidersForTenant(request);
       *   return providers;
       * }
       * ```
       */
      trustedProviders?: Array<LiteralUnion<SocialProviderList[number] | "email-password", string>> | ((request?: Request | undefined) => Awaitable<Array<LiteralUnion<SocialProviderList[number] | "email-password", string>>>);
      /**
       * If enabled (true), this will allow users to manually linking accounts with different email addresses than the main user.
       *
       * @default false
       *
       * ⚠️ Warning: enabling this might lead to account takeovers, so proceed with caution.
       */
      allowDifferentEmails?: boolean;
      /**
       * If enabled (true), this will allow users to unlink all accounts.
       *
       * @default false
       */
      allowUnlinkingAll?: boolean;
      /**
       * If enabled (true), this will update the user information based on the newly linked account
       *
       * @default false
       */
      updateUserInfoOnLink?: boolean;
    };
    /**
     * Encrypt OAuth tokens
     *
     * By default, OAuth tokens (access tokens, refresh tokens, ID tokens) are stored in plain text in the database.
     * This poses a security risk if your database is compromised, as attackers could gain access to user accounts
     * on external services.
     *
     * When enabled, tokens are encrypted using AES-256-GCM before storage, providing protection against:
     * - Database breaches and unauthorized access to raw token data
     * - Internal threats from database administrators or compromised credentials
     * - Token exposure in database backups and logs
     * @default false
     */
    encryptOAuthTokens?: boolean;
    /**
     * Skip state cookie check
     *
     * ⚠︎ this has security implications and should only be enabled if you know what you are doing.
     * @default false
     */
    skipStateCookieCheck?: boolean;
    /**
     * Strategy for storing OAuth state
     *
     * - "cookie": Store state in an encrypted cookie (stateless)
     * - "database": Store state in the database
     *
     * @default "cookie"
     */
    storeStateStrategy?: "database" | "cookie";
    /**
     * Store account data after oauth flow on a cookie
     *
     * This is useful for database-less flow
     *
     * @default false
     *
     * @note This is automatically set to true if you haven't passed a database
     */
    storeAccountCookie?: boolean;
  }) | undefined;
  verification?: (BetterAuthDBOptions<"verification", keyof BaseVerification> & {
    /**
     * disable cleaning up expired values when a verification value is
     * fetched
     */
    disableCleanup?: boolean;
    /**
     * How to store verification identifiers (tokens, OTPs, etc.)
     *
     * @example "hashed"
     *
     * @default "plain"
     */
    storeIdentifier?: StoreIdentifierOption | {
      default: StoreIdentifierOption;
      overrides?: Record<string, StoreIdentifierOption>;
    };
    /**
     * Store verification data in database even when secondary storage is configured.
     * @default false
     */
    storeInDatabase?: boolean;
  }) | undefined;
  /**
   * Additional trusted origins. By default, Better Auth trusts your
   * app's {@link baseURL}. Use this option to allow additional origins
   * (e.g. a separate frontend domain).
   *
   * Can be a static array, a function that returns origins dynamically,
   * or use wildcard patterns (e.g. `"https://*.example.com"`).
   *
   * @param request - The request object.
   * It'll be undefined if no request was
   * made. Like during a create context call
   * or `auth.api` call.
   *
   * Trusted origins will be dynamically
   * calculated based on the request.
   *
   * @example
   * ```ts
   * trustedOrigins: async (request) => {
   *   return [
   *    "https://better-auth.com",
   *    "https://*.better-auth.com",
   *    request.headers.get("x-custom-origin")
   *   ];
   * }
   * ```
   * @returns An array of trusted origins.
   */
  trustedOrigins?: (string[] | ((request?: Request | undefined) => Awaitable<(string | undefined | null)[]>)) | undefined;
  /**
   * Rate limiting configuration
   */
  rateLimit?: BetterAuthRateLimitOptions | undefined;
  /**
   * Advanced options
   */
  advanced?: BetterAuthAdvancedOptions | undefined;
  logger?: Logger | undefined;
  /**
   * allows you to define custom hooks that can be
   * executed during lifecycle of core database
   * operations.
   */
  databaseHooks?: {
    /**
     * User hooks
     */
    user?: {
      create?: {
        /**
         * Hook that is called before a user is created.
         * if the hook returns false, the user will not be created.
         * If the hook returns an object, it'll be used instead of the original data
         */
        before?: (user: User & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<boolean | void | {
          data: Optional<User> & Record<string, any>;
        }>;
        /**
         * Hook that is called after a user is created.
         */
        after?: (user: User & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<void>;
      };
      update?: {
        /**
         * Hook that is called before a user is updated.
         * if the hook returns false, the user will not be updated.
         * If the hook returns an object, it'll be used instead of the original data
         */
        before?: (user: Partial<User> & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<boolean | void | {
          data: Optional<User & Record<string, any>>;
        }>;
        /**
         * Hook that is called after a user is updated.
         */
        after?: (user: User & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<void>;
      };
      delete?: {
        /**
         * Hook that is called before a user is deleted.
         * if the hook returns false, the user will not be deleted.
         */
        before?: (user: User & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<boolean | void>;
        /**
         * Hook that is called after a user is deleted.
         */
        after?: (user: User & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<void>;
      };
    };
    /**
     * Session Hook
     */
    session?: {
      create?: {
        /**
         * Hook that is called before a session is created.
         * if the hook returns false, the session will not be created.
         * If the hook returns an object, it'll be used instead of the original data
         */
        before?: (session: Session & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<boolean | void | {
          data: Optional<Session> & Record<string, any>;
        }>;
        /**
         * Hook that is called after a session is created.
         */
        after?: (session: Session & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<void>;
      };
      /**
       * Update hook
       */
      update?: {
        /**
         * Hook that is called before a user is updated.
         * if the hook returns false, the session will not be updated.
         * If the hook returns an object, it'll be used instead of the original data
         */
        before?: (session: Partial<Session> & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<boolean | void | {
          data: Optional<Session & Record<string, any>>;
        }>;
        /**
         * Hook that is called after a session is updated.
         */
        after?: (session: Session & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<void>;
      };
      delete?: {
        /**
         * Hook that is called before a session is deleted.
         * if the hook returns false, the session will not be deleted.
         */
        before?: (session: Session & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<boolean | void>;
        /**
         * Hook that is called after a session is deleted.
         */
        after?: (session: Session & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<void>;
      };
    };
    /**
     * Account Hook
     */
    account?: {
      create?: {
        /**
         * Hook that is called before a account is created.
         * If the hook returns false, the account will not be created.
         * If the hook returns an object, it'll be used instead of the original data
         */
        before?: (account: Account, context: GenericEndpointContext | null) => Promise<boolean | void | {
          data: Optional<Account> & Record<string, any>;
        }>;
        /**
         * Hook that is called after a account is created.
         */
        after?: (account: Account, context: GenericEndpointContext | null) => Promise<void>;
      };
      /**
       * Update hook
       */
      update?: {
        /**
         * Hook that is called before a account is update.
         * If the hook returns false, the user will not be updated.
         * If the hook returns an object, it'll be used instead of the original data
         */
        before?: (account: Partial<Account> & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<boolean | void | {
          data: Optional<Account & Record<string, any>>;
        }>;
        /**
         * Hook that is called after a account is updated.
         */
        after?: (account: Account & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<void>;
      };
      delete?: {
        /**
         * Hook that is called before an account is deleted.
         * if the hook returns false, the account will not be deleted.
         */
        before?: (account: Account & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<boolean | void>;
        /**
         * Hook that is called after an account is deleted.
         */
        after?: (account: Account & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<void>;
      };
    };
    /**
     * Verification Hook
     */
    verification?: {
      create?: {
        /**
         * Hook that is called before a verification is created.
         * if the hook returns false, the verification will not be created.
         * If the hook returns an object, it'll be used instead of the original data
         */
        before?: (verification: Verification & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<boolean | void | {
          data: Optional<Verification> & Record<string, any>;
        }>;
        /**
         * Hook that is called after a verification is created.
         */
        after?: (verification: Verification & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<void>;
      };
      update?: {
        /**
         * Hook that is called before a verification is updated.
         * if the hook returns false, the verification will not be updated.
         * If the hook returns an object, it'll be used instead of the original data
         */
        before?: (verification: Partial<Verification> & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<boolean | void | {
          data: Optional<Verification & Record<string, any>>;
        }>;
        /**
         * Hook that is called after a verification is updated.
         */
        after?: (verification: Verification & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<void>;
      };
      delete?: {
        /**
         * Hook that is called before a verification is deleted.
         * if the hook returns false, the verification will not be deleted.
         */
        before?: (verification: Verification & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<boolean | void>;
        /**
         * Hook that is called after a verification is deleted.
         */
        after?: (verification: Verification & Record<string, unknown>, context: GenericEndpointContext | null) => Promise<void>;
      };
    };
  } | undefined;
  /**
   * API error handling
   */
  onAPIError?: {
    /**
     * Throw an error on API error
     *
     * @default false
     */
    throw?: boolean;
    /**
     * Custom error handler
     *
     * @param error
     * @param ctx - Auth context
     */
    onError?: (error: unknown, ctx: AuthContext) => void | Promise<void>;
    /**
     * The URL to redirect to on error
     *
     * When errorURL is provided, the error will be added to the URL as a query parameter
     * and the user will be redirected to the errorURL.
     *
     * @default - "/api/auth/error"
     */
    errorURL?: string;
    /**
     * Configure the default error page provided by Better-Auth
     * Start your dev server and go to /api/auth/error to see the error page.
     */
    customizeDefaultErrorPage?: {
      colors?: {
        background?: string;
        foreground?: string;
        primary?: string;
        primaryForeground?: string;
        mutedForeground?: string;
        border?: string;
        destructive?: string;
        titleBorder?: string;
        titleColor?: string;
        gridColor?: string;
        cardBackground?: string;
        cornerBorder?: string;
      };
      size?: {
        radiusSm?: string;
        radiusMd?: string;
        radiusLg?: string;
        textSm?: string;
        text2xl?: string;
        text4xl?: string;
        text6xl?: string;
      };
      font?: {
        defaultFamily?: string;
        monoFamily?: string;
      };
      disableTitleBorder?: boolean;
      disableCornerDecorations?: boolean;
      disableBackgroundGrid?: boolean;
    };
  } | undefined;
  /**
   * Hooks
   */
  hooks?: {
    /**
     * Before a request is processed
     */
    before?: AuthMiddleware;
    /**
     * After a request is processed
     */
    after?: AuthMiddleware;
  } | undefined;
  /**
   * Disabled paths
   *
   * Paths you want to disable.
   */
  disabledPaths?: string[] | undefined;
  /**
   * Telemetry configuration
   */
  telemetry?: {
    /**
     * Enable telemetry collection
     *
     * @default false
     */
    enabled?: boolean;
    /**
     * Enable debug mode
     *
     * @default false
     */
    debug?: boolean;
  } | undefined;
  /**
   * Experimental features
   */
  experimental?: {
    /**
     * Enable experimental joins for your database adapter.
     *
     * 	Please read the adapter documentation for more information regarding joins before enabling this.
     * 	Not all adapters support joins.
     *
     * @default false
     */
    joins?: boolean;
  };
};
//#endregion
export { BaseURLConfig, BetterAuthAdvancedOptions, BetterAuthDBOptions, BetterAuthOptions, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, DynamicBaseURLConfig, GenerateIdFn, StoreIdentifierOption };