vue-permission-directive
Version:
A flexible Vue 3 directive for managing user permissions with support for AND, OR, regex, and pattern-based checks.
178 lines (173 loc) • 6.68 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var vue = require('vue');
// -----------------------------
// 🔧 CONFIG
// -----------------------------
let globalConfig = { permissions: null };
let isDevelopmentMode = false;
const permissionCache = new Map();
const STORAGE_KEY = "__v_permission__";
// وهمي بسيط - غيّره حسب نوع التشفير الحقيقي اللي عندك
const encrypt = (value) => btoa(JSON.stringify(value));
const decrypt = (value) => JSON.parse(atob(value));
const configurePermissionDirective = (permissions, options) => {
var _a;
globalConfig.permissions = permissions;
isDevelopmentMode = (_a = options === null || options === void 0 ? void 0 : options.developmentMode) !== null && _a !== void 0 ? _a : false;
permissionCache.clear();
// ✅ Store encrypted permissions
try {
const encrypted = encrypt(permissions);
localStorage.setItem(STORAGE_KEY, encrypted);
}
catch (e) {
isDevelopmentMode &&
console.warn("[v-permission] Failed to store permissions:", e);
}
};
const initPermissionDirectiveIfNeeded = () => {
try {
const stored = localStorage.getItem(STORAGE_KEY);
if (stored) {
const decrypted = decrypt(stored);
configurePermissionDirective(decrypted);
}
}
catch (e) {
isDevelopmentMode &&
console.warn("[v-permission] Failed to init permissions:", e);
}
};
const setDevelopmentMode = (enabled) => {
isDevelopmentMode = enabled;
};
const clearPermissionCache = () => {
permissionCache.clear();
};
// -----------------------------
// 🔍 INTERNAL HELPERS
// -----------------------------
const getCurrentPermissions = () => {
const { permissions } = globalConfig;
return vue.isRef(permissions) ? permissions.value : permissions !== null && permissions !== void 0 ? permissions : [];
};
const hasCachedPermission = (key) => permissionCache.has(key) ? permissionCache.get(key) : null;
// -----------------------------
// ✅ hasPermission()
// -----------------------------
const hasPermission = async (permissionValue) => {
const currentPermissions = getCurrentPermissions();
const cacheKey = JSON.stringify(permissionValue);
const cached = hasCachedPermission(cacheKey);
if (cached !== null)
return cached;
const checkPermission = async (perm) => currentPermissions.includes(perm);
const evaluate = async (value) => {
var _a, _b;
if (typeof value === "string")
return await checkPermission(value);
if (Array.isArray(value)) {
const results = await Promise.all(value.map(hasPermission));
return results.some(Boolean);
}
if (typeof value === "object" && value.permissions && value.mode) {
const perms = value.permissions;
const mode = value.mode;
const checks = {
and: () => perms.every((p) => currentPermissions.includes(p)),
or: () => perms.some((p) => currentPermissions.includes(p)),
startWith: () => perms.some((p) => currentPermissions.some((u) => u.startsWith(p))),
endWith: () => perms.some((p) => currentPermissions.some((u) => u.endsWith(p))),
exact: () => perms.some((p) => currentPermissions.includes(p)),
regex: () => perms.some((p) => {
try {
const r = new RegExp(p);
return currentPermissions.some((u) => r.test(u));
}
catch (e) {
isDevelopmentMode &&
console.warn("[v-permission] Invalid regex", p, e);
return false;
}
}),
};
return (_b = (_a = checks[mode]) === null || _a === void 0 ? void 0 : _a.call(checks)) !== null && _b !== void 0 ? _b : false;
}
isDevelopmentMode &&
console.warn("[v-permission] Invalid permission value:", value);
return false;
};
const result = await evaluate(permissionValue);
permissionCache.set(cacheKey, result);
return result;
};
// -----------------------------
// 🎯 v-permission Directive
// -----------------------------
const vPermission = {
mounted(el, binding) {
var _a;
const value = binding.value;
const modifiers = binding.modifiers;
const showOnly = binding.arg === "show";
const originalDisplay = el.style.display || "";
const applyPermission = async () => {
var _a, _b;
try {
const allowed = await hasPermission(value);
if (allowed) {
if (showOnly)
el.style.display = originalDisplay;
}
else {
if (showOnly)
el.style.display = "none";
else
(_a = el.remove) === null || _a === void 0 ? void 0 : _a.call(el);
}
}
catch (err) {
isDevelopmentMode &&
console.warn("[v-permission] Error evaluating permission", err);
if (showOnly)
el.style.display = "none";
else
(_b = el.remove) === null || _b === void 0 ? void 0 : _b.call(el);
}
};
if (!globalConfig.permissions) {
isDevelopmentMode &&
console.warn("[v-permission] Permissions not configured");
if (!showOnly)
(_a = el.remove) === null || _a === void 0 ? void 0 : _a.call(el);
return;
}
if (modifiers.once) {
applyPermission();
}
else if (vue.isRef(globalConfig.permissions) && !modifiers.lazy) {
vue.watchEffect(() => {
applyPermission();
});
}
else {
applyPermission();
}
},
};
// -----------------------------
// 🔌 Plugin Installer
// -----------------------------
const PermissionPlugin = {
install(app) {
app.directive("permission", vPermission);
},
};
exports.clearPermissionCache = clearPermissionCache;
exports.configurePermissionDirective = configurePermissionDirective;
exports.default = PermissionPlugin;
exports.hasPermission = hasPermission;
exports.initPermissionDirectiveIfNeeded = initPermissionDirectiveIfNeeded;
exports.setDevelopmentMode = setDevelopmentMode;
exports.vPermission = vPermission;