docusaurus-roles-plugin 1.0.0-beta.1
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.
- package/README.md +249 -0
- package/dist/index.cjs +119 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +35 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +81 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime/index.cjs +202 -0
- package/dist/runtime/index.cjs.map +1 -0
- package/dist/runtime/index.d.cts +43 -0
- package/dist/runtime/index.d.ts +43 -0
- package/dist/runtime/index.js +161 -0
- package/dist/runtime/index.js.map +1 -0
- package/package.json +52 -0
- package/src/theme/BlogListPage/index.tsx +20 -0
- package/src/theme/BlogPostItem/Forbidden.tsx +17 -0
- package/src/theme/BlogPostItem/index.tsx +22 -0
- package/src/theme/BlogSidebar/index.tsx +26 -0
- package/src/theme/DocItem/Forbidden.tsx +15 -0
- package/src/theme/DocItem/index.tsx +20 -0
- package/src/theme/DocSidebar/index.tsx +29 -0
- package/src/theme/NavbarItem/index.tsx +16 -0
- package/src/theme/RoleGate.tsx +53 -0
- package/src/theme/RootWarning.tsx +18 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/runtime/index.ts
|
|
31
|
+
var runtime_exports = {};
|
|
32
|
+
__export(runtime_exports, {
|
|
33
|
+
BaseForbiddenContent: () => BaseForbiddenContent,
|
|
34
|
+
RolesContext: () => RolesContext,
|
|
35
|
+
RolesProvider: () => RolesProvider,
|
|
36
|
+
isAllowed: () => isAllowed,
|
|
37
|
+
useRoles: () => useRoles
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(runtime_exports);
|
|
40
|
+
|
|
41
|
+
// src/runtime/context.tsx
|
|
42
|
+
var import_react = __toESM(require("react"), 1);
|
|
43
|
+
var RolesContext = import_react.default.createContext({
|
|
44
|
+
roles: [],
|
|
45
|
+
loading: false,
|
|
46
|
+
hasProvider: false
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// src/runtime/RolesProvider.tsx
|
|
50
|
+
var import_react2 = require("react");
|
|
51
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
52
|
+
var DefaultRolesLoading = () => {
|
|
53
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
54
|
+
"div",
|
|
55
|
+
{
|
|
56
|
+
style: {
|
|
57
|
+
display: "flex",
|
|
58
|
+
flexGrow: 1,
|
|
59
|
+
flexDirection: "column",
|
|
60
|
+
justifyContent: "center",
|
|
61
|
+
alignItems: "center"
|
|
62
|
+
},
|
|
63
|
+
children: "Checking Permissions..."
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
var DefaultRolesError = ({ error }) => {
|
|
68
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
69
|
+
"div",
|
|
70
|
+
{
|
|
71
|
+
style: {
|
|
72
|
+
display: "flex",
|
|
73
|
+
flexGrow: 1,
|
|
74
|
+
flexDirection: "column",
|
|
75
|
+
justifyContent: "center",
|
|
76
|
+
alignItems: "center",
|
|
77
|
+
color: "#c1121f"
|
|
78
|
+
},
|
|
79
|
+
children: error.message
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
function RolesProvider({
|
|
84
|
+
roles: getRoles,
|
|
85
|
+
slots = {},
|
|
86
|
+
children
|
|
87
|
+
}) {
|
|
88
|
+
const LoadingComponent = slots.loading ?? DefaultRolesLoading;
|
|
89
|
+
const ErrorComponent = slots.error ?? DefaultRolesError;
|
|
90
|
+
const [state, setState] = (0, import_react2.useState)({
|
|
91
|
+
roles: [],
|
|
92
|
+
loading: true,
|
|
93
|
+
hasProvider: true
|
|
94
|
+
});
|
|
95
|
+
(0, import_react2.useEffect)(() => {
|
|
96
|
+
const fetchRoles = async () => {
|
|
97
|
+
try {
|
|
98
|
+
setState((s) => ({ ...s, loading: true }));
|
|
99
|
+
const roles = await getRoles();
|
|
100
|
+
if (!roles) {
|
|
101
|
+
console.warn(
|
|
102
|
+
"No roles were returned an empty array should be returned if user has no roles."
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
setState((s) => ({
|
|
106
|
+
...s,
|
|
107
|
+
loading: false,
|
|
108
|
+
roles
|
|
109
|
+
}));
|
|
110
|
+
} catch (e) {
|
|
111
|
+
setState((s) => ({
|
|
112
|
+
...s,
|
|
113
|
+
loading: false,
|
|
114
|
+
roles: [],
|
|
115
|
+
error: e instanceof Error ? e : new Error(String(e))
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
fetchRoles();
|
|
120
|
+
}, [getRoles]);
|
|
121
|
+
if (state.loading) {
|
|
122
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoadingComponent, {});
|
|
123
|
+
}
|
|
124
|
+
if (state.error) {
|
|
125
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorComponent, { error: state.error });
|
|
126
|
+
}
|
|
127
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RolesContext.Provider, { value: state, children });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/runtime/useRoles.ts
|
|
131
|
+
var import_react3 = require("react");
|
|
132
|
+
function useRoles() {
|
|
133
|
+
return (0, import_react3.useContext)(RolesContext);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// src/runtime/roleUtils.ts
|
|
137
|
+
function isAllowed(userRoles, required, mode) {
|
|
138
|
+
if (!required || required.length === 0) {
|
|
139
|
+
return { allowed: true, missing: [] };
|
|
140
|
+
}
|
|
141
|
+
const userRoleSet = new Set(userRoles);
|
|
142
|
+
if (mode === "all") {
|
|
143
|
+
const missing = required.filter((r) => !userRoleSet.has(r));
|
|
144
|
+
return {
|
|
145
|
+
allowed: missing.length === 0,
|
|
146
|
+
missing
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const hasAny = required.some((r) => userRoleSet.has(r));
|
|
150
|
+
return {
|
|
151
|
+
allowed: hasAny,
|
|
152
|
+
missing: hasAny ? [] : required.slice()
|
|
153
|
+
// nothing matched → all are effectively missing
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// src/runtime/BaseForbiddenContent.tsx
|
|
158
|
+
var import_Translate = __toESM(require("@docusaurus/Translate"), 1);
|
|
159
|
+
var import_Heading = __toESM(require("@theme/Heading"), 1);
|
|
160
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
161
|
+
function BaseForbiddenContent({
|
|
162
|
+
prefixTranslateId,
|
|
163
|
+
title = "Forbidden",
|
|
164
|
+
shortDescription = "You don't have permission to access this page.",
|
|
165
|
+
description = "If you believe this is a mistake, contact the site owner or sign in with an account that has access."
|
|
166
|
+
}) {
|
|
167
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "row", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "col", children: [
|
|
168
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_Heading.default, { as: "h1", className: "hero__title", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
169
|
+
import_Translate.default,
|
|
170
|
+
{
|
|
171
|
+
id: `${prefixTranslateId}.title`,
|
|
172
|
+
description: "The title of the 403 page",
|
|
173
|
+
children: title
|
|
174
|
+
}
|
|
175
|
+
) }),
|
|
176
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
177
|
+
import_Translate.default,
|
|
178
|
+
{
|
|
179
|
+
id: `${prefixTranslateId}.p1`,
|
|
180
|
+
description: "The first paragraph of the 403 page",
|
|
181
|
+
children: shortDescription
|
|
182
|
+
}
|
|
183
|
+
) }),
|
|
184
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
185
|
+
import_Translate.default,
|
|
186
|
+
{
|
|
187
|
+
id: `${prefixTranslateId}.p2`,
|
|
188
|
+
description: "The 2nd paragraph of the 403 page",
|
|
189
|
+
children: description
|
|
190
|
+
}
|
|
191
|
+
) })
|
|
192
|
+
] }) });
|
|
193
|
+
}
|
|
194
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
195
|
+
0 && (module.exports = {
|
|
196
|
+
BaseForbiddenContent,
|
|
197
|
+
RolesContext,
|
|
198
|
+
RolesProvider,
|
|
199
|
+
isAllowed,
|
|
200
|
+
useRoles
|
|
201
|
+
});
|
|
202
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/runtime/index.ts","../../src/runtime/context.tsx","../../src/runtime/RolesProvider.tsx","../../src/runtime/useRoles.ts","../../src/runtime/roleUtils.ts","../../src/runtime/BaseForbiddenContent.tsx"],"sourcesContent":["export { RolesContext } from \"./context\";\nexport type { RolesState } from \"./context\";\n\nexport { RolesProvider } from \"./RolesProvider\";\nexport type { RolesProviderProps } from \"./RolesProvider\";\n\nexport { useRoles } from \"./useRoles\";\nexport { isAllowed } from \"./roleUtils\";\nexport type { RoleMode } from \"./roleUtils\";\nexport * from \"./BaseForbiddenContent\";\n","import React from \"react\";\n\nexport type RolesState = {\n roles: string[];\n loading: boolean;\n error?: Error;\n /** true if RolesProvider is mounted */\n hasProvider: boolean;\n};\n\nexport const RolesContext = React.createContext<RolesState>({\n roles: [],\n loading: false,\n hasProvider: false,\n});\n","import React, { useEffect, useState } from \"react\";\nimport type { PropsWithChildren } from \"react\";\nimport { RolesContext, type RolesState } from \"./context\";\n\nexport type ErrorSlotProps = {\n error: Error;\n};\n\nexport type RolesProviderProps = PropsWithChildren<{\n roles: () => Promise<string[]> | string[];\n slots?: {\n loading?: React.ElementType;\n error?: React.ElementType<ErrorSlotProps>;\n };\n}>;\n\nexport const DefaultRolesLoading = () => {\n return (\n <div\n style={{\n display: \"flex\",\n flexGrow: 1,\n flexDirection: \"column\",\n justifyContent: \"center\",\n alignItems: \"center\",\n }}\n >\n Checking Permissions...\n </div>\n );\n};\n\nexport const DefaultRolesError = ({ error }: ErrorSlotProps) => {\n return (\n <div\n style={{\n display: \"flex\",\n flexGrow: 1,\n flexDirection: \"column\",\n justifyContent: \"center\",\n alignItems: \"center\",\n color: \"#c1121f\",\n }}\n >\n {error.message}\n </div>\n );\n};\n\nexport function RolesProvider({\n roles: getRoles,\n slots = {},\n children,\n}: RolesProviderProps) {\n const LoadingComponent = slots.loading ?? DefaultRolesLoading;\n const ErrorComponent = slots.error ?? DefaultRolesError;\n\n const [state, setState] = useState<RolesState>({\n roles: [],\n loading: true,\n hasProvider: true,\n });\n\n useEffect(() => {\n const fetchRoles = async () => {\n try {\n setState((s) => ({ ...s, loading: true }));\n const roles = await getRoles();\n if (!roles) {\n console.warn(\n \"No roles were returned an empty array should be returned if user has no roles.\",\n );\n }\n setState((s) => ({\n ...s,\n loading: false,\n roles: roles,\n }));\n } catch (e) {\n setState((s) => ({\n ...s,\n loading: false,\n roles: [],\n error: e instanceof Error ? e : new Error(String(e)),\n }));\n }\n };\n\n fetchRoles();\n }, [getRoles]);\n\n if (state.loading) {\n return <LoadingComponent />;\n }\n\n if (state.error) {\n return <ErrorComponent error={state.error} />;\n }\n\n return (\n <RolesContext.Provider value={state}>{children}</RolesContext.Provider>\n );\n}\n","import { useContext } from \"react\";\nimport { RolesContext } from \"./context\";\n\nexport function useRoles() {\n return useContext(RolesContext);\n}\n","export type RoleMode = \"any\" | \"all\";\n\nexport type RoleCheckResult = {\n allowed: boolean;\n missing: string[];\n};\n\nexport function isAllowed(\n userRoles: string[],\n required: string[],\n mode: RoleMode,\n): RoleCheckResult {\n // No requirements → always allowed\n if (!required || required.length === 0) {\n return { allowed: true, missing: [] };\n }\n\n const userRoleSet = new Set(userRoles);\n\n if (mode === \"all\") {\n const missing = required.filter((r) => !userRoleSet.has(r));\n return {\n allowed: missing.length === 0,\n missing,\n };\n }\n\n // mode === \"any\"\n const hasAny = required.some((r) => userRoleSet.has(r));\n return {\n allowed: hasAny,\n missing: hasAny ? [] : required.slice(), // nothing matched → all are effectively missing\n };\n}\n","import { JSX } from \"react\";\nimport type { Props as NotFoundProps } from \"@theme/NotFound/Content\";\nimport Translate from \"@docusaurus/Translate\";\nimport Heading from \"@theme/Heading\";\n\nexport type BaseForbiddenContentProps = {\n prefixTranslateId: string;\n title?: string;\n shortDescription?: string;\n description?: string;\n} & NotFoundProps;\n\nexport function BaseForbiddenContent({\n prefixTranslateId,\n title = \"Forbidden\",\n shortDescription = \"You don't have permission to access this page.\",\n description = \"If you believe this is a mistake, contact the site owner or sign in with an account that has access.\",\n}: BaseForbiddenContentProps): JSX.Element {\n return (\n <div className=\"row\">\n <div className=\"col\">\n <Heading as=\"h1\" className=\"hero__title\">\n <Translate\n id={`${prefixTranslateId}.title`}\n description=\"The title of the 403 page\"\n >\n {title}\n </Translate>\n </Heading>\n <p>\n <Translate\n id={`${prefixTranslateId}.p1`}\n description=\"The first paragraph of the 403 page\"\n >\n {shortDescription}\n </Translate>\n </p>\n <p>\n <Translate\n id={`${prefixTranslateId}.p2`}\n description=\"The 2nd paragraph of the 403 page\"\n >\n {description}\n </Translate>\n </p>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["React","import_react","import_react","import_jsx_runtime","Heading","Translate"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React, { PropsWithChildren, JSX } from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import { Props } from '@theme/NotFound/Content';
|
|
4
|
+
|
|
5
|
+
type RolesState = {
|
|
6
|
+
roles: string[];
|
|
7
|
+
loading: boolean;
|
|
8
|
+
error?: Error;
|
|
9
|
+
/** true if RolesProvider is mounted */
|
|
10
|
+
hasProvider: boolean;
|
|
11
|
+
};
|
|
12
|
+
declare const RolesContext: React.Context<RolesState>;
|
|
13
|
+
|
|
14
|
+
type ErrorSlotProps = {
|
|
15
|
+
error: Error;
|
|
16
|
+
};
|
|
17
|
+
type RolesProviderProps = PropsWithChildren<{
|
|
18
|
+
roles: () => Promise<string[]> | string[];
|
|
19
|
+
slots?: {
|
|
20
|
+
loading?: React.ElementType;
|
|
21
|
+
error?: React.ElementType<ErrorSlotProps>;
|
|
22
|
+
};
|
|
23
|
+
}>;
|
|
24
|
+
declare function RolesProvider({ roles: getRoles, slots, children, }: RolesProviderProps): react_jsx_runtime.JSX.Element;
|
|
25
|
+
|
|
26
|
+
declare function useRoles(): RolesState;
|
|
27
|
+
|
|
28
|
+
type RoleMode = "any" | "all";
|
|
29
|
+
type RoleCheckResult = {
|
|
30
|
+
allowed: boolean;
|
|
31
|
+
missing: string[];
|
|
32
|
+
};
|
|
33
|
+
declare function isAllowed(userRoles: string[], required: string[], mode: RoleMode): RoleCheckResult;
|
|
34
|
+
|
|
35
|
+
type BaseForbiddenContentProps = {
|
|
36
|
+
prefixTranslateId: string;
|
|
37
|
+
title?: string;
|
|
38
|
+
shortDescription?: string;
|
|
39
|
+
description?: string;
|
|
40
|
+
} & Props;
|
|
41
|
+
declare function BaseForbiddenContent({ prefixTranslateId, title, shortDescription, description, }: BaseForbiddenContentProps): JSX.Element;
|
|
42
|
+
|
|
43
|
+
export { BaseForbiddenContent, type BaseForbiddenContentProps, type RoleMode, RolesContext, RolesProvider, type RolesProviderProps, type RolesState, isAllowed, useRoles };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React, { PropsWithChildren, JSX } from 'react';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import { Props } from '@theme/NotFound/Content';
|
|
4
|
+
|
|
5
|
+
type RolesState = {
|
|
6
|
+
roles: string[];
|
|
7
|
+
loading: boolean;
|
|
8
|
+
error?: Error;
|
|
9
|
+
/** true if RolesProvider is mounted */
|
|
10
|
+
hasProvider: boolean;
|
|
11
|
+
};
|
|
12
|
+
declare const RolesContext: React.Context<RolesState>;
|
|
13
|
+
|
|
14
|
+
type ErrorSlotProps = {
|
|
15
|
+
error: Error;
|
|
16
|
+
};
|
|
17
|
+
type RolesProviderProps = PropsWithChildren<{
|
|
18
|
+
roles: () => Promise<string[]> | string[];
|
|
19
|
+
slots?: {
|
|
20
|
+
loading?: React.ElementType;
|
|
21
|
+
error?: React.ElementType<ErrorSlotProps>;
|
|
22
|
+
};
|
|
23
|
+
}>;
|
|
24
|
+
declare function RolesProvider({ roles: getRoles, slots, children, }: RolesProviderProps): react_jsx_runtime.JSX.Element;
|
|
25
|
+
|
|
26
|
+
declare function useRoles(): RolesState;
|
|
27
|
+
|
|
28
|
+
type RoleMode = "any" | "all";
|
|
29
|
+
type RoleCheckResult = {
|
|
30
|
+
allowed: boolean;
|
|
31
|
+
missing: string[];
|
|
32
|
+
};
|
|
33
|
+
declare function isAllowed(userRoles: string[], required: string[], mode: RoleMode): RoleCheckResult;
|
|
34
|
+
|
|
35
|
+
type BaseForbiddenContentProps = {
|
|
36
|
+
prefixTranslateId: string;
|
|
37
|
+
title?: string;
|
|
38
|
+
shortDescription?: string;
|
|
39
|
+
description?: string;
|
|
40
|
+
} & Props;
|
|
41
|
+
declare function BaseForbiddenContent({ prefixTranslateId, title, shortDescription, description, }: BaseForbiddenContentProps): JSX.Element;
|
|
42
|
+
|
|
43
|
+
export { BaseForbiddenContent, type BaseForbiddenContentProps, type RoleMode, RolesContext, RolesProvider, type RolesProviderProps, type RolesState, isAllowed, useRoles };
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// src/runtime/context.tsx
|
|
2
|
+
import React from "react";
|
|
3
|
+
var RolesContext = React.createContext({
|
|
4
|
+
roles: [],
|
|
5
|
+
loading: false,
|
|
6
|
+
hasProvider: false
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
// src/runtime/RolesProvider.tsx
|
|
10
|
+
import { useEffect, useState } from "react";
|
|
11
|
+
import { jsx } from "react/jsx-runtime";
|
|
12
|
+
var DefaultRolesLoading = () => {
|
|
13
|
+
return /* @__PURE__ */ jsx(
|
|
14
|
+
"div",
|
|
15
|
+
{
|
|
16
|
+
style: {
|
|
17
|
+
display: "flex",
|
|
18
|
+
flexGrow: 1,
|
|
19
|
+
flexDirection: "column",
|
|
20
|
+
justifyContent: "center",
|
|
21
|
+
alignItems: "center"
|
|
22
|
+
},
|
|
23
|
+
children: "Checking Permissions..."
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
var DefaultRolesError = ({ error }) => {
|
|
28
|
+
return /* @__PURE__ */ jsx(
|
|
29
|
+
"div",
|
|
30
|
+
{
|
|
31
|
+
style: {
|
|
32
|
+
display: "flex",
|
|
33
|
+
flexGrow: 1,
|
|
34
|
+
flexDirection: "column",
|
|
35
|
+
justifyContent: "center",
|
|
36
|
+
alignItems: "center",
|
|
37
|
+
color: "#c1121f"
|
|
38
|
+
},
|
|
39
|
+
children: error.message
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
function RolesProvider({
|
|
44
|
+
roles: getRoles,
|
|
45
|
+
slots = {},
|
|
46
|
+
children
|
|
47
|
+
}) {
|
|
48
|
+
const LoadingComponent = slots.loading ?? DefaultRolesLoading;
|
|
49
|
+
const ErrorComponent = slots.error ?? DefaultRolesError;
|
|
50
|
+
const [state, setState] = useState({
|
|
51
|
+
roles: [],
|
|
52
|
+
loading: true,
|
|
53
|
+
hasProvider: true
|
|
54
|
+
});
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
const fetchRoles = async () => {
|
|
57
|
+
try {
|
|
58
|
+
setState((s) => ({ ...s, loading: true }));
|
|
59
|
+
const roles = await getRoles();
|
|
60
|
+
if (!roles) {
|
|
61
|
+
console.warn(
|
|
62
|
+
"No roles were returned an empty array should be returned if user has no roles."
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
setState((s) => ({
|
|
66
|
+
...s,
|
|
67
|
+
loading: false,
|
|
68
|
+
roles
|
|
69
|
+
}));
|
|
70
|
+
} catch (e) {
|
|
71
|
+
setState((s) => ({
|
|
72
|
+
...s,
|
|
73
|
+
loading: false,
|
|
74
|
+
roles: [],
|
|
75
|
+
error: e instanceof Error ? e : new Error(String(e))
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
fetchRoles();
|
|
80
|
+
}, [getRoles]);
|
|
81
|
+
if (state.loading) {
|
|
82
|
+
return /* @__PURE__ */ jsx(LoadingComponent, {});
|
|
83
|
+
}
|
|
84
|
+
if (state.error) {
|
|
85
|
+
return /* @__PURE__ */ jsx(ErrorComponent, { error: state.error });
|
|
86
|
+
}
|
|
87
|
+
return /* @__PURE__ */ jsx(RolesContext.Provider, { value: state, children });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/runtime/useRoles.ts
|
|
91
|
+
import { useContext } from "react";
|
|
92
|
+
function useRoles() {
|
|
93
|
+
return useContext(RolesContext);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// src/runtime/roleUtils.ts
|
|
97
|
+
function isAllowed(userRoles, required, mode) {
|
|
98
|
+
if (!required || required.length === 0) {
|
|
99
|
+
return { allowed: true, missing: [] };
|
|
100
|
+
}
|
|
101
|
+
const userRoleSet = new Set(userRoles);
|
|
102
|
+
if (mode === "all") {
|
|
103
|
+
const missing = required.filter((r) => !userRoleSet.has(r));
|
|
104
|
+
return {
|
|
105
|
+
allowed: missing.length === 0,
|
|
106
|
+
missing
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const hasAny = required.some((r) => userRoleSet.has(r));
|
|
110
|
+
return {
|
|
111
|
+
allowed: hasAny,
|
|
112
|
+
missing: hasAny ? [] : required.slice()
|
|
113
|
+
// nothing matched → all are effectively missing
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/runtime/BaseForbiddenContent.tsx
|
|
118
|
+
import Translate from "@docusaurus/Translate";
|
|
119
|
+
import Heading from "@theme/Heading";
|
|
120
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
121
|
+
function BaseForbiddenContent({
|
|
122
|
+
prefixTranslateId,
|
|
123
|
+
title = "Forbidden",
|
|
124
|
+
shortDescription = "You don't have permission to access this page.",
|
|
125
|
+
description = "If you believe this is a mistake, contact the site owner or sign in with an account that has access."
|
|
126
|
+
}) {
|
|
127
|
+
return /* @__PURE__ */ jsx2("div", { className: "row", children: /* @__PURE__ */ jsxs("div", { className: "col", children: [
|
|
128
|
+
/* @__PURE__ */ jsx2(Heading, { as: "h1", className: "hero__title", children: /* @__PURE__ */ jsx2(
|
|
129
|
+
Translate,
|
|
130
|
+
{
|
|
131
|
+
id: `${prefixTranslateId}.title`,
|
|
132
|
+
description: "The title of the 403 page",
|
|
133
|
+
children: title
|
|
134
|
+
}
|
|
135
|
+
) }),
|
|
136
|
+
/* @__PURE__ */ jsx2("p", { children: /* @__PURE__ */ jsx2(
|
|
137
|
+
Translate,
|
|
138
|
+
{
|
|
139
|
+
id: `${prefixTranslateId}.p1`,
|
|
140
|
+
description: "The first paragraph of the 403 page",
|
|
141
|
+
children: shortDescription
|
|
142
|
+
}
|
|
143
|
+
) }),
|
|
144
|
+
/* @__PURE__ */ jsx2("p", { children: /* @__PURE__ */ jsx2(
|
|
145
|
+
Translate,
|
|
146
|
+
{
|
|
147
|
+
id: `${prefixTranslateId}.p2`,
|
|
148
|
+
description: "The 2nd paragraph of the 403 page",
|
|
149
|
+
children: description
|
|
150
|
+
}
|
|
151
|
+
) })
|
|
152
|
+
] }) });
|
|
153
|
+
}
|
|
154
|
+
export {
|
|
155
|
+
BaseForbiddenContent,
|
|
156
|
+
RolesContext,
|
|
157
|
+
RolesProvider,
|
|
158
|
+
isAllowed,
|
|
159
|
+
useRoles
|
|
160
|
+
};
|
|
161
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/runtime/context.tsx","../../src/runtime/RolesProvider.tsx","../../src/runtime/useRoles.ts","../../src/runtime/roleUtils.ts","../../src/runtime/BaseForbiddenContent.tsx"],"sourcesContent":["import React from \"react\";\n\nexport type RolesState = {\n roles: string[];\n loading: boolean;\n error?: Error;\n /** true if RolesProvider is mounted */\n hasProvider: boolean;\n};\n\nexport const RolesContext = React.createContext<RolesState>({\n roles: [],\n loading: false,\n hasProvider: false,\n});\n","import React, { useEffect, useState } from \"react\";\nimport type { PropsWithChildren } from \"react\";\nimport { RolesContext, type RolesState } from \"./context\";\n\nexport type ErrorSlotProps = {\n error: Error;\n};\n\nexport type RolesProviderProps = PropsWithChildren<{\n roles: () => Promise<string[]> | string[];\n slots?: {\n loading?: React.ElementType;\n error?: React.ElementType<ErrorSlotProps>;\n };\n}>;\n\nexport const DefaultRolesLoading = () => {\n return (\n <div\n style={{\n display: \"flex\",\n flexGrow: 1,\n flexDirection: \"column\",\n justifyContent: \"center\",\n alignItems: \"center\",\n }}\n >\n Checking Permissions...\n </div>\n );\n};\n\nexport const DefaultRolesError = ({ error }: ErrorSlotProps) => {\n return (\n <div\n style={{\n display: \"flex\",\n flexGrow: 1,\n flexDirection: \"column\",\n justifyContent: \"center\",\n alignItems: \"center\",\n color: \"#c1121f\",\n }}\n >\n {error.message}\n </div>\n );\n};\n\nexport function RolesProvider({\n roles: getRoles,\n slots = {},\n children,\n}: RolesProviderProps) {\n const LoadingComponent = slots.loading ?? DefaultRolesLoading;\n const ErrorComponent = slots.error ?? DefaultRolesError;\n\n const [state, setState] = useState<RolesState>({\n roles: [],\n loading: true,\n hasProvider: true,\n });\n\n useEffect(() => {\n const fetchRoles = async () => {\n try {\n setState((s) => ({ ...s, loading: true }));\n const roles = await getRoles();\n if (!roles) {\n console.warn(\n \"No roles were returned an empty array should be returned if user has no roles.\",\n );\n }\n setState((s) => ({\n ...s,\n loading: false,\n roles: roles,\n }));\n } catch (e) {\n setState((s) => ({\n ...s,\n loading: false,\n roles: [],\n error: e instanceof Error ? e : new Error(String(e)),\n }));\n }\n };\n\n fetchRoles();\n }, [getRoles]);\n\n if (state.loading) {\n return <LoadingComponent />;\n }\n\n if (state.error) {\n return <ErrorComponent error={state.error} />;\n }\n\n return (\n <RolesContext.Provider value={state}>{children}</RolesContext.Provider>\n );\n}\n","import { useContext } from \"react\";\nimport { RolesContext } from \"./context\";\n\nexport function useRoles() {\n return useContext(RolesContext);\n}\n","export type RoleMode = \"any\" | \"all\";\n\nexport type RoleCheckResult = {\n allowed: boolean;\n missing: string[];\n};\n\nexport function isAllowed(\n userRoles: string[],\n required: string[],\n mode: RoleMode,\n): RoleCheckResult {\n // No requirements → always allowed\n if (!required || required.length === 0) {\n return { allowed: true, missing: [] };\n }\n\n const userRoleSet = new Set(userRoles);\n\n if (mode === \"all\") {\n const missing = required.filter((r) => !userRoleSet.has(r));\n return {\n allowed: missing.length === 0,\n missing,\n };\n }\n\n // mode === \"any\"\n const hasAny = required.some((r) => userRoleSet.has(r));\n return {\n allowed: hasAny,\n missing: hasAny ? [] : required.slice(), // nothing matched → all are effectively missing\n };\n}\n","import { JSX } from \"react\";\nimport type { Props as NotFoundProps } from \"@theme/NotFound/Content\";\nimport Translate from \"@docusaurus/Translate\";\nimport Heading from \"@theme/Heading\";\n\nexport type BaseForbiddenContentProps = {\n prefixTranslateId: string;\n title?: string;\n shortDescription?: string;\n description?: string;\n} & NotFoundProps;\n\nexport function BaseForbiddenContent({\n prefixTranslateId,\n title = \"Forbidden\",\n shortDescription = \"You don't have permission to access this page.\",\n description = \"If you believe this is a mistake, contact the site owner or sign in with an account that has access.\",\n}: BaseForbiddenContentProps): JSX.Element {\n return (\n <div className=\"row\">\n <div className=\"col\">\n <Heading as=\"h1\" className=\"hero__title\">\n <Translate\n id={`${prefixTranslateId}.title`}\n description=\"The title of the 403 page\"\n >\n {title}\n </Translate>\n </Heading>\n <p>\n <Translate\n id={`${prefixTranslateId}.p1`}\n description=\"The first paragraph of the 403 page\"\n >\n {shortDescription}\n </Translate>\n </p>\n <p>\n <Translate\n id={`${prefixTranslateId}.p2`}\n description=\"The 2nd paragraph of the 403 page\"\n >\n {description}\n </Translate>\n </p>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["jsx"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "docusaurus-roles-plugin",
|
|
3
|
+
"version": "1.0.0-beta.1",
|
|
4
|
+
"description": "Role-based gating for Docusaurus docs/blog via React context + front matter",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.cjs",
|
|
8
|
+
"module": "dist/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"require": "./dist/index.cjs",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./runtime": {
|
|
17
|
+
"types": "./dist/runtime/index.d.ts",
|
|
18
|
+
"require": "./dist/runtime/index.cjs",
|
|
19
|
+
"import": "./dist/runtime/index.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md",
|
|
25
|
+
"src/theme"
|
|
26
|
+
],
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@docusaurus/logger": "^3.9.0"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"@docusaurus/core": "^3.9.0",
|
|
32
|
+
"@docusaurus/theme-common": "^3.9.0",
|
|
33
|
+
"@docusaurus/theme-translations": "^3.9.0",
|
|
34
|
+
"@docusaurus/utils-validation": "^3.9.0",
|
|
35
|
+
"react": ">=18",
|
|
36
|
+
"react-dom": ">=18"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"typescript": "^5.9.0",
|
|
40
|
+
"@docusaurus/types": "^3.9.0",
|
|
41
|
+
"@docusaurus/theme-classic": "^3.9.0",
|
|
42
|
+
"@docusaurus/module-type-aliases": "^3.9.0",
|
|
43
|
+
"@docusaurus/plugin-content-blog": "^3.9.0",
|
|
44
|
+
"@docusaurus/plugin-content-docs": "^3.9.0",
|
|
45
|
+
"tsup": "^8.5.0"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsup",
|
|
49
|
+
"dev": "tsup --watch",
|
|
50
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import BlogListPage from "@theme-init/BlogListPage";
|
|
2
|
+
import { useRoles, isAllowed } from "docusaurus-roles-plugin/runtime";
|
|
3
|
+
import type { Props } from "@theme/BlogListPage";
|
|
4
|
+
import { getRoleFrontMatter } from "../../options";
|
|
5
|
+
|
|
6
|
+
export default function BlogListPageWrapper({ items, ...rest }: Props) {
|
|
7
|
+
const { roles, loading } = useRoles();
|
|
8
|
+
|
|
9
|
+
const filteredItems = items.filter((i) => {
|
|
10
|
+
const frontMatter = getRoleFrontMatter(i.content.frontMatter);
|
|
11
|
+
const { allowed } = isAllowed(
|
|
12
|
+
roles,
|
|
13
|
+
frontMatter.required_roles ?? [],
|
|
14
|
+
frontMatter.required_roles_mode ?? "all",
|
|
15
|
+
);
|
|
16
|
+
return allowed;
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return <BlogListPage {...rest} items={filteredItems} />;
|
|
20
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { BaseForbiddenContent } from "docusaurus-roles-plugin/runtime";
|
|
3
|
+
|
|
4
|
+
export default function ForbiddenBlogPostItem({
|
|
5
|
+
missingRoles,
|
|
6
|
+
}: {
|
|
7
|
+
missingRoles: string[];
|
|
8
|
+
}): ReactNode {
|
|
9
|
+
return (
|
|
10
|
+
<main className={"container margin-vert--xl"}>
|
|
11
|
+
<BaseForbiddenContent
|
|
12
|
+
prefixTranslateId="theme.BlogPostItem.Forbidden"
|
|
13
|
+
missingRoles={missingRoles}
|
|
14
|
+
/>
|
|
15
|
+
</main>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import BlogPostItem, { type Props } from "@theme-init/BlogPostItem";
|
|
2
|
+
import RoleGate from "../RoleGate";
|
|
3
|
+
import { getRoleFrontMatter } from "../../options";
|
|
4
|
+
import { useBlogPost } from "@docusaurus/plugin-content-blog/client";
|
|
5
|
+
import ForbiddenBlogPostItem from "./Forbidden";
|
|
6
|
+
|
|
7
|
+
export default function BlogPostItemWrapper(props: Props) {
|
|
8
|
+
const { metadata } = useBlogPost();
|
|
9
|
+
const frontMatter = getRoleFrontMatter(metadata.frontMatter);
|
|
10
|
+
const requiredRoles = frontMatter.required_roles;
|
|
11
|
+
const mode = frontMatter.required_roles_mode;
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<RoleGate
|
|
15
|
+
requiredRoles={requiredRoles}
|
|
16
|
+
mode={mode}
|
|
17
|
+
forbidden={ForbiddenBlogPostItem}
|
|
18
|
+
>
|
|
19
|
+
<BlogPostItem {...props} />
|
|
20
|
+
</RoleGate>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { usePluginData } from "@docusaurus/useGlobalData";
|
|
2
|
+
import BlogSidebar, { type Props } from "@theme-init/BlogSidebar";
|
|
3
|
+
import { isAllowed, useRoles } from "docusaurus-roles-plugin/runtime";
|
|
4
|
+
import { type RoleInfo } from "../..";
|
|
5
|
+
|
|
6
|
+
export default function BlogSidebarWrapper({ sidebar, ...props }: Props) {
|
|
7
|
+
const plugin = usePluginData("docusaurus-roles-plugin") as {
|
|
8
|
+
rolesByPermalink: RoleInfo[];
|
|
9
|
+
};
|
|
10
|
+
const { roles } = useRoles();
|
|
11
|
+
if (sidebar) {
|
|
12
|
+
sidebar.items = sidebar.items.filter((i) => {
|
|
13
|
+
const roleInfo = plugin.rolesByPermalink.find(
|
|
14
|
+
(r) => r.permalink === i.permalink,
|
|
15
|
+
);
|
|
16
|
+
if (!roleInfo) return true;
|
|
17
|
+
const { allowed } = isAllowed(
|
|
18
|
+
roles,
|
|
19
|
+
roleInfo.requiredRoles,
|
|
20
|
+
roleInfo.requiredRolesMode,
|
|
21
|
+
);
|
|
22
|
+
return allowed;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return <BlogSidebar {...props} sidebar={sidebar} />;
|
|
26
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { JSX } from "react";
|
|
2
|
+
import { BaseForbiddenContent } from "docusaurus-roles-plugin/runtime";
|
|
3
|
+
|
|
4
|
+
export default function ForbiddenDocItem({
|
|
5
|
+
missingRoles,
|
|
6
|
+
}: {
|
|
7
|
+
missingRoles: string[];
|
|
8
|
+
}): JSX.Element {
|
|
9
|
+
return (
|
|
10
|
+
<BaseForbiddenContent
|
|
11
|
+
prefixTranslateId="theme.DocItem.Forbidden"
|
|
12
|
+
missingRoles={missingRoles}
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import DocItem, { type Props } from "@theme-init/DocItem";
|
|
2
|
+
import RoleGate from "../RoleGate";
|
|
3
|
+
import { getRoleFrontMatter } from "../../options";
|
|
4
|
+
import ForbiddenDocItem from "./Forbidden";
|
|
5
|
+
|
|
6
|
+
export default function DocItemWrapper(props: Props) {
|
|
7
|
+
const frontMatter = getRoleFrontMatter(props?.content.frontMatter);
|
|
8
|
+
const requiredRoles = frontMatter.required_roles;
|
|
9
|
+
const mode = frontMatter.required_roles_mode;
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<RoleGate
|
|
13
|
+
requiredRoles={requiredRoles}
|
|
14
|
+
mode={mode}
|
|
15
|
+
forbidden={ForbiddenDocItem}
|
|
16
|
+
>
|
|
17
|
+
<DocItem {...props} />
|
|
18
|
+
</RoleGate>
|
|
19
|
+
);
|
|
20
|
+
}
|