@devwizard/laravel-react-permissions
Version:
🔐 Modern, Laravel-inspired permissions system for React/Inertia.js with advanced pattern matching, boolean expressions, and zero dependencies. Features wildcard patterns, custom permissions, and full TypeScript support.
184 lines (182 loc) • 7.48 kB
JavaScript
import { usePage } from '@inertiajs/react';
import { jsx, Fragment } from 'react/jsx-runtime';
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
function usePermissions(permissions) {
const { auth } = usePage().props;
const userPermissions = permissions !== void 0 ? permissions : auth?.user?.permissions || [];
const hasPermission = /* @__PURE__ */ __name((permission) => {
if (permission.trim() === "true") return true;
if (permission.trim() === "false") return false;
if (permission.includes("*") || permission.includes("?") || permission.includes("||") || permission.includes("&&") || permission.includes("|") || permission.includes("&")) {
return hasPermissionPattern(permission);
}
return userPermissions.includes(permission);
}, "hasPermission");
const hasAnyPermission = /* @__PURE__ */ __name((permissions2) => {
return permissions2.some((permission) => userPermissions.includes(permission));
}, "hasAnyPermission");
const hasAllPermissions = /* @__PURE__ */ __name((permissions2) => {
return permissions2.every(
(permission) => userPermissions.includes(permission)
);
}, "hasAllPermissions");
const checkSimplePermissionPattern = /* @__PURE__ */ __name((pattern) => {
if (pattern.trim() === "true") return true;
if (pattern.trim() === "false") return false;
if (pattern.trim() === "*") return true;
let regexPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
regexPattern = `^${regexPattern}$`;
const regex = new RegExp(regexPattern);
return userPermissions.some((permission) => regex.test(permission));
}, "checkSimplePermissionPattern");
const evaluatePermissionExpression = /* @__PURE__ */ __name((expression) => {
if (expression.trim() === "true") return true;
if (expression.trim() === "false") return false;
let jsExpression = expression;
jsExpression = jsExpression.replace(/\|\|/g, " DOUBLE_PIPE ").replace(/&&/g, " DOUBLE_AMP ");
jsExpression = jsExpression.replace(/\|/g, " || ").replace(/&/g, " && ");
jsExpression = jsExpression.replace(/DOUBLE_PIPE/g, " || ").replace(/DOUBLE_AMP/g, " && ");
jsExpression = jsExpression.replace(/\s+/g, " ").trim();
const permissionRegex = /(?:\*|\?|[a-zA-Z_][a-zA-Z0-9_.*?-]*(?:\.[a-zA-Z0-9_.*?-]*)*|true|false)(?![|&])/g;
const permissions2 = jsExpression.match(permissionRegex) || [];
let evaluatedExpression = jsExpression;
for (const permission of permissions2) {
if (permission === "true" || permission === "false") continue;
const hasPermissionResult = checkSimplePermissionPattern(permission);
if (permission === "*" || permission === "?") {
const wildcardRegex = new RegExp(
`\\${permission}(?![a-zA-Z0-9_.])`,
"g"
);
evaluatedExpression = evaluatedExpression.replace(
wildcardRegex,
hasPermissionResult.toString()
);
} else {
const escapedPermission = permission.replace(
/[.*+?^${}()|[\]\\]/g,
"\\$&"
);
const permissionRegex2 = new RegExp(`\\b${escapedPermission}\\b`, "g");
evaluatedExpression = evaluatedExpression.replace(
permissionRegex2,
hasPermissionResult.toString()
);
}
}
try {
return Function(`"use strict"; return (${evaluatedExpression})`)();
} catch (error) {
console.warn("Invalid permission expression:", expression, error);
return false;
}
}, "evaluatePermissionExpression");
const hasPermissionPattern = /* @__PURE__ */ __name((pattern) => {
if (pattern.includes("||") || pattern.includes("&&") || pattern.includes("|") || pattern.includes("&")) {
return evaluatePermissionExpression(pattern);
}
return checkSimplePermissionPattern(pattern);
}, "hasPermissionPattern");
const hasAnyPattern = /* @__PURE__ */ __name((patterns) => {
return patterns.some((pattern) => hasPermissionPattern(pattern));
}, "hasAnyPattern");
const hasAllPatterns = /* @__PURE__ */ __name((patterns) => {
return patterns.every((pattern) => hasPermissionPattern(pattern));
}, "hasAllPatterns");
const getMatchingPermissions = /* @__PURE__ */ __name((pattern) => {
let regexPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".");
regexPattern = `^${regexPattern}$`;
const regex = new RegExp(regexPattern);
return userPermissions.filter((permission) => regex.test(permission));
}, "getMatchingPermissions");
const checkExpression = /* @__PURE__ */ __name((expression) => {
return evaluatePermissionExpression(expression);
}, "checkExpression");
const isValidExpression = /* @__PURE__ */ __name((expression) => {
try {
let testExpression = expression.replace(/\|(?!\|)/g, "||").replace(/&(?!&)/g, "&&");
testExpression = testExpression.replace(/\|\|\|/g, "||").replace(/&&&/g, "&&");
testExpression = testExpression.replace(
/[a-zA-Z_][a-zA-Z0-9_.*?]*(?:\.[a-zA-Z0-9_.*?]*)*(?![|&])/g,
"true"
);
Function(`"use strict"; return (${testExpression})`);
return true;
} catch {
return false;
}
}, "isValidExpression");
return {
userPermissions,
hasPermission,
hasAnyPermission,
hasAllPermissions,
hasPermissionPattern,
hasAnyPattern,
hasAllPatterns,
getMatchingPermissions,
checkExpression,
isValidExpression,
isAuthenticated: !!auth?.user
};
}
__name(usePermissions, "usePermissions");
function Can({
permission,
expression,
anyPermissions,
allPermissions,
pattern,
anyPatterns,
allPatterns,
permissions,
children,
fallback = null,
requireAuth = true
}) {
const {
hasPermission,
hasAnyPermission,
hasAllPermissions,
hasPermissionPattern,
hasAnyPattern,
hasAllPatterns,
checkExpression,
isAuthenticated
} = usePermissions(permissions);
if (requireAuth && !isAuthenticated) {
return /* @__PURE__ */ jsx(Fragment, { children: fallback });
}
let hasAccess = false;
if (expression) {
hasAccess = checkExpression(expression);
} else if (permission) {
hasAccess = hasPermission(permission);
} else if (anyPermissions && anyPermissions.length > 0) {
hasAccess = hasAnyPermission(anyPermissions);
} else if (allPermissions) {
hasAccess = hasAllPermissions(allPermissions);
} else if (anyPatterns && anyPatterns.length > 0) {
hasAccess = hasAnyPattern(anyPatterns);
} else if (allPatterns && allPatterns.length > 0) {
hasAccess = hasAllPatterns(allPatterns);
} else if (pattern) {
hasAccess = hasPermissionPattern(pattern);
} else if (!requireAuth) {
hasAccess = true;
}
return hasAccess ? /* @__PURE__ */ jsx(Fragment, { children }) : /* @__PURE__ */ jsx(Fragment, { children: fallback });
}
__name(Can, "Can");
function withPermission(Component, options) {
const WrappedComponent = /* @__PURE__ */ __name((props) => {
return /* @__PURE__ */ jsx(Can, { ...options, children: /* @__PURE__ */ jsx(Component, { ...props }) });
}, "WrappedComponent");
WrappedComponent.displayName = `withPermission(${Component.displayName || Component.name})`;
return WrappedComponent;
}
__name(withPermission, "withPermission");
export { Can, usePermissions, withPermission };
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map