@justwant/permission
v3.2.0
Published
RBAC/ABAC with data-agnostic repos. Scopes, actors, roles, realms, grant/deny overrides.
Downloads
257
Maintainers
Readme
@justwant/permission
RBAC/ABAC avec repos data-agnostic. Scopes, actors, roles, realms, grant/deny overrides.
Installation
bun add @justwant/permissionUsage
import {
defineScope,
defineActor,
defineAtomicPermission,
defineRole,
defineRealm,
createPermissionService,
} from "@justwant/permission";
const appScope = defineScope({ name: "app" });
const orgScope = defineScope({ name: "org" });
const userActor = defineActor({ name: "user" });
// Or with @justwant/user: defineActor({ from: defineUser() })
const documentRead = defineAtomicPermission({ action: "document:read" });
const documentWrite = defineAtomicPermission({ action: "document:write" });
const appMember = defineRole({
name: "member",
permissions: [documentRead, documentWrite],
realm: "app",
});
const orgAdmin = defineRole({
name: "admin",
permissions: [documentRead, documentWrite],
realm: "org",
});
const appRealm = defineRealm({
name: "app",
scope: appScope,
actors: [userActor],
permissions: [documentRead, documentWrite],
roles: [appMember],
});
const orgRealm = defineRealm({
name: "org",
scope: orgScope,
actors: [userActor],
permissions: [documentRead, documentWrite],
roles: [orgAdmin],
});
// Repos: AssignmentsRepo & OverridesRepo — in-memory, DB via @justwant/db, etc.
// Lookup key is derived from realm.scope.name
const perm = createPermissionService({
repos: { assignments: myAssignmentsRepo, overrides: myOverridesRepo },
realms: [appRealm, orgRealm],
});
const user = userActor("usr_1");
await perm.assign({ actor: user, role: appMember, scope: appScope() });
await perm.assign({ actor: user, role: orgAdmin, scope: orgScope("org_1") });
const canRead = await perm.can({ actor: user, action: documentRead, scope: orgScope("org_1") });
const hasRole = await perm.hasRole({ actor: user, role: orgAdmin, scope: orgScope("org_1") });API : paramètres objet
Toutes les méthodes utilisent des paramètres objet avec des noms explicites :
| Méthode | Params |
|---------|--------|
| can | { actor, action, scope, resource? } |
| assert | { actor, action, scope, resource?, message? } |
| assign | { actor, role, scope } |
| hasRole | { actor, role, scope } |
| unassign | { actor, scope } |
| grant / deny / revokeGrant / revokeDeny | { actor, action, scope, resource? } |
| canAll / canAny | { actor, actions, scope, resource? } |
| canMany | { actors, action, scope, resource? } |
| explain | { actor, action, scope, resource? } |
| revokeScope | { scope } |
| revokeAll | { actor } |
| realm | { name } |
Scopes : singular vs plural
- 0 arg = scope singulier (un seul scope global) :
appScope()→{ type: "app", id: null } - 1 arg = scope pluriel (plusieurs instances) :
orgScope("org_1")→{ type: "org", id: "org_1" }
Subpaths
| Path | Description |
|------|-------------|
| @justwant/permission | API principale (defineScope, defineActor, createPermissionService, etc.) |
| @justwant/permission/types | Actor, Scope, Resource, IdentityLike, ReferenceLike, ScopeLike, Assignment, Override, CreateInput |
| @justwant/permission/errors | PermissionError, PermissionDeniedError, CeilingViolationError |
Features
- Data-agnostic : fournissez vos propres repos (assignments, overrides)
- Modèle plat : Actor, Scope, Resource sans hiérarchie parent-enfant
- Grant/deny overrides : permissions au niveau scope ou resource
- Shorthands :
userIdau lieu de{ type: "user", id }quand un user actor existe
