@leumas/entitlements
Policy-driven entitlement engine — plans/memberships DECLARE capabilities + quota limits as data; one primitive gates & meters everywhere. The swappable membership-access axis (sibling to PassNode's...
@leumas/entitlements
Policy-driven, swappable entitlement engine. Plans/memberships declare capabilities + quota limits as data; one primitive gates & meters everywhere — no if (plan === 'Pro') sprinkled through the code.
This is the membership-access axis (who may use a Leumas platform feature, and how much). It is a sibling of, not the same as, PassNode in @leumas/auth (the tenant→end-user monetization axis).
Model
A capability is a dotted key. Its value is a boolean (feature flag) or a number (quota limit):
imperium.hosting: true imperium.maxSites: 5
imperium.customDomains: false imperium.reverseProxy: true imperium.tenantSeats: 10
Rules live as data in the Studio-editable entitlement_policies collection (one doc per plan/service), with optional per-user overrides in membership.metadata. Change "Pro gets 5 sites + reverse-proxy" by editing a doc — zero code change.
Backend
import { createEntitlements, createEntitlementsRouter } from '@leumas/entitlements';
const entitlements = createEntitlements({
load: () => connector.get().read('entitlement_policies'),
getUserMemberships: (userId) => membershipsService.listMemberships(userId),
});
await entitlements.refresh(); // + refresh on the /db change-feed for entitlement_policies
app.use('/api/thing', entitlements.requireCapability('imperium.hosting'), thingRouter);
await entitlements.checkQuota(req.user, 'imperium.maxSites', currentCount); // throws 402 if over
app.use('/entitlements', createEntitlementsRouter({ entitlements, requireAuth }));
Frontend
The API resolves server-side; the frontend fetches the resolved map once (GET /entitlements/me) and gates off it. @leumas/features ships the React glue: CapabilityProvider, useCapability(cap), useLimit(cap) and <RequireCapability cap=… fallback=… />.
What it exports
23 exports: 6 components, 0 hooks, 17 helpers. Import from @leumas/entitlements.
ACTIVE_STATUSESACTIVE_STATUSESBASE_CAPABILITIESBASE_CAPABILITIESDEFAULT_PLAN_POLICIESDEFAULT_PLAN_POLICIESbaseFrombaseFromcanFromcanFromcreateEntitlementscreateEntitlementscreateEntitlementsRouterisActiveMembershipisActiveMembershiplimitFromlimitFrompolicyMatchespolicyMatchesresolveEntitlementsresolveEntitlementswithDefaultPolicieswithDefaultPolicies