@strapi-community/plugin-better-auth-dashboard 1.0.0-alpha.9 → 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.
@@ -0,0 +1,402 @@
1
+ "use strict";
2
+ const jsxRuntime = require("react/jsx-runtime");
3
+ const reactQuery = require("react-query");
4
+ const client$2 = require("@better-auth/infra/client");
5
+ const client$1 = require("better-auth/client");
6
+ const admin = require("@strapi/strapi/admin");
7
+ const react = require("react");
8
+ const PluginIcon = ({
9
+ size = 16,
10
+ background = "transparent",
11
+ opacity = 1,
12
+ rotation = 0,
13
+ shadow = 0,
14
+ flipHorizontal = false,
15
+ flipVertical = false,
16
+ padding = 0
17
+ }) => {
18
+ const transforms = [];
19
+ if (rotation !== 0) transforms.push(`rotate(${rotation}deg)`);
20
+ if (flipHorizontal) transforms.push("scaleX(-1)");
21
+ if (flipVertical) transforms.push("scaleY(-1)");
22
+ const viewBoxSize = 24 + padding * 2;
23
+ const viewBoxOffset = -padding;
24
+ const viewBox = `${viewBoxOffset} ${viewBoxOffset} ${viewBoxSize} ${viewBoxSize}`;
25
+ return /* @__PURE__ */ jsxRuntime.jsxs(
26
+ "svg",
27
+ {
28
+ xmlns: "http://www.w3.org/2000/svg",
29
+ viewBox,
30
+ width: size,
31
+ height: size,
32
+ fill: "none",
33
+ style: {
34
+ opacity,
35
+ transform: transforms.join(" ") || void 0,
36
+ filter: shadow > 0 ? `drop-shadow(0 ${shadow}px ${shadow * 2}px rgba(0,0,0,0.3))` : void 0,
37
+ backgroundColor: background !== "transparent" ? background : void 0
38
+ },
39
+ children: [
40
+ /* @__PURE__ */ jsxRuntime.jsx("title", { children: "Better Auth Logo" }),
41
+ /* @__PURE__ */ jsxRuntime.jsx(
42
+ "path",
43
+ {
44
+ fill: "currentColor",
45
+ d: "M0 3.39v17.22h5.783v-5.55h6.434V8.939H5.783V3.39Zm12.217 5.55h5.638v6.122h-5.638v5.548H24V3.391H12.217Z"
46
+ }
47
+ )
48
+ ]
49
+ }
50
+ );
51
+ };
52
+ const PLUGIN_ID = "better-auth-dashboard";
53
+ const PERMISSIONS = {
54
+ overview: [{ action: `plugin::${PLUGIN_ID}.overview.read`, subject: null }],
55
+ user: [
56
+ { action: `plugin::${PLUGIN_ID}.user.create`, subject: null },
57
+ { action: `plugin::${PLUGIN_ID}.user.read`, subject: null },
58
+ { action: `plugin::${PLUGIN_ID}.user.update`, subject: null },
59
+ { action: `plugin::${PLUGIN_ID}.user.delete`, subject: null }
60
+ ],
61
+ organization: [
62
+ { action: `plugin::${PLUGIN_ID}.organization.create`, subject: null },
63
+ { action: `plugin::${PLUGIN_ID}.organization.read`, subject: null },
64
+ { action: `plugin::${PLUGIN_ID}.organization.update`, subject: null },
65
+ { action: `plugin::${PLUGIN_ID}.organization.delete`, subject: null }
66
+ ]
67
+ };
68
+ const dashPathMethods = () => ({
69
+ id: "dash-path-methods",
70
+ pathMethods: {
71
+ "/dash/organization/directory/create": "POST",
72
+ "/dash/organization/directory/delete": "POST",
73
+ "/dash/organization/directory/regenerate-token": "POST",
74
+ "/dash/execute-adapter": "POST",
75
+ "/dash/complete-invitation": "POST",
76
+ "/dash/check-user-exists": "POST",
77
+ "/dash/organization/invite-member": "POST",
78
+ "/dash/organization/check-user-by-email": "POST",
79
+ "/dash/organization/cancel-invitation": "POST",
80
+ "/dash/organization/resend-invitation": "POST",
81
+ "/dash/organization/add-member": "POST",
82
+ "/dash/organization/remove-member": "POST",
83
+ "/dash/organization/update-member-role": "POST",
84
+ "/dash/organization/delete": "POST",
85
+ "/dash/organization/delete-many": "POST",
86
+ "/dash/organization/create": "POST",
87
+ "/dash/organization/update": "POST",
88
+ "/dash/organization/update-team": "POST",
89
+ "/dash/organization/delete-team": "POST",
90
+ "/dash/organization/create-team": "POST",
91
+ "/dash/organization/add-team-member": "POST",
92
+ "/dash/organization/remove-team-member": "POST",
93
+ "/dash/sessions/revoke": "POST",
94
+ "/dash/sessions/revoke-all": "POST",
95
+ "/dash/sessions/revoke-many": "POST",
96
+ "/dash/organization/:id/sso-provider/create": "POST",
97
+ "/dash/organization/:id/sso-provider/update": "POST",
98
+ "/dash/organization/:id/sso-provider/request-verification-token": "POST",
99
+ "/dash/organization/:id/sso-provider/verify-domain": "POST",
100
+ "/dash/organization/:id/sso-provider/delete": "POST",
101
+ "/dash/organization/:id/sso-provider/mark-domain-verified": "POST",
102
+ "/dash/enable-two-factor": "POST",
103
+ "/dash/view-two-factor-totp-uri": "POST",
104
+ "/dash/view-backup-codes": "POST",
105
+ "/dash/disable-two-factor": "POST",
106
+ "/dash/generate-backup-codes": "POST",
107
+ "/dash/delete-user": "POST",
108
+ "/dash/delete-many-users": "POST",
109
+ "/dash/create-user": "POST",
110
+ "/dash/set-password": "POST",
111
+ "/dash/unlink-account": "POST",
112
+ "/dash/update-user": "POST",
113
+ "/dash/ban-user": "POST",
114
+ "/dash/ban-many-users": "POST",
115
+ "/dash/unban-user": "POST",
116
+ "/dash/send-verification-email": "POST",
117
+ "/dash/send-many-verification-emails": "POST",
118
+ "/dash/send-reset-password-email": "POST"
119
+ }
120
+ });
121
+ const STORAGE_KEYS = {
122
+ TOKEN: "jwtToken"
123
+ };
124
+ const getCookieValue = (name) => {
125
+ let result = null;
126
+ const cookieArray = document.cookie.split(";");
127
+ cookieArray.forEach((cookie) => {
128
+ const [key, value] = cookie.split("=").map((item) => item.trim());
129
+ if (key === name) {
130
+ result = decodeURIComponent(value);
131
+ }
132
+ });
133
+ return result;
134
+ };
135
+ const getToken = () => {
136
+ const fromLocalStorage = localStorage.getItem(STORAGE_KEYS.TOKEN);
137
+ if (fromLocalStorage) {
138
+ return JSON.parse(fromLocalStorage);
139
+ }
140
+ const fromCookie = getCookieValue(STORAGE_KEYS.TOKEN);
141
+ return fromCookie ?? null;
142
+ };
143
+ function getAuthHeaders() {
144
+ const token = getToken();
145
+ return token ? { Authorization: `Bearer ${token}` } : {};
146
+ }
147
+ const client = client$1.createAuthClient({
148
+ baseURL: window.location.origin,
149
+ basePath: "/auth",
150
+ plugins: [
151
+ client$2.dashClient(),
152
+ dashPathMethods(),
153
+ client$1.InferPlugin()
154
+ ],
155
+ fetchOptions: {
156
+ headers: getAuthHeaders()
157
+ }
158
+ });
159
+ async function getDashConfig() {
160
+ const result = await client.dash.config();
161
+ if (result.error) {
162
+ throw new Error(result.error.message ?? "Failed to load config");
163
+ }
164
+ return result.data;
165
+ }
166
+ function useDashConfig() {
167
+ return reactQuery.useQuery({
168
+ queryKey: ["dash-config"],
169
+ queryFn: getDashConfig,
170
+ staleTime: 5 * 60 * 1e3
171
+ });
172
+ }
173
+ function useOrganizationOptions(enabled = true) {
174
+ return reactQuery.useQuery({
175
+ queryKey: ["dash-org-options"],
176
+ queryFn: async () => {
177
+ const result = await client.dash.organization.options();
178
+ if (result.error) return { teamsEnabled: false };
179
+ return result.data ?? { teamsEnabled: false };
180
+ },
181
+ enabled
182
+ });
183
+ }
184
+ function hasPlugin(config, id) {
185
+ return config?.plugins.some((p) => p.id === id) ?? false;
186
+ }
187
+ const DASH_LINK_AVAILABILITY_STALE_TIME = 5 * 60 * 1e3;
188
+ const getDashLinkAvailabilityQueryKey = (link) => [
189
+ PLUGIN_ID,
190
+ "link-availability",
191
+ link.id,
192
+ link.to
193
+ ];
194
+ const resolveDashLinkAvailability = async (link) => {
195
+ try {
196
+ return await link.isAvailable?.() ?? true;
197
+ } catch {
198
+ return false;
199
+ }
200
+ };
201
+ let currentStore = {};
202
+ const getDashLinks = () => currentStore;
203
+ const RouteProtector = admin.Page.Protect;
204
+ const AvailabilityProtector = ({
205
+ link,
206
+ children
207
+ }) => {
208
+ const { data: isAvailable, isLoading } = reactQuery.useQuery({
209
+ queryKey: getDashLinkAvailabilityQueryKey(link),
210
+ queryFn: () => resolveDashLinkAvailability(link),
211
+ staleTime: DASH_LINK_AVAILABILITY_STALE_TIME
212
+ });
213
+ if (isLoading) return react.createElement(admin.Page.Loading);
214
+ if (!isAvailable) return react.createElement(admin.Page.NoPermissions);
215
+ return children;
216
+ };
217
+ const initDash = (app) => {
218
+ const store = {};
219
+ currentStore = store;
220
+ const addDashLink = (section, link) => {
221
+ const router = app.router;
222
+ const storeIndex = router._routes.findIndex(
223
+ (route2) => route2.path === `plugins/${PLUGIN_ID}/*`
224
+ );
225
+ const route = router._routes[storeIndex];
226
+ if (section) {
227
+ if (!route) {
228
+ throw new Error(
229
+ `Dashboard route for plugin ${PLUGIN_ID} was not found`
230
+ );
231
+ }
232
+ }
233
+ if (!route.children) {
234
+ route.children = [];
235
+ }
236
+ route.children?.push(mapLinkToRoute(link));
237
+ const sectionId = typeof section === "string" ? section : section.id;
238
+ const existing = store[sectionId];
239
+ if (!existing) {
240
+ if (typeof section === "string") {
241
+ throw new Error(`Dashboard section ${sectionId} does not exist`);
242
+ }
243
+ store[sectionId] = {
244
+ ...section,
245
+ links: []
246
+ };
247
+ } else if (typeof section.priority === "number" && section.priority !== existing.priority) {
248
+ console.warn(
249
+ "[DASH] Only the first instance of section can declare its priority."
250
+ );
251
+ }
252
+ store[sectionId].links.push(link);
253
+ };
254
+ const addDashSection = (section) => {
255
+ const existing = store[section.id];
256
+ if (existing) {
257
+ console.warn("[DASH] A section with this ID already exists.");
258
+ return;
259
+ }
260
+ store[section.id] = {
261
+ ...section,
262
+ links: []
263
+ };
264
+ };
265
+ const getDashLinks2 = () => {
266
+ return store;
267
+ };
268
+ return {
269
+ addDashLink,
270
+ addDashSection,
271
+ getDashLinks: getDashLinks2
272
+ };
273
+ };
274
+ const mapLinkToRoute = (link) => {
275
+ if (!link.Component)
276
+ throw new Error(
277
+ `Link with id ${link.to} does not have a Component property`
278
+ );
279
+ const permissions = link.permissions;
280
+ const hasPermissions = Array.isArray(permissions) && permissions.length > 0;
281
+ return {
282
+ path: `${link.to.replace(/^\/+|\/+$/g, "")}/*`,
283
+ lazy: async () => {
284
+ const mod = await link.Component();
285
+ const Component = "default" in mod ? mod.default : mod;
286
+ return {
287
+ Component: () => react.createElement(
288
+ AvailabilityProtector,
289
+ { link },
290
+ hasPermissions ? react.createElement(
291
+ RouteProtector,
292
+ { permissions },
293
+ react.createElement(Component)
294
+ ) : react.createElement(Component)
295
+ )
296
+ };
297
+ }
298
+ };
299
+ };
300
+ const panels = [];
301
+ function addEditViewSidePanel(config) {
302
+ if (panels.some((p) => p.id === config.id)) {
303
+ console.warn(
304
+ `[better-auth-dashboard] Panel with id "${config.id}" is already registered.`
305
+ );
306
+ return;
307
+ }
308
+ panels.push(config);
309
+ }
310
+ function getEditViewSidePanels(model) {
311
+ return panels.filter((p) => {
312
+ if (!p.model) return true;
313
+ if (Array.isArray(p.model)) return p.model.includes(model);
314
+ return p.model === model;
315
+ });
316
+ }
317
+ function captureApp(app) {
318
+ window.__betterAuthDashApp = app;
319
+ }
320
+ function getMediaLibraryComponent() {
321
+ return window.__betterAuthDashApp?.library?.components?.["media-library"] ?? null;
322
+ }
323
+ const plugin = {
324
+ register(app) {
325
+ captureApp(app);
326
+ const dash = initDash(app);
327
+ app.registerPlugin({
328
+ id: PLUGIN_ID,
329
+ name: "Auth Dashboard",
330
+ apis: { addEditViewSidePanel, ...dash }
331
+ });
332
+ app.addMenuLink({
333
+ to: `/plugins/${PLUGIN_ID}`,
334
+ icon: PluginIcon,
335
+ intlLabel: {
336
+ id: `${PLUGIN_ID}.plugin.name`,
337
+ defaultMessage: "Auth Dashboard"
338
+ },
339
+ Component: async () => Promise.resolve().then(() => require("./Root-DDi0mtve.js")),
340
+ permissions: [
341
+ ...PERMISSIONS.overview,
342
+ ...PERMISSIONS.user,
343
+ ...PERMISSIONS.organization
344
+ ]
345
+ });
346
+ },
347
+ bootstrap(app) {
348
+ const dash = app.getPlugin(PLUGIN_ID).apis;
349
+ dash.addDashSection({
350
+ id: "general",
351
+ intlLabel: {
352
+ id: `${PLUGIN_ID}.settings.general`,
353
+ defaultMessage: "General"
354
+ }
355
+ });
356
+ dash.addDashLink("general", {
357
+ id: "overview",
358
+ intlLabel: {
359
+ id: `${PLUGIN_ID}.settings.overview`,
360
+ defaultMessage: "Overview"
361
+ },
362
+ to: "/overview",
363
+ Component: () => Promise.resolve().then(() => require("./index-CqR8WpOa.js")),
364
+ permissions: PERMISSIONS.overview
365
+ });
366
+ dash.addDashLink("general", {
367
+ id: "users",
368
+ intlLabel: {
369
+ id: `${PLUGIN_ID}.settings.users`,
370
+ defaultMessage: "User Management"
371
+ },
372
+ to: "/users",
373
+ Component: () => Promise.resolve().then(() => require("./index-BV-4M_Fp.js")),
374
+ permissions: PERMISSIONS.user
375
+ });
376
+ dash.addDashLink("general", {
377
+ id: "organizations",
378
+ intlLabel: {
379
+ id: `${PLUGIN_ID}.settings.organizations`,
380
+ defaultMessage: "Organization Management"
381
+ },
382
+ to: "/organizations",
383
+ Component: () => Promise.resolve().then(() => require("./index-D6ktNZcj.js")),
384
+ permissions: PERMISSIONS.organization,
385
+ isAvailable: async () => hasPlugin(await getDashConfig(), "organization")
386
+ });
387
+ }
388
+ };
389
+ exports.DASH_LINK_AVAILABILITY_STALE_TIME = DASH_LINK_AVAILABILITY_STALE_TIME;
390
+ exports.PERMISSIONS = PERMISSIONS;
391
+ exports.PLUGIN_ID = PLUGIN_ID;
392
+ exports.client = client;
393
+ exports.getAuthHeaders = getAuthHeaders;
394
+ exports.getDashLinkAvailabilityQueryKey = getDashLinkAvailabilityQueryKey;
395
+ exports.getDashLinks = getDashLinks;
396
+ exports.getEditViewSidePanels = getEditViewSidePanels;
397
+ exports.getMediaLibraryComponent = getMediaLibraryComponent;
398
+ exports.hasPlugin = hasPlugin;
399
+ exports.plugin = plugin;
400
+ exports.resolveDashLinkAvailability = resolveDashLinkAvailability;
401
+ exports.useDashConfig = useDashConfig;
402
+ exports.useOrganizationOptions = useOrganizationOptions;