Package Exports
- @lbstack/accessx
- @lbstack/accessx/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@lbstack/accessx) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
@lbstack/accessx
A TypeScript-first RBAC permission engine with automatic permission generation, designed to be the single source of truth for:
- Backend authorization
- Frontend UI access control
- Database permission storage
- Admin permission management
No manual permission strings.
No role leakage to frontend.
Full autocomplete everywhere.
โจ Key Features
- ๐ Automatic permission generation
- ๐ง Strong TypeScript inference & autocomplete
- ๐๏ธ Single initialization โ use everywhere
- ๐ฅ๏ธ Backend (Express / Nest / Hono)
- ๐จ Frontend (React hooks & components)
- ๐๏ธ Database-friendly permission keys
- ๐ฆ Package & framework agnostic
๐งฉ Core Concept
You define:
- Roles
- Actions
- Resources (modules)
The package automatically generates permissions in this format:
RESOURCE_KEY:ACTION
Example:
BLOGS:CREATE BLOGS:READ USER:DELETE
These permission keys are:
- Stored in DB
- Sent to frontend after login
- Used in UI & API checks
- Fully type-safe
๐ฆ Installation
npm install @lbstack/accessx
or
pnpm add @lbstack/accessx
๐ Initialization (Single Source of Truth)
import { createAccess } from "@lbstack/accessx";
export const access = createAccess({
roles: ["ADMIN", "EDITOR", "CUSTOMER"] as const,
actions: ["CREATE", "READ", "UPDATE", "DELETE"] as const,
resources: [
{
name: "Users",
key: "USER",
description: "User management",
},
{
name: "Blogs",
key: "BLOGS",
description: "Blog posts",
},
] as const,
});
โ ๏ธ as const is required for TypeScript autocomplete.
๐ Automatically Generated Permissions
access.permissionKeys
[
"USER:CREATE",
"USER:READ",
"USER:UPDATE",
"USER:DELETE",
"BLOGS:CREATE",
"BLOGS:READ",
"BLOGS:UPDATE",
"BLOGS:DELETE",
]
No permission strings are written manually.
๐๏ธ Database Usage
Seed permissions table
await db.permissions.insertMany(access.permissions);
Each permission contains metadata:
{
key: "BLOGS:CREATE",
resource: { name, key, description },
action: "CREATE"
}
๐ Backend Usage
Assign permissions to roles
access.allow("ADMIN", "USER:DELETE");
access.allow("EDITOR", "BLOGS:CREATE");
Check permission (Service / Controller)
access.can(user.role, "BLOGS:UPDATE");
Normalize permissions from DB
const permissionsFromDb = ["BLOGS:READ", "USER:DELETE"];
const permissions = access.normalizePermissions(permissionsFromDb);
Ensures only valid generated permissions are used.
Login Response
res.json({
user,
permissions: access.resolvePermissions(user.role),
});
๐จ Frontend Usage (React)
Frontend never uses roles.
It only receives resolved permissions.
useCan Hook
const canEdit = access.useCan(
auth.permissions,
"BLOGS:UPDATE"
);
<button disabled={!canEdit}>Edit</button>
<Can /> Component
<access.Can
permissions={auth.permissions}
permission="USER:DELETE"
>
<DeleteUserButton />
</access.Can>
๐ง Type Safety & Autocomplete
Invalid permission โ โ TypeScript error
Invalid resource/action โ โ TypeScript error
IDE auto-suggests valid permissions everywhere
// โ Invalid
"BLOGS:PUBLISH"
// โ
Valid
"BLOGS:CREATE"
๐๏ธ API Reference
Metadata
access.roles
access.actions
access.resources
access.permissions
access.permissionKeys
Backend
access.allow(role, permission)
access.can(role, permission)
access.resolvePermissions(role)
access.normalizePermissions(raw)
Frontend
access.useCan(permissions, permission)
<access.Can />
๐ Comparison with Keycloak
This package is an application-level authorization engine, not a full IAM system.
Area @accessx/core Keycloak
Identity โ โ
RBAC Core โ
โ
Type Safety โ
โ
Frontend Hooks โ
โ
Performance โ
โ
Admin UI โ โ
Multi-App SSO โ โ
Runtime Policy Change โ โ
Enterprise Compliance โ โ
Ops Overhead Low High
Strengths
Excellent developer experience (TypeScript-first)
Frontend hooks and React components
High performance and low latency
Embedded, framework-agnostic, zero ops
Weaknesses Compared to Keycloak
No identity or login management
No multi-application SSO
No admin UI or delegation
Permissions mostly static (redeploy needed for new resources/actions)
No ABAC / advanced policy language
No enterprise audit / compliance tooling
Ideal Usage
Keycloak (Authentication + Identity)
โ
JWT / Claims
โ
@accessx/core (Authorization + UI permissions)
This is complementary, not a replacement for Keycloak.
๐ Why Use @accessx/core?
Zero manual permission creation
DB, backend & frontend always in sync
Enterprise-grade RBAC foundation for apps
Scales to ABAC, multi-role, multi-tenant systems
## ๐ง ABAC (Attribute-Based Access Control)
You can define dynamic permissions based on context (e.g., user ID, ownership checking).
### 1. Define with Conditions
```typescript
access.allow("USER", "BLOG:UPDATE", (context: { user: any; post: any }) => {
return context.post.authorId === context.user.id;
});2. Check with Context
The can method accepts an optional context object as the third argument.
const canEdit = access.can("USER", "BLOG:UPDATE", { user, post });3. Frontend Usage
React components also support context.
<Can permissions={myPermissions} permission="BLOG:UPDATE" context={{ user, post }}>
<button>Edit Post</button>
</Can>๐งช Testing
The package includes a comprehensive test suite using Jest.
npm test๐ฃ๏ธ Roadmap
Wildcard permissions (BLOGS:*)
Multi-role users
Attribute-based access control (ABAC)
Permission groups
JWT permission compression
CLI generator
๐ License
MIT
๐ก Inspiration
Zanzibar (Google)
Auth0 / Keycloak permission models
CASL & OPA (simplified DX)
One definition. One truth. Everywhere. ๐โจ