JSPM

@lbstack/accessx

0.1.0
    • ESM via JSPM
    • ES Module Entrypoint
    • Export Map
    • Keywords
    • License
    • Repository URL
    • TypeScript Types
    • README
    • Created
    • Published
    • Downloads 15
    • Score
      100M100P100Q42619F
    • License ISC

    A role & resource based access control system with end to end type safety.

    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. ๐Ÿ”โœจ