import { DBFieldAttribute, ModelNames, SecondaryStorage } from "../db/type.mjs";
import { Account } from "../db/schema/account.mjs";
import { RateLimit } from "../db/schema/rate-limit.mjs";
import { Session } from "../db/schema/session.mjs";
import { User } from "../db/schema/user.mjs";
import { Verification } from "../db/schema/verification.mjs";
import "../db/index.mjs";
import { Awaitable, LiteralUnion } from "./helper.mjs";
import { DBAdapterDebugLogOption, DBAdapterInstance } from "../db/adapter/index.mjs";
import { Logger } from "../env/logger.mjs";
import { SocialProviderList, SocialProviders } from "../social-providers/index.mjs";
import { BetterAuthPlugin } from "./plugin.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 { Dialect, Kysely, MysqlPool, PostgresPool, SqliteDatabase } from "kysely";

//#region src/types/init-options.d.ts
type KyselyDatabaseType = "postgres" | "mysql" | "sqlite" | "mssql";
type OmitId<T extends {
  id: unknown;
}> = Omit<T, "id">;
type Optional<T> = { [P in keyof T]?: T[P] | undefined };
type GenerateIdFn = (options: {
  model: ModelNames;
  size?: number | undefined;
}) => string | false;
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 BetterAuthRateLimitOptions = Optional<BetterAuthRateLimitRule> & {
  /**
   * 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;
  /**
   * If database is used as storage, the name of the table to
   * use for rate limiting.
   *
   * @default "rateLimit"
   */
  modelName?: string | undefined;
  /**
   * Custom field names for the rate limit table
   */
  fields?: Partial<Record<keyof RateLimit, string>> | 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 can be grouped by subnet to prevent attackers from
     * bypassing rate limits by rotating through multiple addresses in
     * their allocation.
     *
     * Common values:
     * - 128 (default): Individual IPv6 address
     * - 64: /64 subnet (typical home/business allocation)
     * - 48: /48 subnet (larger network allocation)
     * - 32: /32 subnet (ISP allocation)
     *
     * Note: This only affects IPv6 addresses. IPv4 addresses are always
     * rate limited individually.
     *
     * @default 64 (/64 subnet)
     */
    ipv6Subnet?: 128 | 64 | 48 | 32 | undefined;
  } | undefined;
  /**
   * Use secure cookies
   *
   * @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;
    /**
     * If your database auto increments number ids, set this to `true`.
     *
     * Note: If enabled, we will not handle ID generation (including if you use `generateId`), and it would be expected that your database will provide the ID automatically.
     *
     * @default false
     *
     * @deprecated Please use `generateId` instead. This will be removed in future
     * releases.
     */
    useNumberId?: boolean;
    /**
     * 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 slash validation in route matching
   *
   * @default false
   */
  skipTrailingSlashes?: boolean | undefined;
};
type BetterAuthOptions = {
  /**
   * The name of the application
   *
   * process.env.APP_NAME
   *
   * @default "Better Auth"
   */
  appName?: string | undefined;
  /**
   * Base URL for the Better Auth. This is typically the
   * root URL where your application server is hosted.
   * If not explicitly set,
   * the system will check the following environment variable:
   *
   * process.env.BETTER_AUTH_URL
   */
  baseURL?: string | 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;
  /**
   * Database configuration
   */
  database?: (PostgresPool | MysqlPool | SqliteDatabase | Dialect | DBAdapterInstance | Database | DatabaseSync | {
    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 when a user verifies their email
     * @param user the user that verified their email
     * @param request the request object
     * @deprecated Use `beforeEmailVerification` or `afterEmailVerification` instead. This will be removed in 1.5
     */
    onEmailVerification?: (user: User, request?: Request) => Promise<void>;
    /**
     * 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;
  } | undefined;
  /**
   * list of social providers
   */
  socialProviders?: SocialProviders | undefined;
  /**
   * List of Better Auth plugins
   */
  plugins?: ([] | BetterAuthPlugin[]) | undefined;
  /**
   * User configuration
   */
  user?: {
    /**
     * The model name for the user. Defaults to "user".
     */
    modelName?: string;
    /**
     * Map fields
     *
     * @example
     * ```ts
     * {
     *  userId: "user_id"
     * }
     * ```
     */
    fields?: Partial<Record<keyof OmitId<User>, string>>;
    /**
     * Additional fields for the user
     */
    additionalFields?: {
      [key: string]: DBFieldAttribute;
    };
    /**
     * Changing email configuration
     */
    changeEmail?: {
      /**
       * Enable changing email
       * @default false
       */
      enabled: boolean;
      /**
       * Send a verification email when the user changes their email.
       * @param data the data object
       * @param request the request object
       * @deprecated Use `sendChangeEmailConfirmation` instead
       */
      sendChangeEmailVerification?: (data: {
        user: User;
        newEmail: string;
        url: string;
        token: string;
      }, request?: Request) => Promise<void>;
      /**
       * 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?: {
    /**
     * The model name for the session.
     *
     * @default "session"
     */
    modelName?: string;
    /**
     * Map fields
     *
     * @example
     * ```ts
     * {
     *  userId: "user_id"
     * }
     */
    fields?: Partial<Record<keyof OmitId<Session>, string>>;
    /**
     * 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;
    /**
     * Additional fields for the session
     */
    additionalFields?: {
      [key: string]: DBFieldAttribute;
    };
    /**
     * 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?: {
    /**
     * The model name for the account. Defaults to "account".
     */
    modelName?: string;
    /**
     * Map fields
     */
    fields?: Partial<Record<keyof OmitId<Account>, string>>;
    /**
     * Additional fields for the account
     */
    additionalFields?: {
      [key: string]: DBFieldAttribute;
    };
    /**
     * 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
       */
      trustedProviders?: 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 configuration
   */
  verification?: {
    /**
     * Change the modelName of the verification table
     */
    modelName?: string;
    /**
     * Map verification fields
     */
    fields?: Partial<Record<keyof OmitId<Verification>, string>>;
    /**
     * Additional fields for the verification
     */
    additionalFields?: {
      [key: string]: DBFieldAttribute;
    };
    /**
     * disable cleaning up expired values when a verification value is
     * fetched
     */
    disableCleanup?: boolean;
  } | undefined;
  /**
   * List of trusted origins.
   *
   * @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 { BetterAuthAdvancedOptions, BetterAuthOptions, BetterAuthRateLimitOptions, BetterAuthRateLimitRule, BetterAuthRateLimitStorage, GenerateIdFn };
//# sourceMappingURL=init-options.d.mts.map