Skip to content
TypeWire

@tahanabavi/type-permission

v0.1.0

Framework-less, dependency-free capability permissions: one shared bit map, evaluated identically on client and server, with layered resolution, codecs, a lock file and contract-linkable requirements.

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.

bash
pnpm add @tahanabavi/type-permission

Two ways in — progressive disclosure

ts
// 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: grantsAllimpliesrequires (gating, last, cascading to a fixpoint — so "denied the channel ⇒ can do nothing in it" falls out of the model).