vperms-testing 1.0.0

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,208 @@
1
+ import { Hono } from 'hono';
2
+ import { authMiddleware, requirePermission } from '../middleware/auth.js';
3
+
4
+ const router = new Hono();
5
+
6
+ // All routes require authentication
7
+ router.use('*', authMiddleware);
8
+
9
+ /**
10
+ * GET /api/roles
11
+ * List all roles
12
+ */
13
+ router.get('/', requirePermission('roles.list'), async (c) => {
14
+ const perms = c.get('perms');
15
+
16
+ try {
17
+ const roles = await perms.manager.listRoles();
18
+ return c.json({ roles });
19
+ } catch (error) {
20
+ console.error('List roles error:', error);
21
+ return c.json({ error: 'Failed to list roles' }, 500);
22
+ }
23
+ });
24
+
25
+ /**
26
+ * POST /api/roles
27
+ * Create a new role
28
+ */
29
+ router.post('/', requirePermission('roles.create'), async (c) => {
30
+ const perms = c.get('perms');
31
+
32
+ try {
33
+ const { name, description, priority = 0, isDefault = false } = await c.req.json();
34
+
35
+ if (!name) {
36
+ return c.json({ error: 'Role name required' }, 400);
37
+ }
38
+
39
+ const role = await perms.createRole(name, description, priority, isDefault);
40
+ return c.json({ message: 'Role created', role });
41
+ } catch (error) {
42
+ console.error('Create role error:', error);
43
+ return c.json({ error: error.message || 'Failed to create role' }, 500);
44
+ }
45
+ });
46
+
47
+ /**
48
+ * GET /api/roles/:id
49
+ * Get a specific role with permissions
50
+ */
51
+ router.get('/:id', requirePermission('roles.view'), async (c) => {
52
+ const perms = c.get('perms');
53
+ const roleId = c.req.param('id');
54
+
55
+ try {
56
+ const role = await perms.manager.getRole(roleId);
57
+
58
+ if (!role) {
59
+ return c.json({ error: 'Role not found' }, 404);
60
+ }
61
+
62
+ const permissions = await perms.manager.getRolePermissions(roleId);
63
+ const inheritance = await perms.manager.getRoleInheritance(roleId);
64
+
65
+ return c.json({
66
+ role,
67
+ permissions,
68
+ inheritsFrom: inheritance.map(i => ({
69
+ id: i.inheritsFromId,
70
+ name: i.inheritsFrom.name,
71
+ priority: i.priority,
72
+ })),
73
+ });
74
+ } catch (error) {
75
+ console.error('Get role error:', error);
76
+ return c.json({ error: 'Failed to get role' }, 500);
77
+ }
78
+ });
79
+
80
+ /**
81
+ * PUT /api/roles/:id
82
+ * Update a role
83
+ */
84
+ router.put('/:id', requirePermission('roles.update'), async (c) => {
85
+ const perms = c.get('perms');
86
+ const roleId = c.req.param('id');
87
+
88
+ try {
89
+ const { description, priority, isDefault } = await c.req.json();
90
+
91
+ const data = {};
92
+ if (description !== undefined) data.description = description;
93
+ if (priority !== undefined) data.priority = priority;
94
+ if (isDefault !== undefined) data.isDefault = isDefault;
95
+
96
+ const role = await perms.manager.updateRole(roleId, data);
97
+ return c.json({ message: 'Role updated', role });
98
+ } catch (error) {
99
+ console.error('Update role error:', error);
100
+ return c.json({ error: error.message || 'Failed to update role' }, 500);
101
+ }
102
+ });
103
+
104
+ /**
105
+ * DELETE /api/roles/:id
106
+ * Delete a role
107
+ */
108
+ router.delete('/:id', requirePermission('roles.delete'), async (c) => {
109
+ const perms = c.get('perms');
110
+ const roleId = c.req.param('id');
111
+
112
+ try {
113
+ await perms.deleteRole(roleId);
114
+ return c.json({ message: 'Role deleted' });
115
+ } catch (error) {
116
+ console.error('Delete role error:', error);
117
+ return c.json({ error: error.message || 'Failed to delete role' }, 500);
118
+ }
119
+ });
120
+
121
+ /**
122
+ * POST /api/roles/:id/permissions
123
+ * Assign permission to role
124
+ */
125
+ router.post('/:id/permissions', requirePermission('roles.assign-permission'), async (c) => {
126
+ const perms = c.get('perms');
127
+ const roleId = c.req.param('id');
128
+
129
+ try {
130
+ const { permissionKey, granted = true } = await c.req.json();
131
+
132
+ if (!permissionKey) {
133
+ return c.json({ error: 'Permission key required' }, 400);
134
+ }
135
+
136
+ if (granted) {
137
+ await perms.assignPermission(permissionKey, roleId, 'role');
138
+ } else {
139
+ await perms.banPermission(permissionKey, roleId, 'role');
140
+ }
141
+
142
+ return c.json({ message: 'Permission assigned to role' });
143
+ } catch (error) {
144
+ console.error('Assign permission error:', error);
145
+ return c.json({ error: error.message || 'Failed to assign permission' }, 500);
146
+ }
147
+ });
148
+
149
+ /**
150
+ * DELETE /api/roles/:id/permissions/:key
151
+ * Remove permission from role
152
+ */
153
+ router.delete('/:id/permissions/:key', requirePermission('roles.remove-permission'), async (c) => {
154
+ const perms = c.get('perms');
155
+ const roleId = c.req.param('id');
156
+ const permissionKey = c.req.param('key');
157
+
158
+ try {
159
+ await perms.removePermission(permissionKey, roleId, 'role');
160
+ return c.json({ message: 'Permission removed from role' });
161
+ } catch (error) {
162
+ console.error('Remove permission error:', error);
163
+ return c.json({ error: error.message || 'Failed to remove permission' }, 500);
164
+ }
165
+ });
166
+
167
+ /**
168
+ * POST /api/roles/:id/inheritance
169
+ * Set role inheritance
170
+ */
171
+ router.post('/:id/inheritance', requirePermission('roles.set-inheritance'), async (c) => {
172
+ const perms = c.get('perms');
173
+ const roleId = c.req.param('id');
174
+
175
+ try {
176
+ const { inheritsFromId, priority = 0 } = await c.req.json();
177
+
178
+ if (!inheritsFromId) {
179
+ return c.json({ error: 'inheritsFromId required' }, 400);
180
+ }
181
+
182
+ await perms.manager.setRoleInheritance(roleId, inheritsFromId, priority);
183
+ return c.json({ message: 'Inheritance set' });
184
+ } catch (error) {
185
+ console.error('Set inheritance error:', error);
186
+ return c.json({ error: error.message || 'Failed to set inheritance' }, 500);
187
+ }
188
+ });
189
+
190
+ /**
191
+ * DELETE /api/roles/:id/inheritance/:inheritsFromId
192
+ * Remove role inheritance
193
+ */
194
+ router.delete('/:id/inheritance/:inheritsFromId', requirePermission('roles.remove-inheritance'), async (c) => {
195
+ const perms = c.get('perms');
196
+ const roleId = c.req.param('id');
197
+ const inheritsFromId = c.req.param('inheritsFromId');
198
+
199
+ try {
200
+ await perms.manager.removeRoleInheritance(roleId, inheritsFromId);
201
+ return c.json({ message: 'Inheritance removed' });
202
+ } catch (error) {
203
+ console.error('Remove inheritance error:', error);
204
+ return c.json({ error: error.message || 'Failed to remove inheritance' }, 500);
205
+ }
206
+ });
207
+
208
+ export default router;
@@ -0,0 +1,191 @@
1
+ import { Hono } from 'hono';
2
+ import { authMiddleware, requirePermission } from '../middleware/auth.js';
3
+
4
+ const router = new Hono();
5
+
6
+ // All routes require authentication
7
+ router.use('*', authMiddleware);
8
+
9
+ /**
10
+ * GET /api/users
11
+ * List all users (requires permission)
12
+ */
13
+ router.get('/', requirePermission('users.list'), async (c) => {
14
+ const prisma = c.get('prisma');
15
+
16
+ try {
17
+ const users = await prisma.user.findMany({
18
+ select: {
19
+ id: true,
20
+ email: true,
21
+ name: true,
22
+ createdAt: true,
23
+ userRoles: {
24
+ include: { role: true },
25
+ },
26
+ },
27
+ orderBy: { createdAt: 'desc' },
28
+ });
29
+
30
+ return c.json({
31
+ users: users.map(u => ({
32
+ id: u.id,
33
+ email: u.email,
34
+ name: u.name,
35
+ createdAt: u.createdAt,
36
+ roles: u.userRoles.map(ur => ur.role.name),
37
+ })),
38
+ });
39
+ } catch (error) {
40
+ console.error('List users error:', error);
41
+ return c.json({ error: 'Failed to list users' }, 500);
42
+ }
43
+ });
44
+
45
+ /**
46
+ * GET /api/users/:id
47
+ * Get a specific user
48
+ */
49
+ router.get('/:id', requirePermission('users.view'), async (c) => {
50
+ const prisma = c.get('prisma');
51
+ const perms = c.get('perms');
52
+ const userId = c.req.param('id');
53
+
54
+ try {
55
+ const user = await prisma.user.findUnique({
56
+ where: { id: userId },
57
+ select: {
58
+ id: true,
59
+ email: true,
60
+ name: true,
61
+ createdAt: true,
62
+ },
63
+ });
64
+
65
+ if (!user) {
66
+ return c.json({ error: 'User not found' }, 404);
67
+ }
68
+
69
+ const roles = await perms.manager.getUserRoles(userId);
70
+ const permissions = await perms.manager.getUserPermissions(userId);
71
+
72
+ return c.json({
73
+ user,
74
+ roles,
75
+ permissions,
76
+ });
77
+ } catch (error) {
78
+ console.error('Get user error:', error);
79
+ return c.json({ error: 'Failed to get user' }, 500);
80
+ }
81
+ });
82
+
83
+ /**
84
+ * DELETE /api/users/:id
85
+ * Delete a user
86
+ */
87
+ router.delete('/:id', requirePermission('users.delete'), async (c) => {
88
+ const prisma = c.get('prisma');
89
+ const userId = c.req.param('id');
90
+
91
+ try {
92
+ await prisma.user.delete({
93
+ where: { id: userId },
94
+ });
95
+
96
+ return c.json({ message: 'User deleted' });
97
+ } catch (error) {
98
+ console.error('Delete user error:', error);
99
+ return c.json({ error: 'Failed to delete user' }, 500);
100
+ }
101
+ });
102
+
103
+ /**
104
+ * POST /api/users/:id/roles
105
+ * Assign role to user
106
+ */
107
+ router.post('/:id/roles', requirePermission('users.assign-role'), async (c) => {
108
+ const perms = c.get('perms');
109
+ const userId = c.req.param('id');
110
+
111
+ try {
112
+ const { roleId } = await c.req.json();
113
+
114
+ if (!roleId) {
115
+ return c.json({ error: 'Role ID required' }, 400);
116
+ }
117
+
118
+ await perms.assignRole(roleId, userId);
119
+
120
+ return c.json({ message: 'Role assigned' });
121
+ } catch (error) {
122
+ console.error('Assign role error:', error);
123
+ return c.json({ error: error.message || 'Failed to assign role' }, 500);
124
+ }
125
+ });
126
+
127
+ /**
128
+ * DELETE /api/users/:id/roles/:roleId
129
+ * Remove role from user
130
+ */
131
+ router.delete('/:id/roles/:roleId', requirePermission('users.remove-role'), async (c) => {
132
+ const perms = c.get('perms');
133
+ const userId = c.req.param('id');
134
+ const roleId = c.req.param('roleId');
135
+
136
+ try {
137
+ await perms.removeRole(roleId, userId);
138
+ return c.json({ message: 'Role removed' });
139
+ } catch (error) {
140
+ console.error('Remove role error:', error);
141
+ return c.json({ error: error.message || 'Failed to remove role' }, 500);
142
+ }
143
+ });
144
+
145
+ /**
146
+ * POST /api/users/:id/permissions
147
+ * Assign direct permission to user
148
+ */
149
+ router.post('/:id/permissions', requirePermission('users.assign-permission'), async (c) => {
150
+ const perms = c.get('perms');
151
+ const userId = c.req.param('id');
152
+
153
+ try {
154
+ const { permissionKey, granted = true } = await c.req.json();
155
+
156
+ if (!permissionKey) {
157
+ return c.json({ error: 'Permission key required' }, 400);
158
+ }
159
+
160
+ if (granted) {
161
+ await perms.assignPermission(permissionKey, userId, 'user');
162
+ } else {
163
+ await perms.banPermission(permissionKey, userId, 'user');
164
+ }
165
+
166
+ return c.json({ message: 'Permission assigned' });
167
+ } catch (error) {
168
+ console.error('Assign permission error:', error);
169
+ return c.json({ error: error.message || 'Failed to assign permission' }, 500);
170
+ }
171
+ });
172
+
173
+ /**
174
+ * GET /api/users/:id/check/:permission
175
+ * Check if user has a specific permission
176
+ */
177
+ router.get('/:id/check/:permission', requirePermission('users.check-permission'), async (c) => {
178
+ const perms = c.get('perms');
179
+ const userId = c.req.param('id');
180
+ const permission = c.req.param('permission');
181
+
182
+ try {
183
+ const hasPermission = await perms.can(userId, permission);
184
+ return c.json({ userId, permission, hasPermission });
185
+ } catch (error) {
186
+ console.error('Check permission error:', error);
187
+ return c.json({ error: 'Failed to check permission' }, 500);
188
+ }
189
+ });
190
+
191
+ export default router;
package/server/seed.js ADDED
@@ -0,0 +1,167 @@
1
+ import { PrismaClient } from '@prisma/client';
2
+ import { createPermissionSystem } from '@faryzal2020/v-perms';
3
+ import bcrypt from 'bcryptjs';
4
+
5
+ const prisma = new PrismaClient();
6
+ const perms = createPermissionSystem(prisma, { debug: true });
7
+
8
+ async function main() {
9
+ console.log('🌱 Starting seed...\n');
10
+
11
+ // Create permissions
12
+ const permissions = [
13
+ // User permissions
14
+ { key: 'users.list', description: 'List all users', category: 'users' },
15
+ { key: 'users.view', description: 'View user details', category: 'users' },
16
+ { key: 'users.delete', description: 'Delete users', category: 'users' },
17
+ { key: 'users.assign-role', description: 'Assign roles to users', category: 'users' },
18
+ { key: 'users.remove-role', description: 'Remove roles from users', category: 'users' },
19
+ { key: 'users.assign-permission', description: 'Assign permissions to users', category: 'users' },
20
+ { key: 'users.check-permission', description: 'Check user permissions', category: 'users' },
21
+
22
+ // Role permissions
23
+ { key: 'roles.list', description: 'List all roles', category: 'roles' },
24
+ { key: 'roles.view', description: 'View role details', category: 'roles' },
25
+ { key: 'roles.create', description: 'Create roles', category: 'roles' },
26
+ { key: 'roles.update', description: 'Update roles', category: 'roles' },
27
+ { key: 'roles.delete', description: 'Delete roles', category: 'roles' },
28
+ { key: 'roles.assign-permission', description: 'Assign permissions to roles', category: 'roles' },
29
+ { key: 'roles.remove-permission', description: 'Remove permissions from roles', category: 'roles' },
30
+ { key: 'roles.set-inheritance', description: 'Set role inheritance', category: 'roles' },
31
+ { key: 'roles.remove-inheritance', description: 'Remove role inheritance', category: 'roles' },
32
+
33
+ // Permission permissions
34
+ { key: 'permissions.list', description: 'List all permissions', category: 'permissions' },
35
+ { key: 'permissions.create', description: 'Create permissions', category: 'permissions' },
36
+ { key: 'permissions.delete', description: 'Delete permissions', category: 'permissions' },
37
+ ];
38
+
39
+ console.log('šŸ“ Creating permissions...');
40
+ for (const perm of permissions) {
41
+ try {
42
+ await perms.createPermission(perm.key, perm.description, perm.category);
43
+ console.log(` āœ“ ${perm.key}`);
44
+ } catch (error) {
45
+ console.log(` - ${perm.key} (already exists)`);
46
+ }
47
+ }
48
+
49
+ // Create roles
50
+ console.log('\nšŸ‘„ Creating roles...');
51
+
52
+ // Member role (basic user)
53
+ let memberRole;
54
+ try {
55
+ memberRole = await perms.createRole('member', 'Basic member with limited access', 1, true);
56
+ console.log(' āœ“ member (default role)');
57
+ } catch (error) {
58
+ memberRole = await perms.manager.getRole('member');
59
+ console.log(' - member (already exists)');
60
+ }
61
+
62
+ // Moderator role
63
+ let moderatorRole;
64
+ try {
65
+ moderatorRole = await perms.createRole('moderator', 'Moderator with user management', 5, false);
66
+ console.log(' āœ“ moderator');
67
+ } catch (error) {
68
+ moderatorRole = await perms.manager.getRole('moderator');
69
+ console.log(' - moderator (already exists)');
70
+ }
71
+
72
+ // Admin role
73
+ let adminRole;
74
+ try {
75
+ adminRole = await perms.createRole('admin', 'Administrator with full access', 10, false);
76
+ console.log(' āœ“ admin');
77
+ } catch (error) {
78
+ adminRole = await perms.manager.getRole('admin');
79
+ console.log(' - admin (already exists)');
80
+ }
81
+
82
+ // Assign permissions to roles
83
+ console.log('\nšŸ” Assigning permissions to roles...');
84
+
85
+ // Member gets basic permissions
86
+ await perms.assignPermission('users.view', memberRole.id, 'role');
87
+ await perms.assignPermission('roles.list', memberRole.id, 'role');
88
+ console.log(' āœ“ member: users.view, roles.list');
89
+
90
+ // Moderator inherits from member + gets more
91
+ try {
92
+ await perms.manager.setRoleInheritance(moderatorRole.id, memberRole.id);
93
+ } catch (e) { }
94
+ await perms.assignPermission('users.list', moderatorRole.id, 'role');
95
+ await perms.assignPermission('roles.view', moderatorRole.id, 'role');
96
+ console.log(' āœ“ moderator: inherits member + users.list, roles.view');
97
+
98
+ // Admin gets all permissions via wildcard
99
+ try {
100
+ await perms.manager.setRoleInheritance(adminRole.id, moderatorRole.id);
101
+ } catch (e) { }
102
+ await perms.assignPermission('*', adminRole.id, 'role');
103
+ console.log(' āœ“ admin: inherits moderator + * (all permissions)');
104
+
105
+ // Create test users
106
+ console.log('\nšŸ‘¤ Creating test users...');
107
+
108
+ const hashedPassword = await bcrypt.hash('password123', 10);
109
+
110
+ // Regular user
111
+ let regularUser;
112
+ try {
113
+ regularUser = await prisma.user.create({
114
+ data: {
115
+ email: 'user@example.com',
116
+ password: hashedPassword,
117
+ name: 'Regular User',
118
+ },
119
+ });
120
+ await perms.assignRole(memberRole.id, regularUser.id);
121
+ console.log(' āœ“ user@example.com (member)');
122
+ } catch (error) {
123
+ console.log(' - user@example.com (already exists)');
124
+ }
125
+
126
+ // Moderator user
127
+ let modUser;
128
+ try {
129
+ modUser = await prisma.user.create({
130
+ data: {
131
+ email: 'mod@example.com',
132
+ password: hashedPassword,
133
+ name: 'Moderator User',
134
+ },
135
+ });
136
+ await perms.assignRole(moderatorRole.id, modUser.id);
137
+ console.log(' āœ“ mod@example.com (moderator)');
138
+ } catch (error) {
139
+ console.log(' - mod@example.com (already exists)');
140
+ }
141
+
142
+ // Admin user
143
+ let adminUser;
144
+ try {
145
+ adminUser = await prisma.user.create({
146
+ data: {
147
+ email: 'admin@example.com',
148
+ password: hashedPassword,
149
+ name: 'Admin User',
150
+ },
151
+ });
152
+ await perms.assignRole(adminRole.id, adminUser.id);
153
+ console.log(' āœ“ admin@example.com (admin)');
154
+ } catch (error) {
155
+ console.log(' - admin@example.com (already exists)');
156
+ }
157
+
158
+ console.log('\nāœ… Seed complete!\n');
159
+ console.log('Test accounts (password: password123):');
160
+ console.log(' - user@example.com (member)');
161
+ console.log(' - mod@example.com (moderator)');
162
+ console.log(' - admin@example.com (admin)');
163
+ }
164
+
165
+ main()
166
+ .catch(console.error)
167
+ .finally(() => prisma.$disconnect());