Skip to content

Commit eb4d20f

Browse files
Add Material for MkDocs documentation (#56)
* Add Material for MkDocs documentation * Add GitHub Pages deployment workflow
1 parent 52087b5 commit eb4d20f

File tree

8 files changed

+392
-0
lines changed

8 files changed

+392
-0
lines changed

.github/workflows/ci.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: ci
2+
on:
3+
push:
4+
branches:
5+
- master
6+
- main
7+
permissions:
8+
contents: write
9+
jobs:
10+
deploy:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
- name: Configure Git Credentials
15+
run: |
16+
git config user.name github-actions[bot]
17+
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
18+
- uses: actions/setup-python@v5
19+
with:
20+
python-version: 3.x
21+
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
22+
- uses: actions/cache@v4
23+
with:
24+
key: mkdocs-material-${{ env.cache_id }}
25+
path: ~/.cache
26+
restore-keys: |
27+
mkdocs-material-
28+
- run: pip install mkdocs-material
29+
- run: mkdocs gh-deploy --force

docs/basic-usage.md

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# Basic Usage
2+
3+
This section shows how to configure RBAC, model permissions, and integrate the library into common application layers.
4+
5+
## Configure RBAC
6+
7+
Create an instance by passing configuration and a role map. Configuration accepts a custom logger and a `enableLogger` flag to turn logging on or off.
8+
9+
```ts
10+
import RBAC from '@rbac/rbac';
11+
12+
const rbac = RBAC({ enableLogger: true })({
13+
guest: { can: ['products:find'] }
14+
});
15+
```
16+
17+
## Define roles and permissions
18+
19+
A role definition accepts:
20+
21+
- `can`: An array of strings or objects with a `name` and optional `when` guard. Strings match directly, and patterns can use glob wildcards or regular expressions.
22+
- `inherits`: An optional array of roles to pull permissions from.
23+
24+
```ts
25+
const rbac = RBAC()({
26+
user: { can: ['products:find'] },
27+
supervisor: {
28+
can: [
29+
{ name: 'products:edit', when: () => true },
30+
{ name: 'products:*' } // wildcard
31+
],
32+
inherits: ['user']
33+
}
34+
});
35+
```
36+
37+
`when` guards can be synchronous, async, a returned Promise, or a callback. They receive the `params` object passed to `can`.
38+
39+
```ts
40+
const rbac = RBAC()({
41+
auditor: {
42+
can: [
43+
{ name: 'products:audit:callback', when: (_params, done) => done(null, true) },
44+
{ name: 'products:audit:async', when: async () => true },
45+
{ name: 'products:audit:promise', when: Promise.resolve(true) }
46+
]
47+
}
48+
});
49+
```
50+
51+
## Check permissions
52+
53+
The `can` helper resolves inheritance, matches exact operations, globs, or regexes, and evaluates conditional guards when present:
54+
55+
```ts
56+
await rbac.can('supervisor', 'products:find');
57+
await rbac.can('supervisor', 'products:create');
58+
await rbac.can('auditor', /products:audit/);
59+
await rbac.can('auditor', 'products:audit:async', { requestId: '42' });
60+
```
61+
62+
## Update roles at runtime
63+
64+
Add or merge role definitions without rebuilding your application:
65+
66+
```ts
67+
rbac.addRole('editor', { can: ['products:update'], inherits: ['user'] });
68+
rbac.updateRoles({
69+
user: { can: ['products:find', 'products:share'] }
70+
});
71+
```
72+
73+
## Persist and load roles with adapters
74+
75+
Use the optional adapters to store roles in your database. Each adapter supports a customizable table/collection schema and an optional `tenantId` for multi-tenancy.
76+
77+
```ts
78+
import { MongoRoleAdapter, MySQLRoleAdapter, PostgresRoleAdapter } from '@rbac/rbac/adapters';
79+
80+
const mongoAdapter = new MongoRoleAdapter({
81+
uri: 'mongodb://localhost:27017',
82+
dbName: 'mydb',
83+
collection: 'roles'
84+
});
85+
86+
const mysqlAdapter = new MySQLRoleAdapter({
87+
uri: 'mysql://user:pass@localhost:3306/app',
88+
table: 'roles'
89+
});
90+
91+
const pgAdapter = new PostgresRoleAdapter({
92+
connectionString: 'postgres://user:pass@localhost:5432/app',
93+
table: 'roles'
94+
});
95+
```
96+
97+
Adapters expose `getRoles`, `addRole`, and `updateRoles` to manage definitions in storage.
98+
99+
## Multi-tenant RBAC
100+
101+
Scope RBAC to a specific tenant by loading role definitions with a `tenantId`:
102+
103+
```ts
104+
import { createTenantRBAC, MongoRoleAdapter } from '@rbac/rbac';
105+
106+
const adapter = new MongoRoleAdapter({
107+
uri: 'mongodb://localhost:27017',
108+
dbName: 'mydb',
109+
collection: 'roles'
110+
});
111+
112+
const rbacTenantA = await createTenantRBAC(adapter, 'tenant-a');
113+
await rbacTenantA.can('user', 'products:find');
114+
```
115+
116+
## Web framework middleware
117+
118+
Guard routes using the built-in middleware factories for Express, NestJS, and Fastify. Each factory accepts optional callbacks to extract the role and params or to override the default denied response.
119+
120+
```ts
121+
import RBAC, { createExpressMiddleware } from '@rbac/rbac';
122+
123+
const rbac = RBAC({ enableLogger: false })({
124+
user: { can: ['products:find'] }
125+
});
126+
127+
const canFindProducts = createExpressMiddleware(rbac)('products:find');
128+
app.get('/products', canFindProducts, handler);
129+
```
130+
131+
Swap `createExpressMiddleware` for `createNestMiddleware` or `createFastifyMiddleware` to integrate with other frameworks.

docs/comparison.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Comparison
2+
3+
RBAC focuses on performance and flexibility while keeping the API small. This page highlights how it differs from other access-control approaches and how to measure those differences with the built-in benchmarks.
4+
5+
## Where this library stands out
6+
7+
- **Operation-oriented permissions:** Operations are plain strings that can also be matched with globs or regular expressions, enabling granular checks without designing a resource matrix.
8+
- **Hierarchical roles:** Roles can inherit from one another to avoid duplicating permission lists.
9+
- **Conditional guards:** Permissions can be gated by callbacks, async functions, or promises so that runtime context influences the decision.
10+
- **Runtime mutability:** `addRole` and `updateRoles` let you change the role map without restarting your app.
11+
- **Adapter support:** Optional MongoDB, MySQL, and PostgreSQL adapters make it straightforward to persist and share definitions across services.
12+
- **Multi-tenant aware:** A `tenantId` can be provided to adapters and the `createTenantRBAC` helper to isolate role definitions by tenant.
13+
14+
## Benchmarks
15+
16+
The repository includes a benchmark suite that compares RBAC against popular alternatives such as `accesscontrol`, `rbac`, `easy-rbac`, and `fast-rbac` across direct checks, inherited roles, and conditional permissions.
17+
18+
Run the suite with:
19+
20+
```bash
21+
yarn bench
22+
```
23+
24+
The script builds large permission sets, executes identical operations against each library, and prints timing results to the console.
25+
26+
## Choosing the right model
27+
28+
- Pick this library when you need fast checks on string-based operations, optional glob/regex matching, and minimal setup.
29+
- Use conditional guards when permissions depend on runtime data such as ownership or tenant membership.
30+
- Pair the adapters with the multi-tenant helper if your platform isolates permissions per customer or workspace.

docs/get-started.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Get Started
2+
3+
Follow this guide to install the library, define your first role map, and perform permission checks.
4+
5+
## 1) Install the package
6+
7+
```bash
8+
npm install @rbac/rbac
9+
# or
10+
yarn add @rbac/rbac
11+
```
12+
13+
The package ships with TypeScript types and works in JavaScript and TypeScript projects.
14+
15+
## 2) Create a role map
16+
17+
`RBAC` is a curried factory. First pass configuration, then the role definitions:
18+
19+
```ts
20+
import RBAC from '@rbac/rbac';
21+
22+
const rbac = RBAC({ enableLogger: false })({
23+
reader: { can: ['articles:find'] },
24+
editor: { can: ['articles:update'], inherits: ['reader'] },
25+
admin: { can: ['articles:*'] }
26+
});
27+
```
28+
29+
- `can` is an array of operation strings or objects with a `when` guard.
30+
- `inherits` lets a role reuse permissions from other roles.
31+
32+
## 3) Check permissions
33+
34+
Use the `can` function returned by the factory to verify operations. Operations accept strings, glob-style wildcards, or regular expressions:
35+
36+
```ts
37+
await rbac.can('reader', 'articles:find'); // true
38+
await rbac.can('editor', 'articles:find'); // true via inheritance
39+
await rbac.can('editor', 'articles:delete'); // false
40+
await rbac.can('admin', /articles:/); // true through regex
41+
```
42+
43+
## 4) Add conditions
44+
45+
Attach synchronous, asynchronous, Promise-based, or callback guards to permissions to enforce contextual rules:
46+
47+
```ts
48+
interface Params {
49+
ownerId: string;
50+
currentUserId: string;
51+
}
52+
53+
const rbac = RBAC()({
54+
author: {
55+
can: [{
56+
name: 'articles:update',
57+
when: ({ ownerId, currentUserId }) => ownerId === currentUserId
58+
}]
59+
}
60+
});
61+
62+
await rbac.can('author', 'articles:update', {
63+
ownerId: '123',
64+
currentUserId: '123'
65+
}); // true
66+
```
67+
68+
## 5) Keep iterating
69+
70+
Roles can evolve at runtime without rebuilding your application:
71+
72+
```ts
73+
rbac.addRole('support', { can: ['tickets:find'] });
74+
rbac.updateRoles({
75+
reader: { can: ['articles:find', 'articles:share'] }
76+
});
77+
```
78+
79+
Head to **Basic Usage** for more end-to-end examples that include adapters and web framework middleware.

docs/index.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# RBAC
2+
3+
Hierarchical Role-Based Access Control (RBAC) for Node.js and TypeScript. The library is curried for flexible setup, keeps dependencies to a minimum, and ships with first-class TypeScript types.
4+
5+
## Highlights
6+
7+
- **Operation-first design:** Define operations as strings, globs, or regular expressions, and check them with a simple `can` helper.
8+
- **Hierarchical roles:** Reuse permissions with inheritance and update definitions at runtime without rebuilding your app.
9+
- **Runtime conditions:** Attach synchronous, async, promise-based, or callback-based guards to any permission.
10+
- **Adapters and middleware:** Load or persist role definitions through MongoDB, MySQL, or PostgreSQL adapters and guard routes with Express, NestJS, or Fastify helpers.
11+
- **Multi-tenant ready:** Scope role definitions to tenants using the optional adapter utilities.
12+
13+
## Quick tour
14+
15+
```ts
16+
import RBAC from '@rbac/rbac';
17+
18+
const rbac = RBAC({ enableLogger: false })({
19+
user: { can: ['products:find'] },
20+
admin: { can: ['products:*'], inherits: ['user'] }
21+
});
22+
23+
await rbac.can('user', 'products:find'); // true
24+
await rbac.can('admin', 'products:delete'); // true via inheritance and wildcard
25+
```
26+
27+
Use the navigation to explore setup instructions, conceptual guides, feature comparisons, and practical usage recipes.

docs/installation.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Installation
2+
3+
## Library
4+
5+
Install the package from npm using your preferred package manager:
6+
7+
```bash
8+
npm install @rbac/rbac
9+
# or
10+
yarn add @rbac/rbac
11+
```
12+
13+
The published bundle ships with its TypeScript declaration files so IDEs and build pipelines pick up types automatically.
14+
15+
## Optional database drivers
16+
17+
Role adapters are lazy-loaded and expect their respective drivers to be available in your project. Add the dependency for the adapter you plan to use:
18+
19+
- MongoDB adapter → `npm install mongodb`
20+
- MySQL adapter → `npm install mysql2`
21+
- PostgreSQL adapter → `npm install pg`
22+
23+
Each adapter accepts custom column names and a tenant identifier; see **Basic Usage** for concrete examples.
24+
25+
## Documentation site
26+
27+
This repository includes a ready-to-use [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) configuration. To preview the docs locally:
28+
29+
```bash
30+
pip install mkdocs-material
31+
mkdocs serve
32+
```
33+
34+
The site will be available at `http://127.0.0.1:8000/` by default. To publish to GitHub Pages, run:
35+
36+
```bash
37+
mkdocs gh-deploy
38+
```
39+
40+
The command builds the static site and pushes it to the `gh-pages` branch, which GitHub Pages can serve directly.

docs/le-introduction.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Library Essentials (LE) Introduction
2+
3+
This library centers on an **operation-first** approach to authorization. Instead of tying permissions to resources, you describe the exact operations your application exposes and map roles to those operations.
4+
5+
## How RBAC is structured
6+
7+
- **Curried factory:** `RBAC(config)(roles)` returns an object with the `can`, `addRole`, and `updateRoles` helpers. Configuration accepts a custom logger and a switch to enable or disable logging.
8+
- **Operations:** Any string can be an operation. Use exact matches, glob-style patterns (e.g., `products:*`), or regular expressions to express permissions at the granularity you need.
9+
- **Roles:** Each role lists operations under `can` and can optionally `inherit` other roles, creating a hierarchy without repeating permissions.
10+
- **Conditions:** Every permission can define a `when` guard as a boolean, promise, async function, or callback. The guard receives the `params` object you pass to `can` and returns a truthy or falsy value.
11+
- **Caching:** Permission checks are cached per role to speed up repeated lookups, including glob and regex evaluations.
12+
13+
## What happens during a `can` check
14+
15+
1. Resolve the role and expand inherited permissions.
16+
2. Try direct matches (`operation` string) first.
17+
3. Evaluate glob or regex matches, caching results per role and pattern.
18+
4. If the permission has a `when` guard, normalize it to an async function and evaluate it with the provided params.
19+
5. Log the outcome when logging is enabled.
20+
21+
Understanding these steps makes it easier to choose between exact operations, patterns, or conditional checks for your own system.

mkdocs.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
site_name: RBAC
2+
site_description: Hierarchical, curried RBAC utilities for Node.js and TypeScript
3+
site_url: https://github.com/phellipeandrade/rbac
4+
repo_url: https://github.com/phellipeandrade/rbac
5+
repo_name: phellipeandrade/rbac
6+
theme:
7+
name: material
8+
language: en
9+
features:
10+
- navigation.tabs
11+
- navigation.sections
12+
- navigation.expand
13+
- toc.integrate
14+
- content.code.copy
15+
- content.tabs.link
16+
palette:
17+
- scheme: default
18+
primary: indigo
19+
accent: indigo
20+
markdown_extensions:
21+
- admonition
22+
- codehilite
23+
- def_list
24+
- footnotes
25+
- md_in_html
26+
- toc:
27+
permalink: true
28+
nav:
29+
- Home: index.md
30+
- Get Started: get-started.md
31+
- LE Introduction: le-introduction.md
32+
- Installation: installation.md
33+
- Basic Usage: basic-usage.md
34+
- Comparison: comparison.md
35+
- Migrating from v1 to v2: migrating-v1-to-v2.md

0 commit comments

Comments
 (0)