Class: GroupMembershipService
Defined in: server/access/group-membership-service.ts:28
Sanctioned mutation surface for group / team memberships. A grant to a
group subject flows to every member resolved through the memberships table
when AccessService.compileSnapshot expands group grants.
In v1 a membership change takes effect immediately: every can() compiles a
fresh snapshot, so there is no cached snapshot to invalidate. The per-subject
grant-version bump / member fan-out that powered the deferred snapshot cache
is removed (see docs/rbac/design.md "Maturity"); this service remains the
sanctioned CRUD path for membership mutations so a v2 cache can reintroduce
invalidation here without changing call sites.
Extends
Constructors
Constructor
new GroupMembershipService(deps: AccessFeatureDeps): GroupMembershipService;Defined in: server/access/base-access-service.ts:36
Parameters
| Parameter | Type |
|---|---|
deps | AccessFeatureDeps |
Returns
GroupMembershipService
Inherited from
Properties
deps
protected readonly deps: AccessFeatureDeps;Defined in: server/access/base-access-service.ts:34
Inherited from
Accessors
actorId
Get Signature
get protected actorId(): string | null;Defined in: server/access/base-access-service.ts:40
Returns
string | null
Inherited from
Methods
addMember()
addMember(input: AddMemberInput): Promise<{
createdAt: Date;
createdBy: string | null;
deletedAt: Date | null;
deletedBy: string | null;
groupId: string;
id: string;
memberId: string;
memberType: RbacSubjectType;
organizationId: string;
updatedAt: Date;
updatedBy: string | null;
}>;Defined in: server/access/group-membership-service.ts:30
Add a member to a group.
Parameters
| Parameter | Type |
|---|---|
input | AddMemberInput |
Returns
Promise<{
createdAt: Date;
createdBy: string | null;
deletedAt: Date | null;
deletedBy: string | null;
groupId: string;
id: string;
memberId: string;
memberType: RbacSubjectType;
organizationId: string;
updatedAt: Date;
updatedBy: string | null;
}>
coarsePermissionsForActor()
protected coarsePermissionsForActor(
actor: {
id: string;
type: SubjectType;
},
scope: GrantScope,
now?: Date
): Promise<CoarseActorAuthority>;Defined in: server/access/base-access-service.ts:117
H3: derive an actor's UNCONDITIONALLY-held authority for a target scope —
the delegable set for both GrantService.create's CreateGrantGuard and
RoleService.createVersion's CreateVersionGuard. Only grants the actor
holds with NO selector and NO condition contribute, mirroring
hasCoarsePermission: a narrowly-held permission must not be re-delegable
(as a grant) or re-addable (to a role) unconstrained. Effective-date
validity is honored. Shared here (not duplicated per service) so the two
escalation guards can never drift on what "coarsely held" means.
Derived over scopeChain(scope), so a platform admin can delegate inside
an organization without mode: "system" (which would skip every
escalation guard). The chain is derived here, never accepted as a
parameter — see scopeChain.
scopeKeys reports PROVENANCE: which scopes actually backed the actor.
That is what GrantService's self-org cap reads instead of a
caller-asserted actorOrganizationId, making it server-derived and
unspoofable.
Parameters
| Parameter | Type |
|---|---|
actor | { id: string; type: SubjectType; } |
actor.id | string |
actor.type | SubjectType |
scope | GrantScope |
now | Date |
Returns
Promise<CoarseActorAuthority>
Inherited from
BaseAccessService.coarsePermissionsForActor
loadActiveGrants()
protected loadActiveGrants(
repos: AccessRepositories,
subject: Subject,
scopes: GrantScope[]
): Promise<{
conditionLogic: JsonValue;
createdAt: Date;
createdBy: string | null;
deletedAt: Date | null;
deletedBy: string | null;
effectiveEnd: Date | null;
effectiveStart: Date | null;
grantFingerprint: string;
id: string;
organizationId: string | null;
roleId: string;
scopeKey: string;
scopeType: RbacScopeType;
selector: JsonValue;
subjectId: string;
subjectType: RbacSubjectType;
updatedAt: Date;
updatedBy: string | null;
}[]>;Defined in: server/access/base-access-service.ts:70
Security-critical lookup: load a subject's active grants across a set of scopes, expanding org-group membership for non-group subjects. The single source of truth for "which grants apply to this subject right now" — every caller (snapshot compilation, coarse-permission derivation) funnels here so the scopeKey derivation and group-expansion rule can never drift between call sites.
Queried one scope at a time rather than with a single scopeKey IN (…):
group expansion is a PER-SCOPE rule, not a property of the subject. It runs
only for an organization-scoped lookup AND a non-group subject — a
group subject's grants are read directly (it has no "groups" of its own to
expand), and platform scope has no org-group notion, so a group's
platform-scoped grant must NOT reach its members through an org-scoped
chain. Flattening the chain into one query with a unioned groupIds would
silently widen exactly that.
Must be called inside a repos.transaction(...) so the membership reads
and the grant reads share one transaction.
Parameters
| Parameter | Type |
|---|---|
repos | AccessRepositories |
subject | Subject |
scopes | GrantScope[] |
Returns
Promise<{
conditionLogic: JsonValue;
createdAt: Date;
createdBy: string | null;
deletedAt: Date | null;
deletedBy: string | null;
effectiveEnd: Date | null;
effectiveStart: Date | null;
grantFingerprint: string;
id: string;
organizationId: string | null;
roleId: string;
scopeKey: string;
scopeType: RbacScopeType;
selector: JsonValue;
subjectId: string;
subjectType: RbacSubjectType;
updatedAt: Date;
updatedBy: string | null;
}[]>
Inherited from
BaseAccessService.loadActiveGrants
moveMember()
moveMember(id: string, newGroupId: string): Promise<{
createdAt: Date;
createdBy: string | null;
deletedAt: Date | null;
deletedBy: string | null;
groupId: string;
id: string;
memberId: string;
memberType: RbacSubjectType;
organizationId: string;
updatedAt: Date;
updatedBy: string | null;
}>;Defined in: server/access/group-membership-service.ts:44
Move a membership to a different group.
Parameters
| Parameter | Type |
|---|---|
id | string |
newGroupId | string |
Returns
Promise<{
createdAt: Date;
createdBy: string | null;
deletedAt: Date | null;
deletedBy: string | null;
groupId: string;
id: string;
memberId: string;
memberType: RbacSubjectType;
organizationId: string;
updatedAt: Date;
updatedBy: string | null;
}>
removeMember()
removeMember(id: string): Promise<{
createdAt: Date;
createdBy: string | null;
deletedAt: Date | null;
deletedBy: string | null;
groupId: string;
id: string;
memberId: string;
memberType: RbacSubjectType;
organizationId: string;
updatedAt: Date;
updatedBy: string | null;
}>;Defined in: server/access/group-membership-service.ts:55
Remove (soft-delete) a membership.
Parameters
| Parameter | Type |
|---|---|
id | string |
Returns
Promise<{
createdAt: Date;
createdBy: string | null;
deletedAt: Date | null;
deletedBy: string | null;
groupId: string;
id: string;
memberId: string;
memberType: RbacSubjectType;
organizationId: string;
updatedAt: Date;
updatedBy: string | null;
}>
transaction()
protected transaction<T>(fn: (deps: AccessFeatureDeps) => Promise<T>): Promise<T>;Defined in: server/access/base-access-service.ts:44
Type Parameters
| Type Parameter |
|---|
T |
Parameters
| Parameter | Type |
|---|---|
fn | (deps: AccessFeatureDeps) => Promise<T> |
Returns
Promise<T>