UNPKG

@athenox/talos

Version:

Talos: a backend you describe instead of write. Declare a schema, write the rules in plain language, map URLs to sentences; a small built-in model turns them into query plans.

95 lines (94 loc) • 4.37 kB
import { type H3Event } from 'h3'; import type { Store } from './runtime.ts'; /** * Accounts: sign-in, sign-up, sign-out, the current account, forgotten and * reset passwords — declared, not written. * * Deliberately not the model's: whether a password matches, who is signed in * and whether a reset token is good are plain code here, and the same code for * every app. What differs between apps is data — the table, its columns, how * passwords are hashed, where the session lives, the messages — so that is all * an app gives. * * const readers = accounts({ store, table: 'subscribers', hash, verify, session, * expose: ['id', 'email', 'name'], reset: { table: 'password_reset_tokens', owner: 'subscriber_id', send } }) * // routes: 'POST /api/subscriber/login': readers.login, … ; guard: readers.required * * Emails are compared lower-cased and trimmed. Forgot-password answers the * same whether the account exists or not. Reset tokens are 32 random bytes, * expire, serve once, and asking again drops the unused ones. */ export type AccountsOptions<A = Record<string, any>> = { store: Store; table: string; email?: string; password?: string; /** columns returned and kept in the session (never the password) */ expose: string[]; /** how a column reads back (`{ permissions: v => JSON.parse(v) }`), for the exposed ones */ read?: Record<string, (v: any) => unknown>; hash: (password: string) => string | Promise<string>; verify: (password: string, hash: string) => boolean | Promise<boolean>; /** where the signed-in account lives (e.g. nuxt-auth-utils' setUserSession / getUserSession / clearUserSession) */ session: { /** `body` is the sign-in form, for a remember-me box */ set: (event: H3Event, account: A, body?: Record<string, any>) => unknown; get: (event: H3Event) => A | null | undefined | Promise<A | null | undefined>; clear: (event: H3Event) => unknown; }; /** key of the account in responses (`{ success, subscriber }`); default `account` */ as?: string; /** other columns a sign-up may set, besides email and password */ signUp?: string[]; minPassword?: number; reset?: { table: string; owner: string; token?: string; expires?: string; used?: string; minutes?: number; /** sends the link; `token` goes in it */ send: (account: A, token: string, event: H3Event) => unknown; }; messages?: Partial<Record<'invalid' | 'taken' | 'required' | 'short' | 'signedOut' | 'badToken', string>>; /** how a date is stored (a Date for MySQL drivers, ISO text for SQLite by default) */ date?: (d: Date) => unknown; /** a column that must be truthy for the account to sign in or pass a guard (disabled accounts) */ active?: string; /** columns written on each sign-in: `{ last_login: () => new Date() }` */ onLogin?: Record<string, () => unknown>; /** for a plain HTML form (no script): where a sign-in goes on success and on failure */ redirect?: { success: string; failure: string; }; }; export declare function accounts<A extends Record<string, any> = Record<string, any>>(o: AccountsOptions<A>): { login: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<void | { [x: string]: boolean | A; success: boolean; }>>; register: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{ [x: string]: boolean | A; success: boolean; }>>; logout: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{ success: boolean; }>>; me: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{ [x: string]: A; }>>; forgot: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{ success: boolean; }>>; reset: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{ success: boolean; }>>; change: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{ success: boolean; }>>; current: (event: H3Event) => Promise<A | null>; required: (event: H3Event) => Promise<A>; guard: (check?: (account: A) => boolean, status?: number, message?: string) => (event: H3Event) => Promise<A>; };