import { type Node, type RoleDefinition } from '@substrat-run/contracts'; import type { PermissionChecker } from './permission-checker.js'; type MaybePromise = T | Promise; /** * One tuple row as the spine stores it — snake_case, because that is what both adapters * `SELECT`. `expires_at`/`revoked_at` are what `live()` judges; a revoked row is still * here and still readable as evidence (K-21), it just stops granting. */ export interface PermissionTupleRow { subject: string; relation: string; object: string; expires_at: string | null; revoked_at: string | null; } /** * The scope-local half of the read: scope-level assignments/grants, entity-narrowed grants, * and the declared `parent` edges the entity walk follows. Entity tuples are scope-local by * construction, so all three live together. */ export interface ScopeTupleReader { /** Scope-level tuples for `subject` whose relation starts with `relationPrefix`. */ tuples(subject: string, relationPrefix: string): MaybePromise; /** The one grant tuple (subject, relation, object), if it exists. */ grant(subject: string, relation: string, object: string): MaybePromise; /** The declared `parent` edges out of `object`. */ parents(object: string): MaybePromise; } /** * Everything the evaluator needs to know, and nothing about where it comes from. * * `scopeFor` takes the whole `Node` rather than a scope id so an adapter decides for itself * when a scope store is reachable: the pure adapter resolves `node.scopeId` against its open * databases and answers `undefined` when there is none, while a ScopeDO simply *is* one * scope and always answers itself. */ export interface PermissionTupleReader { /** What "now" means when a tuple's `expires_at` is judged (#956). */ now(): string; /** Tenant-level tuples for `subject` whose relation starts with `relationPrefix`. */ tenantTuples(tenantId: string, subject: string, relationPrefix: string): MaybePromise; /** A role definition, or `undefined` — which is a deny, so an absent projection fails closed. */ getRole(tenantId: string, key: string): MaybePromise; /** The scope store this node's check reads, if there is one. */ scopeFor(node: Node): ScopeTupleReader | undefined; } /** * Build the evaluator over one adapter's reader. Stateless per call: everything it knows it * reads at check time, which is what makes check-after-write consistent (the "no zookies" * property) and what lets `reader.now()` decide expiry rather than the wall clock. */ export declare function createTupleEvaluator(reader: PermissionTupleReader): PermissionChecker; export {}; //# sourceMappingURL=permission-eval.d.ts.map