### Example of Access Control Setup Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/5-types.md This example demonstrates how to initialize the Access Control system with specific roles, resources, and actions using the ISetup interface. ```typescript ac.setup({ roles: { admins: ['admin', 'moderator'], _: ['user'] }, resources: { media: ['photo', 'video'], _: ['post'] }, actions: ['publish', 'approve'] }); ``` -------------------------------- ### Install and Develop Documentation Site Source: https://github.com/onury/accesscontrol/blob/master/site/README.md Commands to install dependencies and run the development server for the documentation site. ```bash npm --prefix site install npm --prefix site run dev # preview at localhost npm --prefix site run build # production build → site/dist ``` -------------------------------- ### Complete AccessControl Initialization and Usage Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/7-configuration.md A comprehensive example showing the initialization of AccessControl with grants and options, setup of roles, resources, and actions, granting permissions, and then checking a permission with specific context. ```typescript import { AccessControl, Charset } from 'accesscontrol'; const ac = new AccessControl( // grants (optional) {}, // options { engine: { pathPrefix: '$', allowRegex: false, charset: Charset.ASCII, safeErrors: true, errorCodePrefix: '' }, policy: { ownerField: 'userId', strict: { checks: true, roles: true, actions: false, resources: false }, actions: ['publish', 'archive'], resources: ['post', 'comment'] }, context: { now: new Date(), env: process.env.NODE_ENV } } ); // Setup vocabulary ac.setup({ roles: { admins: ['admin', 'moderator'], _: ['user'] }, resources: { content: ['post', 'comment'], _: [] }, actions: ['publish', 'archive', 'feature'] }); // Grant permissions ac.grant('user') .readAny('content/post', ['*', '!internalNotes']) .createOwn('content/post'); ac.grant('admin') .extend('user') .updateAny('content/post'); // Use it const perm = ac.can('user', { post: { userId: 7 }, user: { id: 7 } }).createOwn('content/post'); console.log(perm.granted); // true ``` -------------------------------- ### AccessControl Initialization with Configuration Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/whats-new.md Initialize AccessControl with specific engine configurations. This example shows how to disable regex, enable safe errors, and set the charset to ASCII during setup. ```javascript import { AccessControl, Charset, ErrorCode } from 'accesscontrol'; const ac = new AccessControl(grants, { engine: { allowRegex: false, safeErrors: true, charset: Charset.ASCII } }); ``` -------------------------------- ### Quick Start: Define Roles and Permissions Source: https://github.com/onury/accesscontrol/blob/master/README.md Define roles and their associated permissions using the AccessControl API. This example shows how to grant and deny permissions for 'user' and 'admin' roles on 'video' resources. ```js const ac = new AccessControl(); ac.grant('user') // define or modify a role .createOwn('video') // ≡ .createOwn('video', ['*']) .deleteOwn('video') .readAny('video') .grant('admin') // switch role, keep the chain .extend('user') // inherit user's grants .updateAny('video', ['title']) // explicit attributes .deleteAny('video'); ``` ```js ac.can('user').createOwn('video').granted; // true ac.can('admin').updateAny('video').attributes; // ['title'] ``` -------------------------------- ### setup Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/1-AccessControl.md Declares the vocabulary (role groups, resource categories, custom actions). This method is additive and chainable. ```APIDOC ## setup(vocabulary) ### Description Declares the vocabulary (role groups, resource categories, custom actions). Additive and chainable. ### Method ```typescript setup(vocab: ISetup): AccessControl ``` ### Parameters #### `vocab` object - `vocab.roles` (string[] | Record) - Required - Flat array of roles or `{ groupName: ['member1', 'member2'] }`. Reserved `_` key for ungrouped. - `vocab.resources` (string[] | Record) - Required - Flat array of resources or `{ categoryName: ['member1', ...] }`. Reserved `_` key for uncategorized. - `vocab.actions` (string[]) - Required - Custom action names (CRUD verbs always known). ### Returns `AccessControl` — for chaining. ### Throws `AccessControlError` — if locked or a name is invalid. ### Example ```typescript ac.setup({ roles: { admins: ['admin', 'moderator'], _: ['user'] }, resources: { media: ['photo', 'video'], _: ['post'] }, actions: ['publish', 'approve'] }); ``` ``` -------------------------------- ### Install AccessControl Source: https://github.com/onury/accesscontrol/blob/master/README.md Install the AccessControl library using npm. ```sh npm i accesscontrol ``` -------------------------------- ### Install AccessControl with Bun Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/getting-started.md Install the AccessControl library using Bun. AccessControl v3 is compatible with Bun and can be installed and imported directly. ```sh bun add accesscontrol ``` -------------------------------- ### Set Up Vocabulary for Roles and Resources Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/0-INDEX.md Use `setup` to declare roles and resources, enabling organizational clarity and strict-mode validation for your access control schema. ```typescript ac.setup({ roles: { admins: ['admin', 'moderator'], _: ['user'] }, resources: { media: ['photo', 'video'], _: ['post'] } }); ``` -------------------------------- ### Full Example: Granting, Checking, and Filtering Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/2-Permission.md Demonstrates setting up roles and permissions, checking access with context, and then filtering data based on the granted permission. ```typescript const ac = new AccessControl(); ac.grant('user') .readAny('post', ['*', '!internalNotes']) .createOwn('post') .updateOwn('post', ['title', 'body']); // Check and use permission const perm = ac.can('user', { post: { ownerId: 5 }, user: { id: 5 } }) .updateOwn('post'); if (perm.granted) { const postData = { title: 'New Title', body: 'Content', ownerId: 5, locked: true }; const filtered = perm.filter(postData); // { title: 'New Title', body: 'Content', ownerId: 5 } // 'locked' and other fields not in ['title', 'body'] stripped } // Audit ac.on('access', (event) => { console.log(`${event.roles[0]} tried to ${event.action} ${event.resource}: ${event.granted}`); }); ``` -------------------------------- ### getVocabulary Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/1-AccessControl.md Returns the declared vocabulary, which is the inverse of the setup() method. ```APIDOC ## getVocabulary() ### Description Returns the declared vocabulary (inverse of `setup()`). ### Method ```typescript getVocabulary(): ISetup ``` ### Returns `ISetup` — `{ roles, resources, actions }` with unqualified member names, ready to re-feed into `setup()`. ### Example ```typescript const vocab = ac.getVocabulary(); // { roles: { admins: ['admin'] }, resources: { media: ['photo'] }, actions: ['publish'] } ``` ``` -------------------------------- ### Use `once` for Initial Setup Validation Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/10-emitter.md Use the `once` method to register a listener that will execute only the first time an event occurs. This is useful for initial setup validation or one-time tasks. ```typescript ac.once('change', () => { logger.info('First policy change detected'); // Reset counters, alert, etc. }); ``` -------------------------------- ### Declare Vocabulary with Plain Arrays Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/concepts/groups.md When grouping is not needed, pass arrays directly to setup(). These are treated as the '_' bucket for ungrouped members. ```javascript ac.setup({ roles: ['user', 'admin'], resources: ['post', 'comment'] }); ``` -------------------------------- ### Install nestjs-accesscontrol Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/guides/nestjs.md Install the necessary packages for NestJS integration. Ensure you have `@nestjs/common`, `@nestjs/core`, `reflect-metadata`, and `rxjs` as peer dependencies. ```bash npm install nestjs-accesscontrol accesscontrol ``` -------------------------------- ### can(role, context?) Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/1-AccessControl.md Starts a permission query. Returns a Query instance for chainable checking. ```APIDOC ## can(role, context?) ### Description Starts a permission query. Returns a `Query` instance for chainable checking. ### Method Signature ```typescript can(role?: string | string[] | IQueryInfo, context?: UnknownObject): Query ``` ### Parameters #### Path Parameters - **role** (string | string[] | IQueryInfo) - Optional - Role(s) to check, or a fulfilled `IQueryInfo` object. If omitted, throws unless this is `tryCan()`. - **context** (UnknownObject) - Optional - Per-check context data (merged over ambient context), readable from conditions via `$.`. ### Returns `Query` — chainable with action methods (`.createAny()`, `.readOwn()`, etc.) to resolve a permission. ### Throws `AccessControlError` — in strict mode if the role is unknown. Use `tryCan()` to suppress errors. ### Example ```typescript const perm = ac.can('user').readOwn('post'); console.log(perm.granted); // boolean const perm2 = ac.can('admin', { post: { status: 'draft' } }).updateAny('post'); ``` ``` -------------------------------- ### Basic AccessControl Setup and Permissions Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/9-usage-examples.md Demonstrates how to initialize AccessControl, define roles with specific permissions, and check if a role has the granted permission. Ensure you import the AccessControl class. ```typescript import { AccessControl } from 'accesscontrol'; const ac = new AccessControl(); // Define roles and permissions ac.grant('user') .readAny('post') .createOwn('post') .updateOwn('post') .deleteOwn('post'); ac.grant('moderator') .extend('user') .deleteAny('post') .deleteAny('comment'); ac.grant('admin') .extend('moderator') .updateAny('post') .readAny('user'); // Check permissions const userCanRead = ac.can('user').readAny('post').granted; // true const userCanDelete = ac.can('user').deleteAny('post').granted; // false const adminCanDelete = ac.can('admin').deleteAny('post').granted; // true ``` -------------------------------- ### Declare Role and Resource Vocabularies Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/concepts/groups.md Use setup() to declare roles and resources, optionally with custom actions for strict mode. This function is additive and can be called multiple times. Members are qualified as 'group/member' names. ```javascript ac.setup({ roles: { admins: ['admin', 'moderator'], _: ['user'] }, resources: { media: ['photo', 'video'], _: ['profile'] }, actions: ['publish'] // declare custom actions for strict mode }); ``` -------------------------------- ### Role Introspection Methods Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/concepts/roles.md Provides examples of methods for checking role existence, retrieving all defined roles, and getting the inherited roles of a specific role. ```javascript ac.hasRole('admin'); // boolean (single or array) ac.getRoles(); // ['user', 'admin'] ac.getInheritedRolesOf('admin'); // ['user'] ac.removeRoles('admin'); // also strips it from other roles' $extend ``` -------------------------------- ### Groups and Categories for Bulk Grants Source: https://github.com/onury/accesscontrol/blob/master/README.md Organize roles and resources into groups and categories using `setup()`. Grants to groups/categories are inherited dynamically by members, preventing naming collisions. ```javascript ac.setup({ roles: { admins: ['admin', 'moderator'], _: ['user'] }, resources: { media: ['photo', 'video'], _: ['profile'] }, }); ac.grant('admins').readAny('media'); // group × category ac.can('admins/admin').readAny('media/photo').granted; // true ac.group('admins').getRoles(); // ['admins/admin', 'admins/moderator'] ac.category('media').getResources(); // ['media/photo', 'media/video'] ``` -------------------------------- ### Initiating a Permission Query Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/1-AccessControl.md Use `can()` to start a permission query, returning a `Query` instance for chainable checking. It can accept roles or an `IQueryInfo` object and optional context. ```typescript can(role?: string | string[] | IQueryInfo, context?: UnknownObject): Query ``` ```typescript const perm = ac.can('user').readOwn('post'); console.log(perm.granted); // boolean const perm2 = ac.can('admin', { post: { status: 'draft' } }).updateAny('post'); ``` -------------------------------- ### Define Role and Resource Setup Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/5-types.md Use ISetup to declare roles, resources, and actions. This interface allows for both simple arrays and mapped objects for defining these elements. ```typescript interface ISetup { roles?: string[] | Record; resources?: string[] | Record; actions?: string[]; } ``` -------------------------------- ### Organize Roles and Resources with Groups and Categories Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/whats-new.md Define role groups and resource categories using `setup()` for bounded bulk grants. This allows granting access to a group or category once, which then dynamically applies to all its members, providing a safer alternative to wildcards. ```javascript ac.setup({ roles: { admins: ['admin', 'moderator'], _: ['user'] }, resources: { media: ['photo', 'video'], _: ['profile'] }, }); ac.grant('admins').readAny('media'); // group × category ac.can('admins/admin').readAny('media/photo').granted; // true (inherited + categorized) ``` -------------------------------- ### Configuring AccessControl with Engine Options Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/7-configuration.md Example of initializing AccessControl with specific engine configurations, including pathPrefix, allowRegex, charset, safeErrors, and errorCodePrefix. ```typescript const ac = new AccessControl({}, { engine: { pathPrefix: '@', allowRegex: true, charset: Charset.UNICODE, safeErrors: false, errorCodePrefix: 'AC_' } }); ``` -------------------------------- ### Inherit Permissions Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/4-Access.md Example showing how a 'moderator' role can extend the 'user' role to inherit its permissions, then add its own specific grants. ```typescript ac.grant('moderator').extend('user').readAny('post'); ``` -------------------------------- ### Vocabulary Declaration with Strict Mode Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/7-configuration.md Pair strict actions and resources with setup() for maximum safety, ensuring any typo throws an error. ```typescript const ac = new AccessControl({}, { policy: { strict: { actions: true, resources: true } } }); ac.setup({ actions: ['publish', 'approve'], resources: ['post', 'comment', 'user'] }); // Now any typo throws ac.can('user').do('publsh', 'post'); // throws UNKNOWN_ACTION ``` -------------------------------- ### Handling INVALID_SETUP Error Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/6-errors.md Catch and handle errors when the vocabulary object passed to setup() is malformed. Ensure roles and resources are correctly structured as arrays or object maps. ```typescript try { ac.setup({ roles: null }); } catch (err) { if (err.code === 'INVALID_SETUP') { // Ensure roles/resources are arrays or object maps } } ``` -------------------------------- ### Possession Cascade Example Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/concepts/actions.md Demonstrates how an 'any' grant implicitly satisfies an 'own' check. If a role can perform an action on any resource, they can also perform it on their own resources. ```javascript ac.grant('admin').updateAny('order', ['*']); ac.can('admin').updateOwn('order').granted; // true (any ⊇ own) ``` -------------------------------- ### Role Inheritance Example Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/concepts/roles.md Demonstrates how a role inherits grants from another role using `extend()`. The `moderator` role inherits all grants from the `user` role. ```javascript ac.grant('user').readAny('post', ['*']); ac.grant('moderator').extend('user'); ac.can('moderator').readAny('post').granted; // true (inherited) ``` -------------------------------- ### Import AccessControl in Deno Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/getting-started.md Import the AccessControl class in a Deno environment using an npm specifier. No explicit installation step is required. ```js import { AccessControl } from 'npm:accesscontrol'; ``` -------------------------------- ### Layered Gates Example Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/concepts/gates.md Demonstrates how multiple gates at different scopes combine to restrict access. Access is granted only if all applicable gates pass, in addition to a matching role grant. ```javascript const ac = new AccessControl(grants, { context: { env: process.env.NODE_ENV } }); ac.require('$.env == "prod"'); // 1) prod only ac.category('billing').require('$.ip cidr 10.0.0.0/8'); // 2) + from the VPN ac.resource('billing/invoice').require('$.mfa == true'); // 3) + MFA // passes only if prod AND in-VPN AND mfa — on top of a matching grant ac.can('accountant', { ip, mfa: true }) .readAny('billing/invoice').granted; ``` -------------------------------- ### Log Access Events Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/10-emitter.md An example of logging access events with more detail, including roles, action, resource, and the reason for denial if applicable. This is useful for audit trails. ```typescript ac.on('access', (event) => { const line = event.granted ? `✓ ${event.roles[0]} ${event.action} ${event.resource}` : `✗ ${event.roles[0]} ${event.action} ${event.resource} [${event.reason}]`; logger.info(line); }); ``` -------------------------------- ### Version Access Control Vocabulary Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/11-patterns-best-practices.md Manage vocabulary evolution by defining versions and using setup to migrate to newer configurations. This allows for controlled changes to roles, resources, and actions over time. ```typescript const vocabularyV1 = { roles: { admins: ['admin'], _: ['user'] }, resources: { _: ['post'] }, actions: ['publish'] }; // Later, add resource category const vocabularyV2 = { roles: vocabularyV1.roles, resources: { media: ['photo'], _: ['post'] }, actions: vocabularyV1.actions }; // Supports migration ac.setup(vocabularyV2); ``` -------------------------------- ### Scoping Access with Glob Notation Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/concepts/resources.md Scopes read access to specific attributes of an 'account' resource using glob notation. This example allows all attributes except 'password', and includes nested 'profile' attributes. ```javascript ac.grant('user').readOwn('account', [ '*', // all attributes… '!password', // …except password 'profile.*' // (nested paths are supported) ]); ``` -------------------------------- ### Define Grants with AccessControl Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/guides/nestjs.md Define user roles and their permissions using the fluent AccessControl API. This example shows how to grant read, create, update, and delete permissions for 'user' and 'admin' roles on 'article' resources. ```typescript import { AccessControl } from 'accesscontrol'; export const ac = new AccessControl(); ac.grant('user') .readAny('article', ['*', '!authorEmail']) // can't see authorEmail .createOwn('article') .updateOwn('article') .deleteOwn('article'); ac.grant('admin').extend('user').updateAny('article').deleteAny('article'); ac.lock(); ``` -------------------------------- ### Enable Strict Mode for Actions and Resources in Development Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/best-practices.md Enable strict mode for actions and resources during development to catch typos in your authorization vocabulary. Use setup() to declare custom vocabulary, ensuring that undeclared actions/resources throw errors. ```javascript const ac = new AccessControl(grants, { policy: { strict: { actions: true, resources: true } } }); ac.setup({ actions: ['publish', 'approve'] }); // declare custom vocabulary ``` -------------------------------- ### Applying Authorization to GET Route Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/guides/express.md Example of applying the `authorize` middleware to a GET route for fetching an article. It uses 'read:any' permission for the 'article' resource and then filters the fetched article data using `req.permission.filter()` before sending the response. ```javascript router.get( '/articles/:id', authorize('read:any', 'article'), async (req, res) => { const article = await db.findArticle(req.params.id); res.json(req.permission.filter(article)); } ); ``` -------------------------------- ### Get Access Control Vocabulary Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/1-AccessControl.md Retrieves the currently declared vocabulary, including roles, resources, and actions. The returned object is a deep copy, suitable for re-feeding into the setup() method. ```typescript const vocab = ac.getVocabulary(); // { roles: { admins: ['admin'] }, resources: { media: ['photo'] }, actions: ['publish'] } ``` -------------------------------- ### Role Inheritance Configuration v2 vs v3 Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/migration.md Demonstrates the difference in configuring role inheritance between v2 and v3. ```json { role, $extend: [...] } ``` -------------------------------- ### Grant Configuration Syntax v2 vs v3 Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/migration.md Illustrates the change in grant configuration syntax from v2 to v3, particularly for read permissions. ```json { 'read:any': ['*'] } ``` ```json { read: [{ possession: 'any', attributes: ['*'] }] } ``` -------------------------------- ### Listener Isolation Example Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/10-emitter.md Demonstrates that if one listener throws an error, other listeners for the same event will still execute. Errors are logged but do not halt the process. ```typescript ac.on('access', () => { throw new Error('Listener 1 throws'); }); ac.on('access', () => { console.log('Listener 2 runs anyway'); // RUNS }); ac.can('user').readAny('post'); // Logs: "Listener 2 runs anyway" ``` -------------------------------- ### Declare Access Control Vocabulary Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/11-patterns-best-practices.md Initialize AccessControl with strict policy mode to catch typos in roles, resources, and actions immediately during setup. ```typescript const ac = new AccessControl({}, { policy: { strict: true } }); ac.setup({ roles: { admins: ['admin', 'moderator'], _: ['user'] }, resources: { media: ['photo', 'video'], _: ['post'] }, actions: ['publish', 'archive'] }); // Now typos throw immediately ac.can('user').do('publis', 'post'); // throws UNKNOWN_ACTION ``` -------------------------------- ### Define Query Information (IQueryInfo) Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/5-types.md Use IQueryInfo to structure queries about access permissions. It includes role, resource, action, possession, and context. ```typescript interface IQueryInfo { role?: string | string[]; resource?: string; action?: Action | string; possession?: Possession; context?: UnknownObject; } ``` -------------------------------- ### Initializing AccessControl with Grants Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/concepts/serialization.md Demonstrates how to instantiate the AccessControl class using either the flat list or object form of grants. ```javascript const ac = new AccessControl(rows); // flat list const ac2 = new AccessControl(object); // object form — equivalent ``` -------------------------------- ### Lock Grants Model Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/4-Access.md Freezes the underlying grants model, preventing any further mutations. This is useful for ensuring the access control configuration is immutable after setup. ```typescript lock(): AccessControl ``` -------------------------------- ### Get Require() Gates Structure Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/concepts/serialization.md Retrieve the defined require() gates, keyed by scope (global, categories, resources), with conditions in canonical form. ```json { "global": [["$.env", "==", "prod"]], "categories": { "billing": [["$.ip", "cidr", "10.0.0.0/8"]] }, "resources": { "billing/invoice": [["$.mfa", "==", true]] } } ``` -------------------------------- ### Async Access Granted Possession Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/2-Permission.md The `possessionAsync` property provides an asynchronous way to get the effective possession, returning a Promise<'own' | 'any'>. ```typescript const possession = await perm.possessionAsync; ``` -------------------------------- ### Fail-loud startup validation with can Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/best-practices.md Use `can()` for boot/config validation and tests. This ensures that typos or misconfigurations in roles or resources will throw errors loudly, preventing them from being silently ignored. ```js ac.can('admin').readAny('report'); // throws if 'admin'/'report' are typos ``` -------------------------------- ### Groups, Categories, and Bulk Grants Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/9-usage-examples.md Organize roles into groups and resources into categories using '.setup()'. Grant permissions in bulk to groups or categories. Use '.category()' to enforce requirements for entire resource categories. ```typescript const ac = new AccessControl(); ac.setup({ roles: { admin_team: ['superadmin', 'moderator'], _: ['user'] // ungrouped }, resources: { media: ['photo', 'video'], content: ['post', 'comment'], _: ['profile'] // uncategorized } }); // Bulk grant: all admins can manage all media ac.grant('admin_team').readAny('media').updateAny('media').deleteAny('media'); // Expands to: // - admin_team/superadmin on media/photo and media/video // - admin_team/moderator on media/photo and media/video const superCanDeletePhoto = ac.can('admin_team/superadmin').deleteAny('media/photo').granted; // true const modCanDeleteVideo = ac.can('admin_team/moderator').deleteAny('media/video').granted; // true // Category-level gates ac.category('media').require('$.mfaEnabled == true'); const perm = ac.can('user', { user: { mfaEnabled: false } }).readAny('media/photo'); console.log(perm.granted); // false (MFA required for media category) ``` -------------------------------- ### Lock Access Control Configuration Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/4-Access.md Example of locking the access control configuration after defining grants. Attempting to modify grants after locking will result in an error. ```typescript ac.grant('user').readAny('public').lock(); // ac.grant('admin').readAny('post'); // throws now ``` -------------------------------- ### Conditionally Register Access Event Listeners Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/10-emitter.md Register listeners only when they are needed, for example, based on environment variables like LOG_LEVEL. This prevents unnecessary overhead. ```typescript if (process.env.LOG_LEVEL === 'debug') { ac.on('access', (event) => { console.log('Access:', event); }); } ``` -------------------------------- ### Distribute Policy Across Microservices Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/guides/recipes.md Maintain a single source of truth for the policy model using `snapshot()` and distribute it. Consumers load the snapshot on boot and re-check permissions locally. ```js // authority service — persist on change await store.put('policy', JSON.stringify(ac.snapshot())); // each consumer service — load on boot (and on a change signal) const ac = new AccessControl().restore(await store.get('policy')); ``` -------------------------------- ### Database-Backed Access Control Initialization Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/11-patterns-best-practices.md Initialize Access Control by loading grants from a database snapshot on startup. Includes logic to bootstrap with defaults if no snapshot is found. Automatically saves changes to the database on 'change' events. ```typescript // On startup async function initializeAccessControl() { const ac = new AccessControl(); // Load from database const savedPolicy = await db.query( 'SELECT snapshot FROM policies WHERE id = 1' ); if (savedPolicy?.snapshot) { ac.restore(JSON.parse(savedPolicy.snapshot)); } else { // Bootstrap with defaults setupDefaultPolicy(ac); } // Auto-save on changes ac.on('change', async (event) => { await db.query( 'UPDATE policies SET snapshot = ? WHERE id = 1', [JSON.stringify(ac.snapshot())] ); }); return ac; } const ac = await initializeAccessControl(); ``` -------------------------------- ### Auditing Access Decisions Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/guides/express.md Shows how to set up an event listener to log all access decisions, including denials and their reasons. This is useful for auditing and debugging authorization logic. ```javascript ac.on('access', (e) => logger.info('authz', e)); ``` -------------------------------- ### Adding Error Code Prefix Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/6-errors.md Customize error codes by providing a prefix string to the engine configuration. This example shows how to prepend 'AC_' to all error codes. ```typescript const ac = new AccessControl({}, { engine: { errorCodePrefix: 'AC_' } }); try { ac.grant('user'); } catch (err) { console.log(err.code); // 'AC_INVALID_NAME' } ``` -------------------------------- ### Obtain Query Instance Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/3-Query.md Demonstrates various ways to obtain a Query instance using ac.can() and ac.tryCan(). ```typescript // Via can() const query = ac.can('user'); const query2 = ac.can(['user', 'admin']); const query3 = ac.can('user', { post: { ownerId: 7 } }); // Via tryCan() (fail-closed) const query = ac.tryCan('user'); // Via an IQueryInfo object const query = ac.can({ role: 'user', resource: 'post', action: 'read:any' }); ``` -------------------------------- ### AccessControl Main Methods Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/0-INDEX.md Core methods for initializing and configuring the AccessControl instance, managing grants, and performing checks. ```APIDOC ## AccessControl Methods ### `grant()` / `deny()` **Description**: Initiates the building process for access grants or denials. ### `can()` / `tryCan()` **Description**: Starts a permission check for a given subject and resource. ### `check()` **Description**: Performs a one-shot permission check without building a query. ### `getGrants()` / `getGrantsList()` **Description**: Serializes the current grants into a JSON-compatible format. ### `setGrants()` **Description**: Replaces all existing grants with a new set. ### `setup()` **Description**: Declares the vocabulary (roles, resources, actions) for the access control model. ### `require()` **Description**: Adds a mandatory gate that must be satisfied for access. ### `snapshot()` / `restore()` **Description**: Provides full serialization and deserialization capabilities for the access control model. ### `extendRole()` / `removeRoles()` **Description**: Manages role inheritance, allowing roles to inherit permissions from other roles. ### `group()` / `category()` / `resource()` **Description**: Introspects and configures the access control model's structure. ### `lock()` **Description**: Freezes the access control model, preventing further modifications. ### `defineCondition()` **Description**: Registers custom functions that can be used as conditions in grants. ### `on()` / `once()` / `off()` **Description**: Manages event listeners for access control events. ``` -------------------------------- ### Define Roles and Permissions Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/getting-started.md Create roles and define their permissions using chained grant() and deny() methods. Roles can inherit permissions from others using extend(). ```js const ac = new AccessControl(); ac.grant('user') .createOwn('video') .deleteOwn('video') .readAny('video') .grant('admin') .extend('user') .updateAny('video', ['title']) // only the `title` attribute .deleteAny('video'); ``` -------------------------------- ### Get All Require Gates Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/1-AccessControl.md Retrieves all declared `require()` gates, organized by scope (global, categories, resources). Returns a fully detached deep copy of the requirements. ```typescript const gates = ac.getRequirements(); ``` -------------------------------- ### Configure AccessControl with Engine, Policy, and Context Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/best-practices.md Instantiate AccessControl with custom configurations for engine, policy, and context. The engine handles library mechanics, policy defines your authorization model, and context provides ambient data for conditions. ```javascript const ac = new AccessControl(grants, { engine: { allowRegex: false, charset: Charset.ASCII, safeErrors: true }, policy: { ownerField: 'ownerId', strict: { roles: true } }, context: { env: process.env.NODE_ENV } }); ``` -------------------------------- ### Deny-Overrides Example Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/concepts/roles.md Shows how an explicit `deny` rule can carve out specific attributes from an inherited grant. The `moderator` role inherits `readAny('post', ['*'])` but then has `['secret']` explicitly denied. ```javascript ac.grant('user').readAny('post', ['*']); ac.grant('moderator').extend('user'); ac.deny('moderator').readAny('post', ['secret']); // carve a field back ac.can('moderator').readAny('post').attributes; // ['*', '!secret'] ``` -------------------------------- ### check(query) Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/1-AccessControl.md One-shot permission check. Alias for can() with an IQueryInfo object. ```APIDOC ## check(query) ### Description One-shot permission check. Alias for `can()` with an `IQueryInfo` object. ### Method Signature ```typescript check(query: IQueryInfo): Permission ``` ### Parameters #### Path Parameters - **query** (IQueryInfo) - Required - Fulfilled query object: `{ role, resource, action, possession?, context? }`. ### Returns `Permission` — the resolved access. ### Throws `AccessControlError` — if the query is invalid or, in strict mode, unknown vocabularies. ### Example ```typescript const perm = ac.check({ role: 'user', resource: 'post', action: 'read:any' }); ``` ``` -------------------------------- ### Show/Hide UI by Permission Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/guides/recipes.md Compute a boolean or allowed attributes to control rendering. Use `tryCan()` for safe checks that never throw, returning `granted: false` on invalid queries. ```js // any framework / template if (ac.tryCan(role).readAny('dashboard:revenue').granted) { render(revenueWidget); } ``` ```js const caps = { canEditPost: ac.tryCan(role).updateAny('post').granted, revenue: ac.tryCan(role).readAny('dashboard:revenue').granted }; res.json(caps); ``` -------------------------------- ### Importing AccessControl v2 vs v3 Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/migration.md Shows the difference in how to import the AccessControl library between v2 and v3. ```javascript require('accesscontrol') ``` ```javascript import { AccessControl } from 'accesscontrol' ``` -------------------------------- ### Persist and Restore the Entire Model Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/concepts/serialization.md Use `snapshot()` to bundle the grants, gates, and vocabulary into a single JSON object for persistence, and `restore()` to rebuild the model from this object. This is the recommended approach for most use cases. ```javascript await db.savePolicy(JSON.stringify(ac.snapshot())); // persist everything const ac = new AccessControl().restore(await db.loadPolicy()); // restore everything ``` -------------------------------- ### Role Creation and Inheritance Source: https://github.com/onury/accesscontrol/blob/master/README.md Create roles using `.grant()` and `.deny()`. Roles can inherit grants from other roles using `.extend()`. Explicit denies always override grants. ```javascript ac.grant('user').readAny('post', ['*']); ac.grant('moderator').extend('user'); ac.deny('moderator').readAny('post', ['secret']); // carve a field back ac.can('moderator').readAny('post').attributes; // ['*', '!secret'] ``` -------------------------------- ### Rate Limiting via Custom Condition Functions Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/11-patterns-best-practices.md Implement rate limiting for operations using custom condition functions defined with `ac.defineCondition()`. This example uses Redis to track request counts. ```typescript ac.defineCondition('rateLimit', async (ctx, args) => { const requestCount = await redis.incr(`ratelimit:${ctx.user.id}`); if (requestCount === 1) { await redis.expire(`ratelimit:${ctx.user.id}`, args.windowSeconds || 60); } return requestCount <= (args.maxRequests || 100); }); ac.grant('user').where({ fn: 'rateLimit', args: { maxRequests: 100, windowSeconds: 60 } }).do('query', 'api'); ``` -------------------------------- ### Save and Restore Access Control Policies Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/9-usage-examples.md Demonstrates how to save an access control policy snapshot to a database and restore it on application boot. Ensure your database has `savePolicy` and `loadPolicy` methods implemented. ```typescript const ac = new AccessControl(); ac.grant('user').readAny('post'); ac.grant('admin').extend('user').deleteAny('post'); const snapshot = ac.snapshot(); await db.savePolicy(JSON.stringify(snapshot)); // On boot, restore const saved = await db.loadPolicy(); const ac2 = new AccessControl().restore(JSON.parse(saved)); console.log(ac2.can('admin').deleteAny('post').granted); // true ``` -------------------------------- ### Strict Mode for Typo Catching Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/9-usage-examples.md Enable strict mode in AccessControl to immediately catch typos in roles, actions, or resources during setup or permission checks. This helps in identifying configuration errors early. ```typescript const ac = new AccessControl({}, { policy: { strict: { roles: true, // throw on unknown role actions: true, // throw on unknown action resources: true // throw on unknown resource } } }); ac.setup({ roles: ['user', 'admin'], actions: ['create', 'read', 'update', 'delete', 'publish'], resources: ['post', 'comment', 'user'] }); try { ac.can('user').do('publis', 'post'); // typo: "publis" instead of "publish" } catch (err) { console.log(err.code); // UNKNOWN_ACTION // Catches the typo immediately } ``` -------------------------------- ### Checking and Defining Resources Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/concepts/resources.md Checks if a resource exists, defines a new resource by granting access, and retrieves all defined resources. Resources are defined implicitly when access is granted. ```javascript ac.hasResource('banana'); // false ac.grant('monkey').createOwn('banana'); // defined now ac.hasResource('banana'); // true ac.getResources(); // ['account', 'credentials', 'banana'] ``` -------------------------------- ### Persist and Restore the Entire Model Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/concepts/serialization.md Use `snapshot()` to get the entire model as a JSON object and `restore()` to load it back into an AccessControl instance. This method resets the instance before applying the restored policy. ```javascript // persist — one JSON blob with everything const snap = ac.snapshot(); await db.savePolicy(JSON.stringify(snap)); // rebuild on boot — one call const ac = new AccessControl().restore(await db.loadPolicy()); ``` -------------------------------- ### Conditional grants and mandatory gates Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/best-practices.md Demonstrates using `.where()` for conditional grants based on resource attributes (e.g., order value) and `.require()` for mandatory gates that must pass for any access check (e.g., environment or network restrictions). ```js ac.grant('manager') .where('$.order.value <= 100000') // managers, but only small orders .updateAny('order', ['*']); ac.require('$.env == "prod"'); // everyone, every check, prod only ac.category('billing') .require('$.ip cidr 10.0.0.0/8'); // billing/* only from the VPN ``` -------------------------------- ### Unit Test Access Control Conditions Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/11-patterns-best-practices.md Test conditional access control rules by verifying permissions based on specific data states. This example demonstrates how to check if a user can read a post only when the post is published. ```typescript describe('Conditions', () => { let ac; beforeEach(() => { ac = new AccessControl(); ac.grant('user').where('$.post.published == true').readAny('post'); }); it('grants access when condition is true', () => { const perm = ac.can('user', { post: { published: true } }).readAny('post'); expect(perm.granted).toBe(true); }); it('denies access when condition is false', () => { const perm = ac.can('user', { post: { published: false } }).readAny('post'); expect(perm.granted).toBe(false); }); }); ``` -------------------------------- ### createAny Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/3-Query.md Checks `create:any` permission for a given resource and optional attributes. This helper implicitly sets possession. ```APIDOC ## createAny(resource?, attributes?) ### Description Checks `create:any` permission. ### Signature ```typescript createAny(resource?: string, attributes?: string | string[]): Permission ``` ### Example ```typescript ac.can('user').createAny('post'); ``` ``` -------------------------------- ### Centralized Access Control Factory Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/11-patterns-best-practices.md Create a factory function to centralize Access Control initialization, role/resource setup, and grant definitions. This promotes reusability and maintainability. Ensure to optionally persist and restore the AC instance. ```typescript export function createAccessControl() { const ac = new AccessControl({}, { policy: { ownerField: 'ownerId', strict: { roles: true, actions: false, resources: false } } }); ac.setup({ roles: { admins: ['admin', 'moderator'], _: ['user'] }, resources: { content: ['post', 'comment'], _: ['profile'] } }); ac.grant('user') .readAny('content') .createOwn('content') .updateOwn('content') .deleteOwn('content'); ac.grant('admins') .readAny('content') .updateAny('content') .deleteAny('content'); return ac; } // In app initialization const ac = createAccessControl(); // Optionally persist and restore on boot await restoreFromDatabase(ac); export { ac }; ``` -------------------------------- ### Define Vocabulary Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/0-INDEX.md Set up the roles, resources, and actions vocabulary for the AccessControl instance. ```javascript ac.setup({ roles, resources, actions }) ``` -------------------------------- ### tryCan(role, context?) Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/1-AccessControl.md Like can() but fails closed: returns a denied Permission instead of throwing on errors. Never throws. ```APIDOC ## tryCan(role, context?) ### Description Like `can()` but fails closed: returns a denied `Permission` instead of throwing on errors. Never throws. ### Method Signature ```typescript tryCan(role?: string | string[] | IQueryInfo, context?: UnknownObject): Query ``` ### Parameters #### Path Parameters - **role** (string | string[] | IQueryInfo) - Optional - Role(s) to check, or an `IQueryInfo`. If omitted, returns denied. - **context** (UnknownObject) - Optional - Per-check context data. ### Returns `Query` — safe mode: errors resolve to `granted: false`, `attributes: []`. ### Example ```typescript const perm = ac.tryCan('unknownRole').readAny('post'); console.log(perm.granted); // false (no throw) ``` ``` -------------------------------- ### Applying Authorization to PATCH Route with Record Loading Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/guides/express.md Example of applying the `authorize` middleware to a PATCH route for updating an order. It uses 'update:own' permission for the 'order' resource and includes a `loadRecord` function to fetch the specific order for ownership checks. The request body is filtered using `req.permission.filter()` before updating. ```javascript router.patch( '/orders/:id', authorize('update:own', 'order', (req) => db.getOrder(req.params.id)), async (req, res) => { const data = req.permission.filter(req.body); // strip disallowed fields res.json(await db.updateOrder(req.params.id, data)); } ); ``` -------------------------------- ### Implement Deny-Overrides with .deny() Source: https://github.com/onury/accesscontrol/blob/master/site/src/content/docs/whats-new.md Use the `.deny()` method to explicitly revoke access. Deny rules always take precedence over grants, ensuring that specific restrictions are always enforced, even with inherited grants. ```javascript ac.grant('admin').readAny('post', ['*']); ac.deny('admin').readAny('post', ['secret']); ac.can('admin').readAny('post').attributes; // ['*', '!secret'] ``` -------------------------------- ### TypeScript: Create Any Permission Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/3-Query.md Checks `create:any` permission. Use this when a user needs to create resources of a specific type, regardless of ownership. ```typescript ac.can('user').createAny('post'); ``` -------------------------------- ### Import AccessControl Source: https://github.com/onury/accesscontrol/blob/master/README.md Import the AccessControl class from the library. ```js import { AccessControl } from 'accesscontrol'; ``` -------------------------------- ### Tracing Context at Check Time Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/8-conditions.md Illustrates how to perform a permission check with specific context and log the result. This helps in verifying that conditions are evaluated correctly based on the provided context. ```typescript const perm = ac.can('user', { post: { status: 'draft' }, user: { id: 7 } }).readAny('post'); console.log(perm.granted, perm.reason); ``` -------------------------------- ### do Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/4-Access.md An alias for the `action()` method, providing a shorter syntax for granting custom actions on a resource. ```APIDOC ## do(action, resource?, attributes?) ### Description Alias for `action()`. Short form. ### Method Signature ```typescript do(action: string | Action, resource?: string, attributes?: string | string[]): Access ``` ### Parameters * `action` (string | Action) - Action name: CRUD verbs or custom (e.g., `'publish'`, `'approve'`). * `resource` (string, optional) - Resource name. * `attributes` (string | string[], optional) - Allowed attributes. ### Returns `Access` — self for chaining. ### Example ```typescript ac.grant('author').do('publish', 'post', ['*', '!status']); ac.grant('admin').do('publish', 'post'); ``` ``` -------------------------------- ### ReDoS Protection: Trusted vs. Untrusted Regex Sources Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/8-conditions.md Demonstrates how to safely enable regex processing for trusted grant sources and highlights the risks of using untrusted sources. Always ensure regex patterns are validated or come from a secure origin. ```typescript const ac = new AccessControl(dbGrants, { engine: { allowRegex: true } }); ``` ```typescript app.post('/grants', (req, res) => { ac.grant(req.body.role).where(req.body.condition); // could inject regex }); ``` -------------------------------- ### Obtain Access Instance Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/4-Access.md Demonstrates various ways to obtain an Access instance from an AccessControl object. This includes granting or denying permissions for single or multiple roles, or using a detailed IAccessInfo object. ```typescript // Via grant() const access = ac.grant('user'); const access2 = ac.grant(['user', 'admin']); // Via deny() const access = ac.deny('moderator'); // With IAccessInfo object const access = ac.grant({ role: 'user', resource: 'post', action: 'read', attributes: ['*', '!password'], possession: 'any' }); ``` -------------------------------- ### Fluent Resource Switching Source: https://github.com/onury/accesscontrol/blob/master/_autodocs/4-Access.md Demonstrates fluent resource switching, allowing an 'admin' role to define multiple permissions (read, update, delete) across different resources ('post', 'user') in a chained manner. ```typescript ac.grant('admin') .resource('post').readAny().updateAny().deleteAny() .resource('user').readAny().updateAny().deleteAny(); ```