@strapi-community/plugin-better-auth-dashboard 1.0.0-alpha.1 → 1.0.0-alpha.10

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,116 @@
1
+ "use strict";
2
+ const jsxRuntime = require("react/jsx-runtime");
3
+ const PluginIcon = ({
4
+ size = 16,
5
+ background = "transparent",
6
+ opacity = 1,
7
+ rotation = 0,
8
+ shadow = 0,
9
+ flipHorizontal = false,
10
+ flipVertical = false,
11
+ padding = 0
12
+ }) => {
13
+ const transforms = [];
14
+ if (rotation !== 0) transforms.push(`rotate(${rotation}deg)`);
15
+ if (flipHorizontal) transforms.push("scaleX(-1)");
16
+ if (flipVertical) transforms.push("scaleY(-1)");
17
+ const viewBoxSize = 24 + padding * 2;
18
+ const viewBoxOffset = -padding;
19
+ const viewBox = `${viewBoxOffset} ${viewBoxOffset} ${viewBoxSize} ${viewBoxSize}`;
20
+ return /* @__PURE__ */ jsxRuntime.jsxs(
21
+ "svg",
22
+ {
23
+ xmlns: "http://www.w3.org/2000/svg",
24
+ viewBox,
25
+ width: size,
26
+ height: size,
27
+ fill: "none",
28
+ style: {
29
+ opacity,
30
+ transform: transforms.join(" ") || void 0,
31
+ filter: shadow > 0 ? `drop-shadow(0 ${shadow}px ${shadow * 2}px rgba(0,0,0,0.3))` : void 0,
32
+ backgroundColor: background !== "transparent" ? background : void 0
33
+ },
34
+ children: [
35
+ /* @__PURE__ */ jsxRuntime.jsx("title", { children: "Better Auth Logo" }),
36
+ /* @__PURE__ */ jsxRuntime.jsx(
37
+ "path",
38
+ {
39
+ fill: "currentColor",
40
+ d: "M0 3.39v17.22h5.783v-5.55h6.434V8.939H5.783V3.39Zm12.217 5.55h5.638v6.122h-5.638v5.548H24V3.391H12.217Z"
41
+ }
42
+ )
43
+ ]
44
+ }
45
+ );
46
+ };
47
+ const PLUGIN_ID = "better-auth-dashboard";
48
+ const PERMISSIONS = {
49
+ overview: [{ action: `plugin::${PLUGIN_ID}.overview.read`, subject: null }],
50
+ user: [
51
+ { action: `plugin::${PLUGIN_ID}.user.create`, subject: null },
52
+ { action: `plugin::${PLUGIN_ID}.user.read`, subject: null },
53
+ { action: `plugin::${PLUGIN_ID}.user.update`, subject: null },
54
+ { action: `plugin::${PLUGIN_ID}.user.delete`, subject: null }
55
+ ],
56
+ organization: [
57
+ { action: `plugin::${PLUGIN_ID}.organization.create`, subject: null },
58
+ { action: `plugin::${PLUGIN_ID}.organization.read`, subject: null },
59
+ { action: `plugin::${PLUGIN_ID}.organization.update`, subject: null },
60
+ { action: `plugin::${PLUGIN_ID}.organization.delete`, subject: null }
61
+ ]
62
+ };
63
+ const panels = [];
64
+ function addEditViewSidePanel(config) {
65
+ if (panels.some((p) => p.id === config.id)) {
66
+ console.warn(
67
+ `[better-auth-dashboard] Panel with id "${config.id}" is already registered.`
68
+ );
69
+ return;
70
+ }
71
+ panels.push(config);
72
+ }
73
+ function getEditViewSidePanels(model) {
74
+ return panels.filter((p) => {
75
+ if (!p.model) return true;
76
+ if (Array.isArray(p.model)) return p.model.includes(model);
77
+ return p.model === model;
78
+ });
79
+ }
80
+ function captureApp(app) {
81
+ window.__betterAuthDashApp = app;
82
+ }
83
+ function getMediaLibraryComponent() {
84
+ return window.__betterAuthDashApp?.library?.components?.["media-library"] ?? null;
85
+ }
86
+ const plugin = {
87
+ register(app) {
88
+ captureApp(app);
89
+ app.registerPlugin({
90
+ id: PLUGIN_ID,
91
+ name: "Auth Dashboard",
92
+ apis: { addEditViewSidePanel }
93
+ });
94
+ app.addMenuLink({
95
+ to: `/plugins/${PLUGIN_ID}`,
96
+ icon: PluginIcon,
97
+ intlLabel: {
98
+ id: `${PLUGIN_ID}.plugin.name`,
99
+ defaultMessage: "Auth Dashboard"
100
+ },
101
+ Component: async () => Promise.resolve().then(() => require("./Root-CN4cZKCJ.js")),
102
+ permissions: [
103
+ ...PERMISSIONS.overview,
104
+ ...PERMISSIONS.user,
105
+ ...PERMISSIONS.organization
106
+ ]
107
+ });
108
+ },
109
+ bootstrap() {
110
+ }
111
+ };
112
+ exports.PERMISSIONS = PERMISSIONS;
113
+ exports.PLUGIN_ID = PLUGIN_ID;
114
+ exports.getEditViewSidePanels = getEditViewSidePanels;
115
+ exports.getMediaLibraryComponent = getMediaLibraryComponent;
116
+ exports.plugin = plugin;
@@ -0,0 +1,117 @@
1
+ import { jsxs, jsx } from "react/jsx-runtime";
2
+ const PluginIcon = ({
3
+ size = 16,
4
+ background = "transparent",
5
+ opacity = 1,
6
+ rotation = 0,
7
+ shadow = 0,
8
+ flipHorizontal = false,
9
+ flipVertical = false,
10
+ padding = 0
11
+ }) => {
12
+ const transforms = [];
13
+ if (rotation !== 0) transforms.push(`rotate(${rotation}deg)`);
14
+ if (flipHorizontal) transforms.push("scaleX(-1)");
15
+ if (flipVertical) transforms.push("scaleY(-1)");
16
+ const viewBoxSize = 24 + padding * 2;
17
+ const viewBoxOffset = -padding;
18
+ const viewBox = `${viewBoxOffset} ${viewBoxOffset} ${viewBoxSize} ${viewBoxSize}`;
19
+ return /* @__PURE__ */ jsxs(
20
+ "svg",
21
+ {
22
+ xmlns: "http://www.w3.org/2000/svg",
23
+ viewBox,
24
+ width: size,
25
+ height: size,
26
+ fill: "none",
27
+ style: {
28
+ opacity,
29
+ transform: transforms.join(" ") || void 0,
30
+ filter: shadow > 0 ? `drop-shadow(0 ${shadow}px ${shadow * 2}px rgba(0,0,0,0.3))` : void 0,
31
+ backgroundColor: background !== "transparent" ? background : void 0
32
+ },
33
+ children: [
34
+ /* @__PURE__ */ jsx("title", { children: "Better Auth Logo" }),
35
+ /* @__PURE__ */ jsx(
36
+ "path",
37
+ {
38
+ fill: "currentColor",
39
+ d: "M0 3.39v17.22h5.783v-5.55h6.434V8.939H5.783V3.39Zm12.217 5.55h5.638v6.122h-5.638v5.548H24V3.391H12.217Z"
40
+ }
41
+ )
42
+ ]
43
+ }
44
+ );
45
+ };
46
+ const PLUGIN_ID = "better-auth-dashboard";
47
+ const PERMISSIONS = {
48
+ overview: [{ action: `plugin::${PLUGIN_ID}.overview.read`, subject: null }],
49
+ user: [
50
+ { action: `plugin::${PLUGIN_ID}.user.create`, subject: null },
51
+ { action: `plugin::${PLUGIN_ID}.user.read`, subject: null },
52
+ { action: `plugin::${PLUGIN_ID}.user.update`, subject: null },
53
+ { action: `plugin::${PLUGIN_ID}.user.delete`, subject: null }
54
+ ],
55
+ organization: [
56
+ { action: `plugin::${PLUGIN_ID}.organization.create`, subject: null },
57
+ { action: `plugin::${PLUGIN_ID}.organization.read`, subject: null },
58
+ { action: `plugin::${PLUGIN_ID}.organization.update`, subject: null },
59
+ { action: `plugin::${PLUGIN_ID}.organization.delete`, subject: null }
60
+ ]
61
+ };
62
+ const panels = [];
63
+ function addEditViewSidePanel(config) {
64
+ if (panels.some((p) => p.id === config.id)) {
65
+ console.warn(
66
+ `[better-auth-dashboard] Panel with id "${config.id}" is already registered.`
67
+ );
68
+ return;
69
+ }
70
+ panels.push(config);
71
+ }
72
+ function getEditViewSidePanels(model) {
73
+ return panels.filter((p) => {
74
+ if (!p.model) return true;
75
+ if (Array.isArray(p.model)) return p.model.includes(model);
76
+ return p.model === model;
77
+ });
78
+ }
79
+ function captureApp(app) {
80
+ window.__betterAuthDashApp = app;
81
+ }
82
+ function getMediaLibraryComponent() {
83
+ return window.__betterAuthDashApp?.library?.components?.["media-library"] ?? null;
84
+ }
85
+ const plugin = {
86
+ register(app) {
87
+ captureApp(app);
88
+ app.registerPlugin({
89
+ id: PLUGIN_ID,
90
+ name: "Auth Dashboard",
91
+ apis: { addEditViewSidePanel }
92
+ });
93
+ app.addMenuLink({
94
+ to: `/plugins/${PLUGIN_ID}`,
95
+ icon: PluginIcon,
96
+ intlLabel: {
97
+ id: `${PLUGIN_ID}.plugin.name`,
98
+ defaultMessage: "Auth Dashboard"
99
+ },
100
+ Component: async () => import("./Root-6Fpvuogl.mjs"),
101
+ permissions: [
102
+ ...PERMISSIONS.overview,
103
+ ...PERMISSIONS.user,
104
+ ...PERMISSIONS.organization
105
+ ]
106
+ });
107
+ },
108
+ bootstrap() {
109
+ }
110
+ };
111
+ export {
112
+ PLUGIN_ID as P,
113
+ PERMISSIONS as a,
114
+ getEditViewSidePanels as b,
115
+ getMediaLibraryComponent as g,
116
+ plugin as p
117
+ };
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
- const index = require("./index-A9PUvldu.js");
4
- exports.default = index.index;
3
+ const index = require("./index-WTRykUoM.js");
4
+ exports.default = index.plugin;
@@ -1,4 +1,4 @@
1
- import { i } from "./index-Cvcysa5M.mjs";
1
+ import { p } from "./index-X2-Fh6sz.mjs";
2
2
  export {
3
- i as default
3
+ p as default
4
4
  };
@@ -37,7 +37,6 @@ const proxyController = () => ({
37
37
  overrideOptions: { jwt: { expirationTime: "5m" } }
38
38
  }
39
39
  });
40
- console.log("Generated JWT with payload:", { token });
41
40
  const url = new URL(
42
41
  ctx.request.url,
43
42
  `${ctx.request.protocol}://${ctx.request.host}`
@@ -63,17 +62,245 @@ const proxyController = () => ({
63
62
  ctx.set(key, value);
64
63
  });
65
64
  const contentType = response.headers.get("content-type");
66
- if (contentType?.includes("application/json")) {
67
- ctx.body = await response.json();
68
- } else if (contentType?.includes("text/")) {
69
- ctx.body = await response.text();
65
+ const text = await response.text();
66
+ if (!text) {
67
+ ctx.body = {};
68
+ } else if (contentType?.includes("application/json")) {
69
+ ctx.body = JSON.parse(text);
70
70
  } else {
71
- ctx.body = await response.text();
71
+ ctx.body = text;
72
72
  }
73
73
  }
74
74
  });
75
+ function assertValidUid(ctx, uid) {
76
+ if (typeof uid !== "string" || !uid.startsWith("plugin::") && !uid.startsWith("api::") && !uid.startsWith("admin::")) {
77
+ ctx.status = 400;
78
+ ctx.body = { error: "uid must be a valid Strapi content-type UID" };
79
+ return false;
80
+ }
81
+ return true;
82
+ }
83
+ const dbController = () => ({
84
+ /**
85
+ * List documents.
86
+ *
87
+ * Query params (all optional):
88
+ * uid – content-type UID, e.g. plugin::better-auth.session
89
+ * filters – Strapi filter object, supports nested qs syntax:
90
+ * ?filters[userId][$eq]=1
91
+ * sort – sort string or array, e.g. sort[0]=createdAt:desc
92
+ * pagination[page] – 1-indexed page number (default 1)
93
+ * pagination[pageSize] – items per page (default 50)
94
+ * populate – "*" for all relations, or comma-separated field names
95
+ *
96
+ * Response: { results: [...], pagination: { page, pageSize, total, pageCount } }
97
+ */
98
+ async list(ctx) {
99
+ const { uid, filters, pagination, populate } = ctx.query;
100
+ if (!assertValidUid(ctx, uid)) return;
101
+ const page = Math.max(1, parseInt(pagination?.page ?? "1", 10));
102
+ const pageSize = Math.min(
103
+ 200,
104
+ Math.max(1, parseInt(pagination?.pageSize ?? "50", 10))
105
+ );
106
+ const populateArg = populate ? populate === "*" ? "*" : populate.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
107
+ const service = strapi.documents(uid);
108
+ const [results, total] = await Promise.all([
109
+ service.findMany({
110
+ filters: filters ?? {},
111
+ sort: "createdAt:desc",
112
+ limit: pageSize,
113
+ start: (page - 1) * pageSize,
114
+ ...populateArg ? { populate: populateArg } : {}
115
+ }),
116
+ strapi.documents(uid).count({ filters: filters ?? {} })
117
+ ]);
118
+ ctx.body = {
119
+ results,
120
+ pagination: {
121
+ page,
122
+ pageSize,
123
+ total,
124
+ pageCount: Math.ceil(total / pageSize)
125
+ }
126
+ };
127
+ },
128
+ /**
129
+ * Update a single document by its documentId (UUID).
130
+ *
131
+ * Query params:
132
+ * uid – content-type UID
133
+ *
134
+ * Body: partial field values to update.
135
+ *
136
+ * Response: updated document.
137
+ */
138
+ async update(ctx) {
139
+ const { uid } = ctx.query;
140
+ if (!assertValidUid(ctx, uid)) return;
141
+ const { documentId } = ctx.params;
142
+ const result = await strapi.documents(uid).update({
143
+ documentId,
144
+ data: ctx.request.body
145
+ });
146
+ if (!result) {
147
+ ctx.status = 404;
148
+ ctx.body = { error: "Document not found" };
149
+ return;
150
+ }
151
+ ctx.body = result;
152
+ }
153
+ });
75
154
  const controllers = {
76
- "auth-controller": proxyController
155
+ "auth-controller": proxyController,
156
+ "db-controller": dbController
157
+ };
158
+ const { PolicyError } = utils.errors;
159
+ const endpointsCategories = Object.freeze({
160
+ "/auth/dash/config": ["overview", "user", "organization"],
161
+ "/auth/dash/user-stats": ["overview"],
162
+ "/auth/dash/user-graph-data": ["overview"],
163
+ "/auth/dash/user-retention-data": ["overview"],
164
+ "/auth/dash/list-users": ["overview", "user"],
165
+ "/auth/dash/list-organization": ["overview", "organization"],
166
+ "/auth/dash/user": ["user"],
167
+ "/auth/dash/organization": ["organization"]
168
+ });
169
+ const types = Object.freeze({
170
+ POST: "read",
171
+ PUT: "update",
172
+ GET: "read",
173
+ DELETE: "delete"
174
+ });
175
+ const endpointsTypes = Object.freeze({
176
+ "/auth/dash/user-stats": "read",
177
+ "/auth/dash/user-graph-data": "read",
178
+ "/auth/dash/user-retention-data": "read",
179
+ "/auth/dash/list-users": "read",
180
+ "/auth/dash/list-organizations": "read",
181
+ "/auth/dash/organization/options": "read",
182
+ "/auth/dash/create-user": "create",
183
+ "/auth/dash/update-user": "update",
184
+ "/auth/dash/user": "read",
185
+ "/auth/dash/delete-user": "delete",
186
+ "/auth/dash/organization/create": "create",
187
+ "/auth/dash/organization/delete": "delete"
188
+ });
189
+ const hasPermission = async (ctx, _, { strapi: strapi2 }) => {
190
+ const { user, route } = ctx.state;
191
+ if (!user) return false;
192
+ const inherentType = types[route.method];
193
+ const determinedType = endpointsTypes?.[Object.keys(endpointsTypes)?.find(
194
+ (k) => ctx.originalUrl?.includes(k)
195
+ )];
196
+ const found = [];
197
+ for await (const role of user.roles) {
198
+ const categories = endpointsCategories[Object.keys(endpointsCategories).find(
199
+ (key) => ctx.originalUrl.startsWith(key)
200
+ )];
201
+ const permissions = await strapi2.documents("admin::permission").findMany({
202
+ filters: {
203
+ $or: (categories || []).map((cat) => ({
204
+ role: { id: role.id },
205
+ action: {
206
+ $startsWith: "plugin::better-auth-dashboard",
207
+ $containsi: cat,
208
+ $endsWith: determinedType || inherentType
209
+ }
210
+ }))
211
+ }
212
+ });
213
+ if (permissions?.length > 0) found.push(...permissions);
214
+ }
215
+ if (found.length <= 0) {
216
+ throw new PolicyError("You do not have permission to see this content.");
217
+ }
218
+ return true;
219
+ };
220
+ const policies = { "has-permission": hasPermission };
221
+ const strapi$1 = { "name": "better-auth-dashboard" };
222
+ const packageJson = {
223
+ strapi: strapi$1
224
+ };
225
+ const PLUGIN_ID = packageJson.strapi.name;
226
+ const ACTIONS = {
227
+ overview: [
228
+ {
229
+ section: "plugins",
230
+ subCategory: "overview",
231
+ displayName: "Read",
232
+ pluginName: PLUGIN_ID,
233
+ uid: "overview.read"
234
+ }
235
+ ],
236
+ user: [
237
+ {
238
+ section: "plugins",
239
+ subCategory: "user",
240
+ displayName: "Create",
241
+ pluginName: PLUGIN_ID,
242
+ uid: "user.create"
243
+ },
244
+ {
245
+ section: "plugins",
246
+ subCategory: "user",
247
+ displayName: "Read",
248
+ pluginName: PLUGIN_ID,
249
+ uid: "user.read"
250
+ },
251
+ {
252
+ section: "plugins",
253
+ subCategory: "user",
254
+ displayName: "Update",
255
+ pluginName: PLUGIN_ID,
256
+ uid: "user.update"
257
+ },
258
+ {
259
+ section: "plugins",
260
+ subCategory: "user",
261
+ displayName: "Delete",
262
+ pluginName: PLUGIN_ID,
263
+ uid: "user.delete"
264
+ }
265
+ ],
266
+ organization: [
267
+ {
268
+ section: "plugins",
269
+ subCategory: "organization",
270
+ displayName: "Create",
271
+ pluginName: PLUGIN_ID,
272
+ uid: "organization.create"
273
+ },
274
+ {
275
+ section: "plugins",
276
+ subCategory: "organization",
277
+ displayName: "Read",
278
+ pluginName: PLUGIN_ID,
279
+ uid: "organization.read"
280
+ },
281
+ {
282
+ section: "plugins",
283
+ subCategory: "organization",
284
+ displayName: "Update",
285
+ pluginName: PLUGIN_ID,
286
+ uid: "organization.update"
287
+ },
288
+ {
289
+ section: "plugins",
290
+ subCategory: "organization",
291
+ displayName: "Delete",
292
+ pluginName: PLUGIN_ID,
293
+ uid: "organization.delete"
294
+ }
295
+ ]
296
+ };
297
+ const register = ({ strapi: strapi2 }) => {
298
+ const actionsToRegister = [...ACTIONS.overview, ...ACTIONS.user];
299
+ if (strapi2.plugin("better-auth").contentTypes?.organization)
300
+ actionsToRegister.push(...ACTIONS.organization);
301
+ strapi2.admin.services.permission.actionProvider.registerMany(
302
+ actionsToRegister
303
+ );
77
304
  };
78
305
  const adminRoutes = () => ({
79
306
  type: "admin",
@@ -83,9 +310,8 @@ const adminRoutes = () => ({
83
310
  path: "/auth/:path*",
84
311
  handler: "auth-controller.handleAuthRequest",
85
312
  config: {
86
- policies: [],
87
- prefix: "",
88
- auth: false
313
+ policies: ["has-permission"],
314
+ prefix: ""
89
315
  }
90
316
  },
91
317
  {
@@ -93,8 +319,7 @@ const adminRoutes = () => ({
93
319
  path: "/auth/:path*",
94
320
  handler: "auth-controller.handleAuthRequest",
95
321
  config: {
96
- policies: [],
97
- auth: false,
322
+ policies: ["has-permission"],
98
323
  prefix: ""
99
324
  }
100
325
  },
@@ -103,8 +328,7 @@ const adminRoutes = () => ({
103
328
  path: "/auth/:path*",
104
329
  handler: "auth-controller.handleAuthRequest",
105
330
  config: {
106
- policies: [],
107
- auth: false,
331
+ policies: ["has-permission"],
108
332
  prefix: ""
109
333
  }
110
334
  },
@@ -113,8 +337,7 @@ const adminRoutes = () => ({
113
337
  path: "/auth/:path*",
114
338
  handler: "auth-controller.handleAuthRequest",
115
339
  config: {
116
- policies: [],
117
- auth: false,
340
+ policies: ["has-permission"],
118
341
  prefix: ""
119
342
  }
120
343
  },
@@ -123,8 +346,25 @@ const adminRoutes = () => ({
123
346
  path: "/auth/:path*",
124
347
  handler: "auth-controller.handleAuthRequest",
125
348
  config: {
126
- policies: [],
127
- auth: false,
349
+ policies: ["has-permission"],
350
+ prefix: ""
351
+ }
352
+ },
353
+ {
354
+ method: "GET",
355
+ path: "/better-auth-dashboard/db",
356
+ handler: "db-controller.list",
357
+ config: {
358
+ policies: ["has-permission"],
359
+ prefix: ""
360
+ }
361
+ },
362
+ {
363
+ method: "PUT",
364
+ path: "/better-auth-dashboard/db/:documentId",
365
+ handler: "db-controller.update",
366
+ config: {
367
+ policies: ["has-permission"],
128
368
  prefix: ""
129
369
  }
130
370
  }
@@ -133,6 +373,8 @@ const adminRoutes = () => ({
133
373
  const routes = { admin: adminRoutes };
134
374
  const index = {
135
375
  controllers,
136
- routes
376
+ routes,
377
+ policies,
378
+ register
137
379
  };
138
380
  exports.default = index;