{
  "schema": "leumas.docs.page/1",
  "id": "pkg:@leumas/entitlements",
  "slug": "packages/entitlements",
  "kind": "capabilities",
  "bucket": "package",
  "title": "@leumas/entitlements",
  "name": "@leumas/entitlements",
  "eyebrow": null,
  "chip": null,
  "summary": "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...",
  "keywords": [
    "entitlements",
    "policy-driven",
    "swappable",
    "membership-access",
    "memberships",
    "entitlements api",
    "leumas entitlements",
    "how to use entitlements"
  ],
  "audience": "both",
  "funnel": {
    "product": null,
    "cta": null
  },
  "body": "# @leumas/entitlements\n\nPolicy-driven, **swappable** entitlement engine. Plans/memberships **declare** capabilities + quota limits\nas data; one primitive gates & meters everywhere — no `if (plan === 'Pro')` sprinkled through the code.\n\nThis is the **membership-access axis** (who may use a Leumas platform feature, and how much). It is a\nsibling of, not the same as, **PassNode** in `@leumas/auth` (the tenant→end-user *monetization* axis).\n\n## Model\n\nA **capability** is a dotted key. Its value is a boolean (feature flag) or a number (quota limit):\n\n```\nimperium.hosting: true      imperium.maxSites: 5\nimperium.customDomains: false   imperium.reverseProxy: true   imperium.tenantSeats: 10\n```\n\nRules live as **data** in the Studio-editable `entitlement_policies` collection (one doc per plan/service),\nwith optional per-user overrides in `membership.metadata`. Change \"Pro gets 5 sites + reverse-proxy\" by\nediting a doc — zero code change.\n\n## Backend\n\n```js\nimport { createEntitlements, createEntitlementsRouter } from '@leumas/entitlements';\n\nconst entitlements = createEntitlements({\n  load: () => connector.get().read('entitlement_policies'),\n  getUserMemberships: (userId) => membershipsService.listMemberships(userId),\n});\nawait entitlements.refresh();                 // + refresh on the /db change-feed for entitlement_policies\n\napp.use('/api/thing', entitlements.requireCapability('imperium.hosting'), thingRouter);\nawait entitlements.checkQuota(req.user, 'imperium.maxSites', currentCount); // throws 402 if over\napp.use('/entitlements', createEntitlementsRouter({ entitlements, requireAuth }));\n```\n\n## Frontend\n\nThe API resolves server-side; the frontend fetches the resolved map once (`GET /entitlements/me`) and gates\noff it. `@leumas/features` ships the React glue: `CapabilityProvider`, `useCapability(cap)`, `useLimit(cap)`\nand `<RequireCapability cap=… fallback=… />`.\n",
  "source": {
    "path": "shared/packages/entitlements/README.md",
    "blobSha": "",
    "commit": "",
    "committedAt": "",
    "provenance": "no-git",
    "bytes": 2138,
    "hash": "aa8c3c5ee9482c632ef40aa95f8bf1533e4465a9"
  },
  "urls": {
    "html": "/p/packages/entitlements",
    "json": "/docs/packages/entitlements.json",
    "md": "/docs/packages/entitlements.md"
  },
  "links": {
    "composes": [],
    "usedBy": [
      "pkg:@leumas/imperium-server"
    ],
    "product": [],
    "howTo": [],
    "skills": []
  },
  "exports": {
    "total": 23,
    "component": 6,
    "hook": 0,
    "helper": 17,
    "names": [
      {
        "n": "ACTIVE_STATUSES",
        "k": "component"
      },
      {
        "n": "ACTIVE_STATUSES",
        "k": "component"
      },
      {
        "n": "BASE_CAPABILITIES",
        "k": "component"
      },
      {
        "n": "BASE_CAPABILITIES",
        "k": "component"
      },
      {
        "n": "DEFAULT_PLAN_POLICIES",
        "k": "component"
      },
      {
        "n": "DEFAULT_PLAN_POLICIES",
        "k": "component"
      },
      {
        "n": "baseFrom",
        "k": "helper"
      },
      {
        "n": "baseFrom",
        "k": "helper"
      },
      {
        "n": "canFrom",
        "k": "helper"
      },
      {
        "n": "canFrom",
        "k": "helper"
      },
      {
        "n": "createEntitlements",
        "k": "helper"
      },
      {
        "n": "createEntitlements",
        "k": "helper"
      },
      {
        "n": "createEntitlementsRouter",
        "k": "helper"
      },
      {
        "n": "isActiveMembership",
        "k": "helper"
      },
      {
        "n": "isActiveMembership",
        "k": "helper"
      },
      {
        "n": "limitFrom",
        "k": "helper"
      },
      {
        "n": "limitFrom",
        "k": "helper"
      },
      {
        "n": "policyMatches",
        "k": "helper"
      },
      {
        "n": "policyMatches",
        "k": "helper"
      },
      {
        "n": "resolveEntitlements",
        "k": "helper"
      },
      {
        "n": "resolveEntitlements",
        "k": "helper"
      },
      {
        "n": "withDefaultPolicies",
        "k": "helper"
      },
      {
        "n": "withDefaultPolicies",
        "k": "helper"
      }
    ]
  }
}
