Skip to content

withSession

withSession<TRole, T>(
pool: Pool,
auth: { token: string; roleName?: TRole },
fn: (client: PoolClient, ctx: SessionContext<TRole>) => Promise<T>,
options?: { scope?: ScopeHook; logger?: Logger },
): Promise<T>

The default API. It opens a @smplcty/db transaction, resolves the session from its token, validates it, picks the active role, sets the identity GUCs, runs your optional scope hook, runs your callback, and commits — or rolls back on throw.

const widgets = await withSession(pool, { token, roleName: 'user' }, async (client, ctx) => {
// ctx = { userId, activeRole, roles, privileges }
const { rows } = await client.query('SELECT * FROM widgets');
return rows;
});

Active-role selection (in TypeScript, not the resolver)

Section titled “Active-role selection (in TypeScript, not the resolver)”

resolve_session is a pure resolver that validates nothing. withSession picks the active role:

  1. the requested roleName if given — must be one the user holds, else RoleNotHeldError;
  2. otherwise the user’s sole role, if they hold exactly one — counted by distinct name, so the same role across several tenants still counts as one. An admin who only holds security gets it activated without asking, so admins never need the default user role just to have an active role;
  3. otherwise the user’s default role (roles.is_default) — the tie-breaker when they hold two or more;
  4. otherwise none — a privilege-only request, which is not an error.

withSession throws before your callback runs if anything’s wrong:

ErrorWhen
SessionNotFoundErrortoken matches no session
SessionExpiredErrorsession has expired (or was revoked)
RoleNotHeldErrora requested roleName the user does not hold
InvalidInputErrortoken is empty / wrong type

All extend AuthError and carry a code:

try {
await withSession(pool, { token, roleName: 'user' }, fn);
} catch (err) {
if (err instanceof AuthError && err.code === 'SESSION_EXPIRED') {
// redirect to login
}
throw err;
}

roleName defaults to string. Narrow it in a thin wrapper for autocomplete:

export function withSession<T>(
pool: Pool,
auth: { token: string; roleName?: 'user' | 'settings' | 'security' },
fn: (client: PoolClient, ctx: SessionContext<'user' | 'settings' | 'security'>) => Promise<T>,
options?: Parameters<typeof baseWithSession>[3],
) {
return baseWithSession(pool, auth, fn, options);
}