@faryzal2020/v-perms 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.
package/src/index.js ADDED
@@ -0,0 +1,73 @@
1
+ import PrismaAdapter from './adapters/PrismaAdapter.js';
2
+ import PermissionChecker from './core/PermissionChecker.js';
3
+ import PermissionManager from './core/PermissionManager.js';
4
+ import CacheManager from './core/CacheManager.js';
5
+ import Logger from './utils/logger.js';
6
+ import * as errors from './core/errors.js';
7
+
8
+ /**
9
+ * Create permission system instance
10
+ * @param {PrismaClient} prismaClient - Prisma client instance
11
+ * @param {object} options - Configuration options
12
+ * @param {object} options.redis - Redis client instance (optional)
13
+ * @param {boolean} options.enableCache - Enable caching (default: true)
14
+ * @param {number} options.cacheTTL - Cache TTL in seconds (default: 300)
15
+ * @param {boolean} options.debug - Enable debug logging (default: false)
16
+ * @returns {Object} Permission system instance
17
+ */
18
+ function createPermissionSystem(prismaClient, options = {}) {
19
+ const {
20
+ redis = null,
21
+ enableCache = true,
22
+ cacheTTL = 300,
23
+ debug = false,
24
+ } = options;
25
+
26
+ const logger = new Logger(debug);
27
+ const cacheManager = new CacheManager(redis, { enabled: enableCache, ttl: cacheTTL });
28
+ const adapter = new PrismaAdapter(prismaClient, logger);
29
+ const checker = new PermissionChecker(adapter, cacheManager, logger);
30
+ const manager = new PermissionManager(adapter, checker, cacheManager, logger);
31
+
32
+ return {
33
+ // Core components
34
+ manager,
35
+ checker,
36
+ adapter,
37
+ cache: cacheManager,
38
+ logger,
39
+
40
+ // Convenience methods for permission checking
41
+ can: (userId, permission) => checker.checkPermission(userId, permission),
42
+ canRole: (roleId, permission) => checker.checkRolePermission(roleId, permission),
43
+
44
+ // Direct access to commonly used manager methods
45
+ createPermission: (...args) => manager.createPermission(...args),
46
+ deletePermission: (...args) => manager.deletePermission(...args),
47
+ createRole: (...args) => manager.createRole(...args),
48
+ deleteRole: (...args) => manager.deleteRole(...args),
49
+ assignPermission: (...args) => manager.assignPermission(...args),
50
+ removePermission: (...args) => manager.removePermission(...args),
51
+ assignRole: (...args) => manager.assignRole(...args),
52
+ removeRole: (...args) => manager.removeRole(...args),
53
+ banPermission: (...args) => manager.banPermission(...args),
54
+ checkPermission: (...args) => manager.checkPermission(...args),
55
+
56
+ // Cache control
57
+ invalidateUserCache: (userId) => cacheManager.invalidateUser(userId),
58
+ invalidateRoleCache: (roleId) => cacheManager.invalidateRole(roleId),
59
+ clearCache: () => cacheManager.clear(),
60
+ };
61
+ }
62
+
63
+ export {
64
+ createPermissionSystem,
65
+ PrismaAdapter,
66
+ PermissionChecker,
67
+ PermissionManager,
68
+ CacheManager,
69
+ Logger,
70
+ errors,
71
+ };
72
+
73
+ export default createPermissionSystem;
@@ -0,0 +1,86 @@
1
+ // This schema is designed to be copied into your existing Prisma schema
2
+ // Compatible with PostgreSQL, MySQL, and SQLite
3
+
4
+ model Role {
5
+ id String @id @default(cuid())
6
+ name String @unique
7
+ description String?
8
+ priority Int @default(0)
9
+ isDefault Boolean @default(false)
10
+ createdAt DateTime @default(now())
11
+ updatedAt DateTime @updatedAt
12
+
13
+ userRoles UserRole[]
14
+ rolePermissions RolePermission[]
15
+ inheritedRoles RoleInheritance[] @relation("ParentRole")
16
+ inheritsFrom RoleInheritance[] @relation("ChildRole")
17
+
18
+ @@map("roles")
19
+ }
20
+
21
+ model Permission {
22
+ id String @id @default(cuid())
23
+ key String @unique
24
+ description String?
25
+ category String?
26
+ createdAt DateTime @default(now())
27
+
28
+ rolePermissions RolePermission[]
29
+ userPermissions UserPermission[]
30
+
31
+ @@index([category])
32
+ @@map("permissions")
33
+ }
34
+
35
+ model UserRole {
36
+ userId String
37
+ roleId String
38
+ assignedAt DateTime @default(now())
39
+
40
+ // Note: Replace 'User' with your actual User model name
41
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
42
+ role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
43
+
44
+ @@id([userId, roleId])
45
+ @@map("user_roles")
46
+ }
47
+
48
+ model RolePermission {
49
+ roleId String
50
+ permissionId String
51
+ granted Boolean @default(true)
52
+ assignedAt DateTime @default(now())
53
+
54
+ role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
55
+ permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
56
+
57
+ @@id([roleId, permissionId])
58
+ @@map("role_permissions")
59
+ }
60
+
61
+ model UserPermission {
62
+ userId String
63
+ permissionId String
64
+ granted Boolean @default(true)
65
+ assignedAt DateTime @default(now())
66
+
67
+ // Note: Replace 'User' with your actual User model name
68
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
69
+ permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
70
+
71
+ @@id([userId, permissionId])
72
+ @@map("user_permissions")
73
+ }
74
+
75
+ model RoleInheritance {
76
+ roleId String
77
+ inheritsFromId String
78
+ priority Int @default(0)
79
+ createdAt DateTime @default(now())
80
+
81
+ role Role @relation("ParentRole", fields: [roleId], references: [id], onDelete: Cascade)
82
+ inheritsFrom Role @relation("ChildRole", fields: [inheritsFromId], references: [id], onDelete: Cascade)
83
+
84
+ @@id([roleId, inheritsFromId])
85
+ @@map("role_inheritance")
86
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Debug logging utility with on/off toggle
3
+ */
4
+ class Logger {
5
+ constructor(enabled = false) {
6
+ this.enabled = enabled;
7
+ }
8
+
9
+ /**
10
+ * Enable debug logging
11
+ */
12
+ enable() {
13
+ this.enabled = true;
14
+ }
15
+
16
+ /**
17
+ * Disable debug logging
18
+ */
19
+ disable() {
20
+ this.enabled = false;
21
+ }
22
+
23
+ /**
24
+ * Log debug message
25
+ * @param {...any} args - Arguments to log
26
+ */
27
+ debug(...args) {
28
+ if (this.enabled) {
29
+ console.log('[v-perms:debug]', ...args);
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Log info message
35
+ * @param {...any} args - Arguments to log
36
+ */
37
+ info(...args) {
38
+ if (this.enabled) {
39
+ console.info('[v-perms:info]', ...args);
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Log warning message
45
+ * @param {...any} args - Arguments to log
46
+ */
47
+ warn(...args) {
48
+ if (this.enabled) {
49
+ console.warn('[v-perms:warn]', ...args);
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Log error message
55
+ * @param {...any} args - Arguments to log
56
+ */
57
+ error(...args) {
58
+ if (this.enabled) {
59
+ console.error('[v-perms:error]', ...args);
60
+ }
61
+ }
62
+ }
63
+
64
+ export default Logger;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Check if a permission key matches a wildcard pattern
3
+ * @param {string} pattern - Pattern like "endpoint.*" or "*"
4
+ * @param {string} permissionKey - Actual permission like "endpoint.admin.users"
5
+ * @returns {boolean}
6
+ */
7
+ function matchesWildcard(pattern, permissionKey) {
8
+ // Universal wildcard matches everything
9
+ if (pattern === '*') return true;
10
+
11
+ // Exact match
12
+ if (pattern === permissionKey) return true;
13
+
14
+ // Wildcard suffix match (e.g., "endpoint.*")
15
+ if (pattern.endsWith('.*')) {
16
+ const prefix = pattern.slice(0, -2);
17
+ // Matches the prefix itself or anything starting with prefix.
18
+ return permissionKey === prefix || permissionKey.startsWith(prefix + '.');
19
+ }
20
+
21
+ return false;
22
+ }
23
+
24
+ /**
25
+ * Generate all possible wildcard patterns for a permission key
26
+ * @param {string} permissionKey - Like "endpoint.admin.users.delete"
27
+ * @returns {string[]} - ["endpoint.admin.users.*", "endpoint.admin.*", "endpoint.*", "*"]
28
+ */
29
+ function generateWildcardPatterns(permissionKey) {
30
+ const parts = permissionKey.split('.');
31
+ const patterns = ['*'];
32
+
33
+ // Generate patterns from most specific to least specific
34
+ for (let i = parts.length - 1; i > 0; i--) {
35
+ patterns.push([...parts.slice(0, i), '*'].join('.'));
36
+ }
37
+
38
+ return patterns;
39
+ }
40
+
41
+ export {
42
+ matchesWildcard,
43
+ generateWildcardPatterns,
44
+ };