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;
};
httpOnly?: boolean;

Controls the HttpOnly cookie attribute. Defaults to true.

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.

name?: string;

Session cookie name. Defaults to "session_id".

path?: string;

Cookie path. It must start with / and defaults to "/".

sameSite?: "Strict" | "Lax" | "None";

Cookie SameSite attribute. Defaults to "Lax".

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.

Previous
Response
Next
I18N