@casl/mongoose 7.2.2 → 7.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -45
- package/dist/es6c/index.js +1 -1
- package/dist/es6c/index.js.map +1 -1
- package/dist/es6m/index.mjs +1 -1
- package/dist/es6m/index.mjs.map +1 -1
- package/dist/types/accessibleBy.d.ts +21 -0
- package/dist/types/accessibleFieldsBy.d.ts +3 -0
- package/dist/types/index.d.ts +9 -8
- package/dist/types/plugins/accessible_fields.d.ts +49 -0
- package/dist/types/plugins/accessible_records.d.ts +37 -0
- package/package.json +1 -1
- package/dist/types/accessible_fields.d.ts +0 -25
- package/dist/types/accessible_records.d.ts +0 -13
- package/dist/types/mongo.d.ts +0 -22
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ async function main() {
|
|
|
37
37
|
let posts;
|
|
38
38
|
|
|
39
39
|
try {
|
|
40
|
-
posts = await db.collection('posts').find(accessibleBy(ability, 'update').Post);
|
|
40
|
+
posts = await db.collection('posts').find(accessibleBy(ability, 'update').ofType('Post'));
|
|
41
41
|
} finally {
|
|
42
42
|
db.close();
|
|
43
43
|
}
|
|
@@ -51,7 +51,7 @@ This can also be combined with other conditions with help of `$and` operator:
|
|
|
51
51
|
```js
|
|
52
52
|
posts = await db.collection('posts').find({
|
|
53
53
|
$and: [
|
|
54
|
-
accessibleBy(ability, 'update').Post,
|
|
54
|
+
accessibleBy(ability, 'update').ofType('Post'),
|
|
55
55
|
{ public: true }
|
|
56
56
|
]
|
|
57
57
|
});
|
|
@@ -61,7 +61,7 @@ posts = await db.collection('posts').find({
|
|
|
61
61
|
|
|
62
62
|
```js
|
|
63
63
|
// returns { authorId: 1 }
|
|
64
|
-
const permissionRestrictedConditions = accessibleBy(ability, 'update').Post;
|
|
64
|
+
const permissionRestrictedConditions = accessibleBy(ability, 'update').ofType('Post');
|
|
65
65
|
|
|
66
66
|
const query = {
|
|
67
67
|
...permissionRestrictedConditions,
|
|
@@ -71,60 +71,22 @@ const query = {
|
|
|
71
71
|
|
|
72
72
|
In the case above, we overwrote `authorId` property and basically allowed non-authorized access to posts of author with `id = 2`
|
|
73
73
|
|
|
74
|
-
If there are no permissions defined for particular action/subjectType, `accessibleBy` will return `{ $expr:
|
|
74
|
+
If there are no permissions defined for particular action/subjectType, `accessibleBy` will return `{ $expr: { $eq: [0, 1] } }` and when it's sent to MongoDB, database will return an empty result set.
|
|
75
75
|
|
|
76
76
|
#### Mongoose
|
|
77
77
|
|
|
78
|
+
|
|
78
79
|
```js
|
|
79
80
|
const Post = require('./Post') // mongoose model
|
|
80
81
|
const ability = require('./ability') // defines Ability instance
|
|
81
82
|
|
|
82
83
|
async function main() {
|
|
83
|
-
const accessiblePosts = await Post.find(accessibleBy(ability).Post);
|
|
84
|
+
const accessiblePosts = await Post.find(accessibleBy(ability).ofType('Post'));
|
|
84
85
|
console.log(accessiblePosts);
|
|
85
86
|
}
|
|
86
87
|
```
|
|
87
88
|
|
|
88
|
-
`
|
|
89
|
-
|
|
90
|
-
#### `accessibleBy` in TypeScript
|
|
91
|
-
|
|
92
|
-
If we want to get hints in IDE regarding what record types (i.e., entity or model names) can be accessed in return value of `accessibleBy` we can easily do this by using module augmentation:
|
|
93
|
-
|
|
94
|
-
```ts
|
|
95
|
-
import { accessibleBy } from '@casl/mongoose';
|
|
96
|
-
import { ability } from './ability'; // defines Ability instance
|
|
97
|
-
|
|
98
|
-
declare module '@casl/mongoose' {
|
|
99
|
-
interface RecordTypes {
|
|
100
|
-
Post: true
|
|
101
|
-
User: true
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
accessibleBy(ability).User // allows only User and Post properties
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
This can be done either centrally, in the single place or it can be defined in every model/entity definition file. For example, we can augment `@casl/mongoose` in every mongoose model definition file:
|
|
109
|
-
|
|
110
|
-
```js @{data-filename="Post.ts"}
|
|
111
|
-
import mongoose from 'mongoose';
|
|
112
|
-
|
|
113
|
-
const PostSchema = new mongoose.Schema({
|
|
114
|
-
title: String,
|
|
115
|
-
author: String
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
declare module '@casl/mongoose' {
|
|
119
|
-
interface RecordTypes {
|
|
120
|
-
Post: true
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export const Post = mongoose.model('Post', PostSchema)
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Historically, `@casl/mongoose` was intended for super easy integration with [mongoose] but now we re-orient it to be more MongoDB specific package because mongoose keeps bringing complexity and issues with ts types.
|
|
89
|
+
Historically, `@casl/mongoose` was intended for super easy integration with [mongoose] but now we re-orient it to be more MongoDB specific package due to complexity working with mongoose types in TS. This plugins are still shipped but deprecated and we encourage you either write own plugins on app level or use `accessibleBy` and `accessibleFieldsBy` helpers
|
|
128
90
|
|
|
129
91
|
### Accessible Records plugin
|
|
130
92
|
|
|
@@ -309,6 +271,38 @@ post.accessibleFieldsBy(ability); // ['title']
|
|
|
309
271
|
|
|
310
272
|
As you can see, a static method returns all fields that can be read for all posts. At the same time, an instance method returns fields that can be read from this particular `post` instance. That's why there is no much sense (except you want to reduce traffic between app and database) to pass the result of static method into `mongoose.Query`'s `select` method because eventually you will need to call `accessibleFieldsBy` on every instance.
|
|
311
273
|
|
|
274
|
+
### accessibleFieldsBy
|
|
275
|
+
|
|
276
|
+
`accessibleFieldsBy` is companion helper that allows to get only accessible fields for specific subject type of subject:
|
|
277
|
+
|
|
278
|
+
```ts
|
|
279
|
+
import { accessibleFieldsBy } from '@casl/mongoose';
|
|
280
|
+
import { Post } from './models';
|
|
281
|
+
|
|
282
|
+
accessibleFieldsBy(ability).ofType('Post') // returns accessible fields for Post model
|
|
283
|
+
accessibleFieldsBy(ability).ofType(Post) // also possible to pass class if classes are used for rule definition
|
|
284
|
+
accessibleFieldsBy(ability).of(new Post()) // returns accessible fields for Post model
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
This helper is pre-configured to get all fields from `Model.schema.paths`, if this is not desired or you need to restrict public fields your app work with, you need to define your own custom helper:
|
|
288
|
+
|
|
289
|
+
```ts
|
|
290
|
+
import { AnyMongoAbility, Generics } from "@casl/ability";
|
|
291
|
+
import { AccessibleFields, GetSubjectTypeAllFieldsExtractor } from "@casl/ability/extra";
|
|
292
|
+
import mongoose from 'mongoose';
|
|
293
|
+
|
|
294
|
+
const getSubjectTypeAllFieldsExtractor: GetSubjectTypeAllFieldsExtractor = (type) => {
|
|
295
|
+
/** custom implementation of returning all fields */
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
export function accessibleFieldsBy<T extends AnyMongoAbility>(
|
|
299
|
+
ability: T,
|
|
300
|
+
action: Parameters<T['rulesFor']>[0] = 'read'
|
|
301
|
+
): AccessibleFields<Extract<Generics<T>['abilities'], unknown[]>[1]> {
|
|
302
|
+
return new AccessibleFields(ability, action, getSubjectTypeAllFieldsExtractor);
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
312
306
|
## TypeScript support in mongoose
|
|
313
307
|
|
|
314
308
|
The package is written in TypeScript, this makes it easier to work with plugins and `toMongoQuery` helper because IDE provides useful hints. Let's see it in action!
|
package/dist/es6c/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var t=require("@casl/ability");var n=require("@casl/ability
|
|
1
|
+
"use strict";var t=require("@casl/ability/extra");var n=require("@casl/ability");var r=require("mongoose");function e(t){const n=t.conditions;return t.inverted?{$nor:[n]}:n}const o={$expr:{$eq:[0,1]}};class c{constructor(t,n){this.t=t;this.o=n}ofType(n){const r=t.rulesToQuery(this.t,this.o,n,e);return r===null?o:r}}function s(t,n="read"){return new c(t,n)}function i(t,n,r){const e=n.detectSubjectType({constructor:t.model});if(!e)throw new TypeError(`Cannot detect subject type of "${t.model.modelName}" to return accessible records`);const o=s(n,r).ofType(e);return t.and([o])}function u(t,n){return i(this.where(),t,n)}function f(t,n){return i(this,t,n)}function a(t){t.query.accessibleBy=f;t.statics.accessibleBy=u}const l=t=>Object.keys(t.paths);function h(t,r){const e=r.getFields(t);if(!r||!("except"in r))return e;const o=n.wrapArray(r.except);return e.filter((t=>o.indexOf(t)===-1))}function p(){let t;return(r,e)=>{if(!t){const o=e&&"only"in e?n.wrapArray(e.only):h(r,e);t=()=>o}return t}}function d(n,r){const e=Object.assign({getFields:l},r);const o=p();function c(r,c){return new t.AccessibleFields(r,c||"read",o(n,e)).of(this)}function s(r,c){const s={constructor:this};return new t.AccessibleFields(r,c||"read",o(n,e)).of(s)}n.statics.accessibleFieldsBy=s;n.method("accessibleFieldsBy",c)}const w=t=>{const n=typeof t==="string"?r.models[t]:t;if(!n)throw new Error(`Unknown mongoose model "${t}"`);return"schema"in n?Object.keys(n.schema.paths):[]};function b(n,r="read"){return new t.AccessibleFields(n,r,w)}exports.accessibleBy=s;exports.accessibleFieldsBy=b;exports.accessibleFieldsPlugin=d;exports.accessibleRecordsPlugin=a;exports.getSchemaPaths=l;
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/es6c/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/mongo.ts","../../src/accessible_records.ts","../../src/accessible_fields.ts"],"sourcesContent":["import { AnyMongoAbility } from '@casl/ability';\nimport { AbilityQuery, rulesToQuery } from '@casl/ability/extra';\n\nfunction convertToMongoQuery(rule: AnyMongoAbility['rules'][number]) {\n const conditions = rule.conditions!;\n return rule.inverted ? { $nor: [conditions] } : conditions;\n}\n\n/**\n * @deprecated use accessibleBy instead\n *\n * Converts ability action + subjectType to MongoDB query\n */\nexport function toMongoQuery<T extends AnyMongoAbility>(\n ability: T,\n subjectType: Parameters<T['rulesFor']>[1],\n action: Parameters<T['rulesFor']>[0] = 'read'\n): AbilityQuery | null {\n return rulesToQuery(ability, action, subjectType, convertToMongoQuery);\n}\n\nexport interface RecordTypes {\n}\ntype StringOrKeysOf<T> = keyof T extends never ? string : keyof T;\n\n/**\n * Returns Mongo query per record type (i.e., entity type) based on provided Ability and action.\n * In case action is not allowed, it returns `{ $expr: false }`\n */\nexport function accessibleBy<T extends AnyMongoAbility>(\n ability: T,\n action: Parameters<T['rulesFor']>[0] = 'read'\n): Record<StringOrKeysOf<RecordTypes>, AbilityQuery> {\n return new Proxy({\n _ability: ability,\n _action: action\n }, accessibleByProxyHandlers) as unknown as Record<StringOrKeysOf<RecordTypes>, AbilityQuery>;\n}\n\nexport const EMPTY_RESULT_QUERY = { $expr: { $eq: [0, 1] } };\nconst accessibleByProxyHandlers: ProxyHandler<{ _ability: AnyMongoAbility, _action: string }> = {\n get(target, subjectType) {\n const query = rulesToQuery(target._ability, target._action, subjectType, convertToMongoQuery);\n return query === null ? EMPTY_RESULT_QUERY : query;\n }\n};\n","import { Normalize, AnyMongoAbility, Generics, ForbiddenError } from '@casl/ability';\nimport { Schema, QueryWithHelpers, Model, Document, HydratedDocument, Query } from 'mongoose';\nimport { EMPTY_RESULT_QUERY, toMongoQuery } from './mongo';\n\nfunction failedQuery(\n ability: AnyMongoAbility,\n action: string,\n modelName: string,\n query: QueryWithHelpers<Document, Document>\n) {\n query.where(EMPTY_RESULT_QUERY);\n const anyQuery: any = query;\n\n if (typeof anyQuery.pre === 'function') {\n anyQuery.pre((cb: (error?: Error) => void) => {\n const error = ForbiddenError.from(ability).unlessCan(action, modelName);\n cb(error);\n });\n }\n\n return query;\n}\n\nfunction accessibleBy<T extends AnyMongoAbility>(\n baseQuery: Query<any, any>,\n ability: T,\n action?: Normalize<Generics<T>['abilities']>[0]\n): QueryWithHelpers<Document, Document> {\n const subjectType = ability.detectSubjectType({\n constructor: baseQuery.model\n });\n\n if (!subjectType) {\n throw new TypeError(`Cannot detect subject type of \"${baseQuery.model.modelName}\" to return accessible records`);\n }\n\n const query = toMongoQuery(ability, subjectType, action);\n\n if (query === null) {\n return failedQuery(ability, action || 'read', subjectType, baseQuery.where());\n }\n\n return baseQuery.and([query]);\n}\n\ntype GetAccessibleRecords<T, TQueryHelpers, TMethods, TVirtuals> = <U extends AnyMongoAbility>(\n ability: U,\n action?: Normalize<Generics<U>['abilities']>[0]\n) => QueryWithHelpers<\nArray<T>,\nT,\nAccessibleRecordQueryHelpers<T, TQueryHelpers, TMethods, TVirtuals>\n>;\n\nexport type AccessibleRecordQueryHelpers<T, TQueryHelpers = {}, TMethods = {}, TVirtuals = {}> = {\n /** @deprecated use accessibleBy helper instead */\n accessibleBy: GetAccessibleRecords<\n HydratedDocument<T, TMethods, TVirtuals>,\n TQueryHelpers,\n TMethods,\n TVirtuals\n >\n};\nexport interface AccessibleRecordModel<\n T,\n TQueryHelpers = {},\n TMethods = {},\n TVirtuals = {}\n> extends Model<T,\n TQueryHelpers & AccessibleRecordQueryHelpers<T, TQueryHelpers, TMethods, TVirtuals>,\n TMethods,\n TVirtuals> {\n /** @deprecated use accessibleBy helper instead */\n accessibleBy: GetAccessibleRecords<\n HydratedDocument<T, TMethods, TVirtuals>,\n TQueryHelpers,\n TMethods,\n TVirtuals\n >\n}\n\nfunction modelAccessibleBy(this: Model<unknown>, ability: AnyMongoAbility, action?: string) {\n return accessibleBy(this.where(), ability, action);\n}\n\nfunction queryAccessibleBy(\n this: Query<unknown, unknown>,\n ability: AnyMongoAbility,\n action?: string\n) {\n return accessibleBy(this, ability, action);\n}\n\nexport function accessibleRecordsPlugin(schema: Schema<any>): void {\n (schema.query as Record<string, unknown>).accessibleBy = queryAccessibleBy;\n schema.statics.accessibleBy = modelAccessibleBy;\n}\n","import { wrapArray, Normalize, AnyMongoAbility, Generics } from '@casl/ability';\nimport { permittedFieldsOf, PermittedFieldsOptions } from '@casl/ability/extra';\nimport type { Schema, Model, Document } from 'mongoose';\n\nexport type AccessibleFieldsOptions =\n {\n getFields(schema: Schema<Document>): string[]\n } &\n ({ only: string | string[] } | { except: string | string[] });\n\nexport const getSchemaPaths: AccessibleFieldsOptions['getFields'] = schema => Object.keys((schema as { paths: object }).paths);\n\nfunction fieldsOf(schema: Schema<Document>, options: Partial<AccessibleFieldsOptions>) {\n const fields = options.getFields!(schema);\n\n if (!options || !('except' in options)) {\n return fields;\n }\n\n const excludedFields = wrapArray(options.except);\n return fields.filter(field => excludedFields.indexOf(field) === -1);\n}\n\ntype GetAccessibleFields<T> = <U extends AnyMongoAbility>(\n this: Model<T> | T,\n ability: U,\n action?: Normalize<Generics<U>['abilities']>[0]\n) => string[];\n\nexport interface AccessibleFieldsModel<\n T,\n TQueryHelpers = {},\n TMethods = {},\n TVirtuals = {}\n> extends Model<T, TQueryHelpers, TMethods & AccessibleFieldDocumentMethods<T>, TVirtuals> {\n accessibleFieldsBy: GetAccessibleFields<T>\n}\n\nexport interface AccessibleFieldDocumentMethods<T = Document> {\n accessibleFieldsBy: GetAccessibleFields<T>\n}\n\n/**\n * @deprecated Mongoose recommends against `extends Document`, prefer to use `AccessibleFieldsModel` instead.\n * See here: https://mongoosejs.com/docs/typescript.html#using-extends-document\n */\nexport interface AccessibleFieldsDocument extends Document, AccessibleFieldDocumentMethods {}\n\nfunction modelFieldsGetter() {\n let fieldsFrom: PermittedFieldsOptions<AnyMongoAbility>['fieldsFrom'];\n return (schema: Schema<any>, options: Partial<AccessibleFieldsOptions>) => {\n if (!fieldsFrom) {\n const ALL_FIELDS = options && 'only' in options\n ? wrapArray(options.only as string[])\n : fieldsOf(schema, options);\n fieldsFrom = rule => rule.fields || ALL_FIELDS;\n }\n\n return fieldsFrom;\n };\n}\n\nexport function accessibleFieldsPlugin(\n schema: Schema<any>,\n rawOptions?: Partial<AccessibleFieldsOptions>\n): void {\n const options = { getFields: getSchemaPaths, ...rawOptions };\n const fieldsFrom = modelFieldsGetter();\n\n function istanceAccessibleFields(this: Document, ability: AnyMongoAbility, action?: string) {\n return permittedFieldsOf(ability, action || 'read', this, {\n fieldsFrom: fieldsFrom(schema, options)\n });\n }\n\n function modelAccessibleFields(this: Model<unknown>, ability: AnyMongoAbility, action?: string) {\n const document = { constructor: this };\n return permittedFieldsOf(ability, action || 'read', document, {\n fieldsFrom: fieldsFrom(schema, options)\n });\n }\n\n schema.statics.accessibleFieldsBy = modelAccessibleFields;\n schema.method('accessibleFieldsBy', istanceAccessibleFields);\n}\n"],"names":["convertToMongoQuery","rule","conditions","inverted","$nor","toMongoQuery","ability","subjectType","action","rulesToQuery","accessibleBy","Proxy","_ability","_action","accessibleByProxyHandlers","EMPTY_RESULT_QUERY","$expr","$eq","get","target","query","failedQuery","modelName","where","anyQuery","pre","cb","error","ForbiddenError","from","unlessCan","baseQuery","detectSubjectType","constructor","model","TypeError","and","modelAccessibleBy","this","queryAccessibleBy","accessibleRecordsPlugin","schema","statics","getSchemaPaths","Object","keys","paths","fieldsOf","options","fields","getFields","excludedFields","wrapArray","except","filter","field","indexOf","modelFieldsGetter","fieldsFrom","ALL_FIELDS","only","accessibleFieldsPlugin","rawOptions","assign","istanceAccessibleFields","permittedFieldsOf","modelAccessibleFields","document","accessibleFieldsBy","method"],"mappings":"iFAGA,SAASA,EAAoBC,GAC3B,MAAMC,EAAaD,EAAKC,WACxB,OAAOD,EAAKE,SAAW,CAAEC,KAAM,CAACF,IAAgBA,CAClD,CAOO,SAASG,EACdC,EACAC,EACAC,EAAuC,QAEvC,OAAOC,EAAYA,aAACH,EAASE,EAAQD,EAAaP,EACpD,CAUO,SAASU,EACdJ,EACAE,EAAuC,QAEvC,OAAO,IAAIG,MAAM,CACfC,EAAUN,EACVO,EAASL,GACRM,EACL,CAEO,MAAMC,EAAqB,CAAEC,MAAO,CAAEC,IAAK,CAAC,EAAG,KACtD,MAAMH,EAA0F,CAC9FI,GAAAA,CAAIC,EAAQZ,GACV,MAAMa,EAAQX,EAAYA,aAACU,EAAOP,EAAUO,EAAON,EAASN,EAAaP,GACzE,OAAOoB,IAAU,KAAOL,EAAqBK,CAC/C,GCxCF,SAASC,EACPf,EACAE,EACAc,EACAF,GAEAA,EAAMG,MAAMR,GACZ,MAAMS,EAAgBJ,EAEtB,UAAWI,EAASC,MAAQ,WAC1BD,EAASC,KAAKC,IACZ,MAAMC,EAAQC,EAAcA,eAACC,KAAKvB,GAASwB,UAAUtB,EAAQc,GAC7DI,EAAGC,EAAM,IAIb,OAAOP,CACT,CAEA,SAASV,EACPqB,EACAzB,EACAE,GAEA,MAAMD,EAAcD,EAAQ0B,kBAAkB,CAC5CC,YAAaF,EAAUG,QAGzB,IAAK3B,EACH,MAAM,IAAI4B,UAAW,kCAAiCJ,EAAUG,MAAMZ,2CAGxE,MAAMF,EAAQf,EAAaC,EAASC,EAAaC,GAEjD,GAAIY,IAAU,KACZ,OAAOC,EAAYf,EAASE,GAAU,OAAQD,EAAawB,EAAUR,SAGvE,OAAOQ,EAAUK,IAAI,CAAChB,GACxB,CAsCA,SAASiB,EAAwC/B,EAA0BE,GACzE,OAAOE,EAAa4B,KAAKf,QAASjB,EAASE,EAC7C,CAEA,SAAS+B,EAEPjC,EACAE,GAEA,OAAOE,EAAa4B,KAAMhC,EAASE,EACrC,CAEO,SAASgC,EAAwBC,GACrCA,EAAOrB,MAAkCV,aAAe6B,EACzDE,EAAOC,QAAQhC,aAAe2B,CAChC,CCtFaM,MAAAA,EAAuDF,GAAUG,OAAOC,KAAMJ,EAA6BK,OAExH,SAASC,EAASN,EAA0BO,GAC1C,MAAMC,EAASD,EAAQE,UAAWT,GAElC,IAAKO,KAAa,WAAYA,GAC5B,OAAOC,EAGT,MAAME,EAAiBC,EAAAA,UAAUJ,EAAQK,QACzC,OAAOJ,EAAOK,QAAOC,GAASJ,EAAeK,QAAQD,MAAY,GACnE,CA2BA,SAASE,IACP,IAAIC,EACJ,MAAO,CAACjB,EAAqBO,KAC3B,IAAKU,EAAY,CACf,MAAMC,EAAaX,GAAW,SAAUA,EACpCI,EAASA,UAACJ,EAAQY,MAClBb,EAASN,EAAQO,GACrBU,EAAazD,GAAQA,EAAKgD,QAAUU,CACtC,CAEA,OAAOD,CAAU,CAErB,CAEO,SAASG,EACdpB,EACAqB,GAEA,MAAMd,EAAOJ,OAAAmB,OAAA,CAAKb,UAAWP,GAAmBmB,GAChD,MAAMJ,EAAaD,IAEnB,SAASO,EAAwC1D,EAA0BE,GACzE,OAAOyD,EAAiBA,kBAAC3D,EAASE,GAAU,OAAQ8B,KAAM,CACxDoB,WAAYA,EAAWjB,EAAQO,IAEnC,CAEA,SAASkB,EAA4C5D,EAA0BE,GAC7E,MAAM2D,EAAW,CAAElC,YAAaK,MAChC,OAAO2B,EAAiBA,kBAAC3D,EAASE,GAAU,OAAQ2D,EAAU,CAC5DT,WAAYA,EAAWjB,EAAQO,IAEnC,CAEAP,EAAOC,QAAQ0B,mBAAqBF,EACpCzB,EAAO4B,OAAO,qBAAsBL,EACtC"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/accessibleBy.ts","../../src/plugins/accessible_records.ts","../../src/plugins/accessible_fields.ts","../../src/accessibleFieldsBy.ts"],"sourcesContent":["import { AnyMongoAbility, Generics, SubjectType, Abilities, AbilityTuple, ExtractSubjectType } from '@casl/ability';\nimport { rulesToQuery } from '@casl/ability/extra';\n\nfunction convertToMongoQuery(rule: AnyMongoAbility['rules'][number]) {\n const conditions = rule.conditions!;\n return rule.inverted ? { $nor: [conditions] } : conditions;\n}\n\nexport const EMPTY_RESULT_QUERY = { $expr: { $eq: [0, 1] } };\nexport class AccessibleRecords<T extends SubjectType> {\n constructor(\n private readonly _ability: AnyMongoAbility,\n private readonly _action: string\n ) {}\n\n /**\n * In case action is not allowed, it returns `{ $expr: { $eq: [0, 1] } }`\n */\n ofType(subjectType: T): Record<string, unknown> {\n const query = rulesToQuery(this._ability, this._action, subjectType, convertToMongoQuery);\n return query === null ? EMPTY_RESULT_QUERY : query as Record<string, unknown>;\n }\n}\n\ntype SubjectTypes<T extends Abilities> = T extends AbilityTuple\n ? ExtractSubjectType<T[1]>\n : never;\n\n/**\n * Returns accessible records Mongo query per record type (i.e., entity type) based on provided Ability and action.\n */\nexport function accessibleBy<T extends AnyMongoAbility>(\n ability: T,\n action: Parameters<T['rulesFor']>[0] = 'read'\n): AccessibleRecords<SubjectTypes<Generics<T>['abilities']>> {\n return new AccessibleRecords(ability, action);\n}\n","import { AnyMongoAbility, Generics, Normalize } from '@casl/ability';\nimport { Document, HydratedDocument, Model, Query, QueryWithHelpers, Schema } from 'mongoose';\nimport { accessibleBy } from '../accessibleBy';\n\nfunction accessibleRecords<T extends AnyMongoAbility>(\n baseQuery: Query<any, any>,\n ability: T,\n action?: Normalize<Generics<T>['abilities']>[0]\n): QueryWithHelpers<Document, Document> {\n const subjectType = ability.detectSubjectType({\n constructor: baseQuery.model\n });\n\n if (!subjectType) {\n throw new TypeError(`Cannot detect subject type of \"${baseQuery.model.modelName}\" to return accessible records`);\n }\n\n const query = accessibleBy(ability, action).ofType(subjectType);\n\n return baseQuery.and([query]);\n}\n\ntype GetAccessibleRecords<T, TQueryHelpers, TMethods, TVirtuals> = <U extends AnyMongoAbility>(\n ability: U,\n action?: Normalize<Generics<U>['abilities']>[0]\n) => QueryWithHelpers<\nArray<T>,\nT,\nAccessibleRecordQueryHelpers<T, TQueryHelpers, TMethods, TVirtuals>\n>;\n\nexport type AccessibleRecordQueryHelpers<T, TQueryHelpers = {}, TMethods = {}, TVirtuals = {}> = {\n /** @deprecated use accessibleBy helper instead */\n accessibleBy: GetAccessibleRecords<\n HydratedDocument<T, TMethods, TVirtuals>,\n TQueryHelpers,\n TMethods,\n TVirtuals\n >\n};\nexport interface AccessibleRecordModel<\n T,\n TQueryHelpers = {},\n TMethods = {},\n TVirtuals = {}\n> extends Model<T,\n TQueryHelpers & AccessibleRecordQueryHelpers<T, TQueryHelpers, TMethods, TVirtuals>,\n TMethods,\n TVirtuals> {\n /** @deprecated use accessibleBy helper instead */\n accessibleBy: GetAccessibleRecords<\n HydratedDocument<T, TMethods, TVirtuals>,\n TQueryHelpers,\n TMethods,\n TVirtuals\n >\n}\n\nfunction modelAccessibleBy(this: Model<unknown>, ability: AnyMongoAbility, action?: string) {\n return accessibleRecords(this.where(), ability, action);\n}\n\nfunction queryAccessibleBy(\n this: Query<unknown, unknown>,\n ability: AnyMongoAbility,\n action?: string\n) {\n return accessibleRecords(this, ability, action);\n}\n\nexport function accessibleRecordsPlugin(schema: Schema<any>): void {\n (schema.query as Record<string, unknown>).accessibleBy = queryAccessibleBy;\n schema.statics.accessibleBy = modelAccessibleBy;\n}\n","import { AnyMongoAbility, Generics, Normalize, wrapArray } from '@casl/ability';\nimport { AccessibleFields, GetSubjectTypeAllFieldsExtractor } from '@casl/ability/extra';\nimport type { Document, Model, Schema } from 'mongoose';\n\nexport type AccessibleFieldsOptions =\n {\n getFields(schema: Schema<Document>): string[]\n } &\n ({ only: string | string[] } | { except: string | string[] });\n\nexport const getSchemaPaths: AccessibleFieldsOptions['getFields'] = schema => Object.keys((schema as { paths: object }).paths);\n\nfunction fieldsOf(schema: Schema<Document>, options: Partial<AccessibleFieldsOptions>) {\n const fields = options.getFields!(schema);\n\n if (!options || !('except' in options)) {\n return fields;\n }\n\n const excludedFields = wrapArray(options.except);\n return fields.filter(field => excludedFields.indexOf(field) === -1);\n}\n\ntype GetAccessibleFields<T> = <U extends AnyMongoAbility>(\n this: Model<T> | T,\n ability: U,\n action?: Normalize<Generics<U>['abilities']>[0]\n) => string[];\n\nexport interface AccessibleFieldsModel<\n T,\n TQueryHelpers = {},\n TMethods = {},\n TVirtuals = {}\n> extends Model<T, TQueryHelpers, TMethods & AccessibleFieldDocumentMethods<T>, TVirtuals> {\n accessibleFieldsBy: GetAccessibleFields<T>\n}\n\nexport interface AccessibleFieldDocumentMethods<T = Document> {\n accessibleFieldsBy: GetAccessibleFields<T>\n}\n\n/**\n * @deprecated Mongoose recommends against `extends Document`, prefer to use `AccessibleFieldsModel` instead.\n * See here: https://mongoosejs.com/docs/typescript.html#using-extends-document\n */\nexport interface AccessibleFieldsDocument extends Document, AccessibleFieldDocumentMethods {}\n\nfunction getAllSchemaFieldsFactory() {\n let getAllFields: GetSubjectTypeAllFieldsExtractor;\n return (schema: Schema<any>, options: Partial<AccessibleFieldsOptions>) => {\n if (!getAllFields) {\n const ALL_FIELDS = options && 'only' in options\n ? wrapArray(options.only as string[])\n : fieldsOf(schema, options);\n getAllFields = () => ALL_FIELDS;\n }\n\n return getAllFields;\n };\n}\n\nexport function accessibleFieldsPlugin(\n schema: Schema<any>,\n rawOptions?: Partial<AccessibleFieldsOptions>\n): void {\n const options = { getFields: getSchemaPaths, ...rawOptions };\n const getAllFields = getAllSchemaFieldsFactory();\n\n function instanceAccessibleFields(this: Document, ability: AnyMongoAbility, action?: string) {\n return new AccessibleFields(ability, action || 'read', getAllFields(schema, options)).of(this);\n }\n\n function modelAccessibleFields(this: Model<unknown>, ability: AnyMongoAbility, action?: string) {\n // using fake document because at this point we don't know how Ability's detectSubjectType was configured:\n // does it use classes or strings?\n const fakeDocument = { constructor: this };\n return new AccessibleFields(ability, action || 'read', getAllFields(schema, options)).of(fakeDocument);\n }\n\n schema.statics.accessibleFieldsBy = modelAccessibleFields;\n schema.method('accessibleFieldsBy', instanceAccessibleFields);\n}\n","import { AnyMongoAbility, Generics } from \"@casl/ability\";\nimport { AccessibleFields, GetSubjectTypeAllFieldsExtractor } from \"@casl/ability/extra\";\nimport mongoose from 'mongoose';\n\nconst getSubjectTypeAllFieldsExtractor: GetSubjectTypeAllFieldsExtractor = (type) => {\n const Model = typeof type === 'string' ? mongoose.models[type] : type;\n if (!Model) throw new Error(`Unknown mongoose model \"${type}\"`);\n return 'schema' in Model ? Object.keys((Model.schema as any).paths) : [];\n};\n\nexport function accessibleFieldsBy<T extends AnyMongoAbility>(\n ability: T,\n action: Parameters<T['rulesFor']>[0] = 'read'\n): AccessibleFields<Extract<Generics<T>['abilities'], unknown[]>[1]> {\n return new AccessibleFields(ability, action, getSubjectTypeAllFieldsExtractor);\n}\n"],"names":["convertToMongoQuery","rule","conditions","inverted","$nor","EMPTY_RESULT_QUERY","$expr","$eq","AccessibleRecords","constructor","_ability","_action","this","ofType","subjectType","query","rulesToQuery","accessibleBy","ability","action","accessibleRecords","baseQuery","detectSubjectType","model","TypeError","modelName","and","modelAccessibleBy","where","queryAccessibleBy","accessibleRecordsPlugin","schema","statics","getSchemaPaths","Object","keys","paths","fieldsOf","options","fields","getFields","excludedFields","wrapArray","except","filter","field","indexOf","getAllSchemaFieldsFactory","getAllFields","ALL_FIELDS","only","accessibleFieldsPlugin","rawOptions","assign","instanceAccessibleFields","AccessibleFields","of","modelAccessibleFields","fakeDocument","accessibleFieldsBy","method","getSubjectTypeAllFieldsExtractor","type","Model","mongoose","models","Error"],"mappings":"2GAGA,SAASA,EAAoBC,GAC3B,MAAMC,EAAaD,EAAKC,WACxB,OAAOD,EAAKE,SAAW,CAAEC,KAAM,CAACF,IAAgBA,CAClD,CAEO,MAAMG,EAAqB,CAAEC,MAAO,CAAEC,IAAK,CAAC,EAAG,KAC/C,MAAMC,EACXC,WAAAA,CACmBC,EACAC,GACjBC,KAFiBF,EAAAA,EAAyBE,KACzBD,EAAAA,CAChB,CAKHE,MAAAA,CAAOC,GACL,MAAMC,EAAQC,EAAYA,aAACJ,KAAKF,EAAUE,KAAKD,EAASG,EAAad,GACrE,OAAOe,IAAU,KAAOV,EAAqBU,CAC/C,EAUK,SAASE,EACdC,EACAC,EAAuC,QAEvC,OAAO,IAAIX,EAAkBU,EAASC,EACxC,CChCA,SAASC,EACPC,EACAH,EACAC,GAEA,MAAML,EAAcI,EAAQI,kBAAkB,CAC5Cb,YAAaY,EAAUE,QAGzB,IAAKT,EACH,MAAM,IAAIU,UAAW,kCAAiCH,EAAUE,MAAME,2CAGxE,MAAMV,EAAQE,EAAaC,EAASC,GAAQN,OAAOC,GAEnD,OAAOO,EAAUK,IAAI,CAACX,GACxB,CAsCA,SAASY,EAAwCT,EAA0BC,GACzE,OAAOC,EAAkBR,KAAKgB,QAASV,EAASC,EAClD,CAEA,SAASU,EAEPX,EACAC,GAEA,OAAOC,EAAkBR,KAAMM,EAASC,EAC1C,CAEO,SAASW,EAAwBC,GACrCA,EAAOhB,MAAkCE,aAAeY,EACzDE,EAAOC,QAAQf,aAAeU,CAChC,CC/DaM,MAAAA,EAAuDF,GAAUG,OAAOC,KAAMJ,EAA6BK,OAExH,SAASC,EAASN,EAA0BO,GAC1C,MAAMC,EAASD,EAAQE,UAAWT,GAElC,IAAKO,KAAa,WAAYA,GAC5B,OAAOC,EAGT,MAAME,EAAiBC,EAAAA,UAAUJ,EAAQK,QACzC,OAAOJ,EAAOK,QAAOC,GAASJ,EAAeK,QAAQD,MAAY,GACnE,CA2BA,SAASE,IACP,IAAIC,EACJ,MAAO,CAACjB,EAAqBO,KAC3B,IAAKU,EAAc,CACjB,MAAMC,EAAaX,GAAW,SAAUA,EACpCI,EAASA,UAACJ,EAAQY,MAClBb,EAASN,EAAQO,GACrBU,EAAeA,IAAMC,CACvB,CAEA,OAAOD,CAAY,CAEvB,CAEO,SAASG,EACdpB,EACAqB,GAEA,MAAMd,EAAOJ,OAAAmB,OAAA,CAAKb,UAAWP,GAAmBmB,GAChD,MAAMJ,EAAeD,IAErB,SAASO,EAAyCpC,EAA0BC,GAC1E,OAAO,IAAIoC,EAAgBA,iBAACrC,EAASC,GAAU,OAAQ6B,EAAajB,EAAQO,IAAUkB,GAAG5C,KAC3F,CAEA,SAAS6C,EAA4CvC,EAA0BC,GAG7E,MAAMuC,EAAe,CAAEjD,YAAaG,MACpC,OAAO,IAAI2C,EAAgBA,iBAACrC,EAASC,GAAU,OAAQ6B,EAAajB,EAAQO,IAAUkB,GAAGE,EAC3F,CAEA3B,EAAOC,QAAQ2B,mBAAqBF,EACpC1B,EAAO6B,OAAO,qBAAsBN,EACtC,CC9EA,MAAMO,EAAsEC,IAC1E,MAAMC,SAAeD,IAAS,SAAWE,EAASC,OAAOH,GAAQA,EACjE,IAAKC,EAAO,MAAM,IAAIG,MAAO,2BAA0BJ,MACvD,MAAO,WAAYC,EAAQ7B,OAAOC,KAAM4B,EAAMhC,OAAeK,OAAS,EAAE,EAGnE,SAASuB,EACdzC,EACAC,EAAuC,QAEvC,OAAO,IAAIoC,EAAAA,iBAAiBrC,EAASC,EAAQ0C,EAC/C"}
|
package/dist/es6m/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{rulesToQuery as t,AccessibleFields as n}from"@casl/ability/extra";import{wrapArray as r}from"@casl/ability";import o from"mongoose";function e(t){const n=t.conditions;return t.inverted?{$nor:[n]}:n}const c={$expr:{$eq:[0,1]}};class s{constructor(t,n){this.t=t;this.o=n}ofType(n){const r=t(this.t,this.o,n,e);return r===null?c:r}}function i(t,n="read"){return new s(t,n)}function u(t,n,r){const o=n.detectSubjectType({constructor:t.model});if(!o)throw new TypeError(`Cannot detect subject type of "${t.model.modelName}" to return accessible records`);const e=i(n,r).ofType(o);return t.and([e])}function f(t,n){return u(this.where(),t,n)}function a(t,n){return u(this,t,n)}function l(t){t.query.accessibleBy=a;t.statics.accessibleBy=f}const h=t=>Object.keys(t.paths);function m(t,n){const o=n.getFields(t);if(!n||!("except"in n))return o;const e=r(n.except);return o.filter((t=>e.indexOf(t)===-1))}function p(){let t;return(n,o)=>{if(!t){const e=o&&"only"in o?r(o.only):m(n,o);t=()=>e}return t}}function d(t,r){const o=Object.assign({getFields:h},r);const e=p();function c(r,c){return new n(r,c||"read",e(t,o)).of(this)}function s(r,c){const s={constructor:this};return new n(r,c||"read",e(t,o)).of(s)}t.statics.accessibleFieldsBy=s;t.method("accessibleFieldsBy",c)}const w=t=>{const n=typeof t==="string"?o.models[t]:t;if(!n)throw new Error(`Unknown mongoose model "${t}"`);return"schema"in n?Object.keys(n.schema.paths):[]};function b(t,r="read"){return new n(t,r,w)}export{i as accessibleBy,b as accessibleFieldsBy,d as accessibleFieldsPlugin,l as accessibleRecordsPlugin,h as getSchemaPaths};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/es6m/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../../src/mongo.ts","../../src/accessible_records.ts","../../src/accessible_fields.ts"],"sourcesContent":["import { AnyMongoAbility } from '@casl/ability';\nimport { AbilityQuery, rulesToQuery } from '@casl/ability/extra';\n\nfunction convertToMongoQuery(rule: AnyMongoAbility['rules'][number]) {\n const conditions = rule.conditions!;\n return rule.inverted ? { $nor: [conditions] } : conditions;\n}\n\n/**\n * @deprecated use accessibleBy instead\n *\n * Converts ability action + subjectType to MongoDB query\n */\nexport function toMongoQuery<T extends AnyMongoAbility>(\n ability: T,\n subjectType: Parameters<T['rulesFor']>[1],\n action: Parameters<T['rulesFor']>[0] = 'read'\n): AbilityQuery | null {\n return rulesToQuery(ability, action, subjectType, convertToMongoQuery);\n}\n\nexport interface RecordTypes {\n}\ntype StringOrKeysOf<T> = keyof T extends never ? string : keyof T;\n\n/**\n * Returns Mongo query per record type (i.e., entity type) based on provided Ability and action.\n * In case action is not allowed, it returns `{ $expr: false }`\n */\nexport function accessibleBy<T extends AnyMongoAbility>(\n ability: T,\n action: Parameters<T['rulesFor']>[0] = 'read'\n): Record<StringOrKeysOf<RecordTypes>, AbilityQuery> {\n return new Proxy({\n _ability: ability,\n _action: action\n }, accessibleByProxyHandlers) as unknown as Record<StringOrKeysOf<RecordTypes>, AbilityQuery>;\n}\n\nexport const EMPTY_RESULT_QUERY = { $expr: { $eq: [0, 1] } };\nconst accessibleByProxyHandlers: ProxyHandler<{ _ability: AnyMongoAbility, _action: string }> = {\n get(target, subjectType) {\n const query = rulesToQuery(target._ability, target._action, subjectType, convertToMongoQuery);\n return query === null ? EMPTY_RESULT_QUERY : query;\n }\n};\n","import { Normalize, AnyMongoAbility, Generics, ForbiddenError } from '@casl/ability';\nimport { Schema, QueryWithHelpers, Model, Document, HydratedDocument, Query } from 'mongoose';\nimport { EMPTY_RESULT_QUERY, toMongoQuery } from './mongo';\n\nfunction failedQuery(\n ability: AnyMongoAbility,\n action: string,\n modelName: string,\n query: QueryWithHelpers<Document, Document>\n) {\n query.where(EMPTY_RESULT_QUERY);\n const anyQuery: any = query;\n\n if (typeof anyQuery.pre === 'function') {\n anyQuery.pre((cb: (error?: Error) => void) => {\n const error = ForbiddenError.from(ability).unlessCan(action, modelName);\n cb(error);\n });\n }\n\n return query;\n}\n\nfunction accessibleBy<T extends AnyMongoAbility>(\n baseQuery: Query<any, any>,\n ability: T,\n action?: Normalize<Generics<T>['abilities']>[0]\n): QueryWithHelpers<Document, Document> {\n const subjectType = ability.detectSubjectType({\n constructor: baseQuery.model\n });\n\n if (!subjectType) {\n throw new TypeError(`Cannot detect subject type of \"${baseQuery.model.modelName}\" to return accessible records`);\n }\n\n const query = toMongoQuery(ability, subjectType, action);\n\n if (query === null) {\n return failedQuery(ability, action || 'read', subjectType, baseQuery.where());\n }\n\n return baseQuery.and([query]);\n}\n\ntype GetAccessibleRecords<T, TQueryHelpers, TMethods, TVirtuals> = <U extends AnyMongoAbility>(\n ability: U,\n action?: Normalize<Generics<U>['abilities']>[0]\n) => QueryWithHelpers<\nArray<T>,\nT,\nAccessibleRecordQueryHelpers<T, TQueryHelpers, TMethods, TVirtuals>\n>;\n\nexport type AccessibleRecordQueryHelpers<T, TQueryHelpers = {}, TMethods = {}, TVirtuals = {}> = {\n /** @deprecated use accessibleBy helper instead */\n accessibleBy: GetAccessibleRecords<\n HydratedDocument<T, TMethods, TVirtuals>,\n TQueryHelpers,\n TMethods,\n TVirtuals\n >\n};\nexport interface AccessibleRecordModel<\n T,\n TQueryHelpers = {},\n TMethods = {},\n TVirtuals = {}\n> extends Model<T,\n TQueryHelpers & AccessibleRecordQueryHelpers<T, TQueryHelpers, TMethods, TVirtuals>,\n TMethods,\n TVirtuals> {\n /** @deprecated use accessibleBy helper instead */\n accessibleBy: GetAccessibleRecords<\n HydratedDocument<T, TMethods, TVirtuals>,\n TQueryHelpers,\n TMethods,\n TVirtuals\n >\n}\n\nfunction modelAccessibleBy(this: Model<unknown>, ability: AnyMongoAbility, action?: string) {\n return accessibleBy(this.where(), ability, action);\n}\n\nfunction queryAccessibleBy(\n this: Query<unknown, unknown>,\n ability: AnyMongoAbility,\n action?: string\n) {\n return accessibleBy(this, ability, action);\n}\n\nexport function accessibleRecordsPlugin(schema: Schema<any>): void {\n (schema.query as Record<string, unknown>).accessibleBy = queryAccessibleBy;\n schema.statics.accessibleBy = modelAccessibleBy;\n}\n","import { wrapArray, Normalize, AnyMongoAbility, Generics } from '@casl/ability';\nimport { permittedFieldsOf, PermittedFieldsOptions } from '@casl/ability/extra';\nimport type { Schema, Model, Document } from 'mongoose';\n\nexport type AccessibleFieldsOptions =\n {\n getFields(schema: Schema<Document>): string[]\n } &\n ({ only: string | string[] } | { except: string | string[] });\n\nexport const getSchemaPaths: AccessibleFieldsOptions['getFields'] = schema => Object.keys((schema as { paths: object }).paths);\n\nfunction fieldsOf(schema: Schema<Document>, options: Partial<AccessibleFieldsOptions>) {\n const fields = options.getFields!(schema);\n\n if (!options || !('except' in options)) {\n return fields;\n }\n\n const excludedFields = wrapArray(options.except);\n return fields.filter(field => excludedFields.indexOf(field) === -1);\n}\n\ntype GetAccessibleFields<T> = <U extends AnyMongoAbility>(\n this: Model<T> | T,\n ability: U,\n action?: Normalize<Generics<U>['abilities']>[0]\n) => string[];\n\nexport interface AccessibleFieldsModel<\n T,\n TQueryHelpers = {},\n TMethods = {},\n TVirtuals = {}\n> extends Model<T, TQueryHelpers, TMethods & AccessibleFieldDocumentMethods<T>, TVirtuals> {\n accessibleFieldsBy: GetAccessibleFields<T>\n}\n\nexport interface AccessibleFieldDocumentMethods<T = Document> {\n accessibleFieldsBy: GetAccessibleFields<T>\n}\n\n/**\n * @deprecated Mongoose recommends against `extends Document`, prefer to use `AccessibleFieldsModel` instead.\n * See here: https://mongoosejs.com/docs/typescript.html#using-extends-document\n */\nexport interface AccessibleFieldsDocument extends Document, AccessibleFieldDocumentMethods {}\n\nfunction modelFieldsGetter() {\n let fieldsFrom: PermittedFieldsOptions<AnyMongoAbility>['fieldsFrom'];\n return (schema: Schema<any>, options: Partial<AccessibleFieldsOptions>) => {\n if (!fieldsFrom) {\n const ALL_FIELDS = options && 'only' in options\n ? wrapArray(options.only as string[])\n : fieldsOf(schema, options);\n fieldsFrom = rule => rule.fields || ALL_FIELDS;\n }\n\n return fieldsFrom;\n };\n}\n\nexport function accessibleFieldsPlugin(\n schema: Schema<any>,\n rawOptions?: Partial<AccessibleFieldsOptions>\n): void {\n const options = { getFields: getSchemaPaths, ...rawOptions };\n const fieldsFrom = modelFieldsGetter();\n\n function istanceAccessibleFields(this: Document, ability: AnyMongoAbility, action?: string) {\n return permittedFieldsOf(ability, action || 'read', this, {\n fieldsFrom: fieldsFrom(schema, options)\n });\n }\n\n function modelAccessibleFields(this: Model<unknown>, ability: AnyMongoAbility, action?: string) {\n const document = { constructor: this };\n return permittedFieldsOf(ability, action || 'read', document, {\n fieldsFrom: fieldsFrom(schema, options)\n });\n }\n\n schema.statics.accessibleFieldsBy = modelAccessibleFields;\n schema.method('accessibleFieldsBy', istanceAccessibleFields);\n}\n"],"names":["convertToMongoQuery","rule","conditions","inverted","$nor","toMongoQuery","ability","subjectType","action","rulesToQuery","accessibleBy","Proxy","_ability","_action","accessibleByProxyHandlers","EMPTY_RESULT_QUERY","$expr","$eq","get","target","query","failedQuery","modelName","where","anyQuery","pre","cb","error","ForbiddenError","from","unlessCan","baseQuery","detectSubjectType","constructor","model","TypeError","and","modelAccessibleBy","this","queryAccessibleBy","accessibleRecordsPlugin","schema","statics","getSchemaPaths","Object","keys","paths","fieldsOf","options","fields","getFields","excludedFields","wrapArray","except","filter","field","indexOf","modelFieldsGetter","fieldsFrom","ALL_FIELDS","only","accessibleFieldsPlugin","rawOptions","assign","istanceAccessibleFields","permittedFieldsOf","modelAccessibleFields","document","accessibleFieldsBy","method"],"mappings":"wIAGA,SAASA,EAAoBC,GAC3B,MAAMC,EAAaD,EAAKC,WACxB,OAAOD,EAAKE,SAAW,CAAEC,KAAM,CAACF,IAAgBA,CAClD,CAOO,SAASG,EACdC,EACAC,EACAC,EAAuC,QAEvC,OAAOC,EAAaH,EAASE,EAAQD,EAAaP,EACpD,CAUO,SAASU,EACdJ,EACAE,EAAuC,QAEvC,OAAO,IAAIG,MAAM,CACfC,EAAUN,EACVO,EAASL,GACRM,EACL,CAEO,MAAMC,EAAqB,CAAEC,MAAO,CAAEC,IAAK,CAAC,EAAG,KACtD,MAAMH,EAA0F,CAC9FI,GAAAA,CAAIC,EAAQZ,GACV,MAAMa,EAAQX,EAAaU,EAAOP,EAAUO,EAAON,EAASN,EAAaP,GACzE,OAAOoB,IAAU,KAAOL,EAAqBK,CAC/C,GCxCF,SAASC,EACPf,EACAE,EACAc,EACAF,GAEAA,EAAMG,MAAMR,GACZ,MAAMS,EAAgBJ,EAEtB,UAAWI,EAASC,MAAQ,WAC1BD,EAASC,KAAKC,IACZ,MAAMC,EAAQC,EAAeC,KAAKvB,GAASwB,UAAUtB,EAAQc,GAC7DI,EAAGC,EAAM,IAIb,OAAOP,CACT,CAEA,SAASV,EACPqB,EACAzB,EACAE,GAEA,MAAMD,EAAcD,EAAQ0B,kBAAkB,CAC5CC,YAAaF,EAAUG,QAGzB,IAAK3B,EACH,MAAM,IAAI4B,UAAW,kCAAiCJ,EAAUG,MAAMZ,2CAGxE,MAAMF,EAAQf,EAAaC,EAASC,EAAaC,GAEjD,GAAIY,IAAU,KACZ,OAAOC,EAAYf,EAASE,GAAU,OAAQD,EAAawB,EAAUR,SAGvE,OAAOQ,EAAUK,IAAI,CAAChB,GACxB,CAsCA,SAASiB,EAAwC/B,EAA0BE,GACzE,OAAOE,EAAa4B,KAAKf,QAASjB,EAASE,EAC7C,CAEA,SAAS+B,EAEPjC,EACAE,GAEA,OAAOE,EAAa4B,KAAMhC,EAASE,EACrC,CAEO,SAASgC,EAAwBC,GACrCA,EAAOrB,MAAkCV,aAAe6B,EACzDE,EAAOC,QAAQhC,aAAe2B,CAChC,CCtFaM,MAAAA,EAAuDF,GAAUG,OAAOC,KAAMJ,EAA6BK,OAExH,SAASC,EAASN,EAA0BO,GAC1C,MAAMC,EAASD,EAAQE,UAAWT,GAElC,IAAKO,KAAa,WAAYA,GAC5B,OAAOC,EAGT,MAAME,EAAiBC,EAAUJ,EAAQK,QACzC,OAAOJ,EAAOK,QAAOC,GAASJ,EAAeK,QAAQD,MAAY,GACnE,CA2BA,SAASE,IACP,IAAIC,EACJ,MAAO,CAACjB,EAAqBO,KAC3B,IAAKU,EAAY,CACf,MAAMC,EAAaX,GAAW,SAAUA,EACpCI,EAAUJ,EAAQY,MAClBb,EAASN,EAAQO,GACrBU,EAAazD,GAAQA,EAAKgD,QAAUU,CACtC,CAEA,OAAOD,CAAU,CAErB,CAEO,SAASG,EACdpB,EACAqB,GAEA,MAAMd,EAAOJ,OAAAmB,OAAA,CAAKb,UAAWP,GAAmBmB,GAChD,MAAMJ,EAAaD,IAEnB,SAASO,EAAwC1D,EAA0BE,GACzE,OAAOyD,EAAkB3D,EAASE,GAAU,OAAQ8B,KAAM,CACxDoB,WAAYA,EAAWjB,EAAQO,IAEnC,CAEA,SAASkB,EAA4C5D,EAA0BE,GAC7E,MAAM2D,EAAW,CAAElC,YAAaK,MAChC,OAAO2B,EAAkB3D,EAASE,GAAU,OAAQ2D,EAAU,CAC5DT,WAAYA,EAAWjB,EAAQO,IAEnC,CAEAP,EAAOC,QAAQ0B,mBAAqBF,EACpCzB,EAAO4B,OAAO,qBAAsBL,EACtC"}
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../../src/accessibleBy.ts","../../src/plugins/accessible_records.ts","../../src/plugins/accessible_fields.ts","../../src/accessibleFieldsBy.ts"],"sourcesContent":["import { AnyMongoAbility, Generics, SubjectType, Abilities, AbilityTuple, ExtractSubjectType } from '@casl/ability';\nimport { rulesToQuery } from '@casl/ability/extra';\n\nfunction convertToMongoQuery(rule: AnyMongoAbility['rules'][number]) {\n const conditions = rule.conditions!;\n return rule.inverted ? { $nor: [conditions] } : conditions;\n}\n\nexport const EMPTY_RESULT_QUERY = { $expr: { $eq: [0, 1] } };\nexport class AccessibleRecords<T extends SubjectType> {\n constructor(\n private readonly _ability: AnyMongoAbility,\n private readonly _action: string\n ) {}\n\n /**\n * In case action is not allowed, it returns `{ $expr: { $eq: [0, 1] } }`\n */\n ofType(subjectType: T): Record<string, unknown> {\n const query = rulesToQuery(this._ability, this._action, subjectType, convertToMongoQuery);\n return query === null ? EMPTY_RESULT_QUERY : query as Record<string, unknown>;\n }\n}\n\ntype SubjectTypes<T extends Abilities> = T extends AbilityTuple\n ? ExtractSubjectType<T[1]>\n : never;\n\n/**\n * Returns accessible records Mongo query per record type (i.e., entity type) based on provided Ability and action.\n */\nexport function accessibleBy<T extends AnyMongoAbility>(\n ability: T,\n action: Parameters<T['rulesFor']>[0] = 'read'\n): AccessibleRecords<SubjectTypes<Generics<T>['abilities']>> {\n return new AccessibleRecords(ability, action);\n}\n","import { AnyMongoAbility, Generics, Normalize } from '@casl/ability';\nimport { Document, HydratedDocument, Model, Query, QueryWithHelpers, Schema } from 'mongoose';\nimport { accessibleBy } from '../accessibleBy';\n\nfunction accessibleRecords<T extends AnyMongoAbility>(\n baseQuery: Query<any, any>,\n ability: T,\n action?: Normalize<Generics<T>['abilities']>[0]\n): QueryWithHelpers<Document, Document> {\n const subjectType = ability.detectSubjectType({\n constructor: baseQuery.model\n });\n\n if (!subjectType) {\n throw new TypeError(`Cannot detect subject type of \"${baseQuery.model.modelName}\" to return accessible records`);\n }\n\n const query = accessibleBy(ability, action).ofType(subjectType);\n\n return baseQuery.and([query]);\n}\n\ntype GetAccessibleRecords<T, TQueryHelpers, TMethods, TVirtuals> = <U extends AnyMongoAbility>(\n ability: U,\n action?: Normalize<Generics<U>['abilities']>[0]\n) => QueryWithHelpers<\nArray<T>,\nT,\nAccessibleRecordQueryHelpers<T, TQueryHelpers, TMethods, TVirtuals>\n>;\n\nexport type AccessibleRecordQueryHelpers<T, TQueryHelpers = {}, TMethods = {}, TVirtuals = {}> = {\n /** @deprecated use accessibleBy helper instead */\n accessibleBy: GetAccessibleRecords<\n HydratedDocument<T, TMethods, TVirtuals>,\n TQueryHelpers,\n TMethods,\n TVirtuals\n >\n};\nexport interface AccessibleRecordModel<\n T,\n TQueryHelpers = {},\n TMethods = {},\n TVirtuals = {}\n> extends Model<T,\n TQueryHelpers & AccessibleRecordQueryHelpers<T, TQueryHelpers, TMethods, TVirtuals>,\n TMethods,\n TVirtuals> {\n /** @deprecated use accessibleBy helper instead */\n accessibleBy: GetAccessibleRecords<\n HydratedDocument<T, TMethods, TVirtuals>,\n TQueryHelpers,\n TMethods,\n TVirtuals\n >\n}\n\nfunction modelAccessibleBy(this: Model<unknown>, ability: AnyMongoAbility, action?: string) {\n return accessibleRecords(this.where(), ability, action);\n}\n\nfunction queryAccessibleBy(\n this: Query<unknown, unknown>,\n ability: AnyMongoAbility,\n action?: string\n) {\n return accessibleRecords(this, ability, action);\n}\n\nexport function accessibleRecordsPlugin(schema: Schema<any>): void {\n (schema.query as Record<string, unknown>).accessibleBy = queryAccessibleBy;\n schema.statics.accessibleBy = modelAccessibleBy;\n}\n","import { AnyMongoAbility, Generics, Normalize, wrapArray } from '@casl/ability';\nimport { AccessibleFields, GetSubjectTypeAllFieldsExtractor } from '@casl/ability/extra';\nimport type { Document, Model, Schema } from 'mongoose';\n\nexport type AccessibleFieldsOptions =\n {\n getFields(schema: Schema<Document>): string[]\n } &\n ({ only: string | string[] } | { except: string | string[] });\n\nexport const getSchemaPaths: AccessibleFieldsOptions['getFields'] = schema => Object.keys((schema as { paths: object }).paths);\n\nfunction fieldsOf(schema: Schema<Document>, options: Partial<AccessibleFieldsOptions>) {\n const fields = options.getFields!(schema);\n\n if (!options || !('except' in options)) {\n return fields;\n }\n\n const excludedFields = wrapArray(options.except);\n return fields.filter(field => excludedFields.indexOf(field) === -1);\n}\n\ntype GetAccessibleFields<T> = <U extends AnyMongoAbility>(\n this: Model<T> | T,\n ability: U,\n action?: Normalize<Generics<U>['abilities']>[0]\n) => string[];\n\nexport interface AccessibleFieldsModel<\n T,\n TQueryHelpers = {},\n TMethods = {},\n TVirtuals = {}\n> extends Model<T, TQueryHelpers, TMethods & AccessibleFieldDocumentMethods<T>, TVirtuals> {\n accessibleFieldsBy: GetAccessibleFields<T>\n}\n\nexport interface AccessibleFieldDocumentMethods<T = Document> {\n accessibleFieldsBy: GetAccessibleFields<T>\n}\n\n/**\n * @deprecated Mongoose recommends against `extends Document`, prefer to use `AccessibleFieldsModel` instead.\n * See here: https://mongoosejs.com/docs/typescript.html#using-extends-document\n */\nexport interface AccessibleFieldsDocument extends Document, AccessibleFieldDocumentMethods {}\n\nfunction getAllSchemaFieldsFactory() {\n let getAllFields: GetSubjectTypeAllFieldsExtractor;\n return (schema: Schema<any>, options: Partial<AccessibleFieldsOptions>) => {\n if (!getAllFields) {\n const ALL_FIELDS = options && 'only' in options\n ? wrapArray(options.only as string[])\n : fieldsOf(schema, options);\n getAllFields = () => ALL_FIELDS;\n }\n\n return getAllFields;\n };\n}\n\nexport function accessibleFieldsPlugin(\n schema: Schema<any>,\n rawOptions?: Partial<AccessibleFieldsOptions>\n): void {\n const options = { getFields: getSchemaPaths, ...rawOptions };\n const getAllFields = getAllSchemaFieldsFactory();\n\n function instanceAccessibleFields(this: Document, ability: AnyMongoAbility, action?: string) {\n return new AccessibleFields(ability, action || 'read', getAllFields(schema, options)).of(this);\n }\n\n function modelAccessibleFields(this: Model<unknown>, ability: AnyMongoAbility, action?: string) {\n // using fake document because at this point we don't know how Ability's detectSubjectType was configured:\n // does it use classes or strings?\n const fakeDocument = { constructor: this };\n return new AccessibleFields(ability, action || 'read', getAllFields(schema, options)).of(fakeDocument);\n }\n\n schema.statics.accessibleFieldsBy = modelAccessibleFields;\n schema.method('accessibleFieldsBy', instanceAccessibleFields);\n}\n","import { AnyMongoAbility, Generics } from \"@casl/ability\";\nimport { AccessibleFields, GetSubjectTypeAllFieldsExtractor } from \"@casl/ability/extra\";\nimport mongoose from 'mongoose';\n\nconst getSubjectTypeAllFieldsExtractor: GetSubjectTypeAllFieldsExtractor = (type) => {\n const Model = typeof type === 'string' ? mongoose.models[type] : type;\n if (!Model) throw new Error(`Unknown mongoose model \"${type}\"`);\n return 'schema' in Model ? Object.keys((Model.schema as any).paths) : [];\n};\n\nexport function accessibleFieldsBy<T extends AnyMongoAbility>(\n ability: T,\n action: Parameters<T['rulesFor']>[0] = 'read'\n): AccessibleFields<Extract<Generics<T>['abilities'], unknown[]>[1]> {\n return new AccessibleFields(ability, action, getSubjectTypeAllFieldsExtractor);\n}\n"],"names":["convertToMongoQuery","rule","conditions","inverted","$nor","EMPTY_RESULT_QUERY","$expr","$eq","AccessibleRecords","constructor","_ability","_action","this","ofType","subjectType","query","rulesToQuery","accessibleBy","ability","action","accessibleRecords","baseQuery","detectSubjectType","model","TypeError","modelName","and","modelAccessibleBy","where","queryAccessibleBy","accessibleRecordsPlugin","schema","statics","getSchemaPaths","Object","keys","paths","fieldsOf","options","fields","getFields","excludedFields","wrapArray","except","filter","field","indexOf","getAllSchemaFieldsFactory","getAllFields","ALL_FIELDS","only","accessibleFieldsPlugin","rawOptions","assign","instanceAccessibleFields","AccessibleFields","of","modelAccessibleFields","fakeDocument","accessibleFieldsBy","method","getSubjectTypeAllFieldsExtractor","type","Model","mongoose","models","Error"],"mappings":"2IAGA,SAASA,EAAoBC,GAC3B,MAAMC,EAAaD,EAAKC,WACxB,OAAOD,EAAKE,SAAW,CAAEC,KAAM,CAACF,IAAgBA,CAClD,CAEO,MAAMG,EAAqB,CAAEC,MAAO,CAAEC,IAAK,CAAC,EAAG,KAC/C,MAAMC,EACXC,WAAAA,CACmBC,EACAC,GACjBC,KAFiBF,EAAAA,EAAyBE,KACzBD,EAAAA,CAChB,CAKHE,MAAAA,CAAOC,GACL,MAAMC,EAAQC,EAAaJ,KAAKF,EAAUE,KAAKD,EAASG,EAAad,GACrE,OAAOe,IAAU,KAAOV,EAAqBU,CAC/C,EAUK,SAASE,EACdC,EACAC,EAAuC,QAEvC,OAAO,IAAIX,EAAkBU,EAASC,EACxC,CChCA,SAASC,EACPC,EACAH,EACAC,GAEA,MAAML,EAAcI,EAAQI,kBAAkB,CAC5Cb,YAAaY,EAAUE,QAGzB,IAAKT,EACH,MAAM,IAAIU,UAAW,kCAAiCH,EAAUE,MAAME,2CAGxE,MAAMV,EAAQE,EAAaC,EAASC,GAAQN,OAAOC,GAEnD,OAAOO,EAAUK,IAAI,CAACX,GACxB,CAsCA,SAASY,EAAwCT,EAA0BC,GACzE,OAAOC,EAAkBR,KAAKgB,QAASV,EAASC,EAClD,CAEA,SAASU,EAEPX,EACAC,GAEA,OAAOC,EAAkBR,KAAMM,EAASC,EAC1C,CAEO,SAASW,EAAwBC,GACrCA,EAAOhB,MAAkCE,aAAeY,EACzDE,EAAOC,QAAQf,aAAeU,CAChC,CC/DaM,MAAAA,EAAuDF,GAAUG,OAAOC,KAAMJ,EAA6BK,OAExH,SAASC,EAASN,EAA0BO,GAC1C,MAAMC,EAASD,EAAQE,UAAWT,GAElC,IAAKO,KAAa,WAAYA,GAC5B,OAAOC,EAGT,MAAME,EAAiBC,EAAUJ,EAAQK,QACzC,OAAOJ,EAAOK,QAAOC,GAASJ,EAAeK,QAAQD,MAAY,GACnE,CA2BA,SAASE,IACP,IAAIC,EACJ,MAAO,CAACjB,EAAqBO,KAC3B,IAAKU,EAAc,CACjB,MAAMC,EAAaX,GAAW,SAAUA,EACpCI,EAAUJ,EAAQY,MAClBb,EAASN,EAAQO,GACrBU,EAAeA,IAAMC,CACvB,CAEA,OAAOD,CAAY,CAEvB,CAEO,SAASG,EACdpB,EACAqB,GAEA,MAAMd,EAAOJ,OAAAmB,OAAA,CAAKb,UAAWP,GAAmBmB,GAChD,MAAMJ,EAAeD,IAErB,SAASO,EAAyCpC,EAA0BC,GAC1E,OAAO,IAAIoC,EAAiBrC,EAASC,GAAU,OAAQ6B,EAAajB,EAAQO,IAAUkB,GAAG5C,KAC3F,CAEA,SAAS6C,EAA4CvC,EAA0BC,GAG7E,MAAMuC,EAAe,CAAEjD,YAAaG,MACpC,OAAO,IAAI2C,EAAiBrC,EAASC,GAAU,OAAQ6B,EAAajB,EAAQO,IAAUkB,GAAGE,EAC3F,CAEA3B,EAAOC,QAAQ2B,mBAAqBF,EACpC1B,EAAO6B,OAAO,qBAAsBN,EACtC,CC9EA,MAAMO,EAAsEC,IAC1E,MAAMC,SAAeD,IAAS,SAAWE,EAASC,OAAOH,GAAQA,EACjE,IAAKC,EAAO,MAAM,IAAIG,MAAO,2BAA0BJ,MACvD,MAAO,WAAYC,EAAQ7B,OAAOC,KAAM4B,EAAMhC,OAAeK,OAAS,EAAE,EAGnE,SAASuB,EACdzC,EACAC,EAAuC,QAEvC,OAAO,IAAIoC,EAAiBrC,EAASC,EAAQ0C,EAC/C"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { AnyMongoAbility, Generics, SubjectType, Abilities, AbilityTuple, ExtractSubjectType } from '@casl/ability';
|
|
2
|
+
export declare const EMPTY_RESULT_QUERY: {
|
|
3
|
+
$expr: {
|
|
4
|
+
$eq: number[];
|
|
5
|
+
};
|
|
6
|
+
};
|
|
7
|
+
export declare class AccessibleRecords<T extends SubjectType> {
|
|
8
|
+
private readonly _ability;
|
|
9
|
+
private readonly _action;
|
|
10
|
+
constructor(_ability: AnyMongoAbility, _action: string);
|
|
11
|
+
/**
|
|
12
|
+
* In case action is not allowed, it returns `{ $expr: { $eq: [0, 1] } }`
|
|
13
|
+
*/
|
|
14
|
+
ofType(subjectType: T): Record<string, unknown>;
|
|
15
|
+
}
|
|
16
|
+
type SubjectTypes<T extends Abilities> = T extends AbilityTuple ? ExtractSubjectType<T[1]> : never;
|
|
17
|
+
/**
|
|
18
|
+
* Returns accessible records Mongo query per record type (i.e., entity type) based on provided Ability and action.
|
|
19
|
+
*/
|
|
20
|
+
export declare function accessibleBy<T extends AnyMongoAbility>(ability: T, action?: Parameters<T['rulesFor']>[0]): AccessibleRecords<SubjectTypes<Generics<T>['abilities']>>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { AnyMongoAbility, Generics } from "@casl/ability";
|
|
2
|
+
import { AccessibleFields } from "@casl/ability/extra";
|
|
3
|
+
export declare function accessibleFieldsBy<T extends AnyMongoAbility>(ability: T, action?: Parameters<T['rulesFor']>[0]): AccessibleFields<Extract<Generics<T>['abilities'], unknown[]>[1]>;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { AccessibleFieldDocumentMethods, AccessibleFieldsModel } from './accessible_fields';
|
|
2
|
-
import { AccessibleRecordModel, AccessibleRecordQueryHelpers } from './accessible_records';
|
|
1
|
+
import { AccessibleFieldDocumentMethods, AccessibleFieldsModel } from './plugins/accessible_fields';
|
|
2
|
+
import { AccessibleRecordModel, AccessibleRecordQueryHelpers } from './plugins/accessible_records';
|
|
3
3
|
export interface AccessibleModel<T, TQueryHelpers = unknown, TMethods = unknown, TVirtuals = unknown> extends AccessibleRecordModel<T, TQueryHelpers, TMethods & AccessibleFieldDocumentMethods<T>, TVirtuals>, AccessibleFieldsModel<T, TQueryHelpers & AccessibleRecordQueryHelpers<T, TQueryHelpers, TMethods & AccessibleFieldDocumentMethods<T>, TVirtuals>, TMethods, TVirtuals> {
|
|
4
4
|
}
|
|
5
|
-
export { accessibleRecordsPlugin } from './accessible_records';
|
|
6
|
-
export type { AccessibleRecordModel } from './accessible_records';
|
|
7
|
-
export { getSchemaPaths, accessibleFieldsPlugin } from './accessible_fields';
|
|
8
|
-
export type { AccessibleFieldsModel, AccessibleFieldsDocument, AccessibleFieldsOptions } from './accessible_fields';
|
|
9
|
-
export {
|
|
10
|
-
export type {
|
|
5
|
+
export { accessibleRecordsPlugin } from './plugins/accessible_records';
|
|
6
|
+
export type { AccessibleRecordModel } from './plugins/accessible_records';
|
|
7
|
+
export { getSchemaPaths, accessibleFieldsPlugin } from './plugins/accessible_fields';
|
|
8
|
+
export type { AccessibleFieldsModel, AccessibleFieldsDocument, AccessibleFieldsOptions } from './plugins/accessible_fields';
|
|
9
|
+
export { accessibleBy } from './accessibleBy';
|
|
10
|
+
export type { AccessibleRecords } from './accessibleBy';
|
|
11
|
+
export { accessibleFieldsBy } from './accessibleFieldsBy';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/// <reference types="mongoose/types/aggregate" />
|
|
2
|
+
/// <reference types="mongoose/types/callback" />
|
|
3
|
+
/// <reference types="mongoose/types/collection" />
|
|
4
|
+
/// <reference types="mongoose/types/connection" />
|
|
5
|
+
/// <reference types="mongoose/types/cursor" />
|
|
6
|
+
/// <reference types="mongoose/types/document" />
|
|
7
|
+
/// <reference types="mongoose/types/error" />
|
|
8
|
+
/// <reference types="mongoose/types/expressions" />
|
|
9
|
+
/// <reference types="mongoose/types/helpers" />
|
|
10
|
+
/// <reference types="mongoose/types/middlewares" />
|
|
11
|
+
/// <reference types="mongoose/types/indexes" />
|
|
12
|
+
/// <reference types="mongoose/types/models" />
|
|
13
|
+
/// <reference types="mongoose/types/mongooseoptions" />
|
|
14
|
+
/// <reference types="mongoose/types/pipelinestage" />
|
|
15
|
+
/// <reference types="mongoose/types/populate" />
|
|
16
|
+
/// <reference types="mongoose/types/query" />
|
|
17
|
+
/// <reference types="mongoose/types/schemaoptions" />
|
|
18
|
+
/// <reference types="mongoose/types/schematypes" />
|
|
19
|
+
/// <reference types="mongoose/types/session" />
|
|
20
|
+
/// <reference types="mongoose/types/types" />
|
|
21
|
+
/// <reference types="mongoose/types/utility" />
|
|
22
|
+
/// <reference types="mongoose/types/validation" />
|
|
23
|
+
/// <reference types="mongoose/types/virtuals" />
|
|
24
|
+
/// <reference types="mongoose/types/inferschematype" />
|
|
25
|
+
import { AnyMongoAbility, Generics, Normalize } from '@casl/ability';
|
|
26
|
+
import type { Document, Model, Schema } from 'mongoose';
|
|
27
|
+
export type AccessibleFieldsOptions = {
|
|
28
|
+
getFields(schema: Schema<Document>): string[];
|
|
29
|
+
} & ({
|
|
30
|
+
only: string | string[];
|
|
31
|
+
} | {
|
|
32
|
+
except: string | string[];
|
|
33
|
+
});
|
|
34
|
+
export declare const getSchemaPaths: AccessibleFieldsOptions['getFields'];
|
|
35
|
+
type GetAccessibleFields<T> = <U extends AnyMongoAbility>(this: Model<T> | T, ability: U, action?: Normalize<Generics<U>['abilities']>[0]) => string[];
|
|
36
|
+
export interface AccessibleFieldsModel<T, TQueryHelpers = {}, TMethods = {}, TVirtuals = {}> extends Model<T, TQueryHelpers, TMethods & AccessibleFieldDocumentMethods<T>, TVirtuals> {
|
|
37
|
+
accessibleFieldsBy: GetAccessibleFields<T>;
|
|
38
|
+
}
|
|
39
|
+
export interface AccessibleFieldDocumentMethods<T = Document> {
|
|
40
|
+
accessibleFieldsBy: GetAccessibleFields<T>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* @deprecated Mongoose recommends against `extends Document`, prefer to use `AccessibleFieldsModel` instead.
|
|
44
|
+
* See here: https://mongoosejs.com/docs/typescript.html#using-extends-document
|
|
45
|
+
*/
|
|
46
|
+
export interface AccessibleFieldsDocument extends Document, AccessibleFieldDocumentMethods {
|
|
47
|
+
}
|
|
48
|
+
export declare function accessibleFieldsPlugin(schema: Schema<any>, rawOptions?: Partial<AccessibleFieldsOptions>): void;
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/// <reference types="mongoose/types/aggregate" />
|
|
2
|
+
/// <reference types="mongoose/types/callback" />
|
|
3
|
+
/// <reference types="mongoose/types/collection" />
|
|
4
|
+
/// <reference types="mongoose/types/connection" />
|
|
5
|
+
/// <reference types="mongoose/types/cursor" />
|
|
6
|
+
/// <reference types="mongoose/types/document" />
|
|
7
|
+
/// <reference types="mongoose/types/error" />
|
|
8
|
+
/// <reference types="mongoose/types/expressions" />
|
|
9
|
+
/// <reference types="mongoose/types/helpers" />
|
|
10
|
+
/// <reference types="mongoose/types/middlewares" />
|
|
11
|
+
/// <reference types="mongoose/types/indexes" />
|
|
12
|
+
/// <reference types="mongoose/types/models" />
|
|
13
|
+
/// <reference types="mongoose/types/mongooseoptions" />
|
|
14
|
+
/// <reference types="mongoose/types/pipelinestage" />
|
|
15
|
+
/// <reference types="mongoose/types/populate" />
|
|
16
|
+
/// <reference types="mongoose/types/query" />
|
|
17
|
+
/// <reference types="mongoose/types/schemaoptions" />
|
|
18
|
+
/// <reference types="mongoose/types/schematypes" />
|
|
19
|
+
/// <reference types="mongoose/types/session" />
|
|
20
|
+
/// <reference types="mongoose/types/types" />
|
|
21
|
+
/// <reference types="mongoose/types/utility" />
|
|
22
|
+
/// <reference types="mongoose/types/validation" />
|
|
23
|
+
/// <reference types="mongoose/types/virtuals" />
|
|
24
|
+
/// <reference types="mongoose/types/inferschematype" />
|
|
25
|
+
import { AnyMongoAbility, Generics, Normalize } from '@casl/ability';
|
|
26
|
+
import { HydratedDocument, Model, QueryWithHelpers, Schema } from 'mongoose';
|
|
27
|
+
type GetAccessibleRecords<T, TQueryHelpers, TMethods, TVirtuals> = <U extends AnyMongoAbility>(ability: U, action?: Normalize<Generics<U>['abilities']>[0]) => QueryWithHelpers<Array<T>, T, AccessibleRecordQueryHelpers<T, TQueryHelpers, TMethods, TVirtuals>>;
|
|
28
|
+
export type AccessibleRecordQueryHelpers<T, TQueryHelpers = {}, TMethods = {}, TVirtuals = {}> = {
|
|
29
|
+
/** @deprecated use accessibleBy helper instead */
|
|
30
|
+
accessibleBy: GetAccessibleRecords<HydratedDocument<T, TMethods, TVirtuals>, TQueryHelpers, TMethods, TVirtuals>;
|
|
31
|
+
};
|
|
32
|
+
export interface AccessibleRecordModel<T, TQueryHelpers = {}, TMethods = {}, TVirtuals = {}> extends Model<T, TQueryHelpers & AccessibleRecordQueryHelpers<T, TQueryHelpers, TMethods, TVirtuals>, TMethods, TVirtuals> {
|
|
33
|
+
/** @deprecated use accessibleBy helper instead */
|
|
34
|
+
accessibleBy: GetAccessibleRecords<HydratedDocument<T, TMethods, TVirtuals>, TQueryHelpers, TMethods, TVirtuals>;
|
|
35
|
+
}
|
|
36
|
+
export declare function accessibleRecordsPlugin(schema: Schema<any>): void;
|
|
37
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { Normalize, AnyMongoAbility, Generics } from '@casl/ability';
|
|
2
|
-
import type { Schema, Model, Document } from 'mongoose';
|
|
3
|
-
export type AccessibleFieldsOptions = {
|
|
4
|
-
getFields(schema: Schema<Document>): string[];
|
|
5
|
-
} & ({
|
|
6
|
-
only: string | string[];
|
|
7
|
-
} | {
|
|
8
|
-
except: string | string[];
|
|
9
|
-
});
|
|
10
|
-
export declare const getSchemaPaths: AccessibleFieldsOptions['getFields'];
|
|
11
|
-
type GetAccessibleFields<T> = <U extends AnyMongoAbility>(this: Model<T> | T, ability: U, action?: Normalize<Generics<U>['abilities']>[0]) => string[];
|
|
12
|
-
export interface AccessibleFieldsModel<T, TQueryHelpers = {}, TMethods = {}, TVirtuals = {}> extends Model<T, TQueryHelpers, TMethods & AccessibleFieldDocumentMethods<T>, TVirtuals> {
|
|
13
|
-
accessibleFieldsBy: GetAccessibleFields<T>;
|
|
14
|
-
}
|
|
15
|
-
export interface AccessibleFieldDocumentMethods<T = Document> {
|
|
16
|
-
accessibleFieldsBy: GetAccessibleFields<T>;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* @deprecated Mongoose recommends against `extends Document`, prefer to use `AccessibleFieldsModel` instead.
|
|
20
|
-
* See here: https://mongoosejs.com/docs/typescript.html#using-extends-document
|
|
21
|
-
*/
|
|
22
|
-
export interface AccessibleFieldsDocument extends Document, AccessibleFieldDocumentMethods {
|
|
23
|
-
}
|
|
24
|
-
export declare function accessibleFieldsPlugin(schema: Schema<any>, rawOptions?: Partial<AccessibleFieldsOptions>): void;
|
|
25
|
-
export {};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Normalize, AnyMongoAbility, Generics } from '@casl/ability';
|
|
2
|
-
import { Schema, QueryWithHelpers, Model, HydratedDocument } from 'mongoose';
|
|
3
|
-
type GetAccessibleRecords<T, TQueryHelpers, TMethods, TVirtuals> = <U extends AnyMongoAbility>(ability: U, action?: Normalize<Generics<U>['abilities']>[0]) => QueryWithHelpers<Array<T>, T, AccessibleRecordQueryHelpers<T, TQueryHelpers, TMethods, TVirtuals>>;
|
|
4
|
-
export type AccessibleRecordQueryHelpers<T, TQueryHelpers = {}, TMethods = {}, TVirtuals = {}> = {
|
|
5
|
-
/** @deprecated use accessibleBy helper instead */
|
|
6
|
-
accessibleBy: GetAccessibleRecords<HydratedDocument<T, TMethods, TVirtuals>, TQueryHelpers, TMethods, TVirtuals>;
|
|
7
|
-
};
|
|
8
|
-
export interface AccessibleRecordModel<T, TQueryHelpers = {}, TMethods = {}, TVirtuals = {}> extends Model<T, TQueryHelpers & AccessibleRecordQueryHelpers<T, TQueryHelpers, TMethods, TVirtuals>, TMethods, TVirtuals> {
|
|
9
|
-
/** @deprecated use accessibleBy helper instead */
|
|
10
|
-
accessibleBy: GetAccessibleRecords<HydratedDocument<T, TMethods, TVirtuals>, TQueryHelpers, TMethods, TVirtuals>;
|
|
11
|
-
}
|
|
12
|
-
export declare function accessibleRecordsPlugin(schema: Schema<any>): void;
|
|
13
|
-
export {};
|
package/dist/types/mongo.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { AnyMongoAbility } from '@casl/ability';
|
|
2
|
-
import { AbilityQuery } from '@casl/ability/extra';
|
|
3
|
-
/**
|
|
4
|
-
* @deprecated use accessibleBy instead
|
|
5
|
-
*
|
|
6
|
-
* Converts ability action + subjectType to MongoDB query
|
|
7
|
-
*/
|
|
8
|
-
export declare function toMongoQuery<T extends AnyMongoAbility>(ability: T, subjectType: Parameters<T['rulesFor']>[1], action?: Parameters<T['rulesFor']>[0]): AbilityQuery | null;
|
|
9
|
-
export interface RecordTypes {
|
|
10
|
-
}
|
|
11
|
-
type StringOrKeysOf<T> = keyof T extends never ? string : keyof T;
|
|
12
|
-
/**
|
|
13
|
-
* Returns Mongo query per record type (i.e., entity type) based on provided Ability and action.
|
|
14
|
-
* In case action is not allowed, it returns `{ $expr: false }`
|
|
15
|
-
*/
|
|
16
|
-
export declare function accessibleBy<T extends AnyMongoAbility>(ability: T, action?: Parameters<T['rulesFor']>[0]): Record<StringOrKeysOf<RecordTypes>, AbilityQuery>;
|
|
17
|
-
export declare const EMPTY_RESULT_QUERY: {
|
|
18
|
-
$expr: {
|
|
19
|
-
$eq: number[];
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
export {};
|