import { Prisma, PrismaClient } from "@prisma/client"; import { Expression, RuntimeDataModel } from "./expressions"; declare const VALID_OPERATIONS: readonly ["SELECT", "UPDATE", "INSERT", "DELETE"]; type Operation = (typeof VALID_OPERATIONS)[number]; export type Models = Prisma.ModelName; type PrismaExecutor = Pick; interface ResolvedSetupAbilityExpression { abilityExpression: string; policyExpression: string; } export interface SetupMetadata { appName?: string; appRevision?: string; appVersion?: string; } export interface SetupValidationResult { actualHash: string; expectedHash: string; manifestId: string; } export interface SetupManifestAbility { expression: string | null; model: string; operation: Operation; policyName: string; slug: string; } export interface SetupManifestRole { grants: string[] | "*"; roleName: string; } export interface SetupManifest { abilities: SetupManifestAbility[]; databaseScope: string; roles: SetupManifestRole[]; } interface ClientOptions { /** The maximum amount of time Yates will wait to acquire a transaction from the database. The default value is 30 seconds. */ txMaxWait?: number; /** The maximum amount of time the Yates query transaction can run before being canceled and rolled back. The default value is 30 seconds. */ txTimeout?: number; } export interface Ability { description?: string; expression?: Expression; operation: Operation; model?: M; slug?: string; } export type AllAbilities = { [model in YModels]: Ability; }[YModels]; type CRUDOperations = "read" | "create" | "update" | "delete"; export type DefaultAbilities = { [Model in YModels]: { [op in CRUDOperations]: Ability; }; }; export type CustomAbilities = { [model in YModels]?: { [op in string]?: Ability; }; }; export type GetContextFn = () => { role: string; transactionId?: string; context?: { [key in ContextKeys]: string | number | string[]; }; } | null; declare module "@prisma/client" { interface PrismaClient { _executeRequest: (params: any) => Promise; } } export interface SetupParams = CustomAbilities> { /** * The Prisma client instance. Used for database queries and model introspection. */ prisma: PrismaClient; /** * Custom abilities to add to the default abilities. */ customAbilities?: K; /** * A function that returns the roles for your application. * This is parameterised by the abilities, so you can use it to create roles that are a combination of abilities. */ getRoles: (abilities: DefaultAbilities & K) => { [role: string]: AllAbilities[] | "*"; }; /** * A function that returns the context for the current request. * This is called on every prisma query, and is needed to determine the current user's role. * You can also provide additional context here, which will be available in any RLS expressions you've defined. * Returning `null` will result in the permissions being skipped entirely. */ getContext: GetContextFn; metadata?: SetupMetadata; options?: ClientOptions; } export type SetupMigrationParams = CustomAbilities> = Omit, "getContext">; export declare class YatesSetupManifestMismatchError extends Error { readonly manifestId: string; readonly expectedHash: string; readonly actualHash: string | null; constructor(manifestId: string, expectedHash: string, actualHash: string | null); } export declare const sanitizeSlug: (slug: string) => string; export declare class Yates { private prisma; private databaseScope; constructor(prisma: PrismaClient); init: () => Promise; createDatabaseScope: (databaseName: string) => string; getDatabaseScope: () => string; ensureDatabaseScope: () => Promise; setupAbilityTable: () => Promise<[number, number, number, number, number]>; createAbilityName: (model: string, ability: string) => string; createRoleName: (name: string) => string; quoteIdentifier: (identifier: string) => string; enableRowLevelSecurityIfNeeded: (prisma: Pick, table: string) => Promise; createSetupManifestHash: (manifest: SetupManifest) => string; createSetupManifest: (abilities: Partial, roles: { [role: string]: "*" | AllAbilities[]; }) => { abilities: SetupManifestAbility[]; databaseScope: string; roles: { grants: string[] | "*"; roleName: string; }[]; }; getSetupManifestId: () => string; getStoredSetupManifestHash: (manifestId: string, prisma?: PrismaExecutor) => Promise; upsertSetupManifestHash: (manifestId: string, manifestHash: string, prisma?: PrismaExecutor, metadata?: SetupMetadata) => Prisma.PrismaPromise; getDefaultAbilities: (models: Models[]) => Partial>; createClient: (getContext: GetContextFn, options?: ClientOptions) => import("@prisma/client/runtime/client").DynamicClientExtensionThis, Prisma.TypeMapCb, { result: {}; model: {}; query: {}; client: {}; }>; setRLS: (prisma: PrismaExecutor, table: string, roleName: string, slug: string, ability: Ability, resolvedExpression: ResolvedSetupAbilityExpression) => Promise; prepareSetup: = CustomAbilities, T = DefaultAbilities & K>({ customAbilities, getRoles, }: { customAbilities?: Partial | undefined; getRoles: (abilities: T) => { [role: string]: "*" | AllAbilities[]; }; }) => Promise<{ abilities: Partial>; defaultAbilities: Partial>; roles: { [role: string]: "*" | AllAbilities[]; }; setupManifest: { abilities: SetupManifestAbility[]; databaseScope: string; roles: { grants: string[] | "*"; roleName: string; }[]; }; setupManifestHash: string; setupManifestId: string; }>; validateSetup: = CustomAbilities, T = DefaultAbilities & K>({ customAbilities, getRoles, }: { customAbilities?: Partial | undefined; getRoles: (abilities: T) => { [role: string]: "*" | AllAbilities[]; }; }) => Promise; resolveSetupAbilityExpressions: (abilities: Partial) => Promise>; createRoles: = CustomAbilities, T = DefaultAbilities & K>({ customAbilities, getRoles, metadata, options, }: { customAbilities?: Partial | undefined; getRoles: (abilities: T) => { [role: string]: "*" | AllAbilities[]; }; metadata?: SetupMetadata | undefined; options?: ClientOptions | undefined; }) => Promise; reconcileRoles: ({ abilities, defaultAbilities, prisma, resolvedSetupAbilityExpressions, roles, }: { abilities: Partial; defaultAbilities: Partial; prisma: PrismaExecutor; resolvedSetupAbilityExpressions: Record; roles: { [role: string]: "*" | AllAbilities[]; }; }) => Promise; inspectDBRoles: (role: string) => Promise<{ tablename: string; policyname: string; cmd: string; policy_roles: string[]; matched_role: string[]; }[]>; inspectRunTimeDataModel: () => RuntimeDataModel; } /** * Applies Yates roles, grants and row-level security policies. Run this from * an explicit deployment/migration step, not from normal application startup. **/ export declare const migrateYates: = CustomAbilities>(params: SetupMigrationParams) => Promise; /** * Validates that the database has already had the current Yates manifest * applied. This is safe for runtime startup because it does not create, * alter, grant, revoke or drop database authorization state. **/ export declare const validateYatesSetup: = CustomAbilities>(params: SetupMigrationParams) => Promise; /** * Creates an extended client that sets contextual parameters and user role on * every query. Unlike setup(), this validates that migration already happened * instead of mutating database authorization state during app startup. **/ export declare const createYatesClient: = CustomAbilities>(params: SetupParams) => Promise, Prisma.TypeMapCb, { result: {}; model: {}; query: {}; client: {}; }>>; /** * Creates an extended client that sets contextual parameters and user role on every query. * * This remains backwards compatible: it applies/migrates Yates database state * before returning the runtime client. For application startup, prefer running * migrateYates() in an explicit deploy step and createYatesClient() at runtime. **/ export declare const setup: = CustomAbilities>(params: SetupParams) => Promise, Prisma.TypeMapCb, { result: {}; model: {}; query: {}; client: {}; }>>; export {};