/** * Pure resolver — no I/O — that decides which team is "active" for a user * given their memberships and an optional switch preference. Reusable across * apps: it encodes the whole workspace-switching precedence in one place. * * - Honors `activeTeamId` only when the user may access it: a member always * may; a privileged operator may access any team when `allowAnyTeam` is set * (the app decides who is privileged — e.g. a super-admin flag). * - Otherwise falls back to the highest-priority membership (owner > admin > * anything else), matching what dashboard pages have always shown, so the * "current team" never differs between a rendered form and the action it * posts to. */ export declare function selectActiveTeam(opts: { memberships: Array<{ team_id: number | string, role?: string | null }> activeTeamId?: number | null allowAnyTeam?: boolean rolePriority?: Record }): { teamId: number | null, role: string | null }; /** Read the active-team switch preference from a request's cookie. */ export declare function getActiveTeamPreference(request: TeamAuthRequest): number | null; /** * Build the `Set-Cookie` that pins the active team (workspace switcher). A * year-long HttpOnly cookie: only the server needs it (SSR reads it, the * switch action writes it), and it carries no privilege of its own. */ export declare function buildActiveTeamCookie(teamId: number, opts?: { maxAgeSeconds?: number, secure?: boolean }): string; /** Clear the active-team cookie {@link buildActiveTeamCookie} sets. */ export declare function clearActiveTeamCookie(): string; /** * Resolve the requesting user's active team membership (team id + role) * from their auth credential. Driver-aware: reads config/auth.ts's * configured guard driver rather than hardcoding a validation scheme. * * Dashboard forms are plain HTML POSTs (no client JS, no Authorization * header) — the browser only ever sends the auth cookie set on login, * so that's checked for the 'token' driver alongside a bearer-header * fallback for JS/API callers. * * Owner membership wins over admin, which wins over any other active * membership, when a user belongs to more than one team — the same * precedence server-rendered dashboard pages use, so a user never sees * a different "current team" between the page that rendered a form and * the action that form posts to. * * Returns `null` when unauthenticated or without an active team * membership — callers must treat that as "reject the request," not * "fall back to a default team." */ export declare function resolveAuthenticatedMembership(request: TeamAuthRequest): Promise; /** * Full team context for a server-rendered dashboard: the authenticated user, * the resolved active team (honoring the workspace switcher), and the list of * teams the user can switch between. One call replaces the per-page auth+team * boilerplate every dashboard view used to copy, and centralizes the * switch-aware scoping so pages and the actions they post to never disagree. * * `opts.allowAnyTeam(user)` lets an app grant an operator (e.g. a super-admin) * access to every team — they can switch to, and see, teams they aren't a * member of. The full user row is returned so the app can read its own * columns (like a super-admin flag) without a second query. */ export declare function resolveTeamContext(request: TeamAuthRequest, opts?: { allowAnyTeam?: (user: any) => boolean }): Promise; /** * Team id only — the common case for actions that just need to scope a * write to the requester's team. See {@link resolveAuthenticatedMembership} * when the caller also needs the role (e.g. owner/admin-only settings). */ export declare function resolveAuthenticatedTeamId(request: TeamAuthRequest): Promise; /** * The authenticated USER (not team) from a request's real auth * credential — bearer header first, then the login cookie, driver-aware * like {@link resolveAuthenticatedMembership} (which builds on this). * For dashboard form actions that operate on the requester themselves * (security settings, profile) rather than on team-scoped rows: plain * HTML POSTs carry no Authorization header, so `request.user()` (stamped * by the auth middleware from a bearer/session) is undefined there and * the login cookie is the only credential available. */ export declare function resolveAuthenticatedUser(request: TeamAuthRequest): Promise<{ id: number, email?: string } | undefined>; /** * Name of the cookie that remembers which team the user last switched the * dashboard to (a workspace switcher). It is NOT a security credential: the * server re-validates membership against `selectActiveTeam` on every request, * so a tampered value can only ever resolve to a team the user already * belongs to (or, for operators, any team when `allowAnyTeam` is set). */ export declare const ACTIVE_TEAM_COOKIE: 'active_team'; /** * Team resolution from a request's real auth credential (bearer token or * session cookie) — never from a client-supplied form field. Extracted * from app-land (stacksjs/status config/auth-team.ts) because every app * with team-scoped dashboard forms needs exactly this, and `config/` is * for autoloaded config files, not shared helpers. * * Structural request type on purpose: callers pass whatever request * object their action received. Partial objects (tests, non-HTTP * callers) resolve to "unauthenticated" rather than crashing. */ export declare interface TeamAuthRequest { bearerToken?: () => string | null | undefined cookies?: { get: (name: string) => string | null | undefined } } export declare interface TeamMembershipResult { teamId: number role: string } /** A team the authenticated user may switch the dashboard to. */ export declare interface SwitchableTeam { id: number name: string role: string } /** Full dashboard team context — see {@link resolveTeamContext}. */ export declare interface TeamContext { user: any | null teamId: number | null role: string | null teams: SwitchableTeam[] activeTeamId: number | null }