import type { Db } from "../db/connect.js"; import type { Persona, SchemaSnapshot, SeededRow, TableInfo } from "../types.js"; /** * Become a logged-in user of an Auth.js (NextAuth) application, without a * secret and without any cryptography. * * Auth.js has two session strategies. The JWT strategy encrypts its cookie into * a JWE derived from `AUTH_SECRET`, which we cannot and will not forge. The * *database* strategy — the one you get the moment you add an adapter — stores * the session token **in plaintext** in a `session` row, and that stored value * is byte-for-byte the cookie the browser sends back. So the way to become a * user is not to mint a credential but to insert a session, exactly as the * adapter's own `createSession` does, into the database we are already * connected to. * * That keeps the property the rest of the engine rests on. We do not infer an * identity from anything the application said; we created the session, so * "this request is Alice" is a fact about a row we planted, in the same way * that "this row is Bob's" is. * * The schema is the adapter's documented one. It varies in spelling between * adapters and that variation is load-bearing: * * @auth/pg-adapter sessions "sessionToken" "userId" expires * @auth/drizzle-adapter session "sessionToken" "userId" expires * @auth/prisma-adapter Session sessionToken userId expires * …with the snake_case `@map` the docs show: * sessions session_token user_id expires * * So the names are matched from that list rather than hardcoded to one, and * where the answer is not certain we say so and assert nothing instead of * picking a table and hoping. */ /** Column names, when the schema does not use any documented spelling. */ export interface SessionColumns { token?: string; user?: string; expires?: string; } export interface SessionStore { table: TableInfo; tokenColumn: string; userColumn: string; expiresColumn: string; } export type StoreLookup = { ok: true; store: SessionStore; how: string; } | { ok: false; reason: string; }; /** * Find the table Auth.js keeps its sessions in. * * Deliberately narrow. Inserting into the wrong table would be the same class * of mistake as naming the wrong user table: it produces an identity that is * not an identity, and every request made with it means something other than * what the report says it means. So a table qualifies only if it is named the * way the adapters name it, carries all three columns, and the column meant to * hold a user id demonstrably can. Anything else returns a reason. */ export declare function findSessionStore(snapshot: SchemaSnapshot, explicit?: { table?: string; columns?: SessionColumns; }): StoreLookup; export type PlantOutcome = { ok: true; token: string; row: SeededRow; } | { ok: false; reason: string; }; /** * Insert a session for this persona and return the token the browser would send. * * The token is ours, so what comes back through the application is checked * against a value only we could have written — the same oracle as everywhere * else, one level up. The expiry is set into the future explicitly: the generic * seeder fills a required timestamp with `now()`, and a session that expired the * instant it was created would be rejected by the adapter and every request * would silently be anonymous. */ export declare function plantSession(db: Db, store: SessionStore, persona: Persona, snapshot: SchemaSnapshot, lifetimeMs?: number): Promise;