{"version":3,"file":"index.mjs","sources":["../src/utils/autoBind.ts","../src/subscribeManager.ts","../src/utils/stringPairHandler.ts","../src/permissionBuilder.ts","../src/permissionFactory.ts"],"sourcesContent":["import { AnyFunction } from \"../types\"\r\n\r\ninterface TPrototype {\r\n  [key: string]: AnyFunction\r\n}\r\n\r\nconst CONSTRUCTOR = 'constructor'\r\n\r\nfunction isPrototype<T extends object>(value: unknown): value is T {\r\n  return typeof value === 'object'\r\n}\r\n\r\nfunction isFunction(item: unknown): item is AnyFunction {\r\n  return typeof item === 'function'\r\n}\r\n\r\nfunction bind(name: string, instance: unknown, proto?: unknown): void {\r\n  if (!isPrototype<TPrototype>(proto)) {\r\n    return\r\n  }\r\n\r\n  if (!isPrototype<TPrototype>(instance)) {\r\n    return\r\n  }\r\n\r\n  if (name === CONSTRUCTOR) {\r\n    return\r\n  }\r\n\r\n  const descriptor = Object.getOwnPropertyDescriptor(proto, name)\r\n\r\n  if (!descriptor) {\r\n    return\r\n  }\r\n\r\n  if (descriptor.get || descriptor.set) {\r\n    Object.defineProperty(proto, name, {\r\n      ...descriptor,\r\n      get: descriptor.get ? descriptor.get.bind(instance) : undefined,\r\n      set: descriptor.set ? descriptor.set.bind(instance) : undefined,\r\n    })\r\n\r\n    return\r\n  }\r\n\r\n  if (isFunction(descriptor.value)) {\r\n    instance[name] = proto[name].bind(instance)\r\n  }\r\n}\r\n\r\nexport function autoBind(instance: object): void {\r\n  try {\r\n    const proto = Object.getPrototypeOf(instance)\r\n    const properties = Object.getOwnPropertyNames(proto)\r\n    properties.forEach((name: string) => bind(name, instance, proto))\r\n  } catch (error) {\r\n    throw new Error(`Cannot get prototype of ${instance}`)\r\n  }\r\n}\r\n","import { SubscriberMap, AnyFunction } from './types'\r\nimport { autoBind } from './utils/autoBind'\r\n\r\ninterface SubscribeConfig {\r\n  maxSize?: number\r\n  delay: number\r\n}\r\n\r\ninterface SubscribeConfig {\r\n  maxSize?: number\r\n  delay: number\r\n}\r\n\r\nexport class SubscribeManager<S extends string, A extends string> {\r\n  private mapSubscribers: SubscriberMap<S, A> | null = null\r\n\r\n  private timeout: ReturnType<typeof setTimeout> | null = null\r\n  private config: SubscribeConfig = { delay: 20 }\r\n  private queue = new Set<() => void>()\r\n\r\n  constructor(subscribers: SubscriberMap<S, A> = null!, config: SubscribeConfig = { delay: 20 }) {\r\n    autoBind(this)\r\n    this.mapSubscribers = subscribers\r\n    this.config = config\r\n  }\r\n\r\n  set<Subject extends S, Action extends A>(subject: Subject, action: Action, cb: AnyFunction) {\r\n    if (!this.mapSubscribers) {\r\n      this.mapSubscribers = {} as SubscriberMap<S, A>\r\n    }\r\n\r\n    if (!this.mapSubscribers[subject]) {\r\n      this.mapSubscribers[subject] = {} as SubscriberMap<S, A>[Subject]\r\n    }\r\n\r\n    if (!this.mapSubscribers[subject][action]) {\r\n      this.mapSubscribers[subject][action] = new Set()\r\n    }\r\n\r\n    this.mapSubscribers[subject][action].add(cb)\r\n  }\r\n\r\n  remove<Subject extends S, Action extends A>(subject: Subject, action: Action, cb: AnyFunction) {\r\n    if (this.mapSubscribers?.[subject] && this.mapSubscribers?.[subject]?.[action]) {\r\n      this.mapSubscribers[subject][action].delete(cb)\r\n    }\r\n  }\r\n\r\n  call(subject: S, action: A) {\r\n    if (this.mapSubscribers) {\r\n      const currentSet = this.mapSubscribers[subject][action]\r\n\r\n      currentSet.forEach(cb => this.queue.add(cb))\r\n      currentSet.clear()\r\n\r\n      if (this.timeout) {\r\n        clearTimeout(this.timeout)\r\n      }\r\n\r\n      this.timeout = setTimeout(() => this.fetch(), this.config.delay)\r\n    }\r\n  }\r\n\r\n  private fetch() {\r\n    const { queue } = this\r\n\r\n    queue.forEach(cb => cb())\r\n    this.clear()\r\n  }\r\n\r\n  private clear() {\r\n    this.queue.clear()\r\n\r\n    if (this.timeout) {\r\n      clearTimeout(this.timeout)\r\n      this.timeout = null\r\n    }\r\n  }\r\n}\r\n","type Mode = \"forEach\" | \"some\" | \"every\";\r\n\r\nexport const stringPairHandler = <\r\n  F extends string,\r\n  S extends string,\r\n  M extends Mode,\r\n  R = M extends \"forEach\" ? undefined : boolean\r\n>(\r\n  first: F | F[],\r\n  second: S | S[],\r\n  cb: (first: F, second: S) => R,\r\n  mode: M,\r\n  defaultValue: R\r\n): R => {\r\n  if (Array.isArray(first) && typeof second === \"string\") {\r\n    if (!first.length) return defaultValue;\r\n    return first[mode]((f) => cb(f, second)) as R;\r\n  }\r\n\r\n  if (Array.isArray(second) && typeof first === \"string\") {\r\n    if (!second.length) return defaultValue;\r\n    return second[mode]((s) => cb(first, s)) as R;\r\n  }\r\n\r\n  if (Array.isArray(first) && Array.isArray(second)) {\r\n    if (!first.length || !second.length) return defaultValue;\r\n    return first[mode]((s) => second[mode]((a) => cb(s, a))) as R;\r\n  }\r\n\r\n  if (typeof first === \"string\" && typeof second === \"string\") {\r\n    return cb(first, second);\r\n  }\r\n\r\n  return defaultValue;\r\n};","import { SubscribeManager } from './subscribeManager'\r\nimport {\r\n  Rules,\r\n  BaseActions,\r\n  BaseConditions,\r\n  CheckPermissions,\r\n  ConvertRecordValue,\r\n  SubscribedCheckPermissions,\r\n  UnsubscribePermssions,\r\n  PrevSignal,\r\n} from './types'\r\nimport { autoBind } from './utils/autoBind'\r\nimport { stringPairHandler } from './utils/stringPairHandler'\r\nimport { DeepPartial } from './utils/types'\r\n\r\nexport class PermissionBuilder<S extends string, A extends BaseActions<S>, C extends BaseConditions<S>> {\r\n  private rules: Rules<S, A, C> | null\r\n  private subscribeManager: SubscribeManager<S, A[S][number]> = new SubscribeManager()\r\n\r\n  constructor(rules: DeepPartial<Rules<S, A, C>> = null!) {\r\n    autoBind(this)\r\n    this.rules = rules as Rules<S, A, C>\r\n  }\r\n\r\n  update<Subject extends S>(\r\n    subject: Subject,\r\n    action: A[Subject][number],\r\n    value: Rules<S, A, C>[Subject][A[Subject][number]],\r\n  ) {\r\n    if (!this.rules) {\r\n      this.rules = {} as Rules<S, A, C>\r\n    }\r\n\r\n    if (!this.rules?.[subject]) {\r\n      this.rules[subject] = {} as Rules<S, A, C>[Subject]\r\n    }\r\n\r\n    if (this.rules?.[subject] && this.rules[subject]?.[action] !== value) {\r\n      this.rules[subject][action] = value\r\n\r\n      this.subscribeManager.call(subject, action)\r\n    }\r\n  }\r\n\r\n  subscribedCheck<Subjects extends S, Action extends A[Subjects]>({\r\n    signal,\r\n    prevSignal,\r\n    ...args\r\n  }: SubscribedCheckPermissions<Subjects, Action, C> & PrevSignal): boolean {\r\n    if (prevSignal) {\r\n      this.removeSubscribe({ subject: args.subject, action: args.action, prevSignal })\r\n    }\r\n    this.setSubscribe({ subject: args.subject, action: args.action, signal })\r\n\r\n    return this.checkPermission(args as CheckPermissions<S, A[S], C>)\r\n  }\r\n\r\n  private setSubscribe({ subject, action, signal }: SubscribedCheckPermissions<S, A[S], C>) {\r\n    const setTrigger = (subject: S, action: A[S][number]) => {\r\n      this.subscribeManager.set(subject, action, signal)\r\n    }\r\n\r\n    stringPairHandler(subject, action, setTrigger, 'forEach', null)\r\n  }\r\n\r\n  private removeSubscribe({ subject, action, prevSignal }: UnsubscribePermssions<S, A[S], C>) {\r\n    const removeTrigger = (subject: S, action: A[S][number]) => {\r\n      this.subscribeManager.remove(subject, action, prevSignal)\r\n    }\r\n\r\n    stringPairHandler(subject, action, removeTrigger, 'forEach', null)\r\n  }\r\n\r\n  checkPermission({ subject, action, conditions, mode = 'some' }: CheckPermissions<S, A[S], C>): boolean {\r\n    const checkPermissionsCb = (subject: S, action: A[S][number]) => {\r\n      return this.checkPermissions(subject, action, conditions)\r\n    }\r\n\r\n    return stringPairHandler(subject, action, checkPermissionsCb, mode, false)\r\n  }\r\n\r\n  private checkPermissions(subject: S, action: A[S][number], conditions?: C[S] | ConvertRecordValue<C[S]>): boolean {\r\n    if (!this.rules) return false\r\n\r\n    const selfSubject = this.rules?.[subject]\r\n\r\n    if (!selfSubject) {\r\n      return false\r\n    }\r\n\r\n    const permission = selfSubject?.[action]\r\n\r\n    if (typeof permission === 'boolean') {\r\n      return permission\r\n    }\r\n\r\n    if (permission && typeof permission === 'object' && conditions) {\r\n      const typedPermission = permission as unknown as C[S]\r\n      const keys = Object.keys(typedPermission) as (keyof C[S])[]\r\n\r\n      return keys.every(key => {\r\n        if (Array.isArray(conditions[key])) {\r\n          return conditions[key].some((val: C[S][string]) => val === typedPermission[key])\r\n        }\r\n\r\n        return typedPermission[key] === conditions[key]\r\n      })\r\n    }\r\n\r\n    return false\r\n  }\r\n}\r\n\r\ntype keys = 'image' | 'article' | 'comment' | 'like'\r\ninterface Actions {\r\n  image: ['upload', 'download']\r\n  article: ['create', 'update', 'delete']\r\n  comment: ['create', 'update', 'delete']\r\n  like: ['create', 'delete']\r\n}\r\n\r\ninterface TBaseConditions {\r\n  image: never\r\n  article: never\r\n  comment: never\r\n  like: never\r\n}\r\nconst { subscribedCheck } = new PermissionBuilder<keys, Actions, TBaseConditions>()\r\nsubscribedCheck({\r\n  subject: 'image',\r\n  action: ['download', 'upload'],\r\n  signal: () => {},\r\n})\r\n","import { PermissionBuilder } from './permissionBuilder'\r\nimport { BaseActions, BaseConditions, SubscribedCheckPermissions } from './types'\r\n\r\nexport const factoryPermission = <S extends string, A extends BaseActions<S>, C extends BaseConditions<S>>() => {\r\n  const { checkPermission, subscribedCheck, update } = new PermissionBuilder<S, A, C>()\r\n\r\n  const subscribe = () => {\r\n    let prevSignal: () => void\r\n\r\n    return <Subjects extends S, Action extends A[Subjects]>(props: SubscribedCheckPermissions<Subjects, Action, C>) => {\r\n      const result = subscribedCheck({ ...props, prevSignal })\r\n      prevSignal = props.signal\r\n\r\n      return result\r\n    }\r\n  }\r\n\r\n  return { can: checkPermission, subscribe, update }\r\n}\r\n"],"names":["isPrototype","value","autoBind","instance","proto","Object","getPrototypeOf","getOwnPropertyNames","forEach","name","descriptor","getOwnPropertyDescriptor","get","set","defineProperty","bind","undefined","error","Error","SubscribeManager","mapSubscribers","timeout","config","delay","queue","Set","constructor","subscribers","this","subject","action","cb","add","remove","delete","call","currentSet","clear","clearTimeout","setTimeout","fetch","stringPairHandler","first","second","mode","defaultValue","Array","isArray","length","f","s","a","PermissionBuilder","rules","subscribeManager","update","subscribedCheck","signal","prevSignal","args","removeSubscribe","setSubscribe","checkPermission","conditions","checkPermissions","selfSubject","permission","typedPermission","keys","every","key","some","val","factoryPermission","can","subscribe","props","result"],"mappings":"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"}