UNPKG

@taukala/xs-ctrl

Version:

A flexible and powerful access control library for JavaScript applications with dynamic validation support

106 lines (102 loc) 3.76 kB
/** * Creates an access rule builder for constructing authorization rules. * The builder follows a fluent interface pattern allowing method chaining * for creating complex access conditions with both static and dynamic validations. * * Rules can be: * 1. Static only (single/multiple conditions) * 2. Dynamic only (single/multiple conditions) * 3. Mixed (combination of static and dynamic conditions) * * @returns {Object} Rule builder object with methods for building access rules * * @example * // Static only - single condition * const adminRule = createAccessRule() * .addCondition('role', 'admin') * .build(); * * @example * // Static only - multiple conditions * const managerRule = createAccessRule() * .addCondition('role', 'manager') * .addCondition('department', 'IT', 'HR') * .build(); * * @example * // Dynamic only - single condition * const businessRule = createAccessRule() * .addDynamicCondition(({ claims, resources }) => { * const businessIds = claims.businessOwner || []; * return businessIds.includes(resources.business?.id); * }) * .build(); * * @example * // Mixed - static and dynamic conditions * const complexRule = createAccessRule() * .addCondition('role', 'business') * .addDynamicCondition(({ claims, resources }) => { * const businessIds = claims.businessOwner || []; * return businessIds.includes(resources.business?.id); * }) * .addDynamicCondition(({ claims, resources }) => { * return resources.business?.status === 'active'; * }) * .build(); */ export function createAccessRule() { const conditions = []; const dynamicValidators = []; return { /** * Adds a static condition to the access rule. Each condition consists of a key and one or more * acceptable values. When evaluating access, the user must have at least one matching * value for each condition key. * * @param {string} key - The condition key (e.g., 'role', 'department') * @param {...(string|number)} values - One or more acceptable values for the condition * @returns {Object} The builder instance for method chaining * @throws {Error} If key is empty or no values are provided */ addCondition(key, ...values) { if (!key || values.length === 0) { throw new Error('Condition key and values must be non-empty.'); } conditions.push([key, values]); return this; }, /** * Adds a dynamic condition to the access rule. Multiple dynamic conditions can be added * and all must pass for the rule to be valid. Dynamic conditions receive context including * claims and resources for complex validation logic. * * @param {Function} validator - Function that performs dynamic validation * @param {Object} validator.context - Context passed to the validator * @param {Object} validator.context.claims - User claims * @param {Object} validator.context.resources - Resource objects for validation * @param {Object} validator.context.session - User session data * @returns {Object} The builder instance for method chaining * @throws {Error} If validator is not a function */ addDynamicCondition(validator) { if (typeof validator !== 'function') { throw new Error('Dynamic condition must be a function'); } dynamicValidators.push(validator); return this; }, /** * Builds and returns the final rule object containing both static conditions * and dynamic validators if present. * * @returns {Object} Rule object containing conditions and dynamic validators */ build() { return { conditions, dynamicValidators }; } }; }