better-auth-studio 1.0.14-beta.1 → 1.0.15
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 +11 -14
- package/dist/cli.js +1 -1
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +265 -0
- package/dist/routes.js.map +1 -1
- package/dist/studio.js +1 -1
- package/dist/studio.js.map +1 -1
- package/package.json +1 -1
- package/public/assets/main-7EuwGZ9I.js +356 -0
- package/public/assets/main-BdfFEk_g.css +1 -0
- package/public/index.html +2 -2
- package/public/assets/main-DtVcO05R.js +0 -341
- package/public/assets/main-dRPw2V3i.css +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
# Better Auth Studio
|
|
1
|
+
# Better Auth Studio
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> ⚠️ **Alpha Version Notice**
|
|
4
|
+
>
|
|
5
|
+
> Better Auth Studio is currently in **alpha** and in early development. You may encounter bugs or incomplete features. Please report any issues you find on our GitHub repository to help us improve the project. Your feedback is greatly appreciated!
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
A web-based studio interface for managing Better Auth applications. Better Auth Studio provides a comprehensive dashboard for managing users, organizations, teams, and more.
|
|
4
9
|
|
|
5
10
|
## 🚀 Quick Start
|
|
6
11
|
|
|
@@ -111,7 +116,7 @@ export const auth = betterAuth({
|
|
|
111
116
|
- **Edit users** - Update user information, email verification status
|
|
112
117
|
- **Delete users** - Remove users from the system
|
|
113
118
|
- **Bulk operations** - Seed multiple test users
|
|
114
|
-
- **User details** - View user profiles,
|
|
119
|
+
- **User details** - View user profiles, and accounts
|
|
115
120
|
|
|
116
121
|
### 🏢 Organization Management
|
|
117
122
|
- **View organizations** - List all organizations with pagination
|
|
@@ -122,11 +127,6 @@ export const auth = betterAuth({
|
|
|
122
127
|
- **Member management** - Add/remove members from teams
|
|
123
128
|
- **Bulk seeding** - Generate test organizations and teams
|
|
124
129
|
|
|
125
|
-
### 🔐 Session Management
|
|
126
|
-
- **Active sessions** - View all active user sessions
|
|
127
|
-
- **Session details** - IP addresses, user agents, expiration times
|
|
128
|
-
- **Session termination** - Revoke specific sessions
|
|
129
|
-
|
|
130
130
|
### ⚙️ Settings & Configuration
|
|
131
131
|
- **Plugin status** - Check which Better Auth plugins are enabled
|
|
132
132
|
- **Database configuration** - View current database adapter and settings
|
|
@@ -165,7 +165,7 @@ pnpx better-auth-studio --version
|
|
|
165
165
|
|
|
166
166
|
# Show help
|
|
167
167
|
pnpx better-auth-studio --help
|
|
168
|
-
|
|
168
|
+
```
|
|
169
169
|
## 📝 Development
|
|
170
170
|
|
|
171
171
|
### Running from Source
|
|
@@ -199,10 +199,7 @@ MIT License - see [LICENSE](LICENSE) file for details.
|
|
|
199
199
|
|
|
200
200
|
If you encounter any issues or have questions:
|
|
201
201
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
4. **Join our Discord** for community support
|
|
202
|
+
**Search existing issues** on GitHub
|
|
203
|
+
**Create a new issue** with detailed information
|
|
205
204
|
|
|
206
205
|
---
|
|
207
|
-
|
|
208
|
-
**Happy coding with Better Auth Studio! 🚀**
|
package/dist/cli.js
CHANGED
|
@@ -48,7 +48,7 @@ program
|
|
|
48
48
|
program
|
|
49
49
|
.command('start')
|
|
50
50
|
.description('Start Better Auth Studio')
|
|
51
|
-
.option('-p, --port <port>', 'Port to run the studio on', '
|
|
51
|
+
.option('-p, --port <port>', 'Port to run the studio on', '3002')
|
|
52
52
|
.option('-h, --host <host>', 'Host to run the studio on', 'localhost')
|
|
53
53
|
.option('--no-open', 'Do not open browser automatically')
|
|
54
54
|
.action(async (options) => {
|
package/dist/routes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAoCzC,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CA6J/E;AAwBD,wBAAgB,YAAY,CAAC,UAAU,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAoCzC,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CA6J/E;AAwBD,wBAAgB,YAAY,CAAC,UAAU,EAAE,UAAU,8CA6jElD"}
|
package/dist/routes.js
CHANGED
|
@@ -420,6 +420,271 @@ export function createRoutes(authConfig) {
|
|
|
420
420
|
res.status(500).json({ error: 'Failed to fetch users' });
|
|
421
421
|
}
|
|
422
422
|
});
|
|
423
|
+
router.get('/api/users/:userId', async (req, res) => {
|
|
424
|
+
try {
|
|
425
|
+
const { userId } = req.params;
|
|
426
|
+
const adapter = await getAuthAdapter();
|
|
427
|
+
if (!adapter || !adapter.findMany) {
|
|
428
|
+
return res.status(500).json({ error: 'Auth adapter not available' });
|
|
429
|
+
}
|
|
430
|
+
const users = await adapter.findMany({ model: 'user', limit: 10000 });
|
|
431
|
+
const user = users && users.length > 0 ? users.find((u) => u.id === userId) : null;
|
|
432
|
+
if (!user) {
|
|
433
|
+
return res.status(404).json({ error: 'User not found' });
|
|
434
|
+
}
|
|
435
|
+
res.json({ user });
|
|
436
|
+
}
|
|
437
|
+
catch (error) {
|
|
438
|
+
console.error('Error fetching user:', error);
|
|
439
|
+
res.status(500).json({ error: 'Failed to fetch user' });
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
router.put('/api/users/:userId', async (req, res) => {
|
|
443
|
+
try {
|
|
444
|
+
const { userId } = req.params;
|
|
445
|
+
const { name, email } = req.body;
|
|
446
|
+
const adapter = await getAuthAdapter();
|
|
447
|
+
if (!adapter || !adapter.update) {
|
|
448
|
+
return res.status(500).json({ error: 'Auth adapter not available' });
|
|
449
|
+
}
|
|
450
|
+
const user = await adapter.update({
|
|
451
|
+
model: 'user',
|
|
452
|
+
id: userId,
|
|
453
|
+
data: { name, email }
|
|
454
|
+
});
|
|
455
|
+
res.json({ success: true, user });
|
|
456
|
+
}
|
|
457
|
+
catch (error) {
|
|
458
|
+
console.error('Error updating user:', error);
|
|
459
|
+
res.status(500).json({ error: 'Failed to update user' });
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
router.delete('/api/users/:userId', async (req, res) => {
|
|
463
|
+
try {
|
|
464
|
+
const { userId } = req.params;
|
|
465
|
+
const adapter = await getAuthAdapter();
|
|
466
|
+
if (!adapter || !adapter.delete) {
|
|
467
|
+
return res.status(500).json({ error: 'Auth adapter not available' });
|
|
468
|
+
}
|
|
469
|
+
await adapter.delete({ model: 'user', id: userId });
|
|
470
|
+
res.json({ success: true });
|
|
471
|
+
}
|
|
472
|
+
catch (error) {
|
|
473
|
+
console.error('Error deleting user:', error);
|
|
474
|
+
res.status(500).json({ error: 'Failed to delete user' });
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
router.get('/api/users/:userId/organizations', async (req, res) => {
|
|
478
|
+
try {
|
|
479
|
+
const { userId } = req.params;
|
|
480
|
+
const adapter = await getAuthAdapter();
|
|
481
|
+
if (!adapter || !adapter.findMany) {
|
|
482
|
+
return res.status(500).json({ error: 'Auth adapter not available' });
|
|
483
|
+
}
|
|
484
|
+
const [memberships, organizations] = await Promise.all([
|
|
485
|
+
adapter.findMany({ model: 'member', limit: 10000 }),
|
|
486
|
+
adapter.findMany({ model: 'organization', limit: 10000 })
|
|
487
|
+
]);
|
|
488
|
+
const userMemberships = memberships.filter((membership) => membership.userId === userId);
|
|
489
|
+
const formattedMemberships = userMemberships.map((membership) => {
|
|
490
|
+
const organization = organizations.find((org) => org.id === membership.organizationId);
|
|
491
|
+
return {
|
|
492
|
+
id: membership.id,
|
|
493
|
+
organization: organization ? {
|
|
494
|
+
id: organization.id,
|
|
495
|
+
name: organization.name || 'Unknown Organization',
|
|
496
|
+
slug: organization.slug || 'unknown',
|
|
497
|
+
image: organization.image,
|
|
498
|
+
createdAt: organization.createdAt
|
|
499
|
+
} : {
|
|
500
|
+
id: membership.organizationId,
|
|
501
|
+
name: 'Unknown Organization',
|
|
502
|
+
slug: 'unknown',
|
|
503
|
+
createdAt: membership.createdAt
|
|
504
|
+
},
|
|
505
|
+
role: membership.role || 'member',
|
|
506
|
+
joinedAt: membership.createdAt
|
|
507
|
+
};
|
|
508
|
+
});
|
|
509
|
+
res.json({ memberships: formattedMemberships });
|
|
510
|
+
}
|
|
511
|
+
catch (error) {
|
|
512
|
+
console.error('Error fetching user organizations:', error);
|
|
513
|
+
res.status(500).json({ error: 'Failed to fetch user organizations' });
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
router.get('/api/users/:userId/teams', async (req, res) => {
|
|
517
|
+
try {
|
|
518
|
+
const { userId } = req.params;
|
|
519
|
+
const adapter = await getAuthAdapter();
|
|
520
|
+
if (!adapter || !adapter.findMany) {
|
|
521
|
+
return res.status(500).json({ error: 'Auth adapter not available' });
|
|
522
|
+
}
|
|
523
|
+
const [memberships, teams, organizations] = await Promise.all([
|
|
524
|
+
adapter.findMany({ model: 'teamMember', limit: 10000 }),
|
|
525
|
+
adapter.findMany({ model: 'team', limit: 10000 }),
|
|
526
|
+
adapter.findMany({ model: 'organization', limit: 10000 })
|
|
527
|
+
]);
|
|
528
|
+
const userMemberships = memberships.filter((membership) => membership.userId === userId);
|
|
529
|
+
const formattedMemberships = userMemberships.map((membership) => {
|
|
530
|
+
const team = teams.find((t) => t.id === membership.teamId);
|
|
531
|
+
const organization = team ? organizations.find((org) => org.id === team.organizationId) : null;
|
|
532
|
+
return {
|
|
533
|
+
id: membership.id,
|
|
534
|
+
team: team ? {
|
|
535
|
+
id: team.id,
|
|
536
|
+
name: team.name || 'Unknown Team',
|
|
537
|
+
organizationId: team.organizationId,
|
|
538
|
+
organizationName: organization ? organization.name || 'Unknown Organization' : 'Unknown Organization'
|
|
539
|
+
} : {
|
|
540
|
+
id: membership.teamId,
|
|
541
|
+
name: 'Unknown Team',
|
|
542
|
+
organizationId: 'unknown',
|
|
543
|
+
organizationName: 'Unknown Organization'
|
|
544
|
+
},
|
|
545
|
+
role: membership.role || 'member',
|
|
546
|
+
joinedAt: membership.createdAt
|
|
547
|
+
};
|
|
548
|
+
});
|
|
549
|
+
res.json({ memberships: formattedMemberships });
|
|
550
|
+
}
|
|
551
|
+
catch (error) {
|
|
552
|
+
console.error('Error fetching user teams:', error);
|
|
553
|
+
res.status(500).json({ error: 'Failed to fetch user teams' });
|
|
554
|
+
}
|
|
555
|
+
});
|
|
556
|
+
router.delete('/api/organizations/members/:membershipId', async (req, res) => {
|
|
557
|
+
try {
|
|
558
|
+
const { membershipId } = req.params;
|
|
559
|
+
const adapter = await getAuthAdapter();
|
|
560
|
+
if (!adapter || !adapter.delete) {
|
|
561
|
+
return res.status(500).json({ error: 'Auth adapter not available' });
|
|
562
|
+
}
|
|
563
|
+
await adapter.delete({ model: 'member', id: membershipId });
|
|
564
|
+
res.json({ success: true });
|
|
565
|
+
}
|
|
566
|
+
catch (error) {
|
|
567
|
+
console.error('Error removing user from organization:', error);
|
|
568
|
+
res.status(500).json({ error: 'Failed to remove user from organization' });
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
router.delete('/api/teams/members/:membershipId', async (req, res) => {
|
|
572
|
+
try {
|
|
573
|
+
const { membershipId } = req.params;
|
|
574
|
+
const adapter = await getAuthAdapter();
|
|
575
|
+
if (!adapter || !adapter.delete) {
|
|
576
|
+
return res.status(500).json({ error: 'Auth adapter not available' });
|
|
577
|
+
}
|
|
578
|
+
await adapter.delete({ model: 'teamMember', id: membershipId });
|
|
579
|
+
res.json({ success: true });
|
|
580
|
+
}
|
|
581
|
+
catch (error) {
|
|
582
|
+
console.error('Error removing user from team:', error);
|
|
583
|
+
res.status(500).json({ error: 'Failed to remove user from team' });
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
router.post('/api/users/:userId/ban', async (req, res) => {
|
|
587
|
+
try {
|
|
588
|
+
const { userId } = req.params;
|
|
589
|
+
const adapter = await getAuthAdapter();
|
|
590
|
+
if (!adapter || !adapter.update) {
|
|
591
|
+
return res.status(500).json({ error: 'Auth adapter not available' });
|
|
592
|
+
}
|
|
593
|
+
const user = await adapter.update({
|
|
594
|
+
model: 'user',
|
|
595
|
+
id: userId,
|
|
596
|
+
data: { banned: true }
|
|
597
|
+
});
|
|
598
|
+
res.json({ success: true, user });
|
|
599
|
+
}
|
|
600
|
+
catch (error) {
|
|
601
|
+
console.error('Error banning user:', error);
|
|
602
|
+
res.status(500).json({ error: 'Failed to ban user' });
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
router.get('/api/users/:userId/sessions', async (req, res) => {
|
|
606
|
+
try {
|
|
607
|
+
const { userId } = req.params;
|
|
608
|
+
const adapter = await getAuthAdapter();
|
|
609
|
+
if (!adapter || !adapter.findMany) {
|
|
610
|
+
return res.status(500).json({ error: 'Auth adapter not available' });
|
|
611
|
+
}
|
|
612
|
+
const sessions = await adapter.findMany({
|
|
613
|
+
model: 'session',
|
|
614
|
+
limit: 10000
|
|
615
|
+
});
|
|
616
|
+
const userSessions = sessions.filter((session) => session.userId === userId);
|
|
617
|
+
const formattedSessions = userSessions.map((session) => ({
|
|
618
|
+
id: session.id,
|
|
619
|
+
token: session.token,
|
|
620
|
+
expiresAt: session.expiresAt,
|
|
621
|
+
ipAddress: session.ipAddress || 'Unknown',
|
|
622
|
+
userAgent: session.userAgent || 'Unknown',
|
|
623
|
+
activeOrganizationId: session.activeOrganizationId,
|
|
624
|
+
activeTeamId: session.activeTeamId,
|
|
625
|
+
createdAt: session.createdAt,
|
|
626
|
+
updatedAt: session.updatedAt
|
|
627
|
+
}));
|
|
628
|
+
res.json({ sessions: formattedSessions });
|
|
629
|
+
}
|
|
630
|
+
catch (error) {
|
|
631
|
+
console.error('Error fetching user sessions:', error);
|
|
632
|
+
res.status(500).json({ error: 'Failed to fetch user sessions' });
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
router.delete('/api/sessions/:sessionId', async (req, res) => {
|
|
636
|
+
try {
|
|
637
|
+
const { sessionId } = req.params;
|
|
638
|
+
const adapter = await getAuthAdapter();
|
|
639
|
+
if (!adapter || !adapter.delete) {
|
|
640
|
+
return res.status(500).json({ error: 'Auth adapter not available' });
|
|
641
|
+
}
|
|
642
|
+
await adapter.delete({ model: 'session', id: sessionId });
|
|
643
|
+
res.json({ success: true });
|
|
644
|
+
}
|
|
645
|
+
catch (error) {
|
|
646
|
+
console.error('Error deleting session:', error);
|
|
647
|
+
res.status(500).json({ error: 'Failed to delete session' });
|
|
648
|
+
}
|
|
649
|
+
});
|
|
650
|
+
router.get('/api/teams/:teamId', async (req, res) => {
|
|
651
|
+
try {
|
|
652
|
+
const { teamId } = req.params;
|
|
653
|
+
const adapter = await getAuthAdapter();
|
|
654
|
+
if (!adapter || !adapter.findMany) {
|
|
655
|
+
return res.status(500).json({ error: 'Auth adapter not available' });
|
|
656
|
+
}
|
|
657
|
+
const teams = await adapter.findMany({ model: 'team', limit: 10000 });
|
|
658
|
+
const team = teams.find((t) => t.id === teamId);
|
|
659
|
+
if (!team) {
|
|
660
|
+
return res.status(404).json({ error: 'Team not found' });
|
|
661
|
+
}
|
|
662
|
+
res.json({ team });
|
|
663
|
+
}
|
|
664
|
+
catch (error) {
|
|
665
|
+
console.error('Error fetching team:', error);
|
|
666
|
+
res.status(500).json({ error: 'Failed to fetch team' });
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
router.get('/api/organizations/:orgId', async (req, res) => {
|
|
670
|
+
try {
|
|
671
|
+
const { orgId } = req.params;
|
|
672
|
+
const adapter = await getAuthAdapter();
|
|
673
|
+
if (!adapter || !adapter.findMany) {
|
|
674
|
+
return res.status(500).json({ error: 'Auth adapter not available' });
|
|
675
|
+
}
|
|
676
|
+
const organizations = await adapter.findMany({ model: 'organization', limit: 10000 });
|
|
677
|
+
const organization = organizations.find((org) => org.id === orgId);
|
|
678
|
+
if (!organization) {
|
|
679
|
+
return res.status(404).json({ error: 'Organization not found' });
|
|
680
|
+
}
|
|
681
|
+
res.json({ organization });
|
|
682
|
+
}
|
|
683
|
+
catch (error) {
|
|
684
|
+
console.error('Error fetching organization:', error);
|
|
685
|
+
res.status(500).json({ error: 'Failed to fetch organization' });
|
|
686
|
+
}
|
|
687
|
+
});
|
|
423
688
|
router.get('/api/users', async (req, res) => {
|
|
424
689
|
try {
|
|
425
690
|
const page = parseInt(req.query.page) || 1;
|