@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.
- package/README.md +101 -0
- package/dist/admin/{Root-hwPhIfaT.mjs → Root-6Fpvuogl.mjs} +2435 -1507
- package/dist/admin/{Root-Bl4iPGDu.js → Root-CN4cZKCJ.js} +2427 -1499
- package/dist/admin/index-WTRykUoM.js +116 -0
- package/dist/admin/index-X2-Fh6sz.mjs +117 -0
- package/dist/admin/index.js +2 -2
- package/dist/admin/index.mjs +2 -2
- package/dist/server/index.js +261 -19
- package/dist/server/index.mjs +261 -19
- package/package.json +10 -8
- package/dist/admin/index-A9PUvldu.js +0 -26
- package/dist/admin/index-Cvcysa5M.mjs +0 -27
package/dist/server/index.mjs
CHANGED
|
@@ -35,7 +35,6 @@ const proxyController = () => ({
|
|
|
35
35
|
overrideOptions: { jwt: { expirationTime: "5m" } }
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
|
-
console.log("Generated JWT with payload:", { token });
|
|
39
38
|
const url = new URL(
|
|
40
39
|
ctx.request.url,
|
|
41
40
|
`${ctx.request.protocol}://${ctx.request.host}`
|
|
@@ -61,17 +60,245 @@ const proxyController = () => ({
|
|
|
61
60
|
ctx.set(key, value);
|
|
62
61
|
});
|
|
63
62
|
const contentType = response.headers.get("content-type");
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
const text = await response.text();
|
|
64
|
+
if (!text) {
|
|
65
|
+
ctx.body = {};
|
|
66
|
+
} else if (contentType?.includes("application/json")) {
|
|
67
|
+
ctx.body = JSON.parse(text);
|
|
68
68
|
} else {
|
|
69
|
-
ctx.body =
|
|
69
|
+
ctx.body = text;
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
});
|
|
73
|
+
function assertValidUid(ctx, uid) {
|
|
74
|
+
if (typeof uid !== "string" || !uid.startsWith("plugin::") && !uid.startsWith("api::") && !uid.startsWith("admin::")) {
|
|
75
|
+
ctx.status = 400;
|
|
76
|
+
ctx.body = { error: "uid must be a valid Strapi content-type UID" };
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
const dbController = () => ({
|
|
82
|
+
/**
|
|
83
|
+
* List documents.
|
|
84
|
+
*
|
|
85
|
+
* Query params (all optional):
|
|
86
|
+
* uid – content-type UID, e.g. plugin::better-auth.session
|
|
87
|
+
* filters – Strapi filter object, supports nested qs syntax:
|
|
88
|
+
* ?filters[userId][$eq]=1
|
|
89
|
+
* sort – sort string or array, e.g. sort[0]=createdAt:desc
|
|
90
|
+
* pagination[page] – 1-indexed page number (default 1)
|
|
91
|
+
* pagination[pageSize] – items per page (default 50)
|
|
92
|
+
* populate – "*" for all relations, or comma-separated field names
|
|
93
|
+
*
|
|
94
|
+
* Response: { results: [...], pagination: { page, pageSize, total, pageCount } }
|
|
95
|
+
*/
|
|
96
|
+
async list(ctx) {
|
|
97
|
+
const { uid, filters, pagination, populate } = ctx.query;
|
|
98
|
+
if (!assertValidUid(ctx, uid)) return;
|
|
99
|
+
const page = Math.max(1, parseInt(pagination?.page ?? "1", 10));
|
|
100
|
+
const pageSize = Math.min(
|
|
101
|
+
200,
|
|
102
|
+
Math.max(1, parseInt(pagination?.pageSize ?? "50", 10))
|
|
103
|
+
);
|
|
104
|
+
const populateArg = populate ? populate === "*" ? "*" : populate.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
|
|
105
|
+
const service = strapi.documents(uid);
|
|
106
|
+
const [results, total] = await Promise.all([
|
|
107
|
+
service.findMany({
|
|
108
|
+
filters: filters ?? {},
|
|
109
|
+
sort: "createdAt:desc",
|
|
110
|
+
limit: pageSize,
|
|
111
|
+
start: (page - 1) * pageSize,
|
|
112
|
+
...populateArg ? { populate: populateArg } : {}
|
|
113
|
+
}),
|
|
114
|
+
strapi.documents(uid).count({ filters: filters ?? {} })
|
|
115
|
+
]);
|
|
116
|
+
ctx.body = {
|
|
117
|
+
results,
|
|
118
|
+
pagination: {
|
|
119
|
+
page,
|
|
120
|
+
pageSize,
|
|
121
|
+
total,
|
|
122
|
+
pageCount: Math.ceil(total / pageSize)
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
/**
|
|
127
|
+
* Update a single document by its documentId (UUID).
|
|
128
|
+
*
|
|
129
|
+
* Query params:
|
|
130
|
+
* uid – content-type UID
|
|
131
|
+
*
|
|
132
|
+
* Body: partial field values to update.
|
|
133
|
+
*
|
|
134
|
+
* Response: updated document.
|
|
135
|
+
*/
|
|
136
|
+
async update(ctx) {
|
|
137
|
+
const { uid } = ctx.query;
|
|
138
|
+
if (!assertValidUid(ctx, uid)) return;
|
|
139
|
+
const { documentId } = ctx.params;
|
|
140
|
+
const result = await strapi.documents(uid).update({
|
|
141
|
+
documentId,
|
|
142
|
+
data: ctx.request.body
|
|
143
|
+
});
|
|
144
|
+
if (!result) {
|
|
145
|
+
ctx.status = 404;
|
|
146
|
+
ctx.body = { error: "Document not found" };
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
ctx.body = result;
|
|
150
|
+
}
|
|
151
|
+
});
|
|
73
152
|
const controllers = {
|
|
74
|
-
"auth-controller": proxyController
|
|
153
|
+
"auth-controller": proxyController,
|
|
154
|
+
"db-controller": dbController
|
|
155
|
+
};
|
|
156
|
+
const { PolicyError } = errors;
|
|
157
|
+
const endpointsCategories = Object.freeze({
|
|
158
|
+
"/auth/dash/config": ["overview", "user", "organization"],
|
|
159
|
+
"/auth/dash/user-stats": ["overview"],
|
|
160
|
+
"/auth/dash/user-graph-data": ["overview"],
|
|
161
|
+
"/auth/dash/user-retention-data": ["overview"],
|
|
162
|
+
"/auth/dash/list-users": ["overview", "user"],
|
|
163
|
+
"/auth/dash/list-organization": ["overview", "organization"],
|
|
164
|
+
"/auth/dash/user": ["user"],
|
|
165
|
+
"/auth/dash/organization": ["organization"]
|
|
166
|
+
});
|
|
167
|
+
const types = Object.freeze({
|
|
168
|
+
POST: "read",
|
|
169
|
+
PUT: "update",
|
|
170
|
+
GET: "read",
|
|
171
|
+
DELETE: "delete"
|
|
172
|
+
});
|
|
173
|
+
const endpointsTypes = Object.freeze({
|
|
174
|
+
"/auth/dash/user-stats": "read",
|
|
175
|
+
"/auth/dash/user-graph-data": "read",
|
|
176
|
+
"/auth/dash/user-retention-data": "read",
|
|
177
|
+
"/auth/dash/list-users": "read",
|
|
178
|
+
"/auth/dash/list-organizations": "read",
|
|
179
|
+
"/auth/dash/organization/options": "read",
|
|
180
|
+
"/auth/dash/create-user": "create",
|
|
181
|
+
"/auth/dash/update-user": "update",
|
|
182
|
+
"/auth/dash/user": "read",
|
|
183
|
+
"/auth/dash/delete-user": "delete",
|
|
184
|
+
"/auth/dash/organization/create": "create",
|
|
185
|
+
"/auth/dash/organization/delete": "delete"
|
|
186
|
+
});
|
|
187
|
+
const hasPermission = async (ctx, _, { strapi: strapi2 }) => {
|
|
188
|
+
const { user, route } = ctx.state;
|
|
189
|
+
if (!user) return false;
|
|
190
|
+
const inherentType = types[route.method];
|
|
191
|
+
const determinedType = endpointsTypes?.[Object.keys(endpointsTypes)?.find(
|
|
192
|
+
(k) => ctx.originalUrl?.includes(k)
|
|
193
|
+
)];
|
|
194
|
+
const found = [];
|
|
195
|
+
for await (const role of user.roles) {
|
|
196
|
+
const categories = endpointsCategories[Object.keys(endpointsCategories).find(
|
|
197
|
+
(key) => ctx.originalUrl.startsWith(key)
|
|
198
|
+
)];
|
|
199
|
+
const permissions = await strapi2.documents("admin::permission").findMany({
|
|
200
|
+
filters: {
|
|
201
|
+
$or: (categories || []).map((cat) => ({
|
|
202
|
+
role: { id: role.id },
|
|
203
|
+
action: {
|
|
204
|
+
$startsWith: "plugin::better-auth-dashboard",
|
|
205
|
+
$containsi: cat,
|
|
206
|
+
$endsWith: determinedType || inherentType
|
|
207
|
+
}
|
|
208
|
+
}))
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
if (permissions?.length > 0) found.push(...permissions);
|
|
212
|
+
}
|
|
213
|
+
if (found.length <= 0) {
|
|
214
|
+
throw new PolicyError("You do not have permission to see this content.");
|
|
215
|
+
}
|
|
216
|
+
return true;
|
|
217
|
+
};
|
|
218
|
+
const policies = { "has-permission": hasPermission };
|
|
219
|
+
const strapi$1 = { "name": "better-auth-dashboard" };
|
|
220
|
+
const packageJson = {
|
|
221
|
+
strapi: strapi$1
|
|
222
|
+
};
|
|
223
|
+
const PLUGIN_ID = packageJson.strapi.name;
|
|
224
|
+
const ACTIONS = {
|
|
225
|
+
overview: [
|
|
226
|
+
{
|
|
227
|
+
section: "plugins",
|
|
228
|
+
subCategory: "overview",
|
|
229
|
+
displayName: "Read",
|
|
230
|
+
pluginName: PLUGIN_ID,
|
|
231
|
+
uid: "overview.read"
|
|
232
|
+
}
|
|
233
|
+
],
|
|
234
|
+
user: [
|
|
235
|
+
{
|
|
236
|
+
section: "plugins",
|
|
237
|
+
subCategory: "user",
|
|
238
|
+
displayName: "Create",
|
|
239
|
+
pluginName: PLUGIN_ID,
|
|
240
|
+
uid: "user.create"
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
section: "plugins",
|
|
244
|
+
subCategory: "user",
|
|
245
|
+
displayName: "Read",
|
|
246
|
+
pluginName: PLUGIN_ID,
|
|
247
|
+
uid: "user.read"
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
section: "plugins",
|
|
251
|
+
subCategory: "user",
|
|
252
|
+
displayName: "Update",
|
|
253
|
+
pluginName: PLUGIN_ID,
|
|
254
|
+
uid: "user.update"
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
section: "plugins",
|
|
258
|
+
subCategory: "user",
|
|
259
|
+
displayName: "Delete",
|
|
260
|
+
pluginName: PLUGIN_ID,
|
|
261
|
+
uid: "user.delete"
|
|
262
|
+
}
|
|
263
|
+
],
|
|
264
|
+
organization: [
|
|
265
|
+
{
|
|
266
|
+
section: "plugins",
|
|
267
|
+
subCategory: "organization",
|
|
268
|
+
displayName: "Create",
|
|
269
|
+
pluginName: PLUGIN_ID,
|
|
270
|
+
uid: "organization.create"
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
section: "plugins",
|
|
274
|
+
subCategory: "organization",
|
|
275
|
+
displayName: "Read",
|
|
276
|
+
pluginName: PLUGIN_ID,
|
|
277
|
+
uid: "organization.read"
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
section: "plugins",
|
|
281
|
+
subCategory: "organization",
|
|
282
|
+
displayName: "Update",
|
|
283
|
+
pluginName: PLUGIN_ID,
|
|
284
|
+
uid: "organization.update"
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
section: "plugins",
|
|
288
|
+
subCategory: "organization",
|
|
289
|
+
displayName: "Delete",
|
|
290
|
+
pluginName: PLUGIN_ID,
|
|
291
|
+
uid: "organization.delete"
|
|
292
|
+
}
|
|
293
|
+
]
|
|
294
|
+
};
|
|
295
|
+
const register = ({ strapi: strapi2 }) => {
|
|
296
|
+
const actionsToRegister = [...ACTIONS.overview, ...ACTIONS.user];
|
|
297
|
+
if (strapi2.plugin("better-auth").contentTypes?.organization)
|
|
298
|
+
actionsToRegister.push(...ACTIONS.organization);
|
|
299
|
+
strapi2.admin.services.permission.actionProvider.registerMany(
|
|
300
|
+
actionsToRegister
|
|
301
|
+
);
|
|
75
302
|
};
|
|
76
303
|
const adminRoutes = () => ({
|
|
77
304
|
type: "admin",
|
|
@@ -81,9 +308,8 @@ const adminRoutes = () => ({
|
|
|
81
308
|
path: "/auth/:path*",
|
|
82
309
|
handler: "auth-controller.handleAuthRequest",
|
|
83
310
|
config: {
|
|
84
|
-
policies: [],
|
|
85
|
-
prefix: ""
|
|
86
|
-
auth: false
|
|
311
|
+
policies: ["has-permission"],
|
|
312
|
+
prefix: ""
|
|
87
313
|
}
|
|
88
314
|
},
|
|
89
315
|
{
|
|
@@ -91,8 +317,7 @@ const adminRoutes = () => ({
|
|
|
91
317
|
path: "/auth/:path*",
|
|
92
318
|
handler: "auth-controller.handleAuthRequest",
|
|
93
319
|
config: {
|
|
94
|
-
policies: [],
|
|
95
|
-
auth: false,
|
|
320
|
+
policies: ["has-permission"],
|
|
96
321
|
prefix: ""
|
|
97
322
|
}
|
|
98
323
|
},
|
|
@@ -101,8 +326,7 @@ const adminRoutes = () => ({
|
|
|
101
326
|
path: "/auth/:path*",
|
|
102
327
|
handler: "auth-controller.handleAuthRequest",
|
|
103
328
|
config: {
|
|
104
|
-
policies: [],
|
|
105
|
-
auth: false,
|
|
329
|
+
policies: ["has-permission"],
|
|
106
330
|
prefix: ""
|
|
107
331
|
}
|
|
108
332
|
},
|
|
@@ -111,8 +335,7 @@ const adminRoutes = () => ({
|
|
|
111
335
|
path: "/auth/:path*",
|
|
112
336
|
handler: "auth-controller.handleAuthRequest",
|
|
113
337
|
config: {
|
|
114
|
-
policies: [],
|
|
115
|
-
auth: false,
|
|
338
|
+
policies: ["has-permission"],
|
|
116
339
|
prefix: ""
|
|
117
340
|
}
|
|
118
341
|
},
|
|
@@ -121,8 +344,25 @@ const adminRoutes = () => ({
|
|
|
121
344
|
path: "/auth/:path*",
|
|
122
345
|
handler: "auth-controller.handleAuthRequest",
|
|
123
346
|
config: {
|
|
124
|
-
policies: [],
|
|
125
|
-
|
|
347
|
+
policies: ["has-permission"],
|
|
348
|
+
prefix: ""
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
method: "GET",
|
|
353
|
+
path: "/better-auth-dashboard/db",
|
|
354
|
+
handler: "db-controller.list",
|
|
355
|
+
config: {
|
|
356
|
+
policies: ["has-permission"],
|
|
357
|
+
prefix: ""
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
method: "PUT",
|
|
362
|
+
path: "/better-auth-dashboard/db/:documentId",
|
|
363
|
+
handler: "db-controller.update",
|
|
364
|
+
config: {
|
|
365
|
+
policies: ["has-permission"],
|
|
126
366
|
prefix: ""
|
|
127
367
|
}
|
|
128
368
|
}
|
|
@@ -131,7 +371,9 @@ const adminRoutes = () => ({
|
|
|
131
371
|
const routes = { admin: adminRoutes };
|
|
132
372
|
const index = {
|
|
133
373
|
controllers,
|
|
134
|
-
routes
|
|
374
|
+
routes,
|
|
375
|
+
policies,
|
|
376
|
+
register
|
|
135
377
|
};
|
|
136
378
|
export {
|
|
137
379
|
index as default
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi-community/plugin-better-auth-dashboard",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.10",
|
|
4
4
|
"description": "Better Auth dashboard for the Strapi admin panel",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"strapi",
|
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"author": {
|
|
13
13
|
"name": "Boaz Poolman",
|
|
14
|
-
"email": "boaz@
|
|
14
|
+
"email": "boaz.poolman@strapi.io",
|
|
15
15
|
"url": "https://github.com/boazpoolman"
|
|
16
16
|
},
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
19
19
|
"url": "git+https://github.com/strapi-community/plugin-better-auth.git",
|
|
20
|
-
"directory": "
|
|
20
|
+
"directory": "plugins/plugin-better-auth-dashboard"
|
|
21
21
|
},
|
|
22
22
|
"type": "commonjs",
|
|
23
23
|
"exports": {
|
|
@@ -48,7 +48,8 @@
|
|
|
48
48
|
"@types/node": "^22",
|
|
49
49
|
"@types/react": "^18.0.0",
|
|
50
50
|
"@types/styled-components": "^5.1.36",
|
|
51
|
-
"typescript": "^5.9.3"
|
|
51
|
+
"typescript": "^5.9.3",
|
|
52
|
+
"@strapi-community/dev-utils": "0.0.1"
|
|
52
53
|
},
|
|
53
54
|
"peerDependencies": {
|
|
54
55
|
"@better-auth/infra": "^0.2.6",
|
|
@@ -63,6 +64,7 @@
|
|
|
63
64
|
"react-intl": "^6.0.0 || ^7.0.0",
|
|
64
65
|
"react-query": "^3.0.0",
|
|
65
66
|
"styled-components": "^6.0.0",
|
|
67
|
+
"react-router-dom": "^6.0.0",
|
|
66
68
|
"@strapi-community/plugin-better-auth": "^1.0.0-beta.6"
|
|
67
69
|
},
|
|
68
70
|
"strapi": {
|
|
@@ -76,9 +78,9 @@
|
|
|
76
78
|
"watch": "strapi-plugin watch",
|
|
77
79
|
"dev": "strapi-plugin watch",
|
|
78
80
|
"verify": "strapi-plugin verify",
|
|
79
|
-
"
|
|
80
|
-
"
|
|
81
|
-
"
|
|
82
|
-
"
|
|
81
|
+
"lint:ts:server": "cd server && tsc --noEmit",
|
|
82
|
+
"lint:ts:admin": "cd admin && tsc --noEmit",
|
|
83
|
+
"lint": "biome check --fix",
|
|
84
|
+
"test:e2e": "playwright test"
|
|
83
85
|
}
|
|
84
86
|
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
const PLUGIN_ID = "better-auth-dashboard";
|
|
3
|
-
function captureApp(app) {
|
|
4
|
-
window.__betterAuthDashApp = app;
|
|
5
|
-
}
|
|
6
|
-
function getMediaLibraryComponent() {
|
|
7
|
-
return window.__betterAuthDashApp?.library?.components?.["media-library"] ?? null;
|
|
8
|
-
}
|
|
9
|
-
const index = {
|
|
10
|
-
register(app) {
|
|
11
|
-
captureApp(app);
|
|
12
|
-
app.addMenuLink({
|
|
13
|
-
to: `/plugins/${PLUGIN_ID}`,
|
|
14
|
-
icon: () => null,
|
|
15
|
-
intlLabel: {
|
|
16
|
-
id: `${PLUGIN_ID}.plugin.name`,
|
|
17
|
-
defaultMessage: "Auth Dashboard"
|
|
18
|
-
},
|
|
19
|
-
Component: async () => Promise.resolve().then(() => require("./Root-Bl4iPGDu.js"))
|
|
20
|
-
});
|
|
21
|
-
},
|
|
22
|
-
bootstrap() {
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
exports.getMediaLibraryComponent = getMediaLibraryComponent;
|
|
26
|
-
exports.index = index;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
const PLUGIN_ID = "better-auth-dashboard";
|
|
2
|
-
function captureApp(app) {
|
|
3
|
-
window.__betterAuthDashApp = app;
|
|
4
|
-
}
|
|
5
|
-
function getMediaLibraryComponent() {
|
|
6
|
-
return window.__betterAuthDashApp?.library?.components?.["media-library"] ?? null;
|
|
7
|
-
}
|
|
8
|
-
const index = {
|
|
9
|
-
register(app) {
|
|
10
|
-
captureApp(app);
|
|
11
|
-
app.addMenuLink({
|
|
12
|
-
to: `/plugins/${PLUGIN_ID}`,
|
|
13
|
-
icon: () => null,
|
|
14
|
-
intlLabel: {
|
|
15
|
-
id: `${PLUGIN_ID}.plugin.name`,
|
|
16
|
-
defaultMessage: "Auth Dashboard"
|
|
17
|
-
},
|
|
18
|
-
Component: async () => import("./Root-hwPhIfaT.mjs")
|
|
19
|
-
});
|
|
20
|
-
},
|
|
21
|
-
bootstrap() {
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
export {
|
|
25
|
-
getMediaLibraryComponent as g,
|
|
26
|
-
index as i
|
|
27
|
-
};
|