permission-js-core
Version:
1 lines • 14.7 kB
Source Map (JSON)
{"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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"}