Session API
primate/session configures session cookies and storage and returns the facade
used by route and hook code during a request.
import session from "primate/session";Application code normally exports one configured facade from
config/session.ts, then imports that instance in routes. See the
Sessions guide for setup and authentication workflows.
session()
function session<S extends StoreSchema>(
config: { store: Store<S> } & Partial<SessionConfig>,
): SessionFacade<SessionData<S>>;
function session(
config?: Omit<Partial<SessionConfig>, "store">,
): SessionFacade<unknown>;With a custom store, SessionData<S> is the store's inferred record with id
and session_id omitted. Without a store, Primate creates an in-memory store
whose session data is JSON-compatible object data and the facade type is
unknown.
Throws: For invalid configuration. During server initialization, Primate
also rejects a custom store without session_id or whose session_id schema
cannot parse a UUID string.
// config/session.ts
import session from "primate/session";
import Session from "@/stores/Session";
export default session({ store: Session });
SessionConfig
Supporting input shape inferred by the factory; it is not a named export from
primate/session.
type SessionConfig = {
cookie?: {
httpOnly?: boolean;
maxAge?: number;
name?: string;
path?: string;
sameSite?: "Strict" | "Lax" | "None";
secure?: boolean;
};
store?: Store;
};
config.cookie.httpOnly
httpOnly?: boolean;Controls the HttpOnly cookie attribute. Defaults to true.
config.cookie.maxAge
maxAge?: number;Optional non-negative 32-bit integer lifetime in seconds. When omitted, no
Max-Age attribute is emitted and the browser treats it as a session cookie.
A destroyed or stale session is cleared with Max-Age=0.
config.cookie.name
name?: string;Session cookie name. Defaults to "session_id".
config.cookie.path
path?: string;Cookie path. It must start with / and defaults to "/".
config.cookie.sameSite
sameSite?: "Strict" | "Lax" | "None";Cookie SameSite attribute. Defaults to "Lax".
config.cookie.secure
secure?: boolean;Cookie Secure attribute. When omitted, it follows whether the Primate server
has both TLS certificate and key configuration. The same resolved value is used
when setting and clearing the cookie.
config.store
store?: Store;Store used to validate and persist session records. A custom schema must have a
session_id field accepting UUID strings. Its primary id and session_id
fields are excluded from route-facing session data. The default is a new
in-memory store for JSON-compatible object data.
SessionFacade
Request-scoped operation type returned by session(). This
interface is exposed through the factory result but is not a named export from
primate/session.
interface SessionFacade<T> {
readonly id: string | undefined;
readonly exists: boolean;
create(initial?: T): Promise<void>;
get(): Promise<Readonly<T>>;
try(): Promise<Readonly<T> | undefined>;
set(next: T | ((previous: Readonly<T>) => T)): Promise<void>;
destroy(): Promise<void>;
}Server operations require an active request. Accessing the facade outside its request session scope throws a session-handle-unavailable diagnostic.
session.id
readonly id: string | undefined;Current request-local UUID session identifier, or undefined before creation
and after destruction. This accessor is not a separate database lookup; use
await session.try() to check current database state.
session.exists
readonly exists: boolean;Equivalent to checking whether the request-local id is defined. It is not a
separate database lookup.
session.create()
create(initial?: T): Promise<void>;Validates initial, inserts a row and creates a UUID when awaited. Omitted
input is parsed as {}. If a session already exists, the call is a no-op and
does not validate or replace its data.
session.get()
get(): Promise<Readonly<T>>;Reads the current session data from its Store, including writes in an active transaction on the same database.
Throws: Error("session does not exist") when no session exists.
session.try()
try(): Promise<Readonly<T> | undefined>;Reads current data or returns undefined when no session exists.
session.set()
set(next: T | ((previous: Readonly<T>) => T)): Promise<void>;Updates the session row after schema validation. The callback form receives the current read-only database value and must return the complete next value.
Throws: Error("cannot set() on non-existent session") when no session
exists. Schema parse failures also propagate.
session.destroy()
destroy(): Promise<void>;Deletes the current session row when awaited, so id becomes undefined and
exists becomes false. Calling it without a session is a no-op.
When the session Store shares the database instance of a scoped transaction, awaited operations join that transaction. A rollback restores the request-local session ID and discards its pending cookie change; a commit allows the final cookie state to be attached to the response, including an error response. Outside a transaction each awaited write is an ordinary autocommit operation: a later route error cannot undo it. HTTP cookie delivery itself cannot be atomic with a SQL commit.
Browser availability
The browser-conditioned factory returns an inert compatibility facade:
exists is false; mutating methods do nothing. Session state and persistence
are server/request concerns, so do not use this facade as client state.