/** * Personal Access Token (PAT) store. * * PATs are long-lived, user-scoped bearer tokens meant for CLI / local-first * workflows where re-authenticating every hour is impractical. They are * distinct from the short-lived Supabase JWTs and the workspace-wide * BRAINS_API_KEY — each PAT is tied to the Supabase/OAuth user who minted it * and is stored alongside their wiki content under `users//`. * * Two backends, auto-selected (mirrors createTokenStore): * - LocalSQLitePATStore — adds a `pats` table to the existing oauth-tokens * SQLite database. Good for single-instance / local runs. * - PostgresPATStore — PostgREST-backed, stored in a `pats` table. * Requires scripts/pats.sql to be applied once. * * expires_at is nullable — NULL means the token never expires. */ export declare const PAT_EXPIRY_DAYS_DEFAULT = 30; export declare const PAT_EXPIRY_DAYS_MAX = 365; export interface PAT { id: string; subject: string; label: string; scopes: string[]; expiresAt: number | null; createdAt: number; } export interface PATWithToken extends PAT { token: string; } export interface PATStore { /** Mint a new PAT; returns the record including the raw token (only time it's visible). */ create(subject: string, label: string, scopes: string[], expiresAt: number | null): Promise; /** Validate a bearer token; returns the PAT metadata or null if invalid/expired. */ find(token: string): Promise; /** List all non-expired PATs for a subject (token value is never returned). */ list(subject: string): Promise; /** Revoke a PAT by id. Returns true if deleted, false if not found or subject mismatch. */ revoke(id: string, subject: string): Promise; /** Prune expired PATs (called periodically). Never-expiring tokens are not pruned. */ pruneExpired(): Promise; } export declare class LocalSQLitePATStore implements PATStore { private readonly db; constructor(storageLocation: string); private initSchema; /** Migrate existing tables that have NOT NULL on expires_at to allow NULL. */ private migrateNullableExpiry; create(subject: string, label: string, scopes: string[], expiresAt: number | null): Promise; find(token: string): Promise; list(subject: string): Promise; revoke(id: string, subject: string): Promise; pruneExpired(): Promise; } export declare class PostgresPATStore implements PATStore { private readonly supabaseUrl; private readonly serviceRoleKey; /** * Validation cache, keyed by raw token. * * find() runs on every bearer-authenticated request and was an uncached * Supabase round trip — ~175ms, measured (GH #427). Worse, PATs are * indistinguishable from OAuth tokens (both opaque hex), so PAT lookup runs * first and every OAuth/MCP request paid that round trip for a query * guaranteed to miss. Negative results are therefore cached too; that is * where most of the saving is. * * Revocation stays immediate: revoke() and pruneExpired() clear the cache, * and create() seeds it. Only out-of-band changes (direct SQL) wait out the * TTL — the same tradeoff auth/supabase.ts already accepts. */ private readonly cache; constructor(supabaseUrl: string, serviceRoleKey: string); private cacheTtlMs; private cacheSet; /** Drop all cached validations. Called whenever a PAT is revoked or pruned. */ invalidateCache(): void; private get baseUrl(); private headers; create(subject: string, label: string, scopes: string[], expiresAt: number | null): Promise; find(token: string): Promise; list(subject: string): Promise; revoke(id: string, subject: string): Promise; pruneExpired(): Promise; } export declare function createPATStore(storageLocation: string): PATStore; //# sourceMappingURL=patStore.d.ts.map