MCPcopy Create free account
hub / github.com/boringstack-xyz/boringstack / buildAbility

Function buildAbility

apps/api/src/lib/acl/ability.ts:10–66  ·  view source on GitHub ↗
(
  membership: IMembership,
  features: ResolvedFeatures
)

Source from the content-addressed store, hash-verified

8import type { ResolvedFeatures } from "./feature-resolution.types";
9
10export function buildAbility(
11 membership: IMembership,
12 features: ResolvedFeatures
13): AppAbility {
14 const { can, cannot, build } = new AbilityBuilder<AppAbility>(
15 createMongoAbility
16 );
17 const { accountId } = membership;
18
19 switch (membership.role) {
20 case ROLE.owner:
21 can("manage", "TeamMember", { accountId });
22 can("manage", "Site", { accountId });
23 can("manage", "Account", { id: accountId });
24 break;
25 case ROLE.admin:
26 /*
27 * Admin manages content + members + settings, but NOT the account
28 * itself: deleting the account, transferring ownership, and
29 * changing account-level billing stay with the owner. Billing
30 * routes also enforce owner-only at the route layer.
31 */
32 can("manage", "TeamMember", { accountId });
33 can("manage", "Site", { accountId });
34 can("read", "Account", { id: accountId });
35 break;
36 case ROLE.member:
37 can("read", "TeamMember", { accountId });
38 can("read", "Account", { id: accountId });
39 can("create", "Site", { accountId });
40 can("read", "Site", { accountId });
41 can("update", "Site", { accountId });
42 can("delete", "Site", { accountId });
43 break;
44 case ROLE.viewer:
45 can("read", "TeamMember", { accountId });
46 can("read", "Site", { accountId });
47 can("read", "Account", { id: accountId });
48 break;
49 }
50
51 /*
52 * Feature gates: a missing feature forbids the action regardless of
53 * role. Per-account `admin` does NOT bypass plan checks; only
54 * `users.is_platform_admin = true` bypasses, and that bypass is
55 * applied above this layer with an audit row.
56 */
57 if (!features.can_export) {
58 cannot("export", "Site");
59 }
60
61 if (!features.can_invite_team) {
62 cannot("invite", "TeamMember");
63 }
64
65 return build();
66}
67

Callers 1

ability.test.tsFile · 0.90

Calls

no outgoing calls

Tested by

no test coverage detected