node_modules ignore

This commit is contained in:
oier committed 2025-05-08 23:43:47 +02:00
1 parent e19d52f172
commit 4574544c9f
65041 files changed
+10593536

No files matched your search

+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017-2018 Sergii Stotskyi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+149
View File
@@ -0,0 +1,149 @@
# [CASL Ability](https://stalniy.github.io/casl/) [![@casl/ability NPM version](https://badge.fury.io/js/%40casl%2Fability.svg)](https://badge.fury.io/js/%40casl%2Fability) [![](https://img.shields.io/npm/dm/%40casl%2Fability.svg)](https://www.npmjs.com/package/%40casl%2Fability) [![CASL Documentation](https://img.shields.io/badge/documentation-available-brightgreen.svg)](https://stalniy.github.io/casl/) [![CASL Join the chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/stalniy-casl/casl)
This package is the core of CASL. It includes logic responsible for [checking and defining][intro] permissions.
## Installation
```sh
npm install @casl/ability
# or
pnpm install @casl/ability
# or
yarn add @casl/ability
```
## Documentation
This README file contains only basic information about the package. If you need an in depth introduction, please visit [CASL's documentation](https://casl.js.org/).
## Getting Started
**Note**: the best way to get started is to read the [Guide][intro] in the official documentation. In this README file, you will find just basic information.
**Note**: all the examples below are written in ES6 using ES modules but CASL also has a sophisticated support for TypeScript, read [CASL TypeScript support][typescript-support] for details.
### 1. Define Abilities
Lets define `Ability` for a blog website where visitors:
* can read blog posts
* can manage (i.e., do anything) own posts
* cannot delete a post if it was created more than a day ago
```js
import { AbilityBuilder, createMongoAbility } from '@casl/ability';
import { User } from '../models'; // application specific interfaces
/**
* @param user contains details about logged in user: its id, name, email, etc
*/
function defineAbilitiesFor(user) {
const { can, cannot, build } = new AbilityBuilder(createMongoAbility);
// can read blog posts
can('read', 'BlogPost');
// can manage (i.e., do anything) own posts
can('manage', 'BlogPost', { author: user.id });
// cannot delete a post if it was created more than a day ago
cannot('delete', 'BlogPost', {
createdAt: { $lt: Date.now() - 24 * 60 * 60 * 1000 }
});
return build();
});
```
Do you see how easily business requirements were translated into CASL's rules?
And yes, `Ability` class allow you to use some MongoDB operators to define conditions. Don't worry if you don't know MongoDB, it's not required and explained in details in [Defining Abilities][define-abilities]
### 2. Check Abilities
Later on you can check abilities by using `can` and `cannot` methods of `Ability` instance.
```js
import { BlogPost, ForbiddenError } from '../models';
const user = getLoggedInUser(); // app specific function
const ability = defineAbilitiesFor(user)
// true if ability allows to read at least one Post
ability.can('read', 'BlogPost');
// true if there is no ability to read this particular blog post
const post = new BlogPost({ title: 'What is CASL?' });
ability.cannot('read', post);
// you can even throw an error if there is a missed ability
ForbiddenError.from(ability).throwUnlessCan('read', post);
```
Of course, you are not restricted to use only class instances in order to check permissions on objects. See [Introduction][intro] for the detailed explanation.
### 3. Database integration
CASL has a complementary package [@casl/mongoose] which provides easy integration with MongoDB and [mongoose].
```js
import { accessibleRecordsPlugin } from '@casl/mongoose';
import mongoose from 'mongoose';
mongoose.plugin(accessibleRecordsPlugin);
const user = getUserLoggedInUser(); // app specific function
const ability = defineAbilitiesFor(user);
const BlogPost = mongoose.model('BlogPost', mongoose.Schema({
title: String,
author: mongoose.Types.ObjectId,
content: String,
createdAt: Date,
hidden: { type: Boolean, default: false }
}))
// returns mongoose Query, so you can chain it with other conditions
const posts = await Post.accessibleBy(ability).where({ hidden: false });
// you can also call it on existing query to enforce permissions
const hiddenPosts = await Post.find({ hidden: true }).accessibleBy(ability);
// you can even pass the action as a 2nd parameter. By default action is "read"
const updatablePosts = await Post.accessibleBy(ability, 'update');
```
See [Database integration][database-integration] for details.
### 4. Advanced usage
**CASL is incrementally adoptable**, that means you can start your project with simple claim (or action) based authorization and evolve it later, when your app functionality evolves.
**CASL is composable**, that means you can implement alternative conditions matching (e.g., based on [joi], [ajv] or pure functions) and field matching (e.g., to support alternative syntax in fields like `addresses.*.street` or `addresses[0].street`) logic.
See [Advanced usage][advanced-usage] for details.
[joi]: https://www.npmjs.com/package/@hapi/joi
[ajv]: https://www.npmjs.com/package/ajv
### 5. Performance and computational complexity
CASL checks are quite fast, thanks to underlying rule index structure. The estimated complexity of different operations can be found below:
| Operation | Complexity | Notes |
|----------------------------------|------------|---------------|
| `Ability` creation time | O(n) | n - amount of rules |
| Check by action and subject type (e.g., `ability.can('read', 'Todo')`) | O(1) | |
| Check by action and subject object (e.g., `ability.can('read', todo)`) | O(m + k) + O(p) | m - amount of rules for the same pair of action and subject; k - amount of operators in conditions; O(p) - complexity of used operators (e.g., `$in` implementation is more complex than `$lt`) |
## Want to help?
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on guidelines for [contributing]
## License
[MIT License](http://www.opensource.org/licenses/MIT)
[contributing]: https://github.com/stalniy/casl/blob/master/CONTRIBUTING.md
[define-abilities]: https://stalniy.github.io/casl/en/guide/define-rules
[intro]: https://stalniy.github.io/casl/en/guide/intro
[database-integration]: https://stalniy.github.io/casl/en/package/casl-mongoose
[advanced-usage]: https://stalniy.github.io/casl/en/advanced/customize-ability
[typescript-support]: https://stalniy.github.io/casl/en/advanced/typescript
+2
View File
@@ -0,0 +1,2 @@
import{buildOr as r,buildAnd as n,CompoundCondition as t}from"@ucast/mongo2js";function e(r){return Array.isArray(r)?r:[r]}function u(r,n,t){var e=r;var u=n;if(-1!==n.indexOf(".")){var i=n.split(".");u=i.pop();e=i.reduce((function(r,n){r[n]=r[n]||{};return r[n]}),r)}e[u]=t}Object.hasOwn||Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);function i(r,n,t,e){var u={};var i=r.rulesFor(n,t);for(var o=0;o<i.length;o++){var a=i[o];var f=a.inverted?"$and":"$or";if(!a.conditions)if(a.inverted)break;else{delete u[f];return u}else{u[f]=u[f]||[];u[f].push(e(a))}}return u.$or?u:null}function o(r){if(!r.ast)throw new Error('Ability rule "'+JSON.stringify(r)+'" does not have "ast" property. So, cannot be used to generate AST');return r.inverted?new t("not",[r.ast]):r.ast}function a(t,e,u){var a=i(t,e,u,o);if(null===a)return null;if(!a.$and)return a.$or?r(a.$or):n([]);if(a.$or)a.$and.push(r(a.$or));return n(a.$and)}function f(r,n,t){return r.rulesFor(n,t).reduce((function(r,n){if(n.inverted||!n.conditions)return r;return Object.keys(n.conditions).reduce((function(r,t){var e=n.conditions[t];if(!e||e.constructor!==Object)u(r,t,e);return r}),r)}),{})}function c(r,n,t,e){var u=r.detectSubjectType(t);var i=r.possibleRulesFor(n,u);var o=new Set;var a=o.delete.bind(o);var f=o.add.bind(o);var c=i.length;while(c--){var v=i[c];if(v.matchesConditions(t)){var l=v.inverted?a:f;e.fieldsFrom(v).forEach(l)}}return Array.from(o)}var v=function r(n){return Array.isArray(n)?n.join(","):n};function l(r,n){return r.map((function(r){var t=[v(r.action||r.actions),"function"===typeof n?e(r.subject).map(n).join(","):v(r.subject),r.conditions||0,r.inverted?1:0,r.fields?v(r.fields):0,r.reason||""];while(t.length>0&&!t[t.length-1])t.pop();return t}))}function b(r,n){return r.map((function(r){var t=r[0],e=r[1],u=r[2],i=r[3],o=r[4],a=r[5];var f=e.split(",");var c={inverted:!!i,action:t.split(","),subject:"function"===typeof n?f.map(n):f};if(u)c.conditions=u;if(o)c.fields=o.split(",");if(a)c.reason=a;return c}))}export{l as packRules,c as permittedFieldsOf,a as rulesToAST,f as rulesToFields,i as rulesToQuery,b as unpackRules};
//# sourceMappingURL=extra.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"extra.js","sources":["../../src/utils.ts","../../src/extra.ts"],"sourcesContent":["import { AnyObject, Subject, SubjectType, SubjectClass, ForcedSubject, AliasesMap } from './types';\n\nexport function wrapArray<T>(value: T[] | T): T[] {\n return Array.isArray(value) ? value : [value];\n}\n\nexport function setByPath(object: AnyObject, path: string, value: unknown): void {\n let ref = object;\n let lastKey = path;\n\n if (path.indexOf('.') !== -1) {\n const keys = path.split('.');\n\n lastKey = keys.pop()!;\n ref = keys.reduce((res, prop) => {\n res[prop] = res[prop] || {};\n return res[prop] as AnyObject;\n }, object);\n }\n\n ref[lastKey] = value;\n}\n\nconst hasOwnProperty = (Object as any).hasOwn\n || Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);\n\nconst TYPE_FIELD = '__caslSubjectType__';\nexport function setSubjectType<\n T extends string,\n U extends Record<PropertyKey, any>\n>(type: T, object: U): U & ForcedSubject<T> {\n if (object) {\n if (!hasOwnProperty(object, TYPE_FIELD)) {\n Object.defineProperty(object, TYPE_FIELD, { value: type });\n } else if (type !== object[TYPE_FIELD]) {\n throw new Error(`Trying to cast object to subject type ${type} but previously it was casted to ${object[TYPE_FIELD]}`);\n }\n }\n\n return object as U & ForcedSubject<T>;\n}\n\nexport const isSubjectType = (value: unknown): value is SubjectType => {\n const type = typeof value;\n return type === 'string' || type === 'function';\n};\n\nconst getSubjectClassName = (value: SubjectClass) => value.modelName || value.name;\nexport const getSubjectTypeName = (value: SubjectType) => {\n return typeof value === 'string' ? value : getSubjectClassName(value);\n};\n\nexport function detectSubjectType(subject: Exclude<Subject, SubjectType>): string {\n if (hasOwnProperty(subject, TYPE_FIELD)) {\n return subject[TYPE_FIELD];\n }\n\n return getSubjectClassName(subject.constructor as SubjectClass);\n}\n\ntype AliasMerge = (actions: string[], action: string | string[]) => string[];\nfunction expandActions(aliasMap: AliasesMap, rawActions: string | string[], merge: AliasMerge) {\n let actions = wrapArray(rawActions);\n let i = 0;\n\n while (i < actions.length) {\n const action = actions[i++];\n\n if (hasOwnProperty(aliasMap, action)) {\n actions = merge(actions, aliasMap[action]);\n }\n }\n\n return actions;\n}\n\nfunction findDuplicate(actions: string[], actionToFind: string | string[]) {\n if (typeof actionToFind === 'string' && actions.indexOf(actionToFind) !== -1) {\n return actionToFind;\n }\n\n for (let i = 0; i < actionToFind.length; i++) {\n if (actions.indexOf(actionToFind[i]) !== -1) return actionToFind[i];\n }\n\n return null;\n}\n\nconst defaultAliasMerge: AliasMerge = (actions, action) => actions.concat(action);\nfunction validateForCycles(aliasMap: AliasesMap, reservedAction: string) {\n if (reservedAction in aliasMap) {\n throw new Error(`Cannot use \"${reservedAction}\" as an alias because it's reserved action.`);\n }\n\n const keys = Object.keys(aliasMap);\n const mergeAliasesAndDetectCycles: AliasMerge = (actions, action) => {\n const duplicate = findDuplicate(actions, action);\n if (duplicate) throw new Error(`Detected cycle ${duplicate} -> ${actions.join(', ')}`);\n\n const isUsingReservedAction = typeof action === 'string' && action === reservedAction\n || actions.indexOf(reservedAction) !== -1\n || Array.isArray(action) && action.indexOf(reservedAction) !== -1;\n if (isUsingReservedAction) throw new Error(`Cannot make an alias to \"${reservedAction}\" because this is reserved action`);\n\n return actions.concat(action);\n };\n\n for (let i = 0; i < keys.length; i++) {\n expandActions(aliasMap, keys[i], mergeAliasesAndDetectCycles);\n }\n}\n\nexport type AliasResolverOptions = { skipValidate?: boolean; anyAction?: string };\nexport function createAliasResolver(aliasMap: AliasesMap, options?: AliasResolverOptions) {\n if (!options || options.skipValidate !== false) {\n validateForCycles(aliasMap, options && options.anyAction || 'manage');\n }\n\n return (action: string | string[]) => expandActions(aliasMap, action, defaultAliasMerge);\n}\n\nfunction copyArrayTo<T>(dest: T[], target: T[], start: number) {\n for (let i = start; i < target.length; i++) {\n dest.push(target[i]);\n }\n}\n\nexport function mergePrioritized<T extends { priority: number }>(\n array?: T[],\n anotherArray?: T[]\n): T[] {\n if (!array || !array.length) {\n return anotherArray || [];\n }\n\n if (!anotherArray || !anotherArray.length) {\n return array || [];\n }\n\n let i = 0;\n let j = 0;\n const merged: T[] = [];\n\n while (i < array.length && j < anotherArray.length) {\n if (array[i].priority < anotherArray[j].priority) {\n merged.push(array[i]);\n i++;\n } else {\n merged.push(anotherArray[j]);\n j++;\n }\nLine truncated
+2
View File
@@ -0,0 +1,2 @@
import{createFactory as t,$eq as r,$ne as i,$lt as n,$lte as e,$gt as u,$gte as o,$in as s,$nin as a,$all as f,$size as c,$regex as h,$options as v,$elemMatch as l,$exists as d,eq as b,ne as y,lt as p,lte as w,gt as g,gte as A,within as j,nin as E,all as m,size as $,regex as M,elemMatch as O,exists as x,and as F}from"@ucast/mongo2js";function _(t,r){for(var i=0;i<r.length;i++){var n=r[i];n.enumerable=n.enumerable||false;n.configurable=true;if("value"in n)n.writable=true;Object.defineProperty(t,B(n.key),n)}}function S(t,r,i){if(r)_(t.prototype,r);if(i)_(t,i);Object.defineProperty(t,"prototype",{writable:false});return t}function C(){C=Object.assign?Object.assign.bind():function(t){for(var r=1;r<arguments.length;r++){var i=arguments[r];for(var n in i)if(Object.prototype.hasOwnProperty.call(i,n))t[n]=i[n]}return t};return C.apply(this,arguments)}function P(t,r){t.prototype=Object.create(r.prototype);t.prototype.constructor=t;R(t,r)}function R(t,r){R=Object.setPrototypeOf?Object.setPrototypeOf.bind():function t(r,i){r.__proto__=i;return r};return R(t,r)}function T(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function k(t,r){if("object"!==typeof t||null===t)return t;var i=t[Symbol.toPrimitive];if(void 0!==i){var n=i.call(t,r||"default");if("object"!==typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===r?String:Number)(t)}function B(t){var r=k(t,"string");return"symbol"===typeof r?r:String(r)}function q(t){return Array.isArray(t)?t:[t]}var z=Object.hasOwn||Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);var Y="__caslSubjectType__";function D(t,r){if(r)if(!z(r,Y))Object.defineProperty(r,Y,{value:t});else if(t!==r[Y])throw new Error("Trying to cast object to subject type "+t+" but previously it was casted to "+r[Y]);return r}var L=function t(r){var i=typeof r;return"string"===i||"function"===i};var N=function t(r){return r.modelName||r.name};var G=function t(r){return"string"===typeof r?r:N(r)};function H(t){if(z(t,Y))return t[Y];return N(t.constructor)}function I(t,r,i){var n=q(r);var e=0;while(e<n.length){var u=n[e++];if(z(t,u))n=i(n,t[u])}return n}function J(t,r){if("string"===typeof r&&-1!==t.indexOf(r))return r;for(var i=0;i<r.length;i++)if(-1!==t.indexOf(r[i]))return r[i];return null}var K=function t(r,i){return r.concat(i)};function Q(t,r){if(r in t)throw new Error('Cannot use "'+r+"\" as an alias because it's reserved action.");var i=Object.keys(t);var n=function t(i,n){var e=J(i,n);if(e)throw new Error("Detected cycle "+e+" -> "+i.join(", "));var u="string"===typeof n&&n===r||-1!==i.indexOf(r)||Array.isArray(n)&&-1!==n.indexOf(r);if(u)throw new Error('Cannot make an alias to "'+r+'" because this is reserved action');return i.concat(n)};for(var e=0;e<i.length;e++)I(t,i[e],n)}function U(t,r){if(!r||false!==r.skipValidate)Q(t,r&&r.anyAction||"manage");return function(r){return I(t,r,K)}}function V(t,r,i){for(var n=i;n<r.length;n++)t.push(r[n])}function W(t,r){if(!t||!t.length)return r||[];if(!r||!r.length)return t||[];var i=0;var n=0;var e=[];while(i<t.length&&n<r.length)if(t[i].priority<r[n].priority){e.push(t[i]);i++}else{e.push(r[n]);n++}V(e,t,i);V(e,r,n);return e}function X(t,r,i){var n=t.get(r);if(!n){n=i();t.set(r,n)}return n}var Z=function t(r){return r};function tt(t,r){if(Array.isArray(t.fields)&&!t.fields.length)throw new Error("`rawRule.fields` cannot be an empty array. https://bit.ly/390miLa");if(t.fields&&!r.fieldMatcher)throw new Error('You need to pass "fieldMatcher" option in order to restrict access by fields');if(t.conditions&&!r.conditionsMatcher)throw new Error('You need to pass "conditionsMatcher" option in order to restrict access by conditions')}var rt=function(){function t(t,r,i){if(void 0===i)i=0;tt(t,r);this.action=r.resolveAction(t.action);this.subject=t.subject;this.inverted=!!t.inverted;this.conditions=t.conditions;this.reason=t.reason;this.origin=t;this.fields=t.fields?q(t.fields):void 0;this.priority=i;this.t=r}var r=t.prototype;r.i=function t(){if(this.conditions&&!this.u)this.u=this.t.conditionsMatcher(this.conditions);return this.u};r.matchesConditions=function t(r){if(!this.conditions)return true;if(!r||L(r))return!this.inverted;var i=this.i();return i(r)};r.matchesField=function t(r){if(!this.fields)return true;if(!r)return!this.inverted;if(this.fields&&!this.o)this.o=this.t.fieldMatcher(this.fields);return this.o(r)};S(t,[{key:"ast",get:function t(){var r=this.i();return r?r.ast:void 0}}]);return t}();function it(t,r){var i={value:t,prev:r,next:null};if(r)r.next=i;return i}function nt(t){if(t.next)t.next.prev=t.prev;if(t.prev)t.prev.next=t.next;t.next=t.prev=null}var et=function t(r){return{value:r.value,prev:r.prev,next:r.next}};var ut=function t(){return{rules:[],merged:false}};var ot=function t(){return new Map};var st=function(){function t(t,r){if(void 0===t)t=[];if(void 0===r)r={};this.h=false;this.v={conditionsMatcher:r.coLine truncated
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sources":["../../src/utils.ts","../../src/Rule.ts","../../src/structures/LinkedItem.ts","../../src/RuleIndex.ts","../../src/PureAbility.ts","../../src/matchers/conditions.ts","../../src/matchers/field.ts","../../src/Ability.ts","../../src/AbilityBuilder.ts","../../src/ForbiddenError.ts"],"sourcesContent":["import { AnyObject, Subject, SubjectType, SubjectClass, ForcedSubject, AliasesMap } from './types';\n\nexport function wrapArray<T>(value: T[] | T): T[] {\n return Array.isArray(value) ? value : [value];\n}\n\nexport function setByPath(object: AnyObject, path: string, value: unknown): void {\n let ref = object;\n let lastKey = path;\n\n if (path.indexOf('.') !== -1) {\n const keys = path.split('.');\n\n lastKey = keys.pop()!;\n ref = keys.reduce((res, prop) => {\n res[prop] = res[prop] || {};\n return res[prop] as AnyObject;\n }, object);\n }\n\n ref[lastKey] = value;\n}\n\nconst hasOwnProperty = (Object as any).hasOwn\n || Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);\n\nconst TYPE_FIELD = '__caslSubjectType__';\nexport function setSubjectType<\n T extends string,\n U extends Record<PropertyKey, any>\n>(type: T, object: U): U & ForcedSubject<T> {\n if (object) {\n if (!hasOwnProperty(object, TYPE_FIELD)) {\n Object.defineProperty(object, TYPE_FIELD, { value: type });\n } else if (type !== object[TYPE_FIELD]) {\n throw new Error(`Trying to cast object to subject type ${type} but previously it was casted to ${object[TYPE_FIELD]}`);\n }\n }\n\n return object as U & ForcedSubject<T>;\n}\n\nexport const isSubjectType = (value: unknown): value is SubjectType => {\n const type = typeof value;\n return type === 'string' || type === 'function';\n};\n\nconst getSubjectClassName = (value: SubjectClass) => value.modelName || value.name;\nexport const getSubjectTypeName = (value: SubjectType) => {\n return typeof value === 'string' ? value : getSubjectClassName(value);\n};\n\nexport function detectSubjectType(subject: Exclude<Subject, SubjectType>): string {\n if (hasOwnProperty(subject, TYPE_FIELD)) {\n return subject[TYPE_FIELD];\n }\n\n return getSubjectClassName(subject.constructor as SubjectClass);\n}\n\ntype AliasMerge = (actions: string[], action: string | string[]) => string[];\nfunction expandActions(aliasMap: AliasesMap, rawActions: string | string[], merge: AliasMerge) {\n let actions = wrapArray(rawActions);\n let i = 0;\n\n while (i < actions.length) {\n const action = actions[i++];\n\n if (hasOwnProperty(aliasMap, action)) {\n actions = merge(actions, aliasMap[action]);\n }\n }\n\n return actions;\n}\n\nfunction findDuplicate(actions: string[], actionToFind: string | string[]) {\n if (typeof actionToFind === 'string' && actions.indexOf(actionToFind) !== -1) {\n return actionToFind;\n }\n\n for (let i = 0; i < actionToFind.length; i++) {\n if (actions.indexOf(actionToFind[i]) !== -1) return actionToFind[i];\n }\n\n return null;\n}\n\nconst defaultAliasMerge: AliasMerge = (actions, action) => actions.concat(action);\nfunction validateForCycles(aliasMap: AliasesMap, reservedAction: string) {\n if (reservedAction in aliasMap) {\n throw new Error(`Cannot use \"${reservedAction}\" as an alias because it's reserved action.`);\n }\n\n const keys = Object.keys(aliasMap);\n const mergeAliasesAndDetectCycles: AliasMerge = (actions, action) => {\n const duplicate = findDuplicate(actions, action);\n if (duplicate) throw new Error(`Detected cycle ${duplicate} -> ${actions.join(', ')}`);\n\n const isUsingReservedAction = typeof action === 'string' && action === reservedAction\n || actions.indexOf(reservedAction) !== -1\n || Array.isArray(action) && action.indexOf(reservedAction) !== -1;\n if (isUsingReservedAction) throw new Error(`Cannot make an alias to \"${reservedAction}\" because this is reserved action`);\n\n return actions.concat(action);\n };\n\n for (let i = 0; i < keys.length; i++) {\n expandActions(aliasMap, keys[i], mergeAliasesAndDetectCycles);\n }\n}\n\nexport type AliasResolverOptions = { skipValidate?: boolean; anyAction?: string };\nexport function createAliasResolver(aliasMap: AliasesMap, options?: AliasResolverOptions) {\n if (!options || options.skipValidate !== false) {\n validateForCycles(aliasMap, options && options.anyAction || 'manage');\n }\n\n return (action: string | string[]) => expandActions(aliasMap, action, defaultAliasMerge);\n}\n\nfunction copyArrayTo<T>(dest: T[], target: T[], start: number) {\n for (let i = start; i < target.length; i++) {\n dest.push(target[i]);\n }\n}\n\nexport function mergePrioritized<T extends { priority: number }>(\n array?: T[],\n anotherArray?: T[]\n): T[] {\n if (!array || !array.length) {\n return anotherArray || [];\n }\n\n if (!anotherArray || !anotherArray.length) {\n return array || [];\n }\n\n let i = 0;\n let j = 0;\n const merged: T[]Line truncated
+2
View File
@@ -0,0 +1,2 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:true});var t=require("@ucast/mongo2js");function n(t){return Array.isArray(t)?t:[t]}function e(t,n,e){let r=t;let o=n;if(-1!==n.indexOf(".")){const e=n.split(".");o=e.pop();r=e.reduce(((t,n)=>{t[n]=t[n]||{};return t[n]}),t)}r[o]=e}Object.hasOwn||Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);function r(t,n,e,r){const o={};const c=t.rulesFor(n,e);for(let t=0;t<c.length;t++){const n=c[t];const e=n.inverted?"$and":"$or";if(!n.conditions)if(n.inverted)break;else{delete o[e];return o}else{o[e]=o[e]||[];o[e].push(r(n))}}return o.$or?o:null}function o(n){if(!n.ast)throw new Error(`Ability rule "${JSON.stringify(n)}" does not have "ast" property. So, cannot be used to generate AST`);return n.inverted?new t.CompoundCondition("not",[n.ast]):n.ast}function c(n,e,c){const u=r(n,e,c,o);if(null===u)return null;if(!u.$and)return u.$or?t.buildOr(u.$or):t.buildAnd([]);if(u.$or)u.$and.push(t.buildOr(u.$or));return t.buildAnd(u.$and)}function u(t,n,r){return t.rulesFor(n,r).reduce(((t,n)=>{if(n.inverted||!n.conditions)return t;return Object.keys(n.conditions).reduce(((t,r)=>{const o=n.conditions[r];if(!o||o.constructor!==Object)e(t,r,o);return t}),t)}),{})}function s(t,n,e,r){const o=t.detectSubjectType(e);const c=t.possibleRulesFor(n,o);const u=new Set;const s=u.delete.bind(u);const i=u.add.bind(u);let f=c.length;while(f--){const t=c[f];if(t.matchesConditions(e)){const n=t.inverted?s:i;r.fieldsFrom(t).forEach(n)}}return Array.from(u)}const i=t=>Array.isArray(t)?t.join(","):t;function f(t,e){return t.map((t=>{const r=[i(t.action||t.actions),"function"===typeof e?n(t.subject).map(e).join(","):i(t.subject),t.conditions||0,t.inverted?1:0,t.fields?i(t.fields):0,t.reason||""];while(r.length>0&&!r[r.length-1])r.pop();return r}))}function l(t,n){return t.map((([t,e,r,o,c,u])=>{const s=e.split(",");const i={inverted:!!o,action:t.split(","),subject:"function"===typeof n?s.map(n):s};if(r)i.conditions=r;if(c)i.fields=c.split(",");if(u)i.reason=u;return i}))}exports.packRules=f;exports.permittedFieldsOf=s;exports.rulesToAST=c;exports.rulesToFields=u;exports.rulesToQuery=r;exports.unpackRules=l;
//# sourceMappingURL=extra.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"extra.js","sources":["../../src/utils.ts","../../src/extra.ts"],"sourcesContent":["import { AnyObject, Subject, SubjectType, SubjectClass, ForcedSubject, AliasesMap } from './types';\n\nexport function wrapArray<T>(value: T[] | T): T[] {\n return Array.isArray(value) ? value : [value];\n}\n\nexport function setByPath(object: AnyObject, path: string, value: unknown): void {\n let ref = object;\n let lastKey = path;\n\n if (path.indexOf('.') !== -1) {\n const keys = path.split('.');\n\n lastKey = keys.pop()!;\n ref = keys.reduce((res, prop) => {\n res[prop] = res[prop] || {};\n return res[prop] as AnyObject;\n }, object);\n }\n\n ref[lastKey] = value;\n}\n\nconst hasOwnProperty = (Object as any).hasOwn\n || Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);\n\nconst TYPE_FIELD = '__caslSubjectType__';\nexport function setSubjectType<\n T extends string,\n U extends Record<PropertyKey, any>\n>(type: T, object: U): U & ForcedSubject<T> {\n if (object) {\n if (!hasOwnProperty(object, TYPE_FIELD)) {\n Object.defineProperty(object, TYPE_FIELD, { value: type });\n } else if (type !== object[TYPE_FIELD]) {\n throw new Error(`Trying to cast object to subject type ${type} but previously it was casted to ${object[TYPE_FIELD]}`);\n }\n }\n\n return object as U & ForcedSubject<T>;\n}\n\nexport const isSubjectType = (value: unknown): value is SubjectType => {\n const type = typeof value;\n return type === 'string' || type === 'function';\n};\n\nconst getSubjectClassName = (value: SubjectClass) => value.modelName || value.name;\nexport const getSubjectTypeName = (value: SubjectType) => {\n return typeof value === 'string' ? value : getSubjectClassName(value);\n};\n\nexport function detectSubjectType(subject: Exclude<Subject, SubjectType>): string {\n if (hasOwnProperty(subject, TYPE_FIELD)) {\n return subject[TYPE_FIELD];\n }\n\n return getSubjectClassName(subject.constructor as SubjectClass);\n}\n\ntype AliasMerge = (actions: string[], action: string | string[]) => string[];\nfunction expandActions(aliasMap: AliasesMap, rawActions: string | string[], merge: AliasMerge) {\n let actions = wrapArray(rawActions);\n let i = 0;\n\n while (i < actions.length) {\n const action = actions[i++];\n\n if (hasOwnProperty(aliasMap, action)) {\n actions = merge(actions, aliasMap[action]);\n }\n }\n\n return actions;\n}\n\nfunction findDuplicate(actions: string[], actionToFind: string | string[]) {\n if (typeof actionToFind === 'string' && actions.indexOf(actionToFind) !== -1) {\n return actionToFind;\n }\n\n for (let i = 0; i < actionToFind.length; i++) {\n if (actions.indexOf(actionToFind[i]) !== -1) return actionToFind[i];\n }\n\n return null;\n}\n\nconst defaultAliasMerge: AliasMerge = (actions, action) => actions.concat(action);\nfunction validateForCycles(aliasMap: AliasesMap, reservedAction: string) {\n if (reservedAction in aliasMap) {\n throw new Error(`Cannot use \"${reservedAction}\" as an alias because it's reserved action.`);\n }\n\n const keys = Object.keys(aliasMap);\n const mergeAliasesAndDetectCycles: AliasMerge = (actions, action) => {\n const duplicate = findDuplicate(actions, action);\n if (duplicate) throw new Error(`Detected cycle ${duplicate} -> ${actions.join(', ')}`);\n\n const isUsingReservedAction = typeof action === 'string' && action === reservedAction\n || actions.indexOf(reservedAction) !== -1\n || Array.isArray(action) && action.indexOf(reservedAction) !== -1;\n if (isUsingReservedAction) throw new Error(`Cannot make an alias to \"${reservedAction}\" because this is reserved action`);\n\n return actions.concat(action);\n };\n\n for (let i = 0; i < keys.length; i++) {\n expandActions(aliasMap, keys[i], mergeAliasesAndDetectCycles);\n }\n}\n\nexport type AliasResolverOptions = { skipValidate?: boolean; anyAction?: string };\nexport function createAliasResolver(aliasMap: AliasesMap, options?: AliasResolverOptions) {\n if (!options || options.skipValidate !== false) {\n validateForCycles(aliasMap, options && options.anyAction || 'manage');\n }\n\n return (action: string | string[]) => expandActions(aliasMap, action, defaultAliasMerge);\n}\n\nfunction copyArrayTo<T>(dest: T[], target: T[], start: number) {\n for (let i = start; i < target.length; i++) {\n dest.push(target[i]);\n }\n}\n\nexport function mergePrioritized<T extends { priority: number }>(\n array?: T[],\n anotherArray?: T[]\n): T[] {\n if (!array || !array.length) {\n return anotherArray || [];\n }\n\n if (!anotherArray || !anotherArray.length) {\n return array || [];\n }\n\n let i = 0;\n let j = 0;\n const merged: T[] = [];\n\n while (i < array.length && j < anotherArray.length) {\n if (array[i].priority < anotherArray[j].priority) {\n merged.push(array[i]);\n i++;\n } else {\n merged.push(anotherArray[j]);\n j++;\n }\nLine truncated
+2
View File
@@ -0,0 +1,2 @@
"use strict";Object.defineProperty(exports,"__esModule",{value:true});var t=require("@ucast/mongo2js");function e(t){return Array.isArray(t)?t:[t]}const s=Object.hasOwn||Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);const i="__caslSubjectType__";function r(t,e){if(e)if(!s(e,i))Object.defineProperty(e,i,{value:t});else if(t!==e[i])throw new Error(`Trying to cast object to subject type ${t} but previously it was casted to ${e[i]}`);return e}const n=t=>{const e=typeof t;return"string"===e||"function"===e};const o=t=>t.modelName||t.name;const c=t=>"string"===typeof t?t:o(t);function u(t){if(s(t,i))return t[i];return o(t.constructor)}function h(t,i,r){let n=e(i);let o=0;while(o<n.length){const e=n[o++];if(s(t,e))n=r(n,t[e])}return n}function l(t,e){if("string"===typeof e&&-1!==t.indexOf(e))return e;for(let s=0;s<e.length;s++)if(-1!==t.indexOf(e[s]))return e[s];return null}const a=(t,e)=>t.concat(e);function f(t,e){if(e in t)throw new Error(`Cannot use "${e}" as an alias because it's reserved action.`);const s=Object.keys(t);const i=(t,s)=>{const i=l(t,s);if(i)throw new Error(`Detected cycle ${i} -> ${t.join(", ")}`);const r="string"===typeof s&&s===e||-1!==t.indexOf(e)||Array.isArray(s)&&-1!==s.indexOf(e);if(r)throw new Error(`Cannot make an alias to "${e}" because this is reserved action`);return t.concat(s)};for(let e=0;e<s.length;e++)h(t,s[e],i)}function d(t,e){if(!e||false!==e.skipValidate)f(t,e&&e.anyAction||"manage");return e=>h(t,e,a)}function p(t,e,s){for(let i=s;i<e.length;i++)t.push(e[i])}function y(t,e){if(!t||!t.length)return e||[];if(!e||!e.length)return t||[];let s=0;let i=0;const r=[];while(s<t.length&&i<e.length)if(t[s].priority<e[i].priority){r.push(t[s]);s++}else{r.push(e[i]);i++}p(r,t,s);p(r,e,i);return r}function b(t,e,s){let i=t.get(e);if(!i){i=s();t.set(e,i)}return i}const w=t=>t;function g(t,e){if(Array.isArray(t.fields)&&!t.fields.length)throw new Error("`rawRule.fields` cannot be an empty array. https://bit.ly/390miLa");if(t.fields&&!e.fieldMatcher)throw new Error('You need to pass "fieldMatcher" option in order to restrict access by fields');if(t.conditions&&!e.conditionsMatcher)throw new Error('You need to pass "conditionsMatcher" option in order to restrict access by conditions')}class x{constructor(t,s,i=0){g(t,s);this.action=s.resolveAction(t.action);this.subject=t.subject;this.inverted=!!t.inverted;this.conditions=t.conditions;this.reason=t.reason;this.origin=t;this.fields=t.fields?e(t.fields):void 0;this.priority=i;this.t=s}i(){if(this.conditions&&!this.o)this.o=this.t.conditionsMatcher(this.conditions);return this.o}get ast(){const t=this.i();return t?t.ast:void 0}matchesConditions(t){if(!this.conditions)return true;if(!t||n(t))return!this.inverted;const e=this.i();return e(t)}matchesField(t){if(!this.fields)return true;if(!t)return!this.inverted;if(this.fields&&!this.u)this.u=this.t.fieldMatcher(this.fields);return this.u(t)}}function $(t,e){const s={value:t,prev:e,next:null};if(e)e.next=s;return s}function A(t){if(t.next)t.next.prev=t.prev;if(t.prev)t.prev.next=t.next;t.next=t.prev=null}const M=t=>({value:t.value,prev:t.prev,next:t.next});const j=()=>({rules:[],merged:false});const E=()=>new Map;class v{constructor(t=[],e={}){this.h=false;this.l={conditionsMatcher:e.conditionsMatcher,fieldMatcher:e.fieldMatcher,resolveAction:e.resolveAction||w};this.p=e.anyAction||"manage";this.g=e.anySubjectType||"all";this.$=e.detectSubjectType||u;this.A=t;this.M=this.j(t)}get rules(){return this.A}detectSubjectType(t){if(n(t))return t;if(!t)return this.g;return this.$(t)}update(t){const e={rules:t,ability:this,target:this};this.v("update",e);this.A=t;this.M=this.j(t);this.v("updated",e);return this}j(t){const s=new Map;for(let i=t.length-1;i>=0;i--){const r=t.length-i-1;const n=new x(t[i],this.l,r);const o=e(n.action);const c=e(n.subject||this.g);if(!this.h&&n.fields)this.h=true;for(let t=0;t<c.length;t++){const e=b(s,c[t],E);for(let t=0;t<o.length;t++)b(e,o[t],j).rules.push(n)}}return s}possibleRulesFor(t,e=this.g){if(!n(e))throw new Error('"possibleRulesFor" accepts only subject types (i.e., string or class) as the 2nd parameter');const s=b(this.M,e,E);const i=b(s,t,j);if(i.merged)return i.rules;const r=t!==this.p&&s.has(this.p)?s.get(this.p).rules:void 0;let o=y(i.rules,r);if(e!==this.g)o=y(o,this.possibleRulesFor(t,this.g));i.rules=o;i.merged=true;return o}rulesFor(t,e,s){const i=this.possibleRulesFor(t,e);if(s&&"string"!==typeof s)throw new Error("The 3rd, `field` parameter is expected to be a string. See https://stalniy.github.io/casl/en/api/casl-ability#can-of-pure-ability for details");if(!this.h)return i;return i.filter((t=>t.matchesField(s)))}actionsFor(t){if(!n(t))throw new Error('"actionsFor" accepts only subject types (i.e., string or class) as a parameter');const e=new Set;const s=this.M.get(t);if(s)Array.from(s.keys()).forEach((t=>e.add(t)));const i=t!==this.g?this.M.get(this.g):void 0;if(i)Array.from(i.keys()).forEach((t=>e.add(t)));return Array.Line truncated
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sources":["../../src/utils.ts","../../src/Rule.ts","../../src/structures/LinkedItem.ts","../../src/RuleIndex.ts","../../src/PureAbility.ts","../../src/matchers/conditions.ts","../../src/matchers/field.ts","../../src/Ability.ts","../../src/AbilityBuilder.ts","../../src/ForbiddenError.ts"],"sourcesContent":["import { AnyObject, Subject, SubjectType, SubjectClass, ForcedSubject, AliasesMap } from './types';\n\nexport function wrapArray<T>(value: T[] | T): T[] {\n return Array.isArray(value) ? value : [value];\n}\n\nexport function setByPath(object: AnyObject, path: string, value: unknown): void {\n let ref = object;\n let lastKey = path;\n\n if (path.indexOf('.') !== -1) {\n const keys = path.split('.');\n\n lastKey = keys.pop()!;\n ref = keys.reduce((res, prop) => {\n res[prop] = res[prop] || {};\n return res[prop] as AnyObject;\n }, object);\n }\n\n ref[lastKey] = value;\n}\n\nconst hasOwnProperty = (Object as any).hasOwn\n || Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);\n\nconst TYPE_FIELD = '__caslSubjectType__';\nexport function setSubjectType<\n T extends string,\n U extends Record<PropertyKey, any>\n>(type: T, object: U): U & ForcedSubject<T> {\n if (object) {\n if (!hasOwnProperty(object, TYPE_FIELD)) {\n Object.defineProperty(object, TYPE_FIELD, { value: type });\n } else if (type !== object[TYPE_FIELD]) {\n throw new Error(`Trying to cast object to subject type ${type} but previously it was casted to ${object[TYPE_FIELD]}`);\n }\n }\n\n return object as U & ForcedSubject<T>;\n}\n\nexport const isSubjectType = (value: unknown): value is SubjectType => {\n const type = typeof value;\n return type === 'string' || type === 'function';\n};\n\nconst getSubjectClassName = (value: SubjectClass) => value.modelName || value.name;\nexport const getSubjectTypeName = (value: SubjectType) => {\n return typeof value === 'string' ? value : getSubjectClassName(value);\n};\n\nexport function detectSubjectType(subject: Exclude<Subject, SubjectType>): string {\n if (hasOwnProperty(subject, TYPE_FIELD)) {\n return subject[TYPE_FIELD];\n }\n\n return getSubjectClassName(subject.constructor as SubjectClass);\n}\n\ntype AliasMerge = (actions: string[], action: string | string[]) => string[];\nfunction expandActions(aliasMap: AliasesMap, rawActions: string | string[], merge: AliasMerge) {\n let actions = wrapArray(rawActions);\n let i = 0;\n\n while (i < actions.length) {\n const action = actions[i++];\n\n if (hasOwnProperty(aliasMap, action)) {\n actions = merge(actions, aliasMap[action]);\n }\n }\n\n return actions;\n}\n\nfunction findDuplicate(actions: string[], actionToFind: string | string[]) {\n if (typeof actionToFind === 'string' && actions.indexOf(actionToFind) !== -1) {\n return actionToFind;\n }\n\n for (let i = 0; i < actionToFind.length; i++) {\n if (actions.indexOf(actionToFind[i]) !== -1) return actionToFind[i];\n }\n\n return null;\n}\n\nconst defaultAliasMerge: AliasMerge = (actions, action) => actions.concat(action);\nfunction validateForCycles(aliasMap: AliasesMap, reservedAction: string) {\n if (reservedAction in aliasMap) {\n throw new Error(`Cannot use \"${reservedAction}\" as an alias because it's reserved action.`);\n }\n\n const keys = Object.keys(aliasMap);\n const mergeAliasesAndDetectCycles: AliasMerge = (actions, action) => {\n const duplicate = findDuplicate(actions, action);\n if (duplicate) throw new Error(`Detected cycle ${duplicate} -> ${actions.join(', ')}`);\n\n const isUsingReservedAction = typeof action === 'string' && action === reservedAction\n || actions.indexOf(reservedAction) !== -1\n || Array.isArray(action) && action.indexOf(reservedAction) !== -1;\n if (isUsingReservedAction) throw new Error(`Cannot make an alias to \"${reservedAction}\" because this is reserved action`);\n\n return actions.concat(action);\n };\n\n for (let i = 0; i < keys.length; i++) {\n expandActions(aliasMap, keys[i], mergeAliasesAndDetectCycles);\n }\n}\n\nexport type AliasResolverOptions = { skipValidate?: boolean; anyAction?: string };\nexport function createAliasResolver(aliasMap: AliasesMap, options?: AliasResolverOptions) {\n if (!options || options.skipValidate !== false) {\n validateForCycles(aliasMap, options && options.anyAction || 'manage');\n }\n\n return (action: string | string[]) => expandActions(aliasMap, action, defaultAliasMerge);\n}\n\nfunction copyArrayTo<T>(dest: T[], target: T[], start: number) {\n for (let i = start; i < target.length; i++) {\n dest.push(target[i]);\n }\n}\n\nexport function mergePrioritized<T extends { priority: number }>(\n array?: T[],\n anotherArray?: T[]\n): T[] {\n if (!array || !array.length) {\n return anotherArray || [];\n }\n\n if (!anotherArray || !anotherArray.length) {\n return array || [];\n }\n\n let i = 0;\n let j = 0;\n const merged: T[]Line truncated
+2
View File
@@ -0,0 +1,2 @@
import{buildOr as t,buildAnd as n,CompoundCondition as e}from"@ucast/mongo2js";function r(t){return Array.isArray(t)?t:[t]}function o(t,n,e){let r=t;let o=n;if(-1!==n.indexOf(".")){const e=n.split(".");o=e.pop();r=e.reduce(((t,n)=>{t[n]=t[n]||{};return t[n]}),t)}r[o]=e}Object.hasOwn||Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);function c(t,n,e,r){const o={};const c=t.rulesFor(n,e);for(let t=0;t<c.length;t++){const n=c[t];const e=n.inverted?"$and":"$or";if(!n.conditions)if(n.inverted)break;else{delete o[e];return o}else{o[e]=o[e]||[];o[e].push(r(n))}}return o.$or?o:null}function u(t){if(!t.ast)throw new Error(`Ability rule "${JSON.stringify(t)}" does not have "ast" property. So, cannot be used to generate AST`);return t.inverted?new e("not",[t.ast]):t.ast}function i(e,r,o){const i=c(e,r,o,u);if(null===i)return null;if(!i.$and)return i.$or?t(i.$or):n([]);if(i.$or)i.$and.push(t(i.$or));return n(i.$and)}function f(t,n,e){return t.rulesFor(n,e).reduce(((t,n)=>{if(n.inverted||!n.conditions)return t;return Object.keys(n.conditions).reduce(((t,e)=>{const r=n.conditions[e];if(!r||r.constructor!==Object)o(t,e,r);return t}),t)}),{})}function s(t,n,e,r){const o=t.detectSubjectType(e);const c=t.possibleRulesFor(n,o);const u=new Set;const i=u.delete.bind(u);const f=u.add.bind(u);let s=c.length;while(s--){const t=c[s];if(t.matchesConditions(e)){const n=t.inverted?i:f;r.fieldsFrom(t).forEach(n)}}return Array.from(u)}const l=t=>Array.isArray(t)?t.join(","):t;function a(t,n){return t.map((t=>{const e=[l(t.action||t.actions),"function"===typeof n?r(t.subject).map(n).join(","):l(t.subject),t.conditions||0,t.inverted?1:0,t.fields?l(t.fields):0,t.reason||""];while(e.length>0&&!e[e.length-1])e.pop();return e}))}function b(t,n){return t.map((([t,e,r,o,c,u])=>{const i=e.split(",");const f={inverted:!!o,action:t.split(","),subject:"function"===typeof n?i.map(n):i};if(r)f.conditions=r;if(c)f.fields=c.split(",");if(u)f.reason=u;return f}))}export{a as packRules,s as permittedFieldsOf,i as rulesToAST,f as rulesToFields,c as rulesToQuery,b as unpackRules};
//# sourceMappingURL=extra.mjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"extra.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
+2
View File
@@ -0,0 +1,2 @@
import{createFactory as t,$eq as e,$ne as i,$lt as s,$lte as n,$gt as r,$gte as o,$in as c,$nin as u,$all as h,$size as l,$regex as a,$options as f,$elemMatch as d,$exists as y,eq as b,ne as p,lt as w,lte as g,gt as $,gte as A,within as j,nin as M,all as m,size as E,regex as v,elemMatch as x,exists as F,and as _}from"@ucast/mongo2js";function O(t){return Array.isArray(t)?t:[t]}const C=Object.hasOwn||Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);const R="__caslSubjectType__";function P(t,e){if(e)if(!C(e,R))Object.defineProperty(e,R,{value:t});else if(t!==e[R])throw new Error(`Trying to cast object to subject type ${t} but previously it was casted to ${e[R]}`);return e}const S=t=>{const e=typeof t;return"string"===e||"function"===e};const T=t=>t.modelName||t.name;const B=t=>"string"===typeof t?t:T(t);function q(t){if(C(t,R))return t[R];return T(t.constructor)}function z(t,e,i){let s=O(e);let n=0;while(n<s.length){const e=s[n++];if(C(t,e))s=i(s,t[e])}return s}function D(t,e){if("string"===typeof e&&-1!==t.indexOf(e))return e;for(let i=0;i<e.length;i++)if(-1!==t.indexOf(e[i]))return e[i];return null}const Y=(t,e)=>t.concat(e);function k(t,e){if(e in t)throw new Error(`Cannot use "${e}" as an alias because it's reserved action.`);const i=Object.keys(t);const s=(t,i)=>{const s=D(t,i);if(s)throw new Error(`Detected cycle ${s} -> ${t.join(", ")}`);const n="string"===typeof i&&i===e||-1!==t.indexOf(e)||Array.isArray(i)&&-1!==i.indexOf(e);if(n)throw new Error(`Cannot make an alias to "${e}" because this is reserved action`);return t.concat(i)};for(let e=0;e<i.length;e++)z(t,i[e],s)}function I(t,e){if(!e||false!==e.skipValidate)k(t,e&&e.anyAction||"manage");return e=>z(t,e,Y)}function L(t,e,i){for(let s=i;s<e.length;s++)t.push(e[s])}function U(t,e){if(!t||!t.length)return e||[];if(!e||!e.length)return t||[];let i=0;let s=0;const n=[];while(i<t.length&&s<e.length)if(t[i].priority<e[s].priority){n.push(t[i]);i++}else{n.push(e[s]);s++}L(n,t,i);L(n,e,s);return n}function G(t,e,i){let s=t.get(e);if(!s){s=i();t.set(e,s)}return s}const H=t=>t;function J(t,e){if(Array.isArray(t.fields)&&!t.fields.length)throw new Error("`rawRule.fields` cannot be an empty array. https://bit.ly/390miLa");if(t.fields&&!e.fieldMatcher)throw new Error('You need to pass "fieldMatcher" option in order to restrict access by fields');if(t.conditions&&!e.conditionsMatcher)throw new Error('You need to pass "conditionsMatcher" option in order to restrict access by conditions')}class K{constructor(t,e,i=0){J(t,e);this.action=e.resolveAction(t.action);this.subject=t.subject;this.inverted=!!t.inverted;this.conditions=t.conditions;this.reason=t.reason;this.origin=t;this.fields=t.fields?O(t.fields):void 0;this.priority=i;this.t=e}i(){if(this.conditions&&!this.o)this.o=this.t.conditionsMatcher(this.conditions);return this.o}get ast(){const t=this.i();return t?t.ast:void 0}matchesConditions(t){if(!this.conditions)return true;if(!t||S(t))return!this.inverted;const e=this.i();return e(t)}matchesField(t){if(!this.fields)return true;if(!t)return!this.inverted;if(this.fields&&!this.u)this.u=this.t.fieldMatcher(this.fields);return this.u(t)}}function N(t,e){const i={value:t,prev:e,next:null};if(e)e.next=i;return i}function Q(t){if(t.next)t.next.prev=t.prev;if(t.prev)t.prev.next=t.next;t.next=t.prev=null}const V=t=>({value:t.value,prev:t.prev,next:t.next});const W=()=>({rules:[],merged:false});const X=()=>new Map;class Z{constructor(t=[],e={}){this.h=false;this.l={conditionsMatcher:e.conditionsMatcher,fieldMatcher:e.fieldMatcher,resolveAction:e.resolveAction||H};this.p=e.anyAction||"manage";this.g=e.anySubjectType||"all";this.$=e.detectSubjectType||q;this.A=t;this.j=this.M(t)}get rules(){return this.A}detectSubjectType(t){if(S(t))return t;if(!t)return this.g;return this.$(t)}update(t){const e={rules:t,ability:this,target:this};this.m("update",e);this.A=t;this.j=this.M(t);this.m("updated",e);return this}M(t){const e=new Map;for(let i=t.length-1;i>=0;i--){const s=t.length-i-1;const n=new K(t[i],this.l,s);const r=O(n.action);const o=O(n.subject||this.g);if(!this.h&&n.fields)this.h=true;for(let t=0;t<o.length;t++){const i=G(e,o[t],X);for(let t=0;t<r.length;t++)G(i,r[t],W).rules.push(n)}}return e}possibleRulesFor(t,e=this.g){if(!S(e))throw new Error('"possibleRulesFor" accepts only subject types (i.e., string or class) as the 2nd parameter');const i=G(this.j,e,X);const s=G(i,t,W);if(s.merged)return s.rules;const n=t!==this.p&&i.has(this.p)?i.get(this.p).rules:void 0;let r=U(s.rules,n);if(e!==this.g)r=U(r,this.possibleRulesFor(t,this.g));s.rules=r;s.merged=true;return r}rulesFor(t,e,i){const s=this.possibleRulesFor(t,e);if(i&&"string"!==typeof i)throw new Error("The 3rd, `field` parameter is expected to be a string. See https://stalniy.github.io/casl/en/api/casl-ability#can-of-pure-ability for details");if(!this.h)return s;return s.filter((t=>t.matchesField(i)))}actionsFor(t){if(!S(t))throw new Error('"actionsFor" accepts only subject types (iLine truncated
//# sourceMappingURL=index.mjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
+18
View File
@@ -0,0 +1,18 @@
import { PureAbility, AbilityOptions, AbilityOptionsOf } from './PureAbility';
import { RawRuleFrom } from './RawRule';
import { AbilityTuple } from './types';
import { MongoQuery } from './matchers/conditions';
import { Public, RawRuleOf } from './RuleIndex';
/**
* @deprecated use createMongoAbility function instead and MongoAbility<Abilities> interface.
* In the next major version PureAbility will be renamed to Ability and this class will be removed
*/
export declare class Ability<A extends AbilityTuple = AbilityTuple, C extends MongoQuery = MongoQuery> extends PureAbility<A, C> {
constructor(rules?: RawRuleFrom<A, C>[], options?: AbilityOptions<A, C>);
}
export interface AnyMongoAbility extends Public<PureAbility<any, MongoQuery>> {
}
export interface MongoAbility<A extends AbilityTuple = AbilityTuple, C extends MongoQuery = MongoQuery> extends PureAbility<A, C> {
}
export declare function createMongoAbility<T extends AnyMongoAbility = MongoAbility>(rules?: RawRuleOf<T>[], options?: AbilityOptionsOf<T>): T;
export declare function createMongoAbility<A extends AbilityTuple = AbilityTuple, C extends MongoQuery = MongoQuery>(rules?: RawRuleFrom<A, C>[], options?: AbilityOptions<A, C>): MongoAbility<A, C>;
+37
View File
@@ -0,0 +1,37 @@
import { AnyMongoAbility, MongoAbility } from './Ability';
import { ProduceGeneric } from './hkt';
import { AbilityOptionsOf, AnyAbility } from './PureAbility';
import { Generics, RawRuleOf } from './RuleIndex';
import { AbilityTuple, AnyClass, AnyObject, ExtractSubjectType as E, Normalize, SubjectType, TaggedInterface } from './types';
declare class RuleBuilder<T extends AnyAbility> {
_rule: RawRuleOf<T>;
constructor(rule: RawRuleOf<T>);
because(reason: string): this;
}
declare type AbilityFactory<T extends AnyAbility> = AnyClass<T> | ((rules?: any[], options?: any) => T);
declare type InstanceOf<T extends AnyAbility, S extends SubjectType> = S extends AnyClass<infer R> ? R : S extends (...args: any[]) => infer O ? O : S extends string ? Exclude<Normalize<Generics<T>['abilities']>[1], SubjectType> extends TaggedInterface<string> ? Extract<Normalize<Generics<T>['abilities']>[1], TaggedInterface<S>> : AnyObject : never;
declare type ConditionsOf<T extends AnyAbility, I extends {}> = ProduceGeneric<Generics<T>['conditions'], I>;
declare type ActionFrom<T extends AbilityTuple, S extends SubjectType> = T extends any ? S extends Extract<T[1], SubjectType> ? T[0] : never : never;
declare type ActionOf<T extends AnyAbility, S extends SubjectType> = ActionFrom<Generics<T>['abilities'], S>;
declare type SubjectTypeOf<T extends AnyAbility> = E<Normalize<Generics<T>['abilities']>[1]>;
declare type SimpleCanParams<T extends AnyAbility> = Parameters<(action: Generics<T>['abilities'] | Generics<T>['abilities'][]) => 0>;
declare type BuilderCanParameters<S extends SubjectType, I extends InstanceOf<T, S>, T extends AnyAbility> = Generics<T>['abilities'] extends AbilityTuple ? Parameters<(action: ActionOf<T, S> | ActionOf<T, S>[], subject: S | S[], conditions?: ConditionsOf<T, I>) => 0> : SimpleCanParams<T>;
declare type BuilderCanParametersWithFields<S extends SubjectType, I extends InstanceOf<T, S>, F extends string, T extends AnyAbility> = Generics<T>['abilities'] extends AbilityTuple ? Parameters<(action: ActionOf<T, S> | ActionOf<T, S>[], subject: S | S[], fields?: F | F[], conditions?: ConditionsOf<T, I>) => 0> : SimpleCanParams<T>;
declare type Keys<T> = string & keyof T;
declare type AddRule<T extends AnyAbility> = {
<I extends InstanceOf<T, S>, F extends string = Keys<I>, S extends SubjectTypeOf<T> = SubjectTypeOf<T>>(...args: BuilderCanParametersWithFields<S, I, F | Keys<I>, T>): RuleBuilder<T>;
<I extends InstanceOf<T, S>, S extends SubjectTypeOf<T> = SubjectTypeOf<T>>(...args: BuilderCanParameters<S, I, T>): RuleBuilder<T>;
};
export declare class AbilityBuilder<T extends AnyAbility> {
rules: RawRuleOf<T>[];
private readonly _createAbility;
can: AddRule<T>;
cannot: AddRule<T>;
build: (options?: AbilityOptionsOf<T>) => T;
constructor(AbilityType: AbilityFactory<T>);
private _addRule;
}
declare type DSL<T extends AnyAbility, R> = (can: AbilityBuilder<T>['can'], cannot: AbilityBuilder<T>['cannot']) => R;
export declare function defineAbility<T extends AnyMongoAbility = MongoAbility>(define: DSL<T, Promise<void>>, options?: AbilityOptionsOf<T>): Promise<T>;
export declare function defineAbility<T extends AnyMongoAbility = MongoAbility>(define: DSL<T, void>, options?: AbilityOptionsOf<T>): T;
export {};
+22
View File
@@ -0,0 +1,22 @@
import { AnyAbility } from './PureAbility';
import { Normalize } from './types';
import { Generics } from './RuleIndex';
export declare type GetErrorMessage = (error: ForbiddenError<AnyAbility>) => string;
/** @deprecated will be removed in the next major release */
export declare const getDefaultErrorMessage: GetErrorMessage;
declare const NativeError: new (message: string) => Error;
export declare class ForbiddenError<T extends AnyAbility> extends NativeError {
readonly ability: T;
action: Normalize<Generics<T>['abilities']>[0];
subject: Generics<T>['abilities'][1];
field?: string;
subjectType: string;
static _defaultErrorMessage: GetErrorMessage;
static setDefaultMessage(messageOrFn: string | GetErrorMessage): void;
static from<U extends AnyAbility>(ability: U): ForbiddenError<U>;
private constructor();
setMessage(message: string): this;
throwUnlessCan(...args: Parameters<T['can']>): void;
unlessCan(...args: Parameters<T['can']>): this | undefined;
}
export {};
+16
View File
@@ -0,0 +1,16 @@
import { RuleIndex, RuleIndexOptions, RuleIndexOptionsOf, Public, RawRuleOf } from './RuleIndex';
import { Abilities, AbilityTuple, CanParameters } from './types';
import { Rule } from './Rule';
export interface AbilityOptions<A extends Abilities, Conditions> extends RuleIndexOptions<A, Conditions> {
}
export interface AnyAbility extends Public<PureAbility<any, any>> {
}
export interface AbilityOptionsOf<T extends AnyAbility> extends RuleIndexOptionsOf<T> {
}
export declare type AbilityClass<T extends AnyAbility> = new (rules?: RawRuleOf<T>[], options?: AbilityOptionsOf<T>) => T;
export declare type CreateAbility<T extends AnyAbility> = (rules?: RawRuleOf<T>[], options?: AbilityOptionsOf<T>) => T;
export declare class PureAbility<A extends Abilities = AbilityTuple, Conditions = unknown> extends RuleIndex<A, Conditions> {
can(...args: CanParameters<A>): boolean;
relevantRuleFor(...args: CanParameters<A>): Rule<A, Conditions> | null;
cannot(...args: CanParameters<A>): boolean;
}
+21
View File
@@ -0,0 +1,21 @@
import { SubjectType, AbilityTypes, AbilityTupleType, Abilities, ToAbilityTypes } from './types';
interface BaseRawRule<Conditions> {
fields?: string | string[];
conditions?: Conditions;
/** indicates that rule forbids something (i.e., has inverted logic) */
inverted?: boolean;
/** explains the reason of why rule does not allow to do something */
reason?: string;
}
export interface ClaimRawRule<A extends string> extends BaseRawRule<undefined> {
action: A | A[];
subject?: undefined;
}
export interface SubjectRawRule<A extends string, S extends SubjectType, C> extends BaseRawRule<C> {
action: A | A[];
subject: S | S[];
}
declare type DefineRule<T extends AbilityTypes, C, Else = ClaimRawRule<Extract<T, string>>> = T extends AbilityTupleType ? SubjectRawRule<T[0], T[1], C> : Else;
export declare type RawRule<T extends AbilityTypes = AbilityTupleType, C = unknown> = DefineRule<T, C>;
export declare type RawRuleFrom<T extends Abilities, C> = RawRule<ToAbilityTypes<T>, C>;
export {};
+27
View File
@@ -0,0 +1,27 @@
import { Abilities, ToAbilityTypes, Normalize, ConditionsMatcher, FieldMatcher } from './types';
import { RawRule } from './RawRule';
declare type Tuple<A extends Abilities> = Normalize<ToAbilityTypes<A>>;
export interface RuleOptions<Conditions> {
conditionsMatcher?: ConditionsMatcher<Conditions>;
fieldMatcher?: FieldMatcher;
resolveAction(action: string | string[]): string | string[];
}
export declare class Rule<A extends Abilities, C> {
private _matchConditions;
private _matchField;
private readonly _options;
readonly action: Tuple<A>[0] | Tuple<A>[0][];
readonly subject: Tuple<A>[1] | Tuple<A>[1][];
readonly inverted: boolean;
readonly conditions: C | undefined;
readonly fields: string[] | undefined;
readonly reason: string | undefined;
readonly origin: RawRule<ToAbilityTypes<A>, C>;
readonly priority: number;
constructor(rule: RawRule<ToAbilityTypes<A>, C>, options: RuleOptions<C>, priority?: number);
private _conditionsMatcher;
get ast(): import("@ucast/mongo2js").Condition<unknown> | undefined;
matchesConditions(object: Normalize<A>[1] | undefined): boolean;
matchesField(field: string | undefined): boolean;
}
export {};
+68
View File
@@ -0,0 +1,68 @@
import { Rule, RuleOptions } from './Rule';
import { RawRuleFrom } from './RawRule';
import { Abilities, Normalize, SubjectType, AbilityParameters, AbilityTuple, ExtractSubjectType } from './types';
import { LinkedItem } from './structures/LinkedItem';
export interface RuleIndexOptions<A extends Abilities, C> extends Partial<RuleOptions<C>> {
detectSubjectType?(subject: Exclude<Normalize<A>[1], SubjectType>): ExtractSubjectType<Normalize<A>[1]>;
anyAction?: string;
anySubjectType?: string;
}
export declare const ɵabilities: unique symbol;
export declare const ɵconditions: unique symbol;
interface WithGenerics {
[ɵabilities]: any;
[ɵconditions]: any;
}
export declare type Public<T extends WithGenerics> = {
[K in keyof T]: T[K];
};
export interface Generics<T extends WithGenerics> {
abilities: T[typeof ɵabilities];
conditions: T[typeof ɵconditions];
}
export declare type RuleOf<T extends WithGenerics> = Rule<Generics<T>['abilities'], Generics<T>['conditions']>;
export declare type RawRuleOf<T extends WithGenerics> = RawRuleFrom<Generics<T>['abilities'], Generics<T>['conditions']>;
export declare type RuleIndexOptionsOf<T extends WithGenerics> = RuleIndexOptions<Generics<T>['abilities'], Generics<T>['conditions']>;
interface AbilityEvent<T extends WithGenerics> {
target: T;
/** @deprecated use "target" property instead */
ability: T;
}
export interface UpdateEvent<T extends WithGenerics> extends AbilityEvent<T> {
rules: RawRuleOf<T>[];
}
/**
* @deprecated `on`/`emit` properly infer type without this type
* TODO(major): delete
*/
export declare type EventHandler<Event> = (event: Event) => void;
export declare type Events<T extends WithGenerics, K extends keyof EventsMap<T> = keyof EventsMap<T>> = Map<K, LinkedItem<EventsMap<T>[K]> | null>;
interface EventsMap<T extends WithGenerics> {
update(event: UpdateEvent<T>): void;
updated(event: UpdateEvent<T>): void;
}
export declare type Unsubscribe = () => void;
declare type AbilitySubjectTypeParameters<T extends Abilities, IncludeField extends boolean = true> = AbilityParameters<T, T extends AbilityTuple ? IncludeField extends true ? (action: T[0], subject: ExtractSubjectType<T[1]>, field?: string) => 0 : (action: T[0], subject: ExtractSubjectType<T[1]>) => 0 : never, (action: Extract<T, string>) => 0>;
export declare class RuleIndex<A extends Abilities, Conditions> {
private _hasPerFieldRules;
private _events?;
private _indexedRules;
private _rules;
private readonly _ruleOptions;
private readonly _detectSubjectType;
private readonly _anyAction;
private readonly _anySubjectType;
readonly [ɵabilities]: A;
readonly [ɵconditions]: Conditions;
constructor(rules?: RawRuleFrom<A, Conditions>[], options?: RuleIndexOptions<A, Conditions>);
get rules(): (import("./types").ToAbilityTypes<A> extends infer T ? T extends import("./types").ToAbilityTypes<A> ? T extends import("./types").AbilityTupleType<string, SubjectType> ? import("./RawRule").SubjectRawRule<T[0], T[1], Conditions> : import("./RawRule").ClaimRawRule<Extract<import("./types").ToAbilityTypes<A>, string>> : never : never)[];
detectSubjectType(object?: Normalize<A>[1]): ExtractSubjectType<Normalize<A>[1]>;
update(rules: RawRuleFrom<A, Conditions>[]): Public<this>;
private _buildIndexFor;
possibleRulesFor(...args: AbilitySubjectTypeParameters<A, false>): Rule<A, Conditions>[];
rulesFor(...args: AbilitySubjectTypeParameters<A>): Rule<A, Conditions>[];
actionsFor(subjectType: ExtractSubjectType<Normalize<A>[1]>): string[];
on<T extends keyof EventsMap<this>>(event: T, handler: EventsMap<Public<this>>[T]): Unsubscribe;
private _emit;
}
export {};
+49
View File
@@ -0,0 +1,49 @@
import { Condition } from '@ucast/mongo2js';
import { PureAbility, AnyAbility } from './PureAbility';
import { RuleOf } from './RuleIndex';
import { RawRule } from './RawRule';
import { Rule } from './Rule';
import { AnyObject, SubjectType, ExtractSubjectType } from './types';
export declare type RuleToQueryConverter<T extends AnyAbility> = (rule: RuleOf<T>) => object;
export interface AbilityQuery<T = object> {
$or?: T[];
$and?: T[];
}
export declare function rulesToQuery<T extends AnyAbility>(ability: T, action: Parameters<T['rulesFor']>[0], subjectType: ExtractSubjectType<Parameters<T['rulesFor']>[1]>, convert: RuleToQueryConverter<T>): AbilityQuery | null;
export declare function rulesToAST<T extends AnyAbility>(ability: T, action: Parameters<T['rulesFor']>[0], subjectType: ExtractSubjectType<Parameters<T['rulesFor']>[1]>): Condition | null;
export declare function rulesToFields<T extends PureAbility<any, AnyObject>>(ability: T, action: Parameters<T['rulesFor']>[0], subjectType: ExtractSubjectType<Parameters<T['rulesFor']>[1]>): AnyObject;
export declare type GetRuleFields<R extends Rule<any, any>> = (rule: R) => string[];
export interface PermittedFieldsOptions<T extends AnyAbility> {
fieldsFrom: GetRuleFields<RuleOf<T>>;
}
export declare function permittedFieldsOf<T extends AnyAbility>(ability: T, action: Parameters<T['can']>[0], subject: Parameters<T['can']>[1], options: PermittedFieldsOptions<T>): string[];
export declare type PackRule<T extends RawRule<any, any>> = [
string,
string
] | [
string,
string,
T['conditions']
] | [
string,
string,
T['conditions'] | 0,
1
] | [
string,
string,
T['conditions'] | 0,
1 | 0,
string
] | [
string,
string,
T['conditions'] | 0,
1 | 0,
string | 0,
string
];
export declare type PackSubjectType<T extends SubjectType> = (type: T) => string;
export declare function packRules<T extends RawRule<any, any>>(rules: T[], packSubject?: PackSubjectType<T['subject']>): PackRule<T>[];
export declare type UnpackSubjectType<T extends SubjectType> = (type: string) => T;
export declare function unpackRules<T extends RawRule<any, any>>(rules: PackRule<T>[], unpackSubject?: UnpackSubjectType<T['subject']>): T[];
+15
View File
@@ -0,0 +1,15 @@
export declare const ɵvalue: unique symbol;
export declare type Container<T> = {
[ɵvalue]?: T;
};
export declare type Unpack<T extends Container<any>> = Exclude<T[typeof ɵvalue], undefined>;
export interface Generic<T1 = unknown, T2 = unknown, T3 = unknown, T4 = unknown> {
0: T1;
1: T2;
2: T3;
3: T4;
}
export interface GenericFactory<T1 = unknown, T2 = unknown, T3 = unknown, T4 = unknown> extends Generic<T1, T2, T3, T4> {
produce: unknown;
}
export declare type ProduceGeneric<T, U> = T extends Container<any> ? (Unpack<T> & Generic<U>)['produce'] : T;
+12
View File
@@ -0,0 +1,12 @@
export * from './Ability';
export * from './PureAbility';
export * from './AbilityBuilder';
export * from './ForbiddenError';
export * from './RawRule';
export * from './hkt';
export * from './matchers/conditions';
export * from './matchers/field';
export type { SubjectClass, SubjectType, Subject, AbilityTuple, Abilities, Normalize, IfString, AbilityParameters, CanParameters, ExtractSubjectType, InferSubjects, ForcedSubject, MatchConditions, ConditionsMatcher, MatchField, FieldMatcher, } from './types';
export type { Generics, RuleOf, RawRuleOf, UpdateEvent, EventHandler, Unsubscribe } from './RuleIndex';
export * as hkt from './hkt';
export { setSubjectType as subject, detectSubjectType, createAliasResolver, wrapArray } from './utils';
+7
View File
@@ -0,0 +1,7 @@
{
"__symbolic": "module",
"version": 4,
"metadata": {},
"origins": {},
"importAs": "@casl/ability"
}
+35
View File
@@ -0,0 +1,35 @@
import { createFactory, BuildMongoQuery, DefaultOperators } from '@ucast/mongo2js';
import { ConditionsMatcher, AnyObject } from '../types';
import { Container, GenericFactory } from '../hkt';
declare const defaultInstructions: {
$eq: import("@ucast/mongo2js").FieldInstruction<unknown, import("@ucast/mongo2js").FieldParsingContext>;
$ne: import("@ucast/mongo2js").FieldInstruction<unknown, import("@ucast/mongo2js").FieldParsingContext>;
$lt: import("@ucast/mongo2js").FieldInstruction<string | number | Date, import("@ucast/mongo2js").FieldParsingContext>;
$lte: import("@ucast/mongo2js").FieldInstruction<string | number | Date, import("@ucast/mongo2js").FieldParsingContext>;
$gt: import("@ucast/mongo2js").FieldInstruction<string | number | Date, import("@ucast/mongo2js").FieldParsingContext>;
$gte: import("@ucast/mongo2js").FieldInstruction<import("@ucast/mongo2js").Comparable, import("@ucast/mongo2js").FieldParsingContext>;
$in: import("@ucast/mongo2js").FieldInstruction<unknown[], import("@ucast/mongo2js").FieldParsingContext>;
$nin: import("@ucast/mongo2js").FieldInstruction<unknown[], import("@ucast/mongo2js").FieldParsingContext>;
$all: import("@ucast/mongo2js").FieldInstruction<unknown[], import("@ucast/mongo2js").FieldParsingContext>;
$size: import("@ucast/mongo2js").FieldInstruction<number, import("@ucast/mongo2js").FieldParsingContext>;
$regex: import("@ucast/mongo2js").FieldInstruction<string | RegExp, import("@ucast/mongo2js").RegExpFieldContext>;
$options: import("@ucast/mongo2js").FieldInstruction<unknown, import("@ucast/mongo2js").FieldParsingContext>;
$elemMatch: import("@ucast/mongo2js").FieldInstruction<(import("@ucast/mongo2js").MongoQueryFieldOperators<any> & import("@ucast/mongo2js").MongoQueryTopLevelOperators<any>) | ({
[x: string]: any;
} & import("@ucast/mongo2js").MongoQueryTopLevelOperators<any>), import("@ucast/mongo2js").ObjectQueryFieldParsingContext>;
$exists: import("@ucast/mongo2js").FieldInstruction<boolean, import("@ucast/mongo2js").FieldParsingContext>;
};
interface MongoQueryFactory extends GenericFactory {
produce: MongoQuery<this[0]>;
}
declare type MergeUnion<T, Keys extends keyof T = keyof T> = {
[K in Keys]: T[K];
};
export declare type MongoQuery<T = AnyObject> = BuildMongoQuery<MergeUnion<T>, {
toplevel: {};
field: Pick<DefaultOperators<MergeUnion<T>>['field'], keyof typeof defaultInstructions>;
}> & Container<MongoQueryFactory>;
declare type MongoQueryMatcherFactory = (...args: Partial<Parameters<typeof createFactory>>) => ConditionsMatcher<MongoQuery>;
export declare const buildMongoQueryMatcher: MongoQueryMatcherFactory;
export declare const mongoQueryMatcher: import("@ucast/mongo2js").Filter;
export type { MongoQueryFieldOperators, MongoQueryTopLevelOperators, MongoQueryOperators, } from '@ucast/mongo2js';
+2
View File
@@ -0,0 +1,2 @@
import { FieldMatcher } from '../types';
export declare const fieldPatternMatcher: FieldMatcher;
@@ -0,0 +1,12 @@
export interface LinkedItem<T> {
next: LinkedItem<T> | null;
prev: LinkedItem<T> | null;
readonly value: T;
}
export declare function linkedItem<T>(value: T, prev: LinkedItem<T>['prev']): {
value: T;
prev: LinkedItem<T> | null;
next: null;
};
export declare function unlinkItem(item: LinkedItem<any>): void;
export declare const cloneLinkedItem: <T extends LinkedItem<any>>(item: T) => T;
+46
View File
@@ -0,0 +1,46 @@
import type { Condition } from '@ucast/mongo2js';
import { Container, GenericFactory } from './hkt';
declare type Fn = (...args: any[]) => any;
export declare type AnyClass<ReturnType = any> = new (...args: any[]) => ReturnType;
declare type AnyRecord = Record<PropertyKey, any>;
export declare type AnyObject = Record<PropertyKey, unknown>;
export declare type SubjectClass<N extends string = string> = AnyClass & {
modelName?: N;
};
export declare type SubjectType = string | SubjectClass;
export declare type Subject = AnyRecord | SubjectType;
export declare type AbilityTuple<X extends string = string, Y extends Subject = Subject> = [X, Y];
export declare type Abilities = AbilityTuple | string;
export declare type ToAbilityTypes<T extends Abilities> = T extends AbilityTuple ? AbilityTupleType<T[0], ExtractSubjectType<T[1]>> : Extract<T, string>;
export declare type AbilityTupleType<T extends string = string, U extends SubjectType = SubjectType> = [T, U];
export declare type AbilityTypes = string | AbilityTupleType;
export declare type Normalize<T extends Abilities> = T extends AbilityTuple ? T : [T, string];
export declare type IfString<T, U> = T extends string ? U : never;
export declare type AbilityParameters<T extends Abilities, TupleFunction extends Fn, StringFunction extends Fn = () => 0, Else = IfString<T, Parameters<StringFunction>>> = T extends AbilityTuple ? Parameters<TupleFunction> : Else;
export declare type CanParameters<T extends Abilities, IncludeField extends boolean = true> = AbilityParameters<T, T extends AbilityTuple ? IncludeField extends true ? (action: T[0], subject: T[1], field?: string) => 0 : (action: T[0], subject: T[1]) => 0 : never, (action: Extract<T, string>) => 0>;
export declare type ExtractSubjectType<S extends Subject> = Extract<S, SubjectType> | TagName<S>;
declare type SubjectClassWithCustomName<T> = AnyClass & {
modelName: T;
};
export declare type InferSubjects<T, IncludeTagName extends boolean = false> = T | (T extends AnyClass<infer I> ? I | (IncludeTagName extends true ? T extends SubjectClassWithCustomName<infer Name> ? Name : TagName<I> : never) : TagName<T>);
export interface ForcedSubject<T> {
readonly __caslSubjectType__: T;
}
export declare type TaggedInterface<T extends string> = ForcedSubject<T> | {
readonly kind: T;
} | {
readonly __typename: T;
};
declare type TagName<T> = T extends TaggedInterface<infer U> ? U : never;
interface MatchConditionsFactory extends GenericFactory<{}> {
produce: MatchConditions<this[0]>;
}
export declare type MatchConditions<T extends {} = AnyRecord> = Container<MatchConditionsFactory> & {
(object: T): boolean;
ast?: Condition;
};
export declare type ConditionsMatcher<T> = (conditions: T) => MatchConditions;
export declare type MatchField<T extends string> = (field: T) => boolean;
export declare type FieldMatcher = <T extends string>(fields: T[]) => MatchField<T>;
export declare type AliasesMap = Record<string, string | string[]>;
export {};
+17
View File
@@ -0,0 +1,17 @@
import { AnyObject, Subject, SubjectType, ForcedSubject, AliasesMap } from './types';
export declare function wrapArray<T>(value: T[] | T): T[];
export declare function setByPath(object: AnyObject, path: string, value: unknown): void;
export declare function setSubjectType<T extends string, U extends Record<PropertyKey, any>>(type: T, object: U): U & ForcedSubject<T>;
export declare const isSubjectType: (value: unknown) => value is SubjectType;
export declare const getSubjectTypeName: (value: SubjectType) => string;
export declare function detectSubjectType(subject: Exclude<Subject, SubjectType>): string;
export declare type AliasResolverOptions = {
skipValidate?: boolean;
anyAction?: string;
};
export declare function createAliasResolver(aliasMap: AliasesMap, options?: AliasResolverOptions): (action: string | string[]) => string[];
export declare function mergePrioritized<T extends {
priority: number;
}>(array?: T[], anotherArray?: T[]): T[];
export declare function getOrDefault<K, V>(map: Map<K, V>, key: K, defaultValue: () => V): V;
export declare const identity: <T>(x: T) => T;
+2
View File
@@ -0,0 +1,2 @@
(function(r,n){"object"===typeof exports&&"undefined"!==typeof module?n(exports,require("@ucast/mongo2js")):"function"===typeof define&&define.amd?define(["exports","@ucast/mongo2js"],n):(r="undefined"!==typeof globalThis?globalThis:r||self,n((r.casl=r.casl||{},r.casl.extra={}),r.ucast.mongo2js))})(this,(function(r,n){"use strict";function e(r){return Array.isArray(r)?r:[r]}function t(r,n,e){var t=r;var u=n;if(-1!==n.indexOf(".")){var o=n.split(".");u=o.pop();t=o.reduce((function(r,n){r[n]=r[n]||{};return r[n]}),r)}t[u]=e}Object.hasOwn||Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);function u(r,n,e,t){var u={};var o=r.rulesFor(n,e);for(var i=0;i<o.length;i++){var f=o[i];var a=f.inverted?"$and":"$or";if(!f.conditions)if(f.inverted)break;else{delete u[a];return u}else{u[a]=u[a]||[];u[a].push(t(f))}}return u.$or?u:null}function o(r){if(!r.ast)throw new Error('Ability rule "'+JSON.stringify(r)+'" does not have "ast" property. So, cannot be used to generate AST');return r.inverted?new n.CompoundCondition("not",[r.ast]):r.ast}function i(r,e,t){var i=u(r,e,t,o);if(null===i)return null;if(!i.$and)return i.$or?n.buildOr(i.$or):n.buildAnd([]);if(i.$or)i.$and.push(n.buildOr(i.$or));return n.buildAnd(i.$and)}function f(r,n,e){return r.rulesFor(n,e).reduce((function(r,n){if(n.inverted||!n.conditions)return r;return Object.keys(n.conditions).reduce((function(r,e){var u=n.conditions[e];if(!u||u.constructor!==Object)t(r,e,u);return r}),r)}),{})}function a(r,n,e,t){var u=r.detectSubjectType(e);var o=r.possibleRulesFor(n,u);var i=new Set;var f=i.delete.bind(i);var a=i.add.bind(i);var c=o.length;while(c--){var v=o[c];if(v.matchesConditions(e)){var l=v.inverted?f:a;t.fieldsFrom(v).forEach(l)}}return Array.from(i)}var c=function r(n){return Array.isArray(n)?n.join(","):n};function v(r,n){return r.map((function(r){var t=[c(r.action||r.actions),"function"===typeof n?e(r.subject).map(n).join(","):c(r.subject),r.conditions||0,r.inverted?1:0,r.fields?c(r.fields):0,r.reason||""];while(t.length>0&&!t[t.length-1])t.pop();return t}))}function l(r,n){return r.map((function(r){var e=r[0],t=r[1],u=r[2],o=r[3],i=r[4],f=r[5];var a=t.split(",");var c={inverted:!!o,action:e.split(","),subject:"function"===typeof n?a.map(n):a};if(u)c.conditions=u;if(i)c.fields=i.split(",");if(f)c.reason=f;return c}))}r.packRules=v;r.permittedFieldsOf=a;r.rulesToAST=i;r.rulesToFields=f;r.rulesToQuery=u;r.unpackRules=l;Object.defineProperty(r,"__esModule",{value:true})}));
//# sourceMappingURL=extra.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"extra.js","sources":["../../src/utils.ts","../../src/extra.ts"],"sourcesContent":["import { AnyObject, Subject, SubjectType, SubjectClass, ForcedSubject, AliasesMap } from './types';\n\nexport function wrapArray<T>(value: T[] | T): T[] {\n return Array.isArray(value) ? value : [value];\n}\n\nexport function setByPath(object: AnyObject, path: string, value: unknown): void {\n let ref = object;\n let lastKey = path;\n\n if (path.indexOf('.') !== -1) {\n const keys = path.split('.');\n\n lastKey = keys.pop()!;\n ref = keys.reduce((res, prop) => {\n res[prop] = res[prop] || {};\n return res[prop] as AnyObject;\n }, object);\n }\n\n ref[lastKey] = value;\n}\n\nconst hasOwnProperty = (Object as any).hasOwn\n || Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);\n\nconst TYPE_FIELD = '__caslSubjectType__';\nexport function setSubjectType<\n T extends string,\n U extends Record<PropertyKey, any>\n>(type: T, object: U): U & ForcedSubject<T> {\n if (object) {\n if (!hasOwnProperty(object, TYPE_FIELD)) {\n Object.defineProperty(object, TYPE_FIELD, { value: type });\n } else if (type !== object[TYPE_FIELD]) {\n throw new Error(`Trying to cast object to subject type ${type} but previously it was casted to ${object[TYPE_FIELD]}`);\n }\n }\n\n return object as U & ForcedSubject<T>;\n}\n\nexport const isSubjectType = (value: unknown): value is SubjectType => {\n const type = typeof value;\n return type === 'string' || type === 'function';\n};\n\nconst getSubjectClassName = (value: SubjectClass) => value.modelName || value.name;\nexport const getSubjectTypeName = (value: SubjectType) => {\n return typeof value === 'string' ? value : getSubjectClassName(value);\n};\n\nexport function detectSubjectType(subject: Exclude<Subject, SubjectType>): string {\n if (hasOwnProperty(subject, TYPE_FIELD)) {\n return subject[TYPE_FIELD];\n }\n\n return getSubjectClassName(subject.constructor as SubjectClass);\n}\n\ntype AliasMerge = (actions: string[], action: string | string[]) => string[];\nfunction expandActions(aliasMap: AliasesMap, rawActions: string | string[], merge: AliasMerge) {\n let actions = wrapArray(rawActions);\n let i = 0;\n\n while (i < actions.length) {\n const action = actions[i++];\n\n if (hasOwnProperty(aliasMap, action)) {\n actions = merge(actions, aliasMap[action]);\n }\n }\n\n return actions;\n}\n\nfunction findDuplicate(actions: string[], actionToFind: string | string[]) {\n if (typeof actionToFind === 'string' && actions.indexOf(actionToFind) !== -1) {\n return actionToFind;\n }\n\n for (let i = 0; i < actionToFind.length; i++) {\n if (actions.indexOf(actionToFind[i]) !== -1) return actionToFind[i];\n }\n\n return null;\n}\n\nconst defaultAliasMerge: AliasMerge = (actions, action) => actions.concat(action);\nfunction validateForCycles(aliasMap: AliasesMap, reservedAction: string) {\n if (reservedAction in aliasMap) {\n throw new Error(`Cannot use \"${reservedAction}\" as an alias because it's reserved action.`);\n }\n\n const keys = Object.keys(aliasMap);\n const mergeAliasesAndDetectCycles: AliasMerge = (actions, action) => {\n const duplicate = findDuplicate(actions, action);\n if (duplicate) throw new Error(`Detected cycle ${duplicate} -> ${actions.join(', ')}`);\n\n const isUsingReservedAction = typeof action === 'string' && action === reservedAction\n || actions.indexOf(reservedAction) !== -1\n || Array.isArray(action) && action.indexOf(reservedAction) !== -1;\n if (isUsingReservedAction) throw new Error(`Cannot make an alias to \"${reservedAction}\" because this is reserved action`);\n\n return actions.concat(action);\n };\n\n for (let i = 0; i < keys.length; i++) {\n expandActions(aliasMap, keys[i], mergeAliasesAndDetectCycles);\n }\n}\n\nexport type AliasResolverOptions = { skipValidate?: boolean; anyAction?: string };\nexport function createAliasResolver(aliasMap: AliasesMap, options?: AliasResolverOptions) {\n if (!options || options.skipValidate !== false) {\n validateForCycles(aliasMap, options && options.anyAction || 'manage');\n }\n\n return (action: string | string[]) => expandActions(aliasMap, action, defaultAliasMerge);\n}\n\nfunction copyArrayTo<T>(dest: T[], target: T[], start: number) {\n for (let i = start; i < target.length; i++) {\n dest.push(target[i]);\n }\n}\n\nexport function mergePrioritized<T extends { priority: number }>(\n array?: T[],\n anotherArray?: T[]\n): T[] {\n if (!array || !array.length) {\n return anotherArray || [];\n }\n\n if (!anotherArray || !anotherArray.length) {\n return array || [];\n }\n\n let i = 0;\n let j = 0;\n const merged: T[] = [];\n\n while (i < array.length && j < anotherArray.length) {\n if (array[i].priority < anotherArray[j].priority) {\n merged.push(array[i]);\n i++;\n } else {\n merged.push(anotherArray[j]);\n j++;\n }\nLine truncated
+2
View File
@@ -0,0 +1,2 @@
(function(t,r){"object"===typeof exports&&"undefined"!==typeof module?r(exports,require("@ucast/mongo2js")):"function"===typeof define&&define.amd?define(["exports","@ucast/mongo2js"],r):(t="undefined"!==typeof globalThis?globalThis:t||self,r(t.casl={},t.ucast.mongo2js))})(this,(function(t,r){"use strict";function i(t,r){for(var i=0;i<r.length;i++){var n=r[i];n.enumerable=n.enumerable||false;n.configurable=true;if("value"in n)n.writable=true;Object.defineProperty(t,a(n.key),n)}}function n(t,r,n){if(r)i(t.prototype,r);if(n)i(t,n);Object.defineProperty(t,"prototype",{writable:false});return t}function e(){e=Object.assign?Object.assign.bind():function(t){for(var r=1;r<arguments.length;r++){var i=arguments[r];for(var n in i)if(Object.prototype.hasOwnProperty.call(i,n))t[n]=i[n]}return t};return e.apply(this,arguments)}function u(t,r){t.prototype=Object.create(r.prototype);t.prototype.constructor=t;o(t,r)}function o(t,r){o=Object.setPrototypeOf?Object.setPrototypeOf.bind():function t(r,i){r.__proto__=i;return r};return o(t,r)}function f(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function s(t,r){if("object"!==typeof t||null===t)return t;var i=t[Symbol.toPrimitive];if(void 0!==i){var n=i.call(t,r||"default");if("object"!==typeof n)return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===r?String:Number)(t)}function a(t){var r=s(t,"string");return"symbol"===typeof r?r:String(r)}function c(t){return Array.isArray(t)?t:[t]}var h=Object.hasOwn||Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);var v="__caslSubjectType__";function l(t,r){if(r)if(!h(r,v))Object.defineProperty(r,v,{value:t});else if(t!==r[v])throw new Error("Trying to cast object to subject type "+t+" but previously it was casted to "+r[v]);return r}var d=function t(r){var i=typeof r;return"string"===i||"function"===i};var b=function t(r){return r.modelName||r.name};var y=function t(r){return"string"===typeof r?r:b(r)};function p(t){if(h(t,v))return t[v];return b(t.constructor)}function w(t,r,i){var n=c(r);var e=0;while(e<n.length){var u=n[e++];if(h(t,u))n=i(n,t[u])}return n}function g(t,r){if("string"===typeof r&&-1!==t.indexOf(r))return r;for(var i=0;i<r.length;i++)if(-1!==t.indexOf(r[i]))return r[i];return null}var j=function t(r,i){return r.concat(i)};function A(t,r){if(r in t)throw new Error('Cannot use "'+r+"\" as an alias because it's reserved action.");var i=Object.keys(t);var n=function t(i,n){var e=g(i,n);if(e)throw new Error("Detected cycle "+e+" -> "+i.join(", "));var u="string"===typeof n&&n===r||-1!==i.indexOf(r)||Array.isArray(n)&&-1!==n.indexOf(r);if(u)throw new Error('Cannot make an alias to "'+r+'" because this is reserved action');return i.concat(n)};for(var e=0;e<i.length;e++)w(t,i[e],n)}function E(t,r){if(!r||false!==r.skipValidate)A(t,r&&r.anyAction||"manage");return function(r){return w(t,r,j)}}function m(t,r,i){for(var n=i;n<r.length;n++)t.push(r[n])}function M(t,r){if(!t||!t.length)return r||[];if(!r||!r.length)return t||[];var i=0;var n=0;var e=[];while(i<t.length&&n<r.length)if(t[i].priority<r[n].priority){e.push(t[i]);i++}else{e.push(r[n]);n++}m(e,t,i);m(e,r,n);return e}function $(t,r,i){var n=t.get(r);if(!n){n=i();t.set(r,n)}return n}var O=function t(r){return r};function x(t,r){if(Array.isArray(t.fields)&&!t.fields.length)throw new Error("`rawRule.fields` cannot be an empty array. https://bit.ly/390miLa");if(t.fields&&!r.fieldMatcher)throw new Error('You need to pass "fieldMatcher" option in order to restrict access by fields');if(t.conditions&&!r.conditionsMatcher)throw new Error('You need to pass "conditionsMatcher" option in order to restrict access by conditions')}var _=function(){function t(t,r,i){if(void 0===i)i=0;x(t,r);this.action=r.resolveAction(t.action);this.subject=t.subject;this.inverted=!!t.inverted;this.conditions=t.conditions;this.reason=t.reason;this.origin=t;this.fields=t.fields?c(t.fields):void 0;this.priority=i;this.t=r}var r=t.prototype;r.i=function t(){if(this.conditions&&!this.u)this.u=this.t.conditionsMatcher(this.conditions);return this.u};r.matchesConditions=function t(r){if(!this.conditions)return true;if(!r||d(r))return!this.inverted;var i=this.i();return i(r)};r.matchesField=function t(r){if(!this.fields)return true;if(!r)return!this.inverted;if(this.fields&&!this.o)this.o=this.t.fieldMatcher(this.fields);return this.o(r)};n(t,[{key:"ast",get:function t(){var r=this.i();return r?r.ast:void 0}}]);return t}();function F(t,r){var i={value:t,prev:r,next:null};if(r)r.next=i;return i}function S(t){if(t.next)t.next.prev=t.prev;if(t.prev)t.prev.next=t.next;t.next=t.prev=null}var T=function t(r){return{value:r.value,prev:r.prev,next:r.next}};var C=function t(){return{rules:[],merged:false}};var P=function t(){return new Map};var R=function(){function t(t,r){if(void 0===t)t=[];if(void 0===r)r={};this.h=false;this.v={conditionsMatcher:r.conditionsMatcher,fieldMatcher:r.fieldMaLine truncated
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sources":["../../src/utils.ts","../../src/Rule.ts","../../src/structures/LinkedItem.ts","../../src/RuleIndex.ts","../../src/PureAbility.ts","../../src/matchers/conditions.ts","../../src/matchers/field.ts","../../src/Ability.ts","../../src/AbilityBuilder.ts","../../src/ForbiddenError.ts"],"sourcesContent":["import { AnyObject, Subject, SubjectType, SubjectClass, ForcedSubject, AliasesMap } from './types';\n\nexport function wrapArray<T>(value: T[] | T): T[] {\n return Array.isArray(value) ? value : [value];\n}\n\nexport function setByPath(object: AnyObject, path: string, value: unknown): void {\n let ref = object;\n let lastKey = path;\n\n if (path.indexOf('.') !== -1) {\n const keys = path.split('.');\n\n lastKey = keys.pop()!;\n ref = keys.reduce((res, prop) => {\n res[prop] = res[prop] || {};\n return res[prop] as AnyObject;\n }, object);\n }\n\n ref[lastKey] = value;\n}\n\nconst hasOwnProperty = (Object as any).hasOwn\n || Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);\n\nconst TYPE_FIELD = '__caslSubjectType__';\nexport function setSubjectType<\n T extends string,\n U extends Record<PropertyKey, any>\n>(type: T, object: U): U & ForcedSubject<T> {\n if (object) {\n if (!hasOwnProperty(object, TYPE_FIELD)) {\n Object.defineProperty(object, TYPE_FIELD, { value: type });\n } else if (type !== object[TYPE_FIELD]) {\n throw new Error(`Trying to cast object to subject type ${type} but previously it was casted to ${object[TYPE_FIELD]}`);\n }\n }\n\n return object as U & ForcedSubject<T>;\n}\n\nexport const isSubjectType = (value: unknown): value is SubjectType => {\n const type = typeof value;\n return type === 'string' || type === 'function';\n};\n\nconst getSubjectClassName = (value: SubjectClass) => value.modelName || value.name;\nexport const getSubjectTypeName = (value: SubjectType) => {\n return typeof value === 'string' ? value : getSubjectClassName(value);\n};\n\nexport function detectSubjectType(subject: Exclude<Subject, SubjectType>): string {\n if (hasOwnProperty(subject, TYPE_FIELD)) {\n return subject[TYPE_FIELD];\n }\n\n return getSubjectClassName(subject.constructor as SubjectClass);\n}\n\ntype AliasMerge = (actions: string[], action: string | string[]) => string[];\nfunction expandActions(aliasMap: AliasesMap, rawActions: string | string[], merge: AliasMerge) {\n let actions = wrapArray(rawActions);\n let i = 0;\n\n while (i < actions.length) {\n const action = actions[i++];\n\n if (hasOwnProperty(aliasMap, action)) {\n actions = merge(actions, aliasMap[action]);\n }\n }\n\n return actions;\n}\n\nfunction findDuplicate(actions: string[], actionToFind: string | string[]) {\n if (typeof actionToFind === 'string' && actions.indexOf(actionToFind) !== -1) {\n return actionToFind;\n }\n\n for (let i = 0; i < actionToFind.length; i++) {\n if (actions.indexOf(actionToFind[i]) !== -1) return actionToFind[i];\n }\n\n return null;\n}\n\nconst defaultAliasMerge: AliasMerge = (actions, action) => actions.concat(action);\nfunction validateForCycles(aliasMap: AliasesMap, reservedAction: string) {\n if (reservedAction in aliasMap) {\n throw new Error(`Cannot use \"${reservedAction}\" as an alias because it's reserved action.`);\n }\n\n const keys = Object.keys(aliasMap);\n const mergeAliasesAndDetectCycles: AliasMerge = (actions, action) => {\n const duplicate = findDuplicate(actions, action);\n if (duplicate) throw new Error(`Detected cycle ${duplicate} -> ${actions.join(', ')}`);\n\n const isUsingReservedAction = typeof action === 'string' && action === reservedAction\n || actions.indexOf(reservedAction) !== -1\n || Array.isArray(action) && action.indexOf(reservedAction) !== -1;\n if (isUsingReservedAction) throw new Error(`Cannot make an alias to \"${reservedAction}\" because this is reserved action`);\n\n return actions.concat(action);\n };\n\n for (let i = 0; i < keys.length; i++) {\n expandActions(aliasMap, keys[i], mergeAliasesAndDetectCycles);\n }\n}\n\nexport type AliasResolverOptions = { skipValidate?: boolean; anyAction?: string };\nexport function createAliasResolver(aliasMap: AliasesMap, options?: AliasResolverOptions) {\n if (!options || options.skipValidate !== false) {\n validateForCycles(aliasMap, options && options.anyAction || 'manage');\n }\n\n return (action: string | string[]) => expandActions(aliasMap, action, defaultAliasMerge);\n}\n\nfunction copyArrayTo<T>(dest: T[], target: T[], start: number) {\n for (let i = start; i < target.length; i++) {\n dest.push(target[i]);\n }\n}\n\nexport function mergePrioritized<T extends { priority: number }>(\n array?: T[],\n anotherArray?: T[]\n): T[] {\n if (!array || !array.length) {\n return anotherArray || [];\n }\n\n if (!anotherArray || !anotherArray.length) {\n return array || [];\n }\n\n let i = 0;\n let j = 0;\n const merged: T[]Line truncated
+1
View File
@@ -0,0 +1 @@
export * from './extra/extra';
+1
View File
@@ -0,0 +1 @@
export * from '../dist/types/extra';
+7
View File
@@ -0,0 +1,7 @@
{
"name": "@casl/ability/extra",
"typings": "./extra.d.ts",
"main": "../dist/umd/extra.js",
"module": "../dist/es5m/extra.js",
"es2015": "../dist/es6/extra.js"
}
+1
View File
@@ -0,0 +1 @@
export * from './dist/types';
+73
View File
@@ -0,0 +1,73 @@
{
"name": "@casl/ability",
"version": "6.5.0",
"description": "CASL is an isomorphic authorization JavaScript library which restricts what resources a given user is allowed to access",
"funding": "https://github.com/stalniy/casl/blob/master/BACKERS.md",
"main": "dist/es6c/index.js",
"module": "dist/es5m/index.js",
"es2015": "dist/es6m/index.mjs",
"legacy": "dist/umd/index.js",
"typings": "./index.d.ts",
"exports": {
".": {
"types": "./dist/types/index.d.ts",
"import": "./dist/es6m/index.mjs",
"require": "./dist/es6c/index.js"
},
"./extra": {
"types": "./dist/types/extra.d.ts",
"import": "./dist/es6m/extra.mjs",
"require": "./dist/es6c/extra.js"
}
},
"sideEffects": false,
"repository": {
"type": "git",
"url": "https://github.com/stalniy/casl.git",
"directory": "packages/casl-ability"
},
"homepage": "https://casl.js.org",
"publishConfig": {
"access": "public"
},
"scripts": {
"build.core": "dx rollup -n casl -g @ucast/mongo2js:ucast.mongo2js",
"build.extra": "dx rollup -i src/extra.ts -n casl.extra -g @ucast/mongo2js:ucast.mongo2js",
"build.types": "dx tsc && cp index.metadata.json dist/types",
"prebuild": "rm -rf dist/*",
"build": "npm run build.types && npm run build.core && npm run build.extra",
"lint": "dx eslint src/ spec/",
"test": "dx jest",
"prerelease": "npm run lint && npm test && NODE_ENV=production npm run build",
"release": "dx semantic-release",
"preb": "echo 'pre'",
"b": "echo 123"
},
"keywords": [
"permissions",
"authorization",
"acl",
"abac",
"rbac",
"ibac",
"cancan"
],
"author": "Sergii Stotskyi <sergiy.stotskiy@gmail.com>",
"license": "MIT",
"devDependencies": {
"@casl/dx": "workspace:^1.0.0",
"@types/jest": "^29.0.0",
"@types/node": "^18.0.0",
"chai": "^4.1.0",
"chai-spies": "^1.0.0",
"expect-type": "^0.15.0"
},
"files": [
"dist",
"*.d.ts",
"extra"
],
"dependencies": {
"@ucast/mongo2js": "^1.3.0"
}
}