@plyaz/auth 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.
Files changed (113) hide show
  1. package/.github/pull_request_template.md +71 -0
  2. package/.github/workflows/deploy.yml +9 -0
  3. package/.github/workflows/publish.yml +14 -0
  4. package/.github/workflows/security.yml +20 -0
  5. package/README.md +89 -0
  6. package/commits.txt +5 -0
  7. package/dist/common/index.cjs +48 -0
  8. package/dist/common/index.cjs.map +1 -0
  9. package/dist/common/index.mjs +43 -0
  10. package/dist/common/index.mjs.map +1 -0
  11. package/dist/index.cjs +20411 -0
  12. package/dist/index.cjs.map +1 -0
  13. package/dist/index.mjs +5139 -0
  14. package/dist/index.mjs.map +1 -0
  15. package/eslint.config.mjs +13 -0
  16. package/index.html +13 -0
  17. package/package.json +141 -0
  18. package/src/adapters/auth-adapter-factory.ts +26 -0
  19. package/src/adapters/auth-adapter.mapper.ts +53 -0
  20. package/src/adapters/base-auth.adapter.ts +119 -0
  21. package/src/adapters/clerk/clerk.adapter.ts +204 -0
  22. package/src/adapters/custom/custom.adapter.ts +119 -0
  23. package/src/adapters/index.ts +4 -0
  24. package/src/adapters/next-auth/authOptions.ts +81 -0
  25. package/src/adapters/next-auth/next-auth.adapter.ts +211 -0
  26. package/src/api/client.ts +37 -0
  27. package/src/audit/audit.logger.ts +52 -0
  28. package/src/client/components/ProtectedRoute.tsx +37 -0
  29. package/src/client/hooks/useAuth.ts +128 -0
  30. package/src/client/hooks/useConnectedAccounts.ts +108 -0
  31. package/src/client/hooks/usePermissions.ts +36 -0
  32. package/src/client/hooks/useRBAC.ts +36 -0
  33. package/src/client/hooks/useSession.ts +18 -0
  34. package/src/client/providers/AuthProvider.tsx +104 -0
  35. package/src/client/store/auth.store.ts +306 -0
  36. package/src/client/utils/storage.ts +70 -0
  37. package/src/common/constants/oauth-providers.ts +49 -0
  38. package/src/common/errors/auth.errors.ts +64 -0
  39. package/src/common/errors/specific-auth-errors.ts +201 -0
  40. package/src/common/index.ts +19 -0
  41. package/src/common/regex/index.ts +27 -0
  42. package/src/common/types/auth.types.ts +641 -0
  43. package/src/common/types/index.ts +297 -0
  44. package/src/common/utils/index.ts +84 -0
  45. package/src/core/blacklist/token.blacklist.ts +60 -0
  46. package/src/core/index.ts +2 -0
  47. package/src/core/jwt/jwt.manager.ts +131 -0
  48. package/src/core/session/session.manager.ts +56 -0
  49. package/src/db/repositories/connected-account.repository.ts +415 -0
  50. package/src/db/repositories/role.repository.ts +519 -0
  51. package/src/db/repositories/session.repository.ts +308 -0
  52. package/src/db/repositories/user.repository.ts +320 -0
  53. package/src/flows/index.ts +2 -0
  54. package/src/flows/sign-in.flow.ts +106 -0
  55. package/src/flows/sign-up.flow.ts +121 -0
  56. package/src/index.ts +54 -0
  57. package/src/libs/clerk.helper.ts +36 -0
  58. package/src/libs/supabase.helper.ts +255 -0
  59. package/src/libs/supabaseClient.ts +6 -0
  60. package/src/providers/base/auth-provider.interface.ts +42 -0
  61. package/src/providers/base/index.ts +1 -0
  62. package/src/providers/index.ts +2 -0
  63. package/src/providers/oauth/facebook.provider.ts +97 -0
  64. package/src/providers/oauth/github.provider.ts +148 -0
  65. package/src/providers/oauth/google.provider.ts +126 -0
  66. package/src/providers/oauth/index.ts +3 -0
  67. package/src/rbac/dynamic-roles.ts +552 -0
  68. package/src/rbac/index.ts +4 -0
  69. package/src/rbac/permission-checker.ts +464 -0
  70. package/src/rbac/role-hierarchy.ts +545 -0
  71. package/src/rbac/role.manager.ts +75 -0
  72. package/src/security/csrf/csrf.protection.ts +37 -0
  73. package/src/security/index.ts +3 -0
  74. package/src/security/rate-limiting/auth/auth.controller.ts +12 -0
  75. package/src/security/rate-limiting/auth/rate-limiting.interface.ts +67 -0
  76. package/src/security/rate-limiting/auth.module.ts +32 -0
  77. package/src/server/auth.module.ts +158 -0
  78. package/src/server/decorators/auth.decorator.ts +43 -0
  79. package/src/server/decorators/auth.decorators.ts +31 -0
  80. package/src/server/decorators/current-user.decorator.ts +49 -0
  81. package/src/server/decorators/permission.decorator.ts +49 -0
  82. package/src/server/guards/auth.guard.ts +56 -0
  83. package/src/server/guards/custom-throttler.guard.ts +46 -0
  84. package/src/server/guards/permissions.guard.ts +115 -0
  85. package/src/server/guards/roles.guard.ts +31 -0
  86. package/src/server/middleware/auth.middleware.ts +46 -0
  87. package/src/server/middleware/index.ts +2 -0
  88. package/src/server/middleware/middleware.ts +11 -0
  89. package/src/server/middleware/session.middleware.ts +255 -0
  90. package/src/server/services/account.service.ts +269 -0
  91. package/src/server/services/auth.service.ts +79 -0
  92. package/src/server/services/brute-force.service.ts +98 -0
  93. package/src/server/services/index.ts +15 -0
  94. package/src/server/services/rate-limiter.service.ts +60 -0
  95. package/src/server/services/session.service.ts +287 -0
  96. package/src/server/services/token.service.ts +262 -0
  97. package/src/session/cookie-store.ts +255 -0
  98. package/src/session/enhanced-session-manager.ts +406 -0
  99. package/src/session/index.ts +14 -0
  100. package/src/session/memory-store.ts +320 -0
  101. package/src/session/redis-store.ts +443 -0
  102. package/src/strategies/oauth.strategy.ts +128 -0
  103. package/src/strategies/traditional-auth.strategy.ts +116 -0
  104. package/src/tokens/index.ts +4 -0
  105. package/src/tokens/refresh-token-manager.ts +448 -0
  106. package/src/tokens/token-validator.ts +311 -0
  107. package/tsconfig.build.json +28 -0
  108. package/tsconfig.json +38 -0
  109. package/tsup.config.mjs +28 -0
  110. package/vitest.config.mjs +16 -0
  111. package/vitest.setup.d.ts +2 -0
  112. package/vitest.setup.d.ts.map +1 -0
  113. package/vitest.setup.ts +1 -0
@@ -0,0 +1,552 @@
1
+ /**
2
+ * @fileoverview Dynamic roles manager for @plyaz/auth
3
+ * @module @plyaz/auth/rbac/dynamic-roles
4
+ *
5
+ * @description
6
+ * Manages runtime role assignment and modification for role-based access control.
7
+ * Handles temporary roles, conditional role assignment, and role expiration.
8
+ * Enables flexible role management without requiring database schema changes.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { DynamicRoles } from '@plyaz/auth';
13
+ *
14
+ * const dynamicRoles = new DynamicRoles();
15
+ *
16
+ * // Assign temporary role
17
+ * await dynamicRoles.assignTemporaryRole(
18
+ * userId,
19
+ * 'campaign_moderator',
20
+ * { campaignId: '123' },
21
+ * new Date(Date.now() + 24 * 60 * 60 * 1000) // 24 hours
22
+ * );
23
+ * ```
24
+ */
25
+
26
+ import { NUMERIX } from '@plyaz/config';
27
+ import { AUTH_EVENTS } from '@plyaz/types';
28
+
29
+ /**
30
+ * Dynamic role assignment
31
+ */
32
+ export interface DynamicRoleAssignment {
33
+ /** Assignment ID */
34
+ id: string;
35
+ /** User ID */
36
+ userId: string;
37
+ /** Role ID or name */
38
+ roleId: string;
39
+ /** Assignment conditions */
40
+ conditions?: Record<string, string>;
41
+ /** Assignment expiration */
42
+ expiresAt?: Date;
43
+ /** Assignment reason */
44
+ reason?: string;
45
+ /** Assigned by user ID */
46
+ assignedBy?: string;
47
+ /** Assignment metadata */
48
+ metadata?: Record<string, string>;
49
+ /** Created at */
50
+ createdAt: Date;
51
+ /** Is active */
52
+ isActive: boolean;
53
+ }
54
+
55
+ /**
56
+ * Role condition evaluator function
57
+ */
58
+ export type RoleConditionEvaluator = (
59
+ userId: string,
60
+ conditions: Record<string, string>,
61
+ context?: Record<string, string>
62
+ ) => Promise<boolean>;
63
+
64
+ /**
65
+ * Dynamic roles configuration
66
+ */
67
+ export interface DynamicRolesConfig {
68
+ /** Enable role expiration */
69
+ enableExpiration: boolean;
70
+ /** Default role TTL in seconds */
71
+ defaultTTL: number;
72
+ /** Enable condition evaluation */
73
+ enableConditions: boolean;
74
+ /** Maximum assignments per user */
75
+ maxAssignmentsPerUser: number;
76
+ /** Enable audit logging */
77
+ enableAuditLog: boolean;
78
+ }
79
+
80
+ /**
81
+ * Dynamic roles manager implementation
82
+ * Manages runtime role assignments with conditions and expiration
83
+ */
84
+ export class DynamicRoles {
85
+ private readonly config: DynamicRolesConfig;
86
+ private readonly assignments = new Map<string, DynamicRoleAssignment>();
87
+ private readonly userAssignments = new Map<string, Set<string>>();
88
+ private readonly conditionEvaluators = new Map<string, RoleConditionEvaluator>();
89
+ private cleanupTimer?: globalThis.NodeJS.Timeout;
90
+
91
+ constructor(config: Partial<DynamicRolesConfig> = {}) {
92
+ this.config = {
93
+ enableExpiration: true,
94
+ defaultTTL: 86400, // 24 hours
95
+ enableConditions: true,
96
+ maxAssignmentsPerUser: 50,
97
+ enableAuditLog: true,
98
+ ...config
99
+ };
100
+
101
+ // Start cleanup timer if expiration is enabled
102
+ if (this.config.enableExpiration) {
103
+ this.startCleanupTimer();
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Assign role to user
109
+ * @param userId - User identifier
110
+ * @param roleId - Role identifier
111
+ * @param conditions - Assignment conditions
112
+ * @param expiresAt - Assignment expiration
113
+ * @param assignedBy - Assigning user ID
114
+ * @param reason - Assignment reason
115
+ * @returns Assignment ID
116
+ */
117
+ // eslint-disable-next-line max-params
118
+ async assignRole(
119
+ userId: string,
120
+ roleId: string,
121
+ conditions?: Record<string, string>,
122
+ expiresAt?: Date,
123
+ assignedBy?: string,
124
+ reason?: string
125
+ ): Promise<string> {
126
+ // Check assignment limits
127
+ await this.enforceAssignmentLimits(userId);
128
+
129
+ // Generate assignment ID
130
+ const assignmentId = this.generateAssignmentId();
131
+
132
+ // Create assignment
133
+ const assignment: DynamicRoleAssignment = {
134
+ id: assignmentId,
135
+ userId,
136
+ roleId,
137
+ conditions,
138
+ expiresAt: expiresAt ?? (this.config.enableExpiration ?
139
+ new Date(Date.now() + this.config.defaultTTL * NUMERIX.THOUSAND) : undefined),
140
+ reason,
141
+ assignedBy,
142
+ createdAt: new Date(),
143
+ isActive: true
144
+ };
145
+
146
+ // Store assignment
147
+ this.assignments.set(assignmentId, assignment);
148
+
149
+ // Track user assignments
150
+ if (!this.userAssignments.has(userId)) {
151
+ this.userAssignments.set(userId, new Set());
152
+ }
153
+ this.userAssignments.get(userId)!.add(assignmentId);
154
+
155
+ // Emit event
156
+ if (this.config.enableAuditLog) {
157
+ this.emitRoleAssignedEvent(assignment);
158
+ }
159
+
160
+ return assignmentId;
161
+ }
162
+
163
+ /**
164
+ * Assign temporary role to user
165
+ * @param userId - User identifier
166
+ * @param roleId - Role identifier
167
+ * @param conditions - Assignment conditions
168
+ * @param duration - Duration in seconds
169
+ * @param assignedBy - Assigning user ID
170
+ * @param reason - Assignment reason
171
+ * @returns Assignment ID
172
+ */
173
+ // eslint-disable-next-line max-params
174
+ async assignTemporaryRole(
175
+ userId: string,
176
+ roleId: string,
177
+ conditions?: Record<string, string>,
178
+ duration: number = this.config.defaultTTL,
179
+ assignedBy?: string,
180
+ reason?: string
181
+ ): Promise<string> {
182
+ const expiresAt = new Date(Date.now() + duration * NUMERIX.THOUSAND);
183
+
184
+ return await this.assignRole(
185
+ userId,
186
+ roleId,
187
+ conditions,
188
+ expiresAt,
189
+ assignedBy,
190
+ reason ?? 'Temporary assignment'
191
+ );
192
+ }
193
+
194
+ /**
195
+ * Revoke role assignment
196
+ * @param assignmentId - Assignment identifier
197
+ * @param revokedBy - Revoking user ID
198
+ * @param reason - Revocation reason
199
+ */
200
+ async revokeAssignment(
201
+ assignmentId: string,
202
+ revokedBy?: string,
203
+ reason?: string
204
+ ): Promise<void> {
205
+ const assignment = this.assignments.get(assignmentId);
206
+
207
+ if (!assignment?.isActive) {
208
+ return;
209
+ }
210
+
211
+ // Deactivate assignment
212
+ assignment.isActive = false;
213
+ assignment.metadata = {
214
+ ...assignment.metadata,
215
+
216
+ };
217
+
218
+ // Remove from user assignments tracking
219
+ const userAssignmentSet = this.userAssignments.get(assignment.userId);
220
+ if (userAssignmentSet) {
221
+ userAssignmentSet.delete(assignmentId);
222
+ if (userAssignmentSet.size === 0) {
223
+ this.userAssignments.delete(assignment.userId);
224
+ }
225
+ }
226
+
227
+ // Emit event
228
+ if (this.config.enableAuditLog) {
229
+ this.emitRoleRevokedEvent(assignment, revokedBy, reason);
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Revoke all role assignments for user
235
+ * @param userId - User identifier
236
+ * @param revokedBy - Revoking user ID
237
+ * @param reason - Revocation reason
238
+ */
239
+ async revokeAllUserAssignments(
240
+ userId: string,
241
+ revokedBy?: string,
242
+ reason?: string
243
+ ): Promise<void> {
244
+ const userAssignmentSet = this.userAssignments.get(userId);
245
+
246
+ if (!userAssignmentSet) {
247
+ return;
248
+ }
249
+
250
+ const assignmentIds = Array.from(userAssignmentSet);
251
+
252
+ for (const assignmentId of assignmentIds) {
253
+ await this.revokeAssignment(assignmentId, revokedBy, reason);
254
+ }
255
+ }
256
+
257
+ /**
258
+ * Get active roles for user
259
+ * @param userId - User identifier
260
+ * @param context - Evaluation context for conditions
261
+ * @returns Array of active role IDs
262
+ */
263
+ async getUserRoles(userId: string, context?: Record<string, string>): Promise<string[]> {
264
+ const userAssignmentSet = this.userAssignments.get(userId);
265
+
266
+ if (!userAssignmentSet) {
267
+ return [];
268
+ }
269
+
270
+ const activeRoles: string[] = [];
271
+ const now = new Date();
272
+
273
+ for (const assignmentId of userAssignmentSet) {
274
+ const assignment = this.assignments.get(assignmentId);
275
+
276
+ if (!assignment?.isActive) {
277
+ continue;
278
+ }
279
+
280
+ // Check expiration
281
+ if (assignment.expiresAt && assignment.expiresAt < now) {
282
+ await this.revokeAssignment(assignmentId, undefined, 'Expired');
283
+ continue;
284
+ }
285
+
286
+ // Check conditions
287
+ if (this.config.enableConditions && assignment.conditions) {
288
+ const conditionsMet = await this.evaluateConditions(
289
+ userId,
290
+ assignment.conditions,
291
+ context
292
+ );
293
+
294
+ if (!conditionsMet) {
295
+ continue;
296
+ }
297
+ }
298
+
299
+ activeRoles.push(assignment.roleId);
300
+ }
301
+
302
+ return activeRoles;
303
+ }
304
+
305
+ /**
306
+ * Check if user has specific role
307
+ * @param userId - User identifier
308
+ * @param roleId - Role identifier
309
+ * @param context - Evaluation context for conditions
310
+ * @returns True if user has role
311
+ */
312
+ async hasRole(userId: string, roleId: string, context?: Record<string, string>): Promise<boolean> {
313
+ const userRoles = await this.getUserRoles(userId, context);
314
+ return userRoles.includes(roleId);
315
+ }
316
+
317
+ /**
318
+ * Get assignment details
319
+ * @param assignmentId - Assignment identifier
320
+ * @returns Assignment details or null
321
+ */
322
+ getAssignment(assignmentId: string): DynamicRoleAssignment | null {
323
+ return this.assignments.get(assignmentId) ?? null;
324
+ }
325
+
326
+ /**
327
+ * Get all assignments for user
328
+ * @param userId - User identifier
329
+ * @param includeInactive - Include inactive assignments
330
+ * @returns Array of assignments
331
+ */
332
+ getUserAssignments(userId: string, includeInactive = false): DynamicRoleAssignment[] {
333
+ const userAssignmentSet = this.userAssignments.get(userId);
334
+
335
+ if (!userAssignmentSet) {
336
+ return [];
337
+ }
338
+
339
+ const assignments: DynamicRoleAssignment[] = [];
340
+
341
+ for (const assignmentId of userAssignmentSet) {
342
+ const assignment = this.assignments.get(assignmentId);
343
+
344
+ if (assignment && (includeInactive || assignment.isActive)) {
345
+ assignments.push(assignment);
346
+ }
347
+ }
348
+
349
+ return assignments;
350
+ }
351
+
352
+ /**
353
+ * Register condition evaluator
354
+ * @param conditionType - Condition type name
355
+ * @param evaluator - Evaluator function
356
+ */
357
+ registerConditionEvaluator(conditionType: string, evaluator: RoleConditionEvaluator): void {
358
+ this.conditionEvaluators.set(conditionType, evaluator);
359
+ }
360
+
361
+ /**
362
+ * Extend assignment expiration
363
+ * @param assignmentId - Assignment identifier
364
+ * @param newExpiresAt - New expiration date
365
+ */
366
+ async extendAssignment(assignmentId: string, newExpiresAt: Date): Promise<void> {
367
+ const assignment = this.assignments.get(assignmentId);
368
+
369
+ if (!assignment?.isActive) {
370
+ throw new Error('Assignment not found or inactive');
371
+ }
372
+
373
+ assignment.expiresAt = newExpiresAt;
374
+ assignment.metadata = {
375
+ ...assignment.metadata,
376
+ extendedAt: new Date().toString()
377
+ };
378
+ }
379
+
380
+ /**
381
+ * Clean up expired assignments
382
+ * @returns Number of cleaned assignments
383
+ */
384
+ async cleanupExpiredAssignments(): Promise<number> {
385
+ let cleanedCount = 0;
386
+ const now = new Date();
387
+ const expiredAssignments: string[] = [];
388
+
389
+ for (const [assignmentId, assignment] of this.assignments.entries()) {
390
+ if (assignment.isActive && assignment.expiresAt && assignment.expiresAt < now) {
391
+ expiredAssignments.push(assignmentId);
392
+ }
393
+ }
394
+
395
+ for (const assignmentId of expiredAssignments) {
396
+ await this.revokeAssignment(assignmentId, undefined, 'Expired');
397
+ cleanedCount++;
398
+ }
399
+
400
+ return cleanedCount;
401
+ }
402
+
403
+ /**
404
+ * Get assignment statistics
405
+ * @returns Assignment statistics
406
+ */
407
+ getStats(): {
408
+ totalAssignments: number;
409
+ activeAssignments: number;
410
+ expiredAssignments: number;
411
+ usersWithAssignments: number;
412
+ } {
413
+ let activeCount = 0;
414
+ let expiredCount = 0;
415
+ const now = new Date();
416
+
417
+ for (const assignment of this.assignments.values()) {
418
+ if (assignment.isActive) {
419
+ if (assignment.expiresAt && assignment.expiresAt < now) {
420
+ expiredCount++;
421
+ } else {
422
+ activeCount++;
423
+ }
424
+ }
425
+ }
426
+
427
+ return {
428
+ totalAssignments: this.assignments.size,
429
+ activeAssignments: activeCount,
430
+ expiredAssignments: expiredCount,
431
+ usersWithAssignments: this.userAssignments.size
432
+ };
433
+ }
434
+
435
+ /**
436
+ * Destroy dynamic roles manager
437
+ */
438
+ destroy(): void {
439
+ if (this.cleanupTimer) {
440
+ globalThis.clearInterval(this.cleanupTimer);
441
+ this.cleanupTimer = undefined;
442
+ }
443
+
444
+ this.assignments.clear();
445
+ this.userAssignments.clear();
446
+ this.conditionEvaluators.clear();
447
+ }
448
+
449
+ /**
450
+ * Evaluate assignment conditions
451
+ * @param userId - User identifier
452
+ * @param conditions - Assignment conditions
453
+ * @param context - Evaluation context
454
+ * @returns True if conditions are met
455
+ * @private
456
+ */
457
+ private async evaluateConditions(
458
+ userId: string,
459
+ conditions: Record<string, string>,
460
+ context?: Record<string, string>
461
+ ): Promise<boolean> {
462
+ for (const [conditionType, conditionValue] of Object.entries(conditions)) {
463
+ const evaluator = this.conditionEvaluators.get(conditionType);
464
+
465
+ if (evaluator) {
466
+ const result = await evaluator(userId, { [conditionType]: conditionValue }, context);
467
+ if (!result) {
468
+ return false;
469
+ }
470
+ } else {
471
+ // Default evaluation: simple equality check with context
472
+ if (context && context[conditionType] !== conditionValue) {
473
+ return false;
474
+ }
475
+ }
476
+ }
477
+
478
+ return true;
479
+ }
480
+
481
+ /**
482
+ * Enforce assignment limits per user
483
+ * @param userId - User identifier
484
+ * @private
485
+ */
486
+ private async enforceAssignmentLimits(userId: string): Promise<void> {
487
+ const userAssignments = this.getUserAssignments(userId, false);
488
+
489
+ if (userAssignments.length >= this.config.maxAssignmentsPerUser) {
490
+ throw new Error(`Maximum assignments per user exceeded: ${this.config.maxAssignmentsPerUser}`);
491
+ }
492
+ }
493
+
494
+ /**
495
+ * Generate unique assignment ID
496
+ * @returns Assignment identifier
497
+ * @private
498
+ */
499
+ private generateAssignmentId(): string {
500
+ return `dyn_${Date.now()}_${Math.random().toString(NUMERIX.THIRTY_SIX).substr(NUMERIX.TWO, NUMERIX.NINE)}`;
501
+ }
502
+
503
+ /**
504
+ * Start cleanup timer for expired assignments
505
+ * @private
506
+ */
507
+ private startCleanupTimer(): void {
508
+ // Run cleanup every 5 minutes
509
+ this.cleanupTimer = globalThis.setInterval(async () => {
510
+ await this.cleanupExpiredAssignments();
511
+ }, NUMERIX.FIVE * NUMERIX.SIXTY * NUMERIX.THOUSAND);
512
+ }
513
+
514
+ /**
515
+ * Emit role assigned event
516
+ * @param assignment - Role assignment
517
+ * @private
518
+ */
519
+ private emitRoleAssignedEvent(assignment: DynamicRoleAssignment): void {
520
+ // Mock event emission - in real implementation would use event system
521
+ globalThis.console.log(`Event: ${AUTH_EVENTS.ROLE_ASSIGNED}`, {
522
+ userId: assignment.userId,
523
+ roleId: assignment.roleId,
524
+ assignmentId: assignment.id,
525
+ assignedBy: assignment.assignedBy,
526
+ timestamp: assignment.createdAt
527
+ });
528
+ }
529
+
530
+ /**
531
+ * Emit role revoked event
532
+ * @param assignment - Role assignment
533
+ * @param revokedBy - Revoking user ID
534
+ * @param reason - Revocation reason
535
+ * @private
536
+ */
537
+ private emitRoleRevokedEvent(
538
+ assignment: DynamicRoleAssignment,
539
+ revokedBy?: string,
540
+ reason?: string
541
+ ): void {
542
+ // Mock event emission - in real implementation would use event system
543
+ globalThis.console.log(`Event: ${AUTH_EVENTS.ROLE_REVOKED}`, {
544
+ userId: assignment.userId,
545
+ roleId: assignment.roleId,
546
+ assignmentId: assignment.id,
547
+ revokedBy,
548
+ reason,
549
+ timestamp: new Date()
550
+ });
551
+ }
552
+ }
@@ -0,0 +1,4 @@
1
+ export * from './role.manager';
2
+ export * from './permission-checker';
3
+ export * from './role-hierarchy';
4
+ export * from './dynamic-roles';