UNPKG

bknd

Version:

Lightweight Firebase/Supabase alternative built to run anywhere — incl. Next.js, React Router, Astro, Cloudflare, Bun, Node, AWS Lambda & more.

239 lines (238 loc) 11.2 kB
import type { DB } from "../.."; import type { Context } from "hono"; import { sign } from "hono/jwt"; import type { ServerEnv } from "../../modules/Controller"; import { s } from "bknd/utils"; import type { AuthStrategy } from "./strategies/Strategy"; export type JWTPayload = Parameters<typeof sign>[0]; export declare const strategyActions: readonly ["create", "change"]; export type StrategyActionName = (typeof strategyActions)[number]; export type StrategyAction<S extends s.ObjectSchema = s.ObjectSchema> = { schema: S; preprocess: (input: s.Static<S>) => Promise<Omit<DB["users"], "id" | "strategy">>; }; export type StrategyActions = Partial<Record<StrategyActionName, StrategyAction>>; export type User = DB["users"]; export type ProfileExchange = { email?: string; strategy?: string; strategy_value?: string; [key: string]: any; }; export type SafeUser = Omit<User, "strategy_value">; export type CreateUser = Pick<User, "email"> & { [key: string]: any; }; export type AuthResponse = { user: SafeUser; token: string; }; export interface UserPool { findBy: (strategy: string, prop: keyof SafeUser, value: string | number) => Promise<User>; create: (strategy: string, user: CreateUser) => Promise<User>; } export declare const cookieConfig: s.ObjectSchema<{ readonly domain: s.Schema<s.ISchemaOptions, string | undefined, string | undefined>; readonly path: s.Schema<s.ISchemaOptions, string | undefined, string | undefined>; readonly sameSite: s.Schema<s.ISchemaOptions, "strict" | "lax" | "none" | undefined, "strict" | "lax" | "none" | undefined>; readonly secure: s.Schema<s.ISchemaOptions, boolean | undefined, boolean | undefined>; readonly httpOnly: s.Schema<s.ISchemaOptions, boolean | undefined, boolean | undefined>; readonly expires: s.Schema<s.ISchemaOptions, number | undefined, number | undefined>; readonly partitioned: s.Schema<s.ISchemaOptions, boolean | undefined, boolean | undefined>; readonly renew: s.Schema<s.ISchemaOptions, boolean | undefined, boolean | undefined>; readonly pathSuccess: s.Schema<s.ISchemaOptions, string | undefined, string | undefined>; readonly pathLoggedOut: s.Schema<s.ISchemaOptions, string | undefined, string | undefined>; }, s.Merge<s.IObjectOptions & { additionalProperties: false; }>>; export declare const jwtConfig: s.ObjectSchema<{ readonly secret: import("bknd/utils").SecretSchema<{ default: string; }> & { default: string; }; readonly alg: { readonly default: "HS256"; readonly enum: ["HS256", "HS384", "HS512"]; } & s.Schema<s.ISchemaOptions, "HS256" | "HS384" | "HS512" | undefined, "HS256" | "HS384" | "HS512" | undefined>; readonly expires: { default?: any; enum?: (readonly any[] | any[]) | undefined; const?: any; multipleOf?: number | undefined; maximum?: number | undefined; exclusiveMaximum?: number | undefined; minimum?: number | undefined; exclusiveMinimum?: number | undefined; } & s.Schema<s.ISchemaOptions, number | undefined, number | undefined>; readonly issuer: { default?: any; maxLength?: number | undefined; minLength?: number | undefined; pattern?: (string | RegExp) | undefined; format?: string | undefined; enum?: (readonly any[] | any[]) | undefined; const?: any; } & s.Schema<s.ISchemaOptions, string | undefined, string | undefined>; readonly fields: s.ArraySchema<s.StringSchema<s.IStringOptions> & s.IStringOptions, { readonly default: readonly ["id", "email", "role"]; }> & { readonly default: readonly ["id", "email", "role"]; }; }, s.Merge<{ readonly default: {}; } & { additionalProperties: false; }>>; export declare const authenticatorConfig: s.ObjectSchema<{ readonly jwt: s.ObjectSchema<{ readonly secret: import("bknd/utils").SecretSchema<{ default: string; }> & { default: string; }; readonly alg: { readonly default: "HS256"; readonly enum: ["HS256", "HS384", "HS512"]; } & s.Schema<s.ISchemaOptions, "HS256" | "HS384" | "HS512" | undefined, "HS256" | "HS384" | "HS512" | undefined>; readonly expires: { default?: any; enum?: (readonly any[] | any[]) | undefined; const?: any; multipleOf?: number | undefined; maximum?: number | undefined; exclusiveMaximum?: number | undefined; minimum?: number | undefined; exclusiveMinimum?: number | undefined; } & s.Schema<s.ISchemaOptions, number | undefined, number | undefined>; readonly issuer: { default?: any; maxLength?: number | undefined; minLength?: number | undefined; pattern?: (string | RegExp) | undefined; format?: string | undefined; enum?: (readonly any[] | any[]) | undefined; const?: any; } & s.Schema<s.ISchemaOptions, string | undefined, string | undefined>; readonly fields: s.ArraySchema<s.StringSchema<s.IStringOptions> & s.IStringOptions, { readonly default: readonly ["id", "email", "role"]; }> & { readonly default: readonly ["id", "email", "role"]; }; }, s.Merge<{ readonly default: {}; } & { additionalProperties: false; }>>; readonly cookie: s.ObjectSchema<{ readonly domain: s.Schema<s.ISchemaOptions, string | undefined, string | undefined>; readonly path: s.Schema<s.ISchemaOptions, string | undefined, string | undefined>; readonly sameSite: s.Schema<s.ISchemaOptions, "strict" | "lax" | "none" | undefined, "strict" | "lax" | "none" | undefined>; readonly secure: s.Schema<s.ISchemaOptions, boolean | undefined, boolean | undefined>; readonly httpOnly: s.Schema<s.ISchemaOptions, boolean | undefined, boolean | undefined>; readonly expires: s.Schema<s.ISchemaOptions, number | undefined, number | undefined>; readonly partitioned: s.Schema<s.ISchemaOptions, boolean | undefined, boolean | undefined>; readonly renew: s.Schema<s.ISchemaOptions, boolean | undefined, boolean | undefined>; readonly pathSuccess: s.Schema<s.ISchemaOptions, string | undefined, string | undefined>; readonly pathLoggedOut: s.Schema<s.ISchemaOptions, string | undefined, string | undefined>; }, s.Merge<s.IObjectOptions & { additionalProperties: false; }>>; readonly default_role_register: { default?: any; maxLength?: number | undefined; minLength?: number | undefined; pattern?: (string | RegExp) | undefined; format?: string | undefined; enum?: (readonly any[] | any[]) | undefined; const?: any; } & s.Schema<s.ISchemaOptions, string | undefined, string | undefined>; }, s.IObjectOptions> & s.IObjectOptions; type AuthConfig = s.Static<typeof authenticatorConfig>; export type AuthAction = "login" | "register"; export type AuthResolveOptions = { identifier?: "email" | string; redirect?: string; forceJsonResponse?: boolean; }; export type AuthUserResolver = (action: AuthAction, strategy: AuthStrategy, profile: ProfileExchange, opts?: AuthResolveOptions) => Promise<ProfileExchange | undefined>; type AuthClaims = SafeUser & { iat: number; iss?: string; exp?: number; }; export declare class Authenticator<Strategies extends Record<string, AuthStrategy> = Record<string, AuthStrategy>> { private readonly strategies; private readonly userPool; private readonly config; constructor(strategies: Strategies, userPool: UserPool, config?: AuthConfig); resolveLogin(c: Context, strategy: AuthStrategy, profile: Partial<SafeUser>, verify: (user: User) => Promise<void>, opts?: AuthResolveOptions): Promise<(Response & import("hono").TypedResponse<{ user: { id: string | number | { readonly __select__: string | number; readonly __insert__: string | number | undefined; readonly __update__: string | number; }; email: string; role?: string | undefined; strategy: string; }; token: string; }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<undefined, 302, "redirect">)>; resolveRegister(c: Context, strategy: AuthStrategy, profile: CreateUser, verify: (user: User) => Promise<void>, opts?: AuthResolveOptions): Promise<(Response & import("hono").TypedResponse<{ user: { id: string | number | { readonly __select__: string | number; readonly __insert__: string | number | undefined; readonly __update__: string | number; }; email: string; role?: string | undefined; strategy: string; }; token: string; }, import("hono/utils/http-status").ContentfulStatusCode, "json">) | (Response & import("hono").TypedResponse<undefined, 302, "redirect">)>; private respondWithUser; respondWithError(c: Context, error: Error, opts?: AuthResolveOptions): Promise<Response & import("hono").TypedResponse<undefined, 302, "redirect">>; getStrategies(): Strategies; strategy<StrategyName extends keyof Strategies, Strat extends AuthStrategy = Strategies[StrategyName]>(strategy: StrategyName): Strat; jwt(_user: SafeUser | ProfileExchange): Promise<string>; safeAuthResponse(_user: User): Promise<AuthResponse>; verify(jwt: string): Promise<AuthClaims | undefined>; private get cookieOptions(); private getAuthCookie; requestCookieRefresh(c: Context<ServerEnv>): Promise<void>; private setAuthCookie; getAuthCookieHeader(token: string, headers?: Headers): Promise<Headers>; removeAuthCookieHeader(headers?: Headers): Promise<Headers>; unsafeGetAuthCookie(token: string): Promise<string | undefined>; private deleteAuthCookie; logout(c: Context<ServerEnv>): Promise<void>; isJsonRequest(c: Context): boolean; getBody(c: Context): Promise<any>; private getSafeUrl; resolveAuthFromRequest(c: Context | Request | Headers): Promise<SafeUser | undefined>; toJSON(secrets?: boolean): { jwt: { alg?: "HS256" | "HS384" | "HS512" | undefined; expires?: number | undefined; issuer?: string | undefined; secret: string; fields: string[]; } | undefined; default_role_register?: string | undefined; cookie: { path?: string | undefined; expires?: number | undefined; domain?: string | undefined; sameSite?: "strict" | "lax" | "none" | undefined; secure?: boolean | undefined; httpOnly?: boolean | undefined; partitioned?: boolean | undefined; renew?: boolean | undefined; pathSuccess?: string | undefined; pathLoggedOut?: string | undefined; }; }; } export {};