UNPKG

better-auth

Version:

The most comprehensive authentication framework for TypeScript.

413 lines (412 loc) 14.8 kB
import { SessionQueryParams } from "../client/types.mjs"; import { Auth } from "../types/auth.mjs"; import { setCookieToHeader } from "../cookies/cookie-utils.mjs"; import { getTestInstance } from "./test-instance.mjs"; import * as _$_better_auth_core0 from "@better-auth/core"; import { BetterAuthClientOptions, BetterAuthOptions } from "@better-auth/core"; import * as _$_better_auth_core_db_adapter0 from "@better-auth/core/db/adapter"; import * as _$nanostores from "nanostores"; import * as _$_better_fetch_fetch0 from "@better-fetch/fetch"; import { IncomingMessage, ServerResponse, createServer } from "node:http"; import { AddressInfo } from "node:net"; //#region src/test-utils/http-test-instance.d.ts /** A Node request handler that can be installed on an HTTP test listener. */ type HttpTestRequestHandler = (req: IncomingMessage, res: ServerResponse) => unknown | Promise<unknown>; /** A bound HTTP test listener whose request handler can be installed later. */ type HttpTestServer = { url: string; address: AddressInfo; server: ReturnType<typeof createServer>; setRequestHandler: (handler: HttpTestRequestHandler) => void; close: () => Promise<void>; }; type GetTestInstanceConfig = NonNullable<Parameters<typeof getTestInstance>[1]>; type HttpTestInstanceConfig<C extends BetterAuthClientOptions> = Omit<GetTestInstanceConfig, "port" | "clientOptions"> & { clientOptions?: C; /** * Customizes the HTTP request listener. Receives the bound auth instance * and returns a Node request handler. Defaults to * `toNodeHandler(auth.handler)`. * * Use this when the test needs to expose extra routes alongside the auth * handler (e.g. a `.well-known/openid-configuration` shim that calls * `auth.api.getOpenIdConfig()`). */ handler?: (auth: Awaited<ReturnType<typeof getTestInstance>>["auth"]) => HttpTestRequestHandler; }; /** * Binds an HTTP listener to an OS-assigned port before the final request * handler exists. This lets tests construct URL-sensitive applications only * after the listener owns its port, then install the application handler. */ declare function createHttpTestServer(): Promise<HttpTestServer>; /** * Like `getTestInstance`, but bound to an actual HTTP listener on an * OS-assigned port (`port: 0`). The discovered URL is fed back into the auth * instance so its `baseURL` matches the listener. * * This removes the race window that the temp-server-then-rebind pattern * introduces. The listener is bound once, holds the port for its lifetime, * and only swaps in the real request handler after the auth instance is * fully constructed. * * The caller is responsible for calling `server.close()` in `afterAll`. Any * `baseURL` passed in `options` is ignored — the URL must match the * listener. */ declare function getHttpTestInstance<O extends Partial<BetterAuthOptions>, C extends BetterAuthClientOptions>(options?: O, config?: HttpTestInstanceConfig<C>): Promise<{ server: HttpTestServer; baseURL: string; port: number; auth: Auth<O>; client: { hydrateSession(session: null): void; useSession: _$nanostores.Atom<{ data: never; error: _$_better_fetch_fetch0.BetterFetchError | null; isPending: boolean; isRefetching: boolean; refetch: (queryParams?: { query?: SessionQueryParams; } | undefined) => Promise<void>; }>; $fetch: _$_better_fetch_fetch0.BetterFetch<{ plugins: (_$_better_fetch_fetch0.BetterFetchPlugin<Record<string, any>> | { id: string; name: string; hooks: { onSuccess(context: _$_better_fetch_fetch0.SuccessContext<any>): void; }; } | { id: string; name: string; hooks: { onSuccess: ((context: _$_better_fetch_fetch0.SuccessContext<any>) => Promise<void> | void) | undefined; onError: ((context: _$_better_fetch_fetch0.ErrorContext) => Promise<void> | void) | undefined; onRequest: (<T extends Record<string, any>>(context: _$_better_fetch_fetch0.RequestContext<T>) => Promise<_$_better_fetch_fetch0.RequestContext | void> | _$_better_fetch_fetch0.RequestContext | void) | undefined; onResponse: ((context: _$_better_fetch_fetch0.ResponseContext) => Promise<Response | void | _$_better_fetch_fetch0.ResponseContext> | Response | _$_better_fetch_fetch0.ResponseContext | void) | undefined; }; })[]; priority?: RequestPriority | undefined; cache?: RequestCache | undefined; credentials?: RequestCredentials; integrity?: string | undefined; keepalive?: boolean | undefined; method: string; mode?: RequestMode | undefined; redirect?: RequestRedirect | undefined; referrer?: string | undefined; referrerPolicy?: ReferrerPolicy | undefined; signal?: (AbortSignal | null) | undefined; window?: null | undefined; onRetry?: ((response: _$_better_fetch_fetch0.ResponseContext) => Promise<void> | void) | undefined; hookOptions?: { cloneResponse?: boolean; } | undefined; timeout?: number | undefined; customFetchImpl: _$_better_fetch_fetch0.FetchEsque; baseURL: string; throw?: boolean | undefined; auth?: ({ type: "Bearer"; token: string | Promise<string | undefined> | (() => string | Promise<string | undefined> | undefined) | undefined; } | { type: "Basic"; username: string | (() => string | undefined) | undefined; password: string | (() => string | undefined) | undefined; } | { type: "Custom"; prefix: string | (() => string | undefined) | undefined; value: string | (() => string | undefined) | undefined; }) | undefined; headers?: {} | { [x: string]: string | undefined; accept?: ((string & {}) | "application/json" | "text/plain" | "application/octet-stream") | undefined; "content-type"?: ((string & {}) | "application/x-www-form-urlencoded" | "application/json" | "text/plain" | "application/octet-stream" | "multipart/form-data") | undefined; authorization?: ((string & {}) | `Bearer ${string}` | `Basic ${string}`) | undefined; } | undefined; body?: any; query?: any; params?: any; duplex?: "full" | "half" | undefined; jsonParser: (text: string) => Promise<any> | any; retry?: _$_better_fetch_fetch0.RetryOptions | undefined; retryAttempt?: number | undefined; output?: (_$_better_fetch_fetch0.StandardSchemaV1 | typeof Blob | typeof File) | undefined; errorSchema?: _$_better_fetch_fetch0.StandardSchemaV1 | undefined; disableValidation?: boolean | undefined; disableSignal?: boolean | undefined; }, unknown, unknown, {}>; $store: { notify: (signal?: (Omit<string, "$sessionSignal"> | "$sessionSignal") | undefined) => void; listen: (signal: Omit<string, "$sessionSignal"> | "$sessionSignal", listener: (value: boolean, oldValue?: boolean | undefined) => void) => void; atoms: Record<string, _$nanostores.WritableAtom<any>>; }; $Infer: { Session: never; }; $ERROR_CODES: { USER_NOT_FOUND: { readonly code: "USER_NOT_FOUND"; message: string; }; FAILED_TO_CREATE_USER: { readonly code: "FAILED_TO_CREATE_USER"; message: string; }; FAILED_TO_CREATE_SESSION: { readonly code: "FAILED_TO_CREATE_SESSION"; message: string; }; FAILED_TO_UPDATE_USER: { readonly code: "FAILED_TO_UPDATE_USER"; message: string; }; FAILED_TO_GET_SESSION: { readonly code: "FAILED_TO_GET_SESSION"; message: string; }; INVALID_PASSWORD: { readonly code: "INVALID_PASSWORD"; message: string; }; INVALID_EMAIL: { readonly code: "INVALID_EMAIL"; message: string; }; INVALID_EMAIL_OR_PASSWORD: { readonly code: "INVALID_EMAIL_OR_PASSWORD"; message: string; }; INVALID_USER: { readonly code: "INVALID_USER"; message: string; }; SOCIAL_ACCOUNT_ALREADY_LINKED: { readonly code: "SOCIAL_ACCOUNT_ALREADY_LINKED"; message: string; }; PROVIDER_NOT_FOUND: { readonly code: "PROVIDER_NOT_FOUND"; message: string; }; INVALID_TOKEN: { readonly code: "INVALID_TOKEN"; message: string; }; TOKEN_EXPIRED: { readonly code: "TOKEN_EXPIRED"; message: string; }; ID_TOKEN_NOT_SUPPORTED: { readonly code: "ID_TOKEN_NOT_SUPPORTED"; message: string; }; FAILED_TO_GET_USER_INFO: { readonly code: "FAILED_TO_GET_USER_INFO"; message: string; }; USER_EMAIL_NOT_FOUND: { readonly code: "USER_EMAIL_NOT_FOUND"; message: string; }; EMAIL_NOT_VERIFIED: { readonly code: "EMAIL_NOT_VERIFIED"; message: string; }; PASSWORD_TOO_SHORT: { readonly code: "PASSWORD_TOO_SHORT"; message: string; }; PASSWORD_TOO_LONG: { readonly code: "PASSWORD_TOO_LONG"; message: string; }; USER_ALREADY_EXISTS: { readonly code: "USER_ALREADY_EXISTS"; message: string; }; USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL: { readonly code: "USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL"; message: string; }; EMAIL_CAN_NOT_BE_UPDATED: { readonly code: "EMAIL_CAN_NOT_BE_UPDATED"; message: string; }; CHANGE_EMAIL_DISABLED: { readonly code: "CHANGE_EMAIL_DISABLED"; message: string; }; CREDENTIAL_ACCOUNT_NOT_FOUND: { readonly code: "CREDENTIAL_ACCOUNT_NOT_FOUND"; message: string; }; ACCOUNT_NOT_FOUND: { readonly code: "ACCOUNT_NOT_FOUND"; message: string; }; SESSION_EXPIRED: { readonly code: "SESSION_EXPIRED"; message: string; }; FAILED_TO_UNLINK_LAST_ACCOUNT: { readonly code: "FAILED_TO_UNLINK_LAST_ACCOUNT"; message: string; }; USER_ALREADY_HAS_PASSWORD: { readonly code: "USER_ALREADY_HAS_PASSWORD"; message: string; }; CROSS_SITE_NAVIGATION_LOGIN_BLOCKED: { readonly code: "CROSS_SITE_NAVIGATION_LOGIN_BLOCKED"; message: string; }; VERIFICATION_EMAIL_NOT_ENABLED: { readonly code: "VERIFICATION_EMAIL_NOT_ENABLED"; message: string; }; EMAIL_ALREADY_VERIFIED: { readonly code: "EMAIL_ALREADY_VERIFIED"; message: string; }; EMAIL_MISMATCH: { readonly code: "EMAIL_MISMATCH"; message: string; }; SESSION_NOT_FRESH: { readonly code: "SESSION_NOT_FRESH"; message: string; }; LINKED_ACCOUNT_ALREADY_EXISTS: { readonly code: "LINKED_ACCOUNT_ALREADY_EXISTS"; message: string; }; INVALID_ORIGIN: { readonly code: "INVALID_ORIGIN"; message: string; }; INVALID_CALLBACK_URL: { readonly code: "INVALID_CALLBACK_URL"; message: string; }; INVALID_REDIRECT_URL: { readonly code: "INVALID_REDIRECT_URL"; message: string; }; INVALID_ERROR_CALLBACK_URL: { readonly code: "INVALID_ERROR_CALLBACK_URL"; message: string; }; INVALID_NEW_USER_CALLBACK_URL: { readonly code: "INVALID_NEW_USER_CALLBACK_URL"; message: string; }; MISSING_OR_NULL_ORIGIN: { readonly code: "MISSING_OR_NULL_ORIGIN"; message: string; }; CALLBACK_URL_REQUIRED: { readonly code: "CALLBACK_URL_REQUIRED"; message: string; }; FAILED_TO_CREATE_VERIFICATION: { readonly code: "FAILED_TO_CREATE_VERIFICATION"; message: string; }; FIELD_NOT_ALLOWED: { readonly code: "FIELD_NOT_ALLOWED"; message: string; }; ASYNC_VALIDATION_NOT_SUPPORTED: { readonly code: "ASYNC_VALIDATION_NOT_SUPPORTED"; message: string; }; VALIDATION_ERROR: { readonly code: "VALIDATION_ERROR"; message: string; }; MISSING_FIELD: { readonly code: "MISSING_FIELD"; message: string; }; METHOD_NOT_ALLOWED_DEFER_SESSION_REQUIRED: { readonly code: "METHOD_NOT_ALLOWED_DEFER_SESSION_REQUIRED"; message: string; }; BODY_MUST_BE_AN_OBJECT: { readonly code: "BODY_MUST_BE_AN_OBJECT"; message: string; }; PASSWORD_ALREADY_SET: { readonly code: "PASSWORD_ALREADY_SET"; message: string; }; }; }; testUser: { id?: string | undefined; createdAt?: Date | undefined; updatedAt?: Date | undefined; email: string; emailVerified?: boolean | undefined; name: string; image?: string | null | undefined; password: string; }; signInWithTestUser: () => Promise<{ session: { id: string; createdAt: Date; updatedAt: Date; userId: string; expiresAt: Date; token: string; ipAddress?: string | null | undefined; userAgent?: string | null | undefined; }; user: { id: string; createdAt: Date; updatedAt: Date; email: string; emailVerified: boolean; name: string; image?: string | null | undefined; }; headers: Headers; setCookie: (name: string, value: string) => void; runWithUser: (fn: (headers: Headers) => Promise<void>) => Promise<void>; }>; signInWithUser: (email: string, password: string) => Promise<{ res: { user: { id: string; createdAt: Date; updatedAt: Date; email: string; emailVerified: boolean; name: string; image?: string | null | undefined; }; session: { id: string; createdAt: Date; updatedAt: Date; userId: string; expiresAt: Date; token: string; ipAddress?: string | null | undefined; userAgent?: string | null | undefined; }; }; headers: Headers; }>; cookieSetter: typeof setCookieToHeader; customFetchImpl: (url: string | URL | Request, init?: RequestInit | undefined) => Promise<Response>; sessionSetter: (headers: Headers) => (context: _$_better_fetch_fetch0.SuccessContext) => void; db: _$_better_auth_core_db_adapter0.DBAdapter<BetterAuthOptions>; runWithUser: (email: string, password: string, fn: (headers: Headers) => _$_better_auth_core0.Awaitable<void>) => Promise<void>; }>; //#endregion export { HttpTestInstanceConfig, HttpTestRequestHandler, HttpTestServer, createHttpTestServer, getHttpTestInstance };