{"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 type { Document as Doc, 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<Doc, Doc> {\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<T[], T, AccessibleRecordQueryHelpers<T, TQueryHelpers, TMethods, TVirtuals>>;\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 as Doc, Model, Schema } from 'mongoose';\n\nexport type AccessibleFieldsOptions =\n  {\n    getFields(schema: Schema<Doc>): 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<Doc>, 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 = Doc> {\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: Doc, 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,UAAU,kCAAkCH,EAAUE,MAAME,2CAGxE,MAAMV,EAAQE,EAAaC,EAASC,GAAQN,OAAOC,GAEnD,OAAOO,EAAUK,IAAI,CAACX,GACxB,CAkCA,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,CC3DO,MAAMM,EAAuDF,GAAUG,OAAOC,KAAMJ,EAA6BK,OAExH,SAASC,EAASN,EAAqBO,GACrC,MAAMC,EAASD,EAAQE,UAAWT,GAElC,IAAKO,KAAa,WAAYA,GAC5B,OAAOC,EAGT,MAAME,EAAiBC,EAAUJ,EAAQK,QACzC,OAAOJ,EAAOK,OAAOC,GAASJ,EAAeK,QAAQD,QACvD,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,EAEX,CAEO,SAASG,EACdpB,EACAqB,GAEA,MAAMd,EAAOJ,OAAAmB,OAAA,CAAKb,UAAWP,GAAmBmB,GAChD,MAAMJ,EAAeD,IAErB,SAASO,EAAoCpC,EAA0BC,GACrE,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,MAAM,2BAA2BJ,MACvD,MAAO,WAAYC,EAAQ7B,OAAOC,KAAM4B,EAAMhC,OAAeK,OAAS,IAGjE,SAASuB,EACdzC,EACAC,EAAuC,QAEvC,OAAO,IAAIoC,EAAiBrC,EAASC,EAAQ0C,EAC/C"}