/**
 * Team / access-control read models for the Users admin tab.
 *
 * Pure data shaping over the Prisma client (no config or request coupling) so it
 * unit-tests cleanly. The API layer derives `workspaceDomain` / `seatLimit` from
 * config and passes them in.
 *
 *   - `listTeamMembers`  — active/suspended/locked members, de-duplicated against
 *                          pending invites (a placeholder user for a pending
 *                          invite is shown only as the invite row).
 *   - `getUserStats`     — the four summary cards (members, pending, admins, seats).
 *   - `computeAccessReview` — risk recommendations from real signals.
 */
import { type DisplayRole, type UserRoleEnum } from './roles.js';
export type MemberStatus = 'active' | 'suspended' | 'locked' | 'deactivated';
export interface TeamMember {
    id: string;
    name: string;
    email: string;
    initials: string;
    role: UserRoleEnum;
    roleName: DisplayRole;
    status: MemberStatus;
    mfaEnabled: boolean;
    mfaRequired: boolean;
    externalDomain: boolean;
    authProvider: string | null;
    lastLoginAt: string | null;
    lastActiveAt: string | null;
    acceptedInviteAt: string | null;
    createdAt: string;
    isCurrentUser: boolean;
}
export interface TeamOptions {
    /** Registrable workspace domain, e.g. "actuatemedia.com". */
    workspaceDomain?: string | null;
    /** Seat cap; null/undefined = unlimited. */
    seatLimit?: number | null;
    /** Used to mark the current row + protect self-actions. */
    currentUserId?: string;
    /** Access-review recommendation ids the workspace has dismissed. */
    dismissedIds?: string[];
}
export interface MemberFilter {
    search?: string;
    /** Display-role filter ("Owner"/"Admin"/"Editor"/"Viewer"/"all"). */
    role?: string;
    status?: string;
}
export declare function listTeamMembers(db: any, filter?: MemberFilter, opts?: TeamOptions): Promise<TeamMember[]>;
export interface UserStats {
    members: number;
    pendingInvites: number;
    admins: number;
    seatsUsed: number;
    seatLimit: number | null;
    seatsAvailable: number | null;
}
export declare function getUserStats(db: any, opts?: TeamOptions): Promise<UserStats>;
export type Severity = 'low' | 'medium' | 'high' | 'critical';
export type RecommendationType = 'inactive_user' | 'external_domain' | 'admin_without_mfa' | 'owner_without_mfa' | 'stale_invite' | 'never_signed_in';
export interface AccessReviewRecommendation {
    id: string;
    userId: string | null;
    inviteId?: string | null;
    severity: Severity;
    type: RecommendationType;
    title: string;
    description: string;
    recommendedAction: string;
    status: 'open';
}
/**
 * Build one primary recommendation per member (highest-risk signal), plus a
 * recommendation per stale pending invite. Dismissed ids are filtered out and
 * the result is sorted highest-severity first.
 */
export declare function buildRecommendations(members: TeamMember[], pendingInvites: Array<{
    id: string;
    email: string;
    createdAt: string;
}>, dismissed: Set<string>): AccessReviewRecommendation[];
export declare function computeAccessReview(db: any, opts?: TeamOptions): Promise<AccessReviewRecommendation[]>;
/** Derive the registrable workspace domain from a site URL, if any. */
export declare function workspaceDomainFromUrl(siteUrl?: string | null): string | null;
//# sourceMappingURL=team.d.ts.map