session.ts93 lines · main
1/**
2 * briven-engine session helpers (Doltgres-native).
3 */
4
5import {
6 getSessionByHandle,
7 listSessionHandles,
8 revokeAllForUser,
9 revokeEngineSession,
10} from './native-session.js';
11import { isAuthCoreInitialized } from './engine.js';
12
13export type VerifySessionResult =
14 | {
15 ok: true;
16 session: {
17 getUserId: () => string;
18 getHandle: () => string;
19 getAccessTokenPayload: () => Record<string, unknown>;
20 };
21 }
22 | { ok: false; reason: string; status?: number };
23
24/**
25 * Resolve session handle from headers/cookies (pure — unit-tested).
26 * Phase 2: sAccessToken cookie value = session handle.
27 */
28export function extractSessionHandle(opts: {
29 headers?: Headers | { get: (n: string) => string | null };
30 cookieHeader?: string | null;
31}): string | null {
32 const get = (n: string) => opts.headers?.get(n) ?? null;
33 let handle =
34 get('x-briven-session-handle') ?? get('x-session-handle') ?? null;
35 if (handle === 'cookie') handle = null;
36 if (handle) return handle;
37 const cookie = opts.cookieHeader ?? get('cookie') ?? '';
38 const m =
39 /(?:^|;\s*)sAccessToken=([^;]+)/.exec(cookie) ??
40 /(?:^|;\s*)briven_session=([^;]+)/.exec(cookie);
41 if (!m?.[1]) return null;
42 try {
43 return decodeURIComponent(m[1]);
44 } catch {
45 return m[1];
46 }
47}
48
49export async function verifyAuthCoreSession(opts: {
50 url: string;
51 method: string;
52 headers: Headers;
53 cookieHeader?: string;
54}): Promise<VerifySessionResult> {
55 if (!isAuthCoreInitialized()) {
56 return { ok: false, reason: 'auth_core_sdk_not_ready', status: 503 };
57 }
58 const handle = extractSessionHandle({
59 headers: opts.headers,
60 cookieHeader: opts.cookieHeader,
61 });
62 if (!handle) {
63 return { ok: false, reason: 'no_session', status: 401 };
64 }
65 const row = await getSessionByHandle(handle);
66 if (!row) return { ok: false, reason: 'invalid_session', status: 401 };
67 return {
68 ok: true,
69 session: {
70 getUserId: () => row.userId,
71 getHandle: () => handle,
72 getAccessTokenPayload: () => ({
73 sub: row.userId,
74 tenantId: row.tenantId,
75 }),
76 },
77 };
78}
79
80export async function listSessionsForUser(userId: string): Promise<string[]> {
81 if (!isAuthCoreInitialized()) return [];
82 return listSessionHandles(userId);
83}
84
85export async function revokeSession(sessionHandle: string): Promise<boolean> {
86 if (!isAuthCoreInitialized()) return false;
87 return revokeEngineSession(sessionHandle);
88}
89
90export async function revokeAllSessionsForUser(userId: string): Promise<number> {
91 if (!isAuthCoreInitialized()) return 0;
92 return revokeAllForUser(userId);
93}