Skip to content

RolePermissions

RolePermissions<TSubjects, TUser, TOrg, TUserSlug, TOrgSlug> = { [S in keyof TSubjects | TUserSlug | (TOrgSlug extends string ? TOrgSlug : never)]?: boolean | { [A in TSubjects[S][“action”]]?: A extends QueryAction ? PermissionCheck<TSubjects[S][“data”], TUser, TOrg, TSubjects[S][“indexFields”]> : A extends Exclude<(…) | (…), QueryAction> | typeof WILDCARD_KEY ? AnyActionPermissionCheck<(…)[(…)][“data”], TUser, TOrg> : A extends (…)[(…)][“queryAction”] ? PermissionCheck<(…)[(…)], TUser, TOrg, (…)[(…)]> : AnyActionPermissionCheck<(…)[(…)], TUser, TOrg> } & { [W in typeof WILDCARD_KEY]?: AnyActionPermissionCheck<TSubjects[S][“data”], TUser, TOrg> } } & { [W in typeof WILDCARD_KEY]?: boolean }

Defined in: packages/core/src/access/types.ts:709

Per-role permission matrix, typed against the resolved SubjectMap.

Each subject key accepts boolean (all actions) or a per-action map whose keys are that subject’s action union plus the action-level wildcard (WILDCARD_KEY).

Only withIndex is gated on QueryAction (DD 14). A query-shaped action gets the full PermissionCheck, whose q carries withIndex — there is a query to narrow. Every other action gets the plain shapes plus ConstrainedPermissionCheck: a create/update/delete has no query to narrow, but its constraints are still meaningful, interpreted per-document via constraintsToPredicate. Restricting the object form to query actions is what used to force a read+update pair to express one predicate twice — once as a constraint, once as a hand-written callback — which is the dual-expression footgun this design removes.

The action-level wildcard stays plain: it spans actions of mixed shape, so a constraint written there could not be typed against one document consistently. The role-level wildcard is boolean-only. Precedence: explicit action > subject wildcard > role wildcard > defaults.

TSubjects extends Record<string, SubjectEntry>

The resolved SubjectMap.

TUser = Record<string, unknown>

User document shape.

TOrg = never

Organization document shape, or never.

TUserSlug extends CollectionSlug = CollectionSlug

TOrgSlug extends CollectionSlug | undefined = never