Skip to content

vperms

vperms is the main package. It re-exports the core engine and adds the validated service, request runtime and export helpers.

Values: VeguiPermsAdapter, VeguiPermsMemoryAdapter, SubjectType, SELF_PERMISSIONS_PERMISSION, subjectPermissionsPermission, canResolved, resolveSubjectPermissions, BUILTIN_PERMISSION_LAYER.

Types: Subject, SubjectId, Principal, DefaultParents, PermissionGrant, ResolvedPermission, ResolvedPermissionGrant, ResolvedSubject.

interface VeguiPermsServiceOptions {
adapter: VeguiPermsAdapter;
defaultParents?: DefaultParents;
}
class VeguiPermsService {
constructor(options: VeguiPermsServiceOptions);
can(
workspaceId: string,
subject: SubjectId | Principal,
permission: string,
): Promise<boolean>;
resolvePermissions(
workspaceId: string,
subject: SubjectId | Principal,
): Promise<ResolvedSubject>;
saveSubject(workspaceId: string, subject: Subject): Promise<Subject>;
deleteSubject(workspaceId: string, subject: Subject): Promise<boolean>;
setPermission(
workspaceId: string,
subject: SubjectId | Principal,
permission: string,
value: boolean,
): Promise<PermissionGrant>;
unsetPermission(
workspaceId: string,
subject: SubjectId | Principal,
permission: string,
): Promise<boolean>;
}

can returns false when the subject has no record. It checks direct grants first, then inherited grants, and finally matches SELF_PERMISSIONS_PERMISSION. resolvePermissions throws SubjectNotFoundError when the subject has no record. Every input is validated with Zod; a Principal is normalized with getSubjectId().

const WorkspaceIdSchema; // non-empty string
const SubjectIdSchema; // non-empty string
const PermissionSchema; // dot-separated non-empty segments
const SubjectTypeSchema;
const SubjectSchema;
const PermissionGrantSchema;
const DefaultParentIdSchema; // rejects a leading "!"
const DefaultParentsSchema;
const ResolvedPermissionSchema;
const ResolvedSubjectSchema;

Each schema infers a Validated* type.

interface Ability {
can(permission: string): Promise<boolean>;
}
const ANONYMOUS_SUBJECT_ID = "anonymous";
function resolveSubjectId(subject: SubjectId | Principal): SubjectId;
function createAbility(
service: VeguiPermsService,
workspaceId: string,
subject: SubjectId | Principal,
): Ability;
function ensureAnonymousSubject(
adapter: VeguiPermsAdapter,
service: VeguiPermsService,
workspaceId: string,
): Promise<Subject>;
interface RequestContextInput {
adapter: VeguiPermsAdapter;
service: VeguiPermsService;
workspaceId: string;
subject: SubjectId | Principal | null | undefined;
}
interface RequestContext {
id: SubjectId;
subject: Subject | undefined;
kind: SubjectType | undefined;
ability: Ability;
}
function resolveRequestContext(
input: RequestContextInput,
): Promise<RequestContext>;

createAbility memoizes can() per permission. resolveRequestContext creates the anonymous subject on demand when subject is null or undefined, otherwise loads the subject record.

function parsePermissionsExportPath(path: string): PermissionsExportPath;
interface PermissionsExportPath {
path: string;
base: string;
routePattern: string;
param: string;
match(pathname: string): PermissionsExportMatch | null;
}
function exportResolvedSubject(
input: ExportResolvedSubjectInput,
): Promise<ResolvedSubject>;

exportResolvedSubject authorizes the caller before returning anything: self requests require SELF_PERMISSIONS_PERMISSION, other targets require subjectPermissionsPermission(target). It then loads the subject and resolves its permissions. Throws PermissionDeniedError, SubjectNotFoundError or InvalidSubjectIdError.

status = 403. Thrown when the caller may not read the requested permissions. Holds .permission.

status = 404. Thrown when the subject has no record. Holds .subjectId.

status = 400. Thrown when a subject id fails validation. Holds .subjectId.

See Errors for the full reference.