vue-nuxt-permission
Version:
A unified permission system for Vue 3 and Nuxt 3 / Nuxt 4 with directives, guards, and async support.
1 lines • 34.2 kB
Source Map (JSON)
{"version":3,"file":"plugin-BkYe8puG.cjs","sources":["../src/utils/storage.ts","../src/core/config.ts","../src/core/cache.ts","../src/utils/helpers.ts","../src/core/evaluator.ts","../src/utils/debug.ts","../src/directives/v-permission.ts","../src/plugin.ts"],"sourcesContent":["const STORAGE_KEY = \"__v_permission__\";\r\n\r\n// Check if browser environment is available (dynamic check to support testing)\r\nconst getIsBrowser = (): boolean =>\r\n typeof window !== \"undefined\" && typeof localStorage !== \"undefined\";\r\n\r\nconst encrypt = (value: any): string => {\r\n try {\r\n const json = JSON.stringify(value);\r\n // Use TextEncoder for proper unicode handling\r\n if (typeof TextEncoder !== \"undefined\") {\r\n const encoded = new TextEncoder().encode(json);\r\n const binaryString = Array.from(encoded, (byte) =>\r\n String.fromCharCode(byte)\r\n ).join(\"\");\r\n return btoa(binaryString);\r\n }\r\n // Fallback for environments without TextEncoder\r\n return btoa(unescape(encodeURIComponent(json)));\r\n } catch {\r\n return \"\";\r\n }\r\n};\r\n\r\nconst decrypt = (value: string): any => {\r\n try {\r\n const binaryString = atob(value);\r\n // Use TextDecoder for proper unicode handling\r\n if (typeof TextDecoder !== \"undefined\") {\r\n const bytes = new Uint8Array(binaryString.length);\r\n for (let i = 0; i < binaryString.length; i++) {\r\n bytes[i] = binaryString.charCodeAt(i);\r\n }\r\n const json = new TextDecoder().decode(bytes);\r\n return JSON.parse(json);\r\n }\r\n // Fallback\r\n const json = decodeURIComponent(escape(binaryString));\r\n return JSON.parse(json);\r\n } catch {\r\n return null;\r\n }\r\n};\r\n\r\nexport const savePermissionsToStorage = (permissions: any) => {\r\n if (!getIsBrowser()) return;\r\n try {\r\n localStorage.setItem(STORAGE_KEY, encrypt(permissions));\r\n } catch (e) {\r\n console.warn(\"[v-permission] Failed to save permissions to storage:\", e);\r\n }\r\n};\r\n\r\nexport const getPermissionsFromStorage = () => {\r\n if (!getIsBrowser()) return null;\r\n try {\r\n const stored = localStorage.getItem(STORAGE_KEY);\r\n return stored ? decrypt(stored) : null;\r\n } catch (e) {\r\n console.warn(\"[v-permission] Failed to read permissions from storage:\", e);\r\n return null;\r\n }\r\n};\r\n\r\nexport const clearPermissionsFromStorage = () => {\r\n if (!getIsBrowser()) return;\r\n try {\r\n localStorage.removeItem(STORAGE_KEY);\r\n } catch (e) {\r\n console.warn(\"[v-permission] Failed to clear permissions from storage:\", e);\r\n }\r\n};\r\n","import { isRef, ref, type Ref } from \"vue\";\r\nimport type {\r\n ConfigurePermissionOptions,\r\n DecryptHook,\r\n GlobalConfig,\r\n PermissionsArray,\r\n} from \"../types\";\r\nimport { savePermissionsToStorage } from \"../utils/storage\";\r\n\r\nexport type { GlobalConfig };\r\n\r\nconst globalConfig: GlobalConfig = {\r\n permissions: null,\r\n developmentMode: false,\r\n decrypt: undefined,\r\n};\r\n\r\n// Global reactive permissions - synchronized with globalConfig\r\nconst globalReactivePermissions = ref<string[]>([]);\r\n\r\nexport const getDecryptHook = (): DecryptHook | undefined => globalConfig.decrypt;\r\n\r\nexport const setDecryptHook = (hook?: DecryptHook): void => {\r\n globalConfig.decrypt = hook;\r\n};\r\n\r\nexport const configurePermission = (\r\n permissions: PermissionsArray | any,\r\n options?: ConfigurePermissionOptions,\r\n) => {\r\n const decryptFn =\r\n options?.decrypt ?? options?.transform ?? globalConfig.decrypt;\r\n if (options?.decrypt || options?.transform) {\r\n globalConfig.decrypt = options.decrypt ?? options.transform;\r\n }\r\n globalConfig.developmentMode = options?.developmentMode ?? false;\r\n\r\n if (isRef(permissions)) {\r\n const refPerms = permissions as Ref<any>;\r\n globalConfig.permissions = refPerms;\r\n if (decryptFn && refPerms.value && !Array.isArray(refPerms.value)) {\r\n const decrypted = decryptFn(refPerms.value);\r\n if (decrypted instanceof Promise) {\r\n decrypted.then((res) => {\r\n const perms = Array.isArray(res) ? res : [];\r\n refPerms.value = perms;\r\n globalReactivePermissions.value = perms;\r\n if (options?.persist !== false) {\r\n savePermissionsToStorage(perms);\r\n }\r\n });\r\n return;\r\n } else {\r\n const perms = Array.isArray(decrypted) ? decrypted : [];\r\n refPerms.value = perms;\r\n }\r\n }\r\n const currentVal = Array.isArray(refPerms.value) ? refPerms.value : [];\r\n globalReactivePermissions.value = currentVal;\r\n if (options?.persist !== false) {\r\n savePermissionsToStorage(currentVal);\r\n }\r\n return;\r\n }\r\n\r\n // Handle decrypt for raw non-array or encrypted payload\r\n if (\r\n decryptFn &&\r\n permissions !== null &&\r\n permissions !== undefined &&\r\n !Array.isArray(permissions)\r\n ) {\r\n const decrypted = decryptFn(permissions);\r\n if (decrypted instanceof Promise) {\r\n decrypted.then((res) => {\r\n const perms = Array.isArray(res) ? res : [];\r\n globalConfig.permissions = perms;\r\n globalReactivePermissions.value = perms;\r\n if (options?.persist !== false) {\r\n savePermissionsToStorage(perms);\r\n }\r\n });\r\n return;\r\n } else {\r\n const perms = Array.isArray(decrypted) ? decrypted : [];\r\n globalConfig.permissions = perms;\r\n globalReactivePermissions.value = perms;\r\n if (options?.persist !== false) {\r\n savePermissionsToStorage(perms);\r\n }\r\n return;\r\n }\r\n }\r\n\r\n const permsArray = Array.isArray(permissions) ? permissions : [];\r\n globalConfig.permissions = permsArray;\r\n globalReactivePermissions.value = permsArray;\r\n\r\n // Persist to storage so permissions survive page reloads\r\n if (options?.persist !== false) {\r\n savePermissionsToStorage(permsArray);\r\n }\r\n};\r\n\r\nexport const getReactivePermissions = () => globalReactivePermissions;\r\n\r\nexport const getCurrentPermissions = (): string[] => {\r\n const { permissions } = globalConfig;\r\n if (!permissions) return [];\r\n\r\n if (isRef(permissions)) {\r\n const val = permissions.value;\r\n return Array.isArray(val) ? val : [];\r\n }\r\n return Array.isArray(permissions) ? permissions : [];\r\n};\r\n\r\nexport const isDevMode = () => globalConfig.developmentMode;\r\n\r\nexport default globalConfig;\r\n\r\n","const permissionCache = new Map<\r\n string,\r\n { value: boolean; timestamp: number }\r\n>();\r\nconst CACHE_MAX_SIZE = 1000;\r\nconst CACHE_TTL = 5 * 60 * 1000; // 5 minutes\r\n\r\nexport const getCachedPermission = (key: string): boolean | null => {\r\n const cached = permissionCache.get(key);\r\n if (!cached) return null;\r\n\r\n // Check TTL\r\n if (Date.now() - cached.timestamp > CACHE_TTL) {\r\n permissionCache.delete(key);\r\n return null;\r\n }\r\n\r\n return cached.value;\r\n};\r\n\r\nexport const setCachedPermission = (key: string, value: boolean) => {\r\n // Prevent unbounded growth\r\n if (permissionCache.size >= CACHE_MAX_SIZE) {\r\n // Remove oldest entry\r\n const oldestKey = permissionCache.keys().next().value as string | undefined;\r\n if (oldestKey) {\r\n permissionCache.delete(oldestKey);\r\n }\r\n }\r\n\r\n permissionCache.set(key, {\r\n value,\r\n timestamp: Date.now(),\r\n });\r\n};\r\n\r\nexport const clearPermissionCache = () => permissionCache.clear();\r\n\r\nexport const invalidateCache = () => {\r\n // Clear expired entries periodically\r\n const now = Date.now();\r\n for (const [key, cached] of permissionCache.entries()) {\r\n if (now - cached.timestamp > CACHE_TTL) {\r\n permissionCache.delete(key);\r\n }\r\n }\r\n};\r\n","import type { PermissionMode, PermissionsArray } from \"@/types\";\r\nimport { isRef } from \"vue\";\r\n\r\nexport const normalizePermissions = (\r\n p: PermissionsArray | null | undefined,\r\n): string[] => {\r\n if (!p) return [];\r\n const v = isRef(p) ? p.value : p;\r\n return Array.isArray(v) ? v.filter(Boolean) : [];\r\n};\r\n\r\nexport const sortUniq = (arr: string[]) => Array.from(new Set(arr)).sort();\r\n\r\n/* Stable stringify for cache keys */\r\nexport const stableStringify = (value: any): string => {\r\n const seen = new WeakSet();\r\n\r\n return JSON.stringify(value, (_k, v) => {\r\n if (v && typeof v === \"object\") {\r\n if (seen.has(v)) return;\r\n seen.add(v);\r\n\r\n if (Array.isArray(v)) return v;\r\n\r\n return Object.keys(v)\r\n .sort()\r\n .reduce((acc: any, key) => {\r\n acc[key] = v[key];\r\n return acc;\r\n }, {});\r\n }\r\n return v;\r\n });\r\n};\r\n\r\nexport const isPermissionObject = (\r\n v: unknown,\r\n): v is { permissions: string[]; mode: PermissionMode } =>\r\n !!v &&\r\n typeof v === \"object\" &&\r\n !Array.isArray(v) &&\r\n \"permissions\" in v &&\r\n \"mode\" in v;\r\n","import { getCachedPermission, setCachedPermission } from \"@/core/cache\";\r\nimport { getCurrentPermissions, isDevMode } from \"./config\";\r\nimport { stableStringify, isPermissionObject } from \"@/utils/helpers\";\r\nimport type { PermissionValue, PermissionMode } from \"../types\";\r\n\r\n/**\r\n * Main Permission Evaluator\r\n * --------------------------\r\n * Supports:\r\n * - \"*\" (universal access)\r\n * - string[]\r\n * - object { permissions, mode }\r\n * - async caching\r\n */\r\n\r\nconst VALID_MODES = new Set<PermissionMode>([\r\n \"and\",\r\n \"or\",\r\n \"not\",\r\n \"startWith\",\r\n \"endWith\",\r\n \"regex\",\r\n]);\r\n\r\nconst validateRegexPattern = (pattern: string): boolean => {\r\n try {\r\n const regex = new RegExp(pattern);\r\n regex.test(\"\");\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n};\r\n\r\n/**\r\n * Synchronous permission evaluation\r\n * Used internally by directives that need immediate results\r\n */\r\nexport const checkPermissionSync = (\r\n permissionValue: PermissionValue,\r\n userPermissions?: string[]\r\n): boolean => {\r\n const current = userPermissions ?? getCurrentPermissions();\r\n\r\n if (permissionValue === \"*\") return true;\r\n\r\n if (typeof permissionValue === \"string\") {\r\n return current.includes(permissionValue);\r\n }\r\n\r\n if (Array.isArray(permissionValue)) {\r\n if (permissionValue.includes(\"*\")) return true;\r\n return permissionValue.some((v) => current.includes(v));\r\n }\r\n\r\n if (isPermissionObject(permissionValue)) {\r\n const { permissions, mode } = permissionValue;\r\n\r\n if (!VALID_MODES.has(mode)) {\r\n return false;\r\n }\r\n\r\n if (!Array.isArray(permissions) || permissions.length === 0) {\r\n return false;\r\n }\r\n\r\n if (permissions.includes(\"*\")) return true;\r\n\r\n const checks: Record<string, () => boolean> = {\r\n and: () => permissions.every((p) => current.includes(p)),\r\n or: () => permissions.some((p) => current.includes(p)),\r\n not: () => !permissions.some((p) => current.includes(p)),\r\n startWith: () =>\r\n permissions.some((p) => current.some((u) => u.startsWith(p))),\r\n endWith: () =>\r\n permissions.some((p) => current.some((u) => u.endsWith(p))),\r\n regex: () =>\r\n permissions.some((p) => {\r\n if (!validateRegexPattern(p)) {\r\n return false;\r\n }\r\n try {\r\n const r = new RegExp(p);\r\n return current.some((u) => r.test(u));\r\n } catch {\r\n return false;\r\n }\r\n }),\r\n };\r\n\r\n return checks[mode]?.() ?? false;\r\n }\r\n\r\n return false;\r\n};\r\n\r\nexport const hasPermission = async (\r\n permissionValue: PermissionValue,\r\n userPermissions?: string[]\r\n): Promise<boolean> => {\r\n const current = userPermissions ?? getCurrentPermissions();\r\n const cacheKey = stableStringify({ permissionValue, current });\r\n const cached = getCachedPermission(cacheKey);\r\n if (cached !== null) return cached;\r\n\r\n const log = (...args: any[]) => {\r\n if (isDevMode()) console.log(\"[v-permission:core]\", ...args);\r\n };\r\n\r\n const evaluate = async (value: PermissionValue): Promise<boolean> => {\r\n if (value === \"*\") return true;\r\n\r\n if (typeof value === \"string\") return current.includes(value);\r\n if (Array.isArray(value)) {\r\n if (value.includes(\"*\")) return true;\r\n return value.some((v) => current.includes(v));\r\n }\r\n if (isPermissionObject(value)) {\r\n const { permissions, mode } = value;\r\n\r\n if (!VALID_MODES.has(mode)) {\r\n log(\r\n `Invalid permission mode: \"${mode}\". Valid modes:`,\r\n Array.from(VALID_MODES)\r\n );\r\n return false;\r\n }\r\n\r\n if (!Array.isArray(permissions) || permissions.length === 0) {\r\n log(\"Permission array is empty or invalid\");\r\n return false;\r\n }\r\n\r\n if (permissions.includes(\"*\")) return true;\r\n\r\n const checks: Record<string, () => boolean> = {\r\n and: () => permissions.every((p) => current.includes(p)),\r\n or: () => permissions.some((p) => current.includes(p)),\r\n not: () => !permissions.some((p) => current.includes(p)),\r\n startWith: () =>\r\n permissions.some((p) => current.some((u) => u.startsWith(p))),\r\n endWith: () =>\r\n permissions.some((p) => current.some((u) => u.endsWith(p))),\r\n regex: () =>\r\n permissions.some((p) => {\r\n if (!validateRegexPattern(p)) {\r\n log(\"Invalid or dangerous regex pattern:\", p);\r\n return false;\r\n }\r\n try {\r\n const r = new RegExp(p);\r\n return current.some((u) => r.test(u));\r\n } catch (e) {\r\n log(\"Regex evaluation error:\", p, e);\r\n return false;\r\n }\r\n }),\r\n };\r\n\r\n return checks[mode]?.() ?? false;\r\n }\r\n\r\n log(\"Invalid permission value:\", value);\r\n return false;\r\n };\r\n\r\n const result = await evaluate(permissionValue);\r\n setCachedPermission(cacheKey, result);\r\n return result;\r\n};\r\n","import { isDevMode } from \"@/core\";\r\n\r\nexport const logDebug = (...args: any[]) => {\r\n if (isDevMode()) {\r\n console.groupCollapsed(\"[v-permission:debug]\");\r\n console.log(...args);\r\n console.groupEnd();\r\n }\r\n};\r\n","import { getReactivePermissions } from \"@/core/config\";\r\nimport { checkPermissionSync, hasPermission } from \"@/core/evaluator\";\r\nimport { logDebug } from \"@/utils/debug\";\r\nimport type { DirectiveBinding } from \"vue\";\r\nimport { isRef, watch } from \"vue\";\r\n\r\n/**\r\n * v-permission directive\r\n * -----------------------\r\n * Usage:\r\n * <button v-permission=\"'admin'\">Admin Only</button>\r\n * <div v-permission:show=\"['editor','moderator']\">Visible only for editors</div>\r\n */\r\n\r\ninterface PermissionElement extends HTMLElement {\r\n _vPermissionOriginalDisplay?: string;\r\n _vPermissionSkipUpdates?: boolean;\r\n _vPermissionParent?: Node | null;\r\n _vPermissionNextSibling?: Node | null;\r\n _vPermissionComment?: Comment | null;\r\n _vPermissionValueRef?: any;\r\n _vPermissionUnwatch?: () => void;\r\n _vPermissionUseShow?: boolean;\r\n}\r\n\r\n/**\r\n * Resolve the binding value, unwrapping a Ref if necessary.\r\n */\r\nfunction resolveValue(el: PermissionElement, raw: any): any {\r\n const storedRef = el._vPermissionValueRef;\r\n if (storedRef && isRef(storedRef)) return storedRef.value;\r\n if (isRef(raw)) return raw.value;\r\n return raw;\r\n}\r\n\r\n/**\r\n * Capture the element's original display value so we can restore it later\r\n * when toggling via the .show / :show modifier.\r\n */\r\nfunction captureOriginalDisplay(el: PermissionElement): void {\r\n try {\r\n const computed = window.getComputedStyle(el);\r\n el._vPermissionOriginalDisplay = computed.display || el.style.display || \"\";\r\n } catch {\r\n el._vPermissionOriginalDisplay = el.style.display || \"\";\r\n }\r\n}\r\n\r\n/**\r\n * Remove element from DOM by replacing it with a comment placeholder.\r\n */\r\nfunction removeFromDom(el: PermissionElement): void {\r\n if (el.parentNode && !el._vPermissionComment) {\r\n const comment = document.createComment(\"v-permission\");\r\n el._vPermissionParent = el.parentNode;\r\n el._vPermissionNextSibling = el.nextSibling;\r\n el._vPermissionComment = comment;\r\n el.replaceWith(comment);\r\n logDebug(\"Removed element from DOM\");\r\n }\r\n}\r\n\r\n/**\r\n * Restore element previously removed from DOM via the comment placeholder.\r\n */\r\nfunction restoreToDom(el: PermissionElement): void {\r\n if (el._vPermissionComment) {\r\n const comment = el._vPermissionComment;\r\n if (!el.parentNode) {\r\n comment.replaceWith(el);\r\n } else {\r\n comment.remove();\r\n }\r\n el._vPermissionComment = undefined;\r\n }\r\n}\r\n\r\n/**\r\n * Apply the resolved permission state to the element.\r\n * Handles both DOM removal and display:none strategies.\r\n */\r\nfunction applyPermissionState(el: PermissionElement, value: any): void {\r\n const useShow = el._vPermissionUseShow === true;\r\n const allowed = checkPermissionSync(value);\r\n\r\n if (allowed) {\r\n restoreToDom(el);\r\n if (useShow) {\r\n el.style.display = el._vPermissionOriginalDisplay || \"\";\r\n }\r\n } else if (useShow) {\r\n el.style.display = \"none\";\r\n } else {\r\n removeFromDom(el);\r\n }\r\n\r\n // Populate the async cache in the background. Don't let the result override\r\n // the sync decision above — the sync evaluator already covers every mode\r\n // supported by hasPermission.\r\n hasPermission(value).catch((e) => {\r\n console.error(\"[v-permission] Async evaluation failed:\", e);\r\n });\r\n}\r\n\r\nexport const vPermission = {\r\n mounted(el: PermissionElement, binding: DirectiveBinding) {\r\n const { modifiers, arg } = binding;\r\n\r\n el._vPermissionUseShow = arg === \"show\" || modifiers.show === true;\r\n el._vPermissionValueRef = isRef(binding.value) ? binding.value : null;\r\n\r\n captureOriginalDisplay(el);\r\n\r\n if (modifiers.once) {\r\n el._vPermissionSkipUpdates = true;\r\n }\r\n\r\n const value = resolveValue(el, binding.value);\r\n applyPermissionState(el, value);\r\n logDebug(\"Mounted v-permission =>\", value);\r\n\r\n // Re-evaluate when the global permissions ref changes\r\n // (e.g., after login/logout via setPermissions or configurePermission).\r\n if (!modifiers.once) {\r\n const stop = watch(\r\n getReactivePermissions(),\r\n () => {\r\n if (el._vPermissionSkipUpdates) return;\r\n const current = resolveValue(el, binding.value);\r\n applyPermissionState(el, current);\r\n },\r\n { deep: true },\r\n );\r\n el._vPermissionUnwatch = stop;\r\n }\r\n },\r\n\r\n updated(el: PermissionElement, binding: DirectiveBinding) {\r\n if (el._vPermissionSkipUpdates) return;\r\n\r\n const value = resolveValue(el, binding.value);\r\n let oldValue = binding.oldValue;\r\n if (isRef(oldValue)) oldValue = oldValue.value;\r\n\r\n const valueChanged = JSON.stringify(value) !== JSON.stringify(oldValue);\r\n\r\n // .lazy: only re-evaluate when the binding value itself changes.\r\n if (binding.modifiers.lazy && !valueChanged) return;\r\n\r\n if (valueChanged && el.parentNode) {\r\n captureOriginalDisplay(el);\r\n }\r\n\r\n applyPermissionState(el, value);\r\n },\r\n\r\n unmounted(el: PermissionElement) {\r\n if (el._vPermissionUnwatch) {\r\n el._vPermissionUnwatch();\r\n el._vPermissionUnwatch = undefined;\r\n }\r\n if (el._vPermissionComment) {\r\n el._vPermissionComment.remove();\r\n }\r\n delete el._vPermissionOriginalDisplay;\r\n delete el._vPermissionSkipUpdates;\r\n delete el._vPermissionParent;\r\n delete el._vPermissionNextSibling;\r\n delete el._vPermissionComment;\r\n delete el._vPermissionValueRef;\r\n delete el._vPermissionUseShow;\r\n },\r\n};\r\n\r\nexport {};\r\n","import {\r\n clearPermissionCache,\r\n configurePermission,\r\n getReactivePermissions,\r\n} from \"@/core\";\r\nimport { vPermission } from \"@/directives/v-permission\";\r\nimport type { PluginOptions } from \"@/types\";\r\nimport { normalizePermissions } from \"@/utils/helpers\";\r\nimport { getPermissionsFromStorage } from \"@/utils/storage\";\r\nimport type { App } from \"vue\";\r\n\r\nexport default {\r\n async install(app: App, options?: PluginOptions) {\r\n let permissions: any = [];\r\n const decryptFn = options?.decrypt ?? options?.transform;\r\n\r\n if (options?.fetchPermissions) {\r\n try {\r\n const fetched = await options.fetchPermissions();\r\n if (decryptFn && fetched && !Array.isArray(fetched)) {\r\n const decrypted = await decryptFn(fetched);\r\n permissions = Array.isArray(decrypted) ? decrypted : [];\r\n } else {\r\n permissions = normalizePermissions(fetched);\r\n }\r\n } catch (e) {\r\n console.error(\"[v-permission] Failed to fetch permissions:\", e);\r\n permissions = getPermissionsFromStorage() ?? [];\r\n }\r\n } else if (options?.permissions !== undefined) {\r\n if (decryptFn && options.permissions && !Array.isArray(options.permissions)) {\r\n const decrypted = await decryptFn(options.permissions);\r\n permissions = Array.isArray(decrypted) ? decrypted : [];\r\n } else {\r\n permissions = normalizePermissions(options.permissions);\r\n }\r\n } else {\r\n permissions = getPermissionsFromStorage() ?? [];\r\n }\r\n\r\n clearPermissionCache();\r\n // configurePermission also handles persistence based on the persist flag,\r\n // so we forward it here instead of saving twice.\r\n configurePermission(permissions, {\r\n developmentMode: options?.developmentMode,\r\n persist: options?.persist,\r\n decrypt: options?.decrypt,\r\n transform: options?.transform,\r\n });\r\n\r\n // Provide reactive permissions to components and directives\r\n const reactivePermissions = getReactivePermissions();\r\n app.provide(\"__v_permission_reactive__\", reactivePermissions);\r\n\r\n app.directive(\"permission\", vPermission);\r\n },\r\n};\r\n"],"names":["STORAGE_KEY","getIsBrowser","encrypt","value","json","encoded","binaryString","byte","decrypt","bytes","i","savePermissionsToStorage","permissions","e","getPermissionsFromStorage","stored","clearPermissionsFromStorage","globalConfig","globalReactivePermissions","ref","getDecryptHook","setDecryptHook","hook","configurePermission","options","decryptFn","isRef","refPerms","decrypted","res","perms","currentVal","permsArray","getReactivePermissions","getCurrentPermissions","val","isDevMode","permissionCache","CACHE_MAX_SIZE","CACHE_TTL","getCachedPermission","key","cached","setCachedPermission","oldestKey","clearPermissionCache","invalidateCache","now","normalizePermissions","p","v","sortUniq","arr","stableStringify","seen","_k","acc","isPermissionObject","VALID_MODES","validateRegexPattern","pattern","checkPermissionSync","permissionValue","userPermissions","current","mode","checks","u","r","_a","hasPermission","cacheKey","log","args","result","logDebug","resolveValue","el","raw","storedRef","captureOriginalDisplay","computed","removeFromDom","comment","restoreToDom","applyPermissionState","useShow","vPermission","binding","modifiers","arg","stop","watch","oldValue","valueChanged","PermissionPlugin","app","fetched","reactivePermissions"],"mappings":"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"}