react-permission-gate 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,31 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ interface ProtectedRouteProps {
5
+ /** Required permission to access route */
6
+ permission?: string;
7
+ /** Allow access if user has ANY of these permissions */
8
+ anyOf?: string[];
9
+ /** Allow access if user has ALL of these permissions */
10
+ allOf?: string[];
11
+ /** Route content */
12
+ children: ReactNode;
13
+ /** Redirect path when access is denied (default: "/") */
14
+ redirectTo?: string;
15
+ /** Component to show while loading (default: null) */
16
+ loadingComponent?: ReactNode;
17
+ }
18
+ /**
19
+ * Route wrapper that checks permissions before rendering.
20
+ * Redirects when permission check fails. Admin users bypass all checks.
21
+ *
22
+ * @example
23
+ * <Route path="/users" element={
24
+ * <ProtectedRoute permission="users.read">
25
+ * <UsersPage />
26
+ * </ProtectedRoute>
27
+ * } />
28
+ */
29
+ declare function ProtectedRoute({ permission, anyOf, allOf, children, redirectTo, loadingComponent, }: ProtectedRouteProps): react_jsx_runtime.JSX.Element;
30
+
31
+ export { ProtectedRoute, type ProtectedRouteProps };
@@ -0,0 +1,31 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ interface ProtectedRouteProps {
5
+ /** Required permission to access route */
6
+ permission?: string;
7
+ /** Allow access if user has ANY of these permissions */
8
+ anyOf?: string[];
9
+ /** Allow access if user has ALL of these permissions */
10
+ allOf?: string[];
11
+ /** Route content */
12
+ children: ReactNode;
13
+ /** Redirect path when access is denied (default: "/") */
14
+ redirectTo?: string;
15
+ /** Component to show while loading (default: null) */
16
+ loadingComponent?: ReactNode;
17
+ }
18
+ /**
19
+ * Route wrapper that checks permissions before rendering.
20
+ * Redirects when permission check fails. Admin users bypass all checks.
21
+ *
22
+ * @example
23
+ * <Route path="/users" element={
24
+ * <ProtectedRoute permission="users.read">
25
+ * <UsersPage />
26
+ * </ProtectedRoute>
27
+ * } />
28
+ */
29
+ declare function ProtectedRoute({ permission, anyOf, allOf, children, redirectTo, loadingComponent, }: ProtectedRouteProps): react_jsx_runtime.JSX.Element;
30
+
31
+ export { ProtectedRoute, type ProtectedRouteProps };
@@ -0,0 +1,74 @@
1
+ // src/react-router/protected-route.tsx
2
+ import { Navigate, useLocation } from "react-router-dom";
3
+
4
+ // src/react/use-permissions.ts
5
+ import { useContext } from "react";
6
+
7
+ // src/react/context.ts
8
+ import { createContext } from "react";
9
+ var PermissionContext = createContext(
10
+ null
11
+ );
12
+
13
+ // src/react/use-permissions.ts
14
+ function usePermissions() {
15
+ const context = useContext(PermissionContext);
16
+ if (!context) {
17
+ throw new Error(
18
+ "usePermissions must be used within a <PermissionProvider>"
19
+ );
20
+ }
21
+ const { checker, permissions, userType, isAdmin, isLoading } = context;
22
+ return {
23
+ /** Raw permission strings */
24
+ permissions,
25
+ /** User type string */
26
+ userType,
27
+ /** Whether the user is an admin type */
28
+ isAdmin,
29
+ /** Whether permission data is still loading */
30
+ isLoading,
31
+ /** Check if user has a specific permission */
32
+ hasPermission: (permission) => checker.hasPermission(permission),
33
+ /** Check if user has ANY of the given permissions */
34
+ hasAnyPermission: (permissionList) => checker.hasAnyPermission(permissionList),
35
+ /** Check if user has ALL of the given permissions */
36
+ hasAllPermissions: (permissionList) => checker.hasAllPermissions(permissionList),
37
+ /** Detailed permission check with reason */
38
+ check: (permission) => checker.check(permission)
39
+ };
40
+ }
41
+
42
+ // src/react-router/protected-route.tsx
43
+ import { Fragment, jsx } from "react/jsx-runtime";
44
+ function ProtectedRoute({
45
+ permission,
46
+ anyOf,
47
+ allOf,
48
+ children,
49
+ redirectTo = "/",
50
+ loadingComponent = null
51
+ }) {
52
+ const location = useLocation();
53
+ const { hasPermission, hasAnyPermission, hasAllPermissions, isAdmin, isLoading } = usePermissions();
54
+ if (isLoading) {
55
+ return /* @__PURE__ */ jsx(Fragment, { children: loadingComponent });
56
+ }
57
+ if (isAdmin) {
58
+ return /* @__PURE__ */ jsx(Fragment, { children });
59
+ }
60
+ if (permission && !hasPermission(permission)) {
61
+ return /* @__PURE__ */ jsx(Navigate, { to: redirectTo, state: { from: location }, replace: true });
62
+ }
63
+ if (anyOf && anyOf.length > 0 && !hasAnyPermission(anyOf)) {
64
+ return /* @__PURE__ */ jsx(Navigate, { to: redirectTo, state: { from: location }, replace: true });
65
+ }
66
+ if (allOf && allOf.length > 0 && !hasAllPermissions(allOf)) {
67
+ return /* @__PURE__ */ jsx(Navigate, { to: redirectTo, state: { from: location }, replace: true });
68
+ }
69
+ return /* @__PURE__ */ jsx(Fragment, { children });
70
+ }
71
+ export {
72
+ ProtectedRoute
73
+ };
74
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/react-router/protected-route.tsx","../../src/react/use-permissions.ts","../../src/react/context.ts"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport { Navigate, useLocation } from \"react-router-dom\";\nimport { usePermissions } from \"../react/use-permissions\";\n\nexport interface ProtectedRouteProps {\n /** Required permission to access route */\n permission?: string;\n /** Allow access if user has ANY of these permissions */\n anyOf?: string[];\n /** Allow access if user has ALL of these permissions */\n allOf?: string[];\n /** Route content */\n children: ReactNode;\n /** Redirect path when access is denied (default: \"/\") */\n redirectTo?: string;\n /** Component to show while loading (default: null) */\n loadingComponent?: ReactNode;\n}\n\n/**\n * Route wrapper that checks permissions before rendering.\n * Redirects when permission check fails. Admin users bypass all checks.\n *\n * @example\n * <Route path=\"/users\" element={\n * <ProtectedRoute permission=\"users.read\">\n * <UsersPage />\n * </ProtectedRoute>\n * } />\n */\nexport function ProtectedRoute({\n permission,\n anyOf,\n allOf,\n children,\n redirectTo = \"/\",\n loadingComponent = null,\n}: ProtectedRouteProps) {\n const location = useLocation();\n const { hasPermission, hasAnyPermission, hasAllPermissions, isAdmin, isLoading } =\n usePermissions();\n\n if (isLoading) {\n return <>{loadingComponent}</>;\n }\n\n if (isAdmin) {\n return <>{children}</>;\n }\n\n if (permission && !hasPermission(permission)) {\n return <Navigate to={redirectTo} state={{ from: location }} replace />;\n }\n\n if (anyOf && anyOf.length > 0 && !hasAnyPermission(anyOf)) {\n return <Navigate to={redirectTo} state={{ from: location }} replace />;\n }\n\n if (allOf && allOf.length > 0 && !hasAllPermissions(allOf)) {\n return <Navigate to={redirectTo} state={{ from: location }} replace />;\n }\n\n return <>{children}</>;\n}\n","import { useContext } from \"react\";\nimport type { PermissionCheckResult } from \"../core/types\";\nimport { PermissionContext } from \"./context\";\n\n/**\n * Hook for checking user permissions within a PermissionProvider.\n *\n * @example\n * const { hasPermission, isAdmin } = usePermissions();\n *\n * if (hasPermission(\"users.read\")) { ... }\n * if (isAdmin) { ... }\n */\nexport function usePermissions() {\n const context = useContext(PermissionContext);\n\n if (!context) {\n throw new Error(\n \"usePermissions must be used within a <PermissionProvider>\",\n );\n }\n\n const { checker, permissions, userType, isAdmin, isLoading } = context;\n\n return {\n /** Raw permission strings */\n permissions,\n /** User type string */\n userType,\n /** Whether the user is an admin type */\n isAdmin,\n /** Whether permission data is still loading */\n isLoading,\n /** Check if user has a specific permission */\n hasPermission: (permission: string): boolean =>\n checker.hasPermission(permission),\n /** Check if user has ANY of the given permissions */\n hasAnyPermission: (permissionList: string[]): boolean =>\n checker.hasAnyPermission(permissionList),\n /** Check if user has ALL of the given permissions */\n hasAllPermissions: (permissionList: string[]): boolean =>\n checker.hasAllPermissions(permissionList),\n /** Detailed permission check with reason */\n check: (permission: string): PermissionCheckResult =>\n checker.check(permission),\n };\n}\n","import { createContext } from \"react\";\nimport type { PermissionChecker } from \"../core/permission-checker\";\n\nexport interface PermissionContextValue {\n checker: PermissionChecker;\n permissions: string[];\n userType: string;\n isAdmin: boolean;\n isLoading: boolean;\n}\n\nexport const PermissionContext = createContext<PermissionContextValue | null>(\n null,\n);\n"],"mappings":";AACA,SAAS,UAAU,mBAAmB;;;ACDtC,SAAS,kBAAkB;;;ACA3B,SAAS,qBAAqB;AAWvB,IAAM,oBAAoB;AAAA,EAC/B;AACF;;;ADAO,SAAS,iBAAiB;AAC/B,QAAM,UAAU,WAAW,iBAAiB;AAE5C,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,EAAE,SAAS,aAAa,UAAU,SAAS,UAAU,IAAI;AAE/D,SAAO;AAAA;AAAA,IAEL;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA;AAAA;AAAA,IAEA,eAAe,CAAC,eACd,QAAQ,cAAc,UAAU;AAAA;AAAA,IAElC,kBAAkB,CAAC,mBACjB,QAAQ,iBAAiB,cAAc;AAAA;AAAA,IAEzC,mBAAmB,CAAC,mBAClB,QAAQ,kBAAkB,cAAc;AAAA;AAAA,IAE1C,OAAO,CAAC,eACN,QAAQ,MAAM,UAAU;AAAA,EAC5B;AACF;;;ADHW;AAbJ,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb,mBAAmB;AACrB,GAAwB;AACtB,QAAM,WAAW,YAAY;AAC7B,QAAM,EAAE,eAAe,kBAAkB,mBAAmB,SAAS,UAAU,IAC7E,eAAe;AAEjB,MAAI,WAAW;AACb,WAAO,gCAAG,4BAAiB;AAAA,EAC7B;AAEA,MAAI,SAAS;AACX,WAAO,gCAAG,UAAS;AAAA,EACrB;AAEA,MAAI,cAAc,CAAC,cAAc,UAAU,GAAG;AAC5C,WAAO,oBAAC,YAAS,IAAI,YAAY,OAAO,EAAE,MAAM,SAAS,GAAG,SAAO,MAAC;AAAA,EACtE;AAEA,MAAI,SAAS,MAAM,SAAS,KAAK,CAAC,iBAAiB,KAAK,GAAG;AACzD,WAAO,oBAAC,YAAS,IAAI,YAAY,OAAO,EAAE,MAAM,SAAS,GAAG,SAAO,MAAC;AAAA,EACtE;AAEA,MAAI,SAAS,MAAM,SAAS,KAAK,CAAC,kBAAkB,KAAK,GAAG;AAC1D,WAAO,oBAAC,YAAS,IAAI,YAAY,OAAO,EAAE,MAAM,SAAS,GAAG,SAAO,MAAC;AAAA,EACtE;AAEA,SAAO,gCAAG,UAAS;AACrB;","names":[]}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "react-permission-gate",
3
+ "version": "0.1.0",
4
+ "description": "Flexible, type-safe permission management for React and React Router applications",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "import": "./dist/core/index.js",
9
+ "require": "./dist/core/index.cjs",
10
+ "types": "./dist/core/index.d.ts"
11
+ },
12
+ "./react": {
13
+ "import": "./dist/react/index.js",
14
+ "require": "./dist/react/index.cjs",
15
+ "types": "./dist/react/index.d.ts"
16
+ },
17
+ "./react-router": {
18
+ "import": "./dist/react-router/index.js",
19
+ "require": "./dist/react-router/index.cjs",
20
+ "types": "./dist/react-router/index.d.ts"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "README.md",
26
+ "LICENSE"
27
+ ],
28
+ "scripts": {
29
+ "build": "tsup",
30
+ "test": "vitest run",
31
+ "test:watch": "vitest",
32
+ "typecheck": "tsc --noEmit",
33
+ "prepublishOnly": "npm run build"
34
+ },
35
+ "keywords": [
36
+ "react",
37
+ "permissions",
38
+ "authorization",
39
+ "rbac",
40
+ "access-control",
41
+ "react-router",
42
+ "gate"
43
+ ],
44
+ "author": "",
45
+ "license": "MIT",
46
+ "peerDependencies": {
47
+ "react": ">=18",
48
+ "react-router-dom": ">=6"
49
+ },
50
+ "peerDependenciesMeta": {
51
+ "react": {
52
+ "optional": true
53
+ },
54
+ "react-router-dom": {
55
+ "optional": true
56
+ }
57
+ },
58
+ "devDependencies": {
59
+ "@testing-library/jest-dom": "^6.6.3",
60
+ "@testing-library/react": "^16.3.0",
61
+ "@types/react": "^19.1.0",
62
+ "@types/react-dom": "^19.1.2",
63
+ "jsdom": "^26.0.0",
64
+ "react": "^19.1.0",
65
+ "react-dom": "^19.1.0",
66
+ "react-router-dom": "^7.4.0",
67
+ "tsup": "^8.4.0",
68
+ "typescript": "^5.8.2",
69
+ "vitest": "^3.1.1"
70
+ }
71
+ }