import { type SQL } from "drizzle-orm"; import { type DbExec } from "../db/client.js"; import { type ShareableResourceRegistration } from "./registry.js"; import { type ShareRole, type Visibility } from "./schema.js"; export declare class ForbiddenError extends Error { statusCode: number; constructor(message?: string); } export interface AccessContext { transaction?: DbExec; userEmail?: string; orgId?: string; authCapability?: string; federationMembershipValidated?: boolean; } export declare function currentAccess(): AccessContext; export declare function resolveRegisteredAccessContext(reg: ShareableResourceRegistration | undefined, ctx: AccessContext): AccessContext; export declare function hasCurrentOrgMembership(reg: Pick, memberOrgId: string, email: string, ctx: AccessContext): Promise; export declare function accessFilter(resourceTable: any, sharesTable: any, rawCtx?: AccessContext, minRole?: ShareRole, options?: { includePublic?: boolean; }): SQL; export interface ResolvedAccess { role: "owner" | ShareRole; resource: any; } /** * Minimal resource shape returned when a caller opts into a projected access * load via `{ skipResourceBody: true }`. Contains exactly the columns the * access-decision logic itself reads — identity, ownership, org scope, and * visibility, plus any columns the registration's availability rule reads — * never a resource type's heavy body columns (`data`, `content`, and similar * blobs). */ export interface AccessProjectedResource { id: string; ownerEmail: string; orgId: string | null; visibility: Visibility; } export interface ResolvedAccessProjected { role: "owner" | ShareRole; resource: AccessProjectedResource; } export interface ResolveAccessOptions { skipResourceBody?: boolean; } /** * Whether a loaded row passes its registration's availability rule. A row * loaded without an availability column (an older schema) counts as * available, the same as a registration without a rule. */ export declare function isResourceAvailable(reg: ShareableResourceRegistration, resource: any): boolean; export declare function resolveAccess(resourceType: string, resourceId: string, rawCtx?: AccessContext, options?: { skipResourceBody?: false; }): Promise; export declare function resolveAccess(resourceType: string, resourceId: string, rawCtx: AccessContext | undefined, options: { skipResourceBody: true; }): Promise; /** * Host hook: for resources that live inside another product (a design bound * to a Builder project), the host is the authority on who may open them. The * resolver returns a role, `null` to deny, or `undefined` to fall through to * AN's own owner/org/share rules. AN keeps no copy of the host's members, * orgs or roles: it asks, per resource, per request. It is asked only about * signed-in requests unless registered with `includeSignedOut`. */ export type HostAccessResolver = (resource: any, ctx: AccessContext) => Promise; export interface HostAccessResolverOptions { /** * Also ask about signed-out requests, with `ctx.userEmail` unset. Only a * resolver written to vouch for someone with no identity may set this: any * role it returns then goes to an anonymous request. */ includeSignedOut?: boolean; } export declare function registerHostAccessResolver(resourceType: string, resolver: HostAccessResolver | null, options?: HostAccessResolverOptions): void; /** * What a link to a shareable resource can honestly say to the person who * opened it. * * - `allowed`: they can open it. * - `trashed`: they could open it, but it fails the registration's * availability rule (for example it is in the trash). * - `denied`: they are signed in, can't open it, and it exists. * - `missing`: they are signed in and it doesn't exist, or it is unavailable * and they can't open it, so trash looks the same as deleted. * - `signed-out`: nobody is signed in, so nothing about it is revealed, not * even whether it exists or is public. */ export type ResourceAccessState = "allowed" | "trashed" | "denied" | "missing" | "signed-out"; export interface ResourceAccessStatus { state: ResourceAccessState; /** The viewer's role, only when they can open the resource. */ role?: ResolvedAccess["role"]; } /** * Resolves a link's {@link ResourceAccessState} for the current viewer. It * never returns the resource's title, owner, visibility, or workspace, and * database failures stay errors rather than reading as `missing`. A * signed-out visitor gets `signed-out` before any row is read, so nothing * about the link, including whether it exists, depends on the resource. */ export declare function resolveAccessStatus(resourceType: string, resourceId: string, ctx?: AccessContext): Promise; export declare function assertAccess(resourceType: string, resourceId: string, minRole?: ShareRole | "owner", ctx?: AccessContext, options?: { skipResourceBody?: false; }): Promise; export declare function assertAccess(resourceType: string, resourceId: string, minRole: ShareRole | "owner" | undefined, ctx: AccessContext | undefined, options: { skipResourceBody: true; }): Promise;