Framework-less, dependency-free capability permissions. One shared bit map, evaluated identically on the client and the server by the same pure functions — no adapters, no runtime dependencies (not even Zod), no framework imports. It runs in a browser, Node, Bun, Deno, an edge worker, a Discord bot, or a CLI, unchanged.
It answers "does this actor hold capability X?" from a bigint bitfield —
Discord's model, generalized. It deliberately does not answer "can I edit my
own post?"; that needs the resource, which needs a database, which needs a
framework. Keeping ownership out is what keeps this tiny. Full design rationale in
docs/PERMISSION.md.
pnpm add @tahanabavi/type-permissionTwo ways in — progressive disclosure
// simple app: names in, effective bits out
const perms = P.from(["post.read", "post.write"]);
// scoped app (Discord's channel-overwrite chain), as data:
const perms = P.resolve([
{ allow: everyoneRole, source: "@everyone" },
{ allow: [roleA, roleB], source: "roles" },
{ allow: chOverwrite.allow, deny: chOverwrite.deny, source: "channel" },
]);Each layer applies (perms & ~deny) | allow; allow beats deny within a tier, a
later tier beats an earlier one. Then three post-passes run in a fixed order:
grantsAll → implies → requires (gating, last, cascading to a fixpoint — so
"denied the channel ⇒ can do nothing in it" falls out of the model).