@magnet-cms/core 1.0.3 → 3.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 (39) hide show
  1. package/dist/cache.settings-WVD3J7KS.js +5 -0
  2. package/dist/{chunk-VRD3SNTH.js → chunk-4KTI5N3Y.js} +5 -5
  3. package/dist/{chunk-2G3SJVME.js → chunk-57BXP7WT.js} +3 -3
  4. package/dist/{chunk-GRTSRYQ3.js → chunk-5ZNZ457Y.js} +1 -1
  5. package/dist/{chunk-UPVWRKGL.js → chunk-BLOJL7F5.js} +1 -1
  6. package/dist/{chunk-IRYV6KDU.js → chunk-D3C3IDJE.js} +1806 -2919
  7. package/dist/chunk-FPVW2XEK.js +77 -0
  8. package/dist/{chunk-VPQMUAKT.js → chunk-L5S66O2C.js} +2945 -1418
  9. package/dist/{chunk-5KKPPI6S.js → chunk-LSFWCRI6.js} +3 -3
  10. package/dist/{dist-es-EKS5UN6W.js → dist-es-FN4ZDH7H.js} +3 -3
  11. package/dist/dist-es-IFKE2QTH.js +1 -1
  12. package/dist/{dist-es-J4ID6CFE.js → dist-es-JOTZAW56.js} +3 -3
  13. package/dist/{dist-es-SH3IYNFH.js → dist-es-UU6EFY2O.js} +2 -2
  14. package/dist/index.cjs +62120 -8608
  15. package/dist/index.d.cts +22 -7
  16. package/dist/index.d.ts +22 -7
  17. package/dist/index.js +53223 -193
  18. package/dist/{loadCognitoIdentity-IDLT73F5.js → loadCognitoIdentity-VHCOBTS2.js} +4 -4
  19. package/dist/{loadSso-VKQ2MGWC.js → loadSso-5XNIYOZP.js} +4 -4
  20. package/dist/{loadSts-CDV5EIAC.js → loadSts-IC4PURXF.js} +6 -6
  21. package/dist/magnet-module-imports.cjs +3864 -3393
  22. package/dist/magnet-module-imports.d.cts +6 -2
  23. package/dist/magnet-module-imports.d.ts +6 -2
  24. package/dist/magnet-module-imports.js +12 -11
  25. package/dist/modules.cjs +3921 -2174
  26. package/dist/modules.d.cts +298 -618
  27. package/dist/modules.d.ts +298 -618
  28. package/dist/modules.js +179 -15
  29. package/dist/permission.guard-B8HLjHP2.d.cts +912 -0
  30. package/dist/permission.guard-B8HLjHP2.d.ts +912 -0
  31. package/dist/{settings.module-CS9n15pg.d.cts → settings.module-CX5Cs5fA.d.cts} +29 -3
  32. package/dist/{settings.module-CS9n15pg.d.ts → settings.module-CX5Cs5fA.d.ts} +29 -3
  33. package/dist/{signin-OTF7SOKV.js → signin-TXX6BWCZ.js} +4 -4
  34. package/dist/{sso-oidc-IU7NSPWD.js → sso-oidc-CMVLR2KO.js} +4 -4
  35. package/dist/{sts-IGHPXD4X.js → sts-MASJMUF3.js} +6 -6
  36. package/package.json +3 -3
  37. package/dist/auth-strategy.factory-D2p1hfeq.d.cts +0 -303
  38. package/dist/auth-strategy.factory-D2p1hfeq.d.ts +0 -303
  39. package/dist/{chunk-ISB33RLS.js → chunk-47RGXMWN.js} +3 -3
@@ -0,0 +1,912 @@
1
+ import * as _magnet_cms_common from '@magnet-cms/common';
2
+ import { LogMetadata, EventName, EventHandler, EventHandlerOptions, EventPayload, BaseEventPayload, EventHistoryEntry, PluginMetadata, PluginFrontendManifest, Model, AuthConfig, AuthStrategy, ControllerMetadata, MethodMetadata, SchemaMetadata, PluginConfig, EnrichedPluginManifest, RegisteredPluginInfo, PermissionSource, PermissionDefinition, PermissionGroup, CategorizedPermissions, RoleWithPermissions } from '@magnet-cms/common';
3
+ import { LoggerService, OnModuleDestroy, Type, OnModuleInit, CanActivate, ExecutionContext } from '@nestjs/common';
4
+ import { ModulesContainer, Reflector } from '@nestjs/core';
5
+ import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
6
+
7
+ /**
8
+ * Structured logger for Magnet CMS.
9
+ *
10
+ * Implements NestJS LoggerService with JSON/pretty output, log level
11
+ * filtering, sensitive field redaction, and automatic request context
12
+ * enrichment from EventContext (AsyncLocalStorage).
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * constructor(private readonly logger: MagnetLogger) {
17
+ * this.logger.setContext(MyService.name)
18
+ * }
19
+ *
20
+ * doWork() {
21
+ * this.logger.log('Starting work', { operation: 'doWork' })
22
+ * }
23
+ * ```
24
+ */
25
+ declare class MagnetLogger implements LoggerService {
26
+ private context;
27
+ private cachedConfig;
28
+ /** Create a standalone logger instance (for use before DI is available). */
29
+ static create(context?: string): MagnetLogger;
30
+ /** Set the logger context (service name). Call in constructor. */
31
+ setContext(context: string): void;
32
+ /** Return a child logger with a namespaced context (parent:child). */
33
+ child(context: string): MagnetLogger;
34
+ log(message: string, metadata?: LogMetadata): void;
35
+ error(message: string, trace?: unknown, metadata?: LogMetadata): void;
36
+ warn(message: string, metadata?: LogMetadata): void;
37
+ debug(message: string, metadata?: LogMetadata): void;
38
+ verbose(message: string, metadata?: LogMetadata): void;
39
+ private getConfig;
40
+ private write;
41
+ private formatJson;
42
+ private formatPretty;
43
+ }
44
+
45
+ /**
46
+ * Type-safe event service for decoupled communication between modules.
47
+ *
48
+ * Features:
49
+ * - Type-safe events with payload validation
50
+ * - Priority-based handler execution
51
+ * - Async handlers that don't block the request
52
+ * - Error isolation (one handler failure doesn't affect others)
53
+ * - Event history for debugging
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * // Emitting events
58
+ * await this.eventService.emit('content.created', {
59
+ * schema: 'posts',
60
+ * documentId: '123',
61
+ * }, getEventContext())
62
+ *
63
+ * // Registering handlers programmatically
64
+ * const unsubscribe = this.eventService.on('content.created', async (payload) => {
65
+ * console.log('Content created:', payload.documentId)
66
+ * })
67
+ *
68
+ * // Or use the @OnEvent decorator
69
+ * @OnEvent('content.created')
70
+ * async handleContentCreated(payload: EventPayload<'content.created'>): Promise<void> {
71
+ * // ...
72
+ * }
73
+ * ```
74
+ */
75
+ declare class EventService implements OnModuleDestroy {
76
+ private readonly logger;
77
+ private readonly handlers;
78
+ private readonly eventHistory;
79
+ private readonly maxHistorySize;
80
+ constructor(logger: MagnetLogger);
81
+ /**
82
+ * Register an event handler
83
+ *
84
+ * @param event - The event name to listen for
85
+ * @param handler - The handler function
86
+ * @param options - Handler options (priority, async, name)
87
+ * @returns Unsubscribe function
88
+ */
89
+ on<E extends EventName>(event: E, handler: EventHandler<E>, options?: EventHandlerOptions): () => void;
90
+ /**
91
+ * Unregister an event handler
92
+ *
93
+ * @param event - The event name
94
+ * @param handler - The handler function to remove
95
+ */
96
+ off<E extends EventName>(event: E, handler: EventHandler<E>): void;
97
+ /**
98
+ * Emit an event
99
+ *
100
+ * Executes sync handlers sequentially (awaiting each), then fires async
101
+ * handlers in parallel without waiting for them.
102
+ *
103
+ * @param event - The event name
104
+ * @param payload - The event payload (without base fields)
105
+ * @param context - Optional context (userId, requestId, ipAddress)
106
+ */
107
+ emit<E extends EventName>(event: E, payload: Omit<EventPayload<E>, keyof BaseEventPayload>, context?: Partial<BaseEventPayload>): Promise<void>;
108
+ /**
109
+ * Emit multiple events
110
+ *
111
+ * Events are emitted sequentially in the order provided.
112
+ *
113
+ * @param events - Array of event objects with event name and payload
114
+ * @param context - Optional shared context for all events
115
+ */
116
+ emitBatch(events: Array<{
117
+ event: EventName;
118
+ payload: Record<string, unknown>;
119
+ }>, context?: Partial<BaseEventPayload>): Promise<void>;
120
+ /**
121
+ * Get recent event history (for debugging)
122
+ *
123
+ * @param limit - Maximum number of events to return (default 100)
124
+ * @returns Array of recent events
125
+ */
126
+ getHistory(limit?: number): EventHistoryEntry[];
127
+ /**
128
+ * Get all registered handlers (for debugging)
129
+ *
130
+ * @returns Map of event names to handler info
131
+ */
132
+ getHandlers(): Map<EventName, Array<{
133
+ name: string;
134
+ priority: number;
135
+ async: boolean;
136
+ }>>;
137
+ /**
138
+ * Check if an event has any handlers registered
139
+ *
140
+ * @param event - The event name to check
141
+ * @returns True if at least one handler is registered
142
+ */
143
+ hasHandlers(event: EventName): boolean;
144
+ /**
145
+ * Get the number of handlers for an event
146
+ *
147
+ * @param event - The event name
148
+ * @returns Number of registered handlers
149
+ */
150
+ getHandlerCount(event: EventName): number;
151
+ /**
152
+ * Clear all handlers (for testing)
153
+ */
154
+ clearAllHandlers(): void;
155
+ /**
156
+ * Clear event history (for testing)
157
+ */
158
+ clearHistory(): void;
159
+ private addToHistory;
160
+ private logHandlerError;
161
+ onModuleDestroy(): void;
162
+ }
163
+
164
+ interface PluginDecoratorOptions extends Omit<PluginMetadata, 'module'> {
165
+ /** Frontend manifest for this plugin */
166
+ frontend?: Omit<PluginFrontendManifest, 'pluginName'>;
167
+ /**
168
+ * NestJS module containing controllers/services (auto-imported).
169
+ * Use a getter () => MyModule to defer loading until after DatabaseModule.register().
170
+ */
171
+ module?: Type<unknown> | (() => Type<unknown>);
172
+ }
173
+ /**
174
+ * Decorator to mark a class as a Magnet plugin
175
+ *
176
+ * @example
177
+ * ```ts
178
+ * @Plugin({
179
+ * name: 'playground',
180
+ * description: 'Visual schema builder',
181
+ * version: '1.0.0',
182
+ * frontend: {
183
+ * routes: [{ path: 'playground', componentId: 'PlaygroundIndex' }],
184
+ * sidebar: [{ id: 'playground', title: 'Playground', url: '/playground', icon: 'Boxes' }]
185
+ * }
186
+ * })
187
+ * export class PlaygroundPlugin {}
188
+ * ```
189
+ */
190
+ declare function Plugin(options: PluginDecoratorOptions): ClassDecorator;
191
+
192
+ declare function Hook(hookName: string): MethodDecorator;
193
+
194
+ /**
195
+ * Decorator to inject plugin options using standardized token.
196
+ *
197
+ * @param pluginName - The plugin name (e.g., 'playground')
198
+ *
199
+ * @example
200
+ * ```ts
201
+ * @Injectable()
202
+ * export class MyService {
203
+ * constructor(
204
+ * @InjectPluginOptions('playground')
205
+ * private readonly options: PlaygroundPluginOptions
206
+ * ) {}
207
+ * }
208
+ * ```
209
+ */
210
+ declare function InjectPluginOptions(pluginName: string): ParameterDecorator;
211
+
212
+ declare class CreateUserDto {
213
+ id?: string;
214
+ email: string;
215
+ password?: string | null;
216
+ name: string;
217
+ role?: string;
218
+ provider?: string | null;
219
+ providerId?: string | null;
220
+ }
221
+
222
+ declare class User {
223
+ email: string;
224
+ /** Null for OAuth-only users who have never set a local password */
225
+ password?: string | null;
226
+ name: string;
227
+ role?: string;
228
+ /** OAuth provider name (e.g. 'google', 'github'). Null for local-only users. */
229
+ provider?: string | null;
230
+ /** OAuth provider user ID. Null for local-only users. */
231
+ providerId?: string | null;
232
+ isActive?: boolean;
233
+ emailVerified?: boolean;
234
+ lastLogin?: Date;
235
+ createdAt?: Date;
236
+ hashPassword(): Promise<void>;
237
+ }
238
+
239
+ interface PaginatedUserResult {
240
+ users: User[];
241
+ total: number;
242
+ page: number;
243
+ limit: number;
244
+ }
245
+ declare class UserService {
246
+ private readonly userModel;
247
+ constructor(userModel: Model<User>);
248
+ findAll(): Promise<_magnet_cms_common.BaseSchema<User>[]>;
249
+ findAllPaginated(page?: number, limit?: number): Promise<PaginatedUserResult>;
250
+ findOne(query: Partial<User>): Promise<_magnet_cms_common.BaseSchema<User> | null>;
251
+ findOneById(id: string): Promise<_magnet_cms_common.BaseSchema<User> | null>;
252
+ create(userData: CreateUserDto): Promise<_magnet_cms_common.BaseSchema<User>>;
253
+ update(id: string, updateUserDto: Partial<User>): Promise<_magnet_cms_common.BaseSchema<User>>;
254
+ remove(id: string): Promise<boolean>;
255
+ resetPassword(id: string, newPassword: string): Promise<{
256
+ message: string;
257
+ }>;
258
+ }
259
+
260
+ type AuthStrategyConstructor = new (config: AuthConfig, userService: UserService) => AuthStrategy;
261
+ /**
262
+ * Factory for creating auth strategy instances.
263
+ *
264
+ * The JWT strategy is built-in. Other strategies (supabase, clerk)
265
+ * register themselves via their adapter's `.forRoot()` method.
266
+ *
267
+ * @example
268
+ * ```typescript
269
+ * // Strategies are auto-registered by adapter forRoot():
270
+ * MagnetModule.forRoot([
271
+ * SupabaseAuthAdapter.forRoot(), // registers 'supabase' strategy internally
272
+ * ])
273
+ * ```
274
+ */
275
+ declare class AuthStrategyFactory {
276
+ private static cachedStrategy;
277
+ private static cachedConfig;
278
+ private static customStrategies;
279
+ /**
280
+ * Register a custom auth strategy class.
281
+ * Called internally by auth adapter `.forRoot()` methods.
282
+ *
283
+ * @param name - Unique name for the strategy (used in config.strategy)
284
+ * @param strategyClass - Class constructor implementing AuthStrategy
285
+ */
286
+ static registerStrategy(name: string, strategyClass: AuthStrategyConstructor): void;
287
+ /**
288
+ * Get or create an auth strategy based on configuration.
289
+ * Called internally by AuthModule.forRoot().
290
+ *
291
+ * @param config - Auth configuration
292
+ * @param userService - UserService for database operations
293
+ * @param jwtSecret - JWT secret (fallback from global options)
294
+ */
295
+ static getStrategy(config: AuthConfig | undefined, userService: UserService, jwtSecret: string): AuthStrategy;
296
+ /** Clear the cached strategy (useful for testing) */
297
+ static clearCache(): void;
298
+ /** Clear all registered custom strategies (useful for testing) */
299
+ static clearStrategies(): void;
300
+ /** Check if a strategy is registered */
301
+ static hasStrategy(name: string): boolean;
302
+ private static configMatches;
303
+ }
304
+
305
+ /**
306
+ * DTO for creating a new role
307
+ */
308
+ declare class CreateRoleDto {
309
+ /**
310
+ * Role slug (lowercase, no spaces)
311
+ * Must start with a letter, can contain letters, numbers, and hyphens
312
+ */
313
+ name: string;
314
+ /**
315
+ * Human-readable display name
316
+ */
317
+ displayName: string;
318
+ /**
319
+ * Optional description
320
+ */
321
+ description?: string;
322
+ /**
323
+ * Initial permissions to assign
324
+ */
325
+ permissions?: string[];
326
+ }
327
+
328
+ /**
329
+ * DTO for duplicating a role
330
+ */
331
+ declare class DuplicateRoleDto {
332
+ /**
333
+ * Name for the new role (slug)
334
+ */
335
+ name: string;
336
+ /**
337
+ * Optional display name for the new role
338
+ * If not provided, defaults to "Copy of [original]"
339
+ */
340
+ displayName?: string;
341
+ }
342
+
343
+ /**
344
+ * DTO for updating a role
345
+ */
346
+ declare class UpdateRoleDto {
347
+ /**
348
+ * Updated display name
349
+ */
350
+ displayName?: string;
351
+ /**
352
+ * Updated description
353
+ */
354
+ description?: string;
355
+ }
356
+
357
+ /**
358
+ * Role schema for storing user roles and their permissions.
359
+ *
360
+ * Roles contain:
361
+ * - A unique name (slug) for programmatic access
362
+ * - A display name for UI
363
+ * - An array of permission IDs
364
+ * - System flag for protecting default roles
365
+ */
366
+ declare class Role {
367
+ /**
368
+ * Unique role identifier (slug)
369
+ * Used for programmatic access (e.g., 'admin', 'editor', 'authenticated')
370
+ */
371
+ name: string;
372
+ /**
373
+ * Human-readable display name
374
+ */
375
+ displayName: string;
376
+ /**
377
+ * Role description for admin UI
378
+ */
379
+ description?: string;
380
+ /**
381
+ * Array of permission IDs assigned to this role
382
+ * Use '*' for wildcard (all permissions)
383
+ * Use 'content.*' for category wildcard
384
+ */
385
+ permissions: string[];
386
+ /**
387
+ * Whether this is a system role (cannot be deleted)
388
+ * System roles: admin, authenticated, public
389
+ */
390
+ isSystem: boolean;
391
+ /**
392
+ * User count (computed, not stored)
393
+ * Populated when listing roles
394
+ */
395
+ userCount?: number;
396
+ /**
397
+ * When this role was created
398
+ */
399
+ createdAt: Date;
400
+ /**
401
+ * When this role was last updated
402
+ */
403
+ updatedAt?: Date;
404
+ }
405
+
406
+ declare class MetadataExtractorService {
407
+ extractControllerMetadata(wrapper: InstanceWrapper<object>): ControllerMetadata;
408
+ extractMethodMetadata(instance: object, method: string): MethodMetadata | null;
409
+ extractSchemaMetadata(wrapper: InstanceWrapper<unknown>): SchemaMetadata | null;
410
+ /**
411
+ * Build schema properties from Field metadata, Setting Field metadata, and legacy Prop/UI metadata.
412
+ * Priority: Field metadata > Setting Field metadata > legacy Prop/UI metadata
413
+ */
414
+ private buildProperties;
415
+ /**
416
+ * Get the type name from field metadata
417
+ */
418
+ private getTypeNameFromFieldMetadata;
419
+ /**
420
+ * Get type name from a type constructor or design type
421
+ */
422
+ private getTypeName;
423
+ /**
424
+ * Check if a field is an array type
425
+ */
426
+ private isArrayField;
427
+ /**
428
+ * Build UI options from field metadata
429
+ */
430
+ private buildUIFromFieldMetadata;
431
+ /**
432
+ * Convert select/enum options to UI format
433
+ */
434
+ private convertSelectOptions;
435
+ /**
436
+ * Get ref (relationship reference) from field metadata
437
+ */
438
+ private getRefFromFieldMetadata;
439
+ /**
440
+ * Get the type name from setting field metadata
441
+ */
442
+ private getTypeNameFromSettingFieldMetadata;
443
+ /**
444
+ * Build UI options from setting field metadata
445
+ */
446
+ private buildUIFromSettingFieldMetadata;
447
+ /**
448
+ * Convert setting select options to UI format
449
+ */
450
+ private convertSettingSelectOptions;
451
+ getParamDetails(controller: Function, methodName: string): {
452
+ arg: string;
453
+ type: string;
454
+ name: string;
455
+ }[];
456
+ private getValidationMetadata;
457
+ }
458
+
459
+ declare class ControllerDiscoveryService {
460
+ private readonly modulesContainer;
461
+ private readonly metadataExtractor;
462
+ constructor(modulesContainer: ModulesContainer, metadataExtractor: MetadataExtractorService);
463
+ discoverControllers(): ControllerMetadata[];
464
+ }
465
+
466
+ declare class MethodDiscoveryService {
467
+ private readonly modulesContainer;
468
+ private readonly metadataExtractor;
469
+ constructor(modulesContainer: ModulesContainer, metadataExtractor: MetadataExtractorService);
470
+ getMethodDetails(path: string, methodName: string, controllers: ControllerMetadata[]): MethodMetadata | {
471
+ error: string;
472
+ };
473
+ }
474
+
475
+ declare class SchemaDiscoveryService {
476
+ private readonly modulesContainer;
477
+ private readonly metadataExtractor;
478
+ constructor(modulesContainer: ModulesContainer, metadataExtractor: MetadataExtractorService);
479
+ discoverSchemas(): {
480
+ schemas: SchemaMetadata[];
481
+ settings: SchemaMetadata[];
482
+ };
483
+ }
484
+
485
+ declare class DiscoveryService implements OnModuleInit {
486
+ private readonly controllerDiscovery;
487
+ private readonly schemaDiscovery;
488
+ private readonly methodDiscovery;
489
+ private controllers;
490
+ private schemas;
491
+ private settingsSchemas;
492
+ constructor(controllerDiscovery: ControllerDiscoveryService, schemaDiscovery: SchemaDiscoveryService, methodDiscovery: MethodDiscoveryService);
493
+ onModuleInit(): void;
494
+ getDiscoveredSchemas(): string[];
495
+ getAllDiscoveredSchemas(): SchemaMetadata[];
496
+ getDiscoveredSchema(name: string): SchemaMetadata | {
497
+ error: string;
498
+ };
499
+ getDiscoveredSettingsSchemas(): string[];
500
+ getAllDiscoveredSettingsSchemas(): SchemaMetadata[];
501
+ getDiscoveredSettingsSchemaNames(): string[];
502
+ getDiscoveredSettingsSchema(name: string): SchemaMetadata | {
503
+ error: string;
504
+ };
505
+ getDiscoveredControllers(): string[];
506
+ getDiscoveredController(name: string): ControllerMetadata | {
507
+ error: string;
508
+ };
509
+ getMethodDetails(path: string, methodName: string): MethodMetadata | {
510
+ error: string;
511
+ };
512
+ }
513
+
514
+ interface RegisteredPlugin {
515
+ metadata: PluginMetadata;
516
+ instance: unknown;
517
+ frontendManifest?: PluginFrontendManifest;
518
+ config: PluginConfig;
519
+ }
520
+ declare class PluginRegistryService implements OnModuleInit {
521
+ private readonly modulesContainer;
522
+ private readonly logger;
523
+ private readonly pluginsConfig;
524
+ private plugins;
525
+ constructor(modulesContainer: ModulesContainer, logger: MagnetLogger, pluginsConfig?: PluginConfig[]);
526
+ onModuleInit(): void;
527
+ private discoverPlugins;
528
+ /**
529
+ * Get a registered plugin by name
530
+ */
531
+ getPlugin(name: string): RegisteredPlugin | undefined;
532
+ /**
533
+ * Get all registered plugins
534
+ */
535
+ getAllPlugins(): RegisteredPlugin[];
536
+ /**
537
+ * Get metadata for all plugins
538
+ */
539
+ getPluginMetadata(): PluginMetadata[];
540
+ /**
541
+ * Get frontend manifests for all plugins with bundle URLs
542
+ * Used by admin UI to dynamically load plugin frontends at runtime
543
+ */
544
+ getFrontendManifests(): EnrichedPluginManifest[];
545
+ /**
546
+ * Get full plugin info for API response
547
+ */
548
+ getPluginInfo(name: string): RegisteredPluginInfo | null;
549
+ /**
550
+ * Get all plugins info for API response
551
+ */
552
+ getAllPluginsInfo(): RegisteredPluginInfo[];
553
+ }
554
+
555
+ /**
556
+ * Permission schema for persisting discovered permissions.
557
+ *
558
+ * Permissions are auto-registered from:
559
+ * - Schema definitions (CRUD)
560
+ * - Controller methods (@RequirePermission)
561
+ * - Plugins
562
+ * - System definitions
563
+ *
564
+ * Used for validation when assigning permissions to roles.
565
+ */
566
+ declare class Permission {
567
+ /**
568
+ * Unique permission identifier (e.g., 'content.cat.create', 'roles.find')
569
+ * This is the key used when assigning permissions to roles.
570
+ */
571
+ permissionId: string;
572
+ /**
573
+ * Human-readable name for the admin UI
574
+ */
575
+ name: string;
576
+ /**
577
+ * Description for the admin UI
578
+ */
579
+ description?: string;
580
+ /**
581
+ * Group for organization (e.g., 'Content', 'Users', 'Settings')
582
+ */
583
+ group?: string;
584
+ /**
585
+ * API identifier (e.g., 'api::posts', 'plugin::playground', 'system::users')
586
+ */
587
+ apiId?: string;
588
+ /**
589
+ * Source of this permission
590
+ */
591
+ source?: PermissionSource;
592
+ /**
593
+ * Controller name if discovered from controller
594
+ */
595
+ controller?: string;
596
+ /**
597
+ * Method name if discovered from controller
598
+ */
599
+ method?: string;
600
+ /**
601
+ * Plugin name if from plugin
602
+ */
603
+ plugin?: string;
604
+ /**
605
+ * Schema name if auto-generated from schema
606
+ */
607
+ schema?: string;
608
+ /**
609
+ * When this permission was first registered
610
+ */
611
+ createdAt: Date;
612
+ /**
613
+ * When this permission was last updated
614
+ */
615
+ updatedAt?: Date;
616
+ }
617
+
618
+ interface ValidatePermissionIdsResult {
619
+ valid: string[];
620
+ invalid: string[];
621
+ }
622
+ /**
623
+ * Service for persisting and validating permissions.
624
+ *
625
+ * Permissions are synced from PermissionDiscoveryService on startup
626
+ * and used to validate role permission assignments.
627
+ */
628
+ declare class PermissionService {
629
+ private readonly permissionModel;
630
+ private readonly logger;
631
+ constructor(permissionModel: Model<Permission>, logger: MagnetLogger);
632
+ /**
633
+ * Upsert a single permission from a definition
634
+ */
635
+ upsertFromDefinition(def: PermissionDefinition): Promise<void>;
636
+ /**
637
+ * Batch upsert permissions from definitions
638
+ */
639
+ upsertMany(definitions: PermissionDefinition[]): Promise<void>;
640
+ /**
641
+ * Find a permission by ID
642
+ */
643
+ findById(permissionId: string): Promise<Permission | null>;
644
+ /**
645
+ * Get all registered permission IDs
646
+ */
647
+ findAllIds(): Promise<string[]>;
648
+ /**
649
+ * Validate that all permission IDs exist (in DB or can be matched by wildcard)
650
+ * Returns valid and invalid IDs.
651
+ */
652
+ validatePermissionIds(ids: string[], knownIds?: string[]): Promise<ValidatePermissionIdsResult>;
653
+ private definitionToPermissionData;
654
+ }
655
+
656
+ /**
657
+ * Service for discovering all permissions in the system.
658
+ *
659
+ * Permissions are discovered from:
660
+ * 1. Schema definitions - auto-generated CRUD permissions
661
+ * 2. Controller methods - @RequirePermission decorated methods
662
+ * 3. Plugins - permissions defined in plugin manifests
663
+ */
664
+ declare class PermissionDiscoveryService implements OnModuleInit {
665
+ private readonly discoveryService;
666
+ private readonly modulesContainer;
667
+ private readonly pluginRegistry;
668
+ private readonly permissionService;
669
+ private permissions;
670
+ private initialized;
671
+ constructor(discoveryService: DiscoveryService, modulesContainer: ModulesContainer, pluginRegistry: PluginRegistryService, permissionService: PermissionService);
672
+ onModuleInit(): Promise<void>;
673
+ /**
674
+ * Discover all permissions from schemas, controllers, and plugins
675
+ */
676
+ private discoverPermissions;
677
+ /**
678
+ * Auto-generate CRUD permissions for each discovered schema
679
+ */
680
+ private discoverSchemaPermissions;
681
+ /**
682
+ * Discover @RequirePermission decorated methods from controllers
683
+ */
684
+ private discoverControllerPermissions;
685
+ /**
686
+ * Extract permissions from a controller's methods
687
+ */
688
+ private extractControllerPermissions;
689
+ /**
690
+ * Discover permissions from registered plugins
691
+ */
692
+ private discoverPluginPermissions;
693
+ /**
694
+ * Add system-level permissions
695
+ */
696
+ private discoverSystemPermissions;
697
+ /**
698
+ * Get all discovered permissions
699
+ */
700
+ getAll(): PermissionDefinition[];
701
+ /**
702
+ * Get a specific permission by ID
703
+ */
704
+ get(id: string): PermissionDefinition | undefined;
705
+ /**
706
+ * Check if a permission exists
707
+ */
708
+ has(id: string): boolean;
709
+ /**
710
+ * Get permissions grouped for UI display
711
+ */
712
+ getGrouped(): PermissionGroup[];
713
+ /**
714
+ * Get permissions categorized by type (for admin UI)
715
+ * - collectionTypes: schema-based (api::*), each schema = one accordion
716
+ * - controllers: from @RequirePermission, each controller = one accordion
717
+ * - plugins: plugin::*
718
+ * - system: system::*
719
+ */
720
+ getCategorized(): CategorizedPermissions;
721
+ /**
722
+ * Group controller permissions by controller (each = one accordion)
723
+ */
724
+ private groupByController;
725
+ /**
726
+ * Get permissions for a specific schema
727
+ */
728
+ getSchemaPermissions(schemaName: string): PermissionDefinition[];
729
+ /**
730
+ * Get permissions for a specific plugin
731
+ */
732
+ getPluginPermissions(pluginName: string): PermissionDefinition[];
733
+ /**
734
+ * Mark permissions as checked/unchecked based on role's permissions
735
+ */
736
+ markPermissions(groups: PermissionGroup[], rolePermissions: string[]): PermissionGroup[];
737
+ /**
738
+ * Check if a permission is enabled (including wildcard matching)
739
+ */
740
+ private isPermissionEnabled;
741
+ /**
742
+ * Get human-readable action label
743
+ */
744
+ private getActionLabel;
745
+ /**
746
+ * Format permission ID into a readable name
747
+ */
748
+ private formatPermissionName;
749
+ }
750
+
751
+ /**
752
+ * Service for managing roles and checking permissions
753
+ */
754
+ declare class RoleService implements OnModuleInit {
755
+ private readonly roleModel;
756
+ private readonly permissionDiscovery;
757
+ private readonly permissionService;
758
+ private readonly eventService;
759
+ private readonly userService;
760
+ private readonly logger;
761
+ private permissionCache;
762
+ private cacheEnabled;
763
+ private cacheTTL;
764
+ constructor(roleModel: Model<Role>, permissionDiscovery: PermissionDiscoveryService, permissionService: PermissionService, eventService: EventService, userService: UserService, logger: MagnetLogger);
765
+ onModuleInit(): Promise<void>;
766
+ /**
767
+ * Ensure default system roles exist
768
+ */
769
+ private ensureDefaultRoles;
770
+ /**
771
+ * Get all roles
772
+ */
773
+ findAll(): Promise<Role[]>;
774
+ /**
775
+ * Get all roles with user counts
776
+ */
777
+ findAllWithCounts(): Promise<(Role & {
778
+ userCount: number;
779
+ })[]>;
780
+ /**
781
+ * Get a role by ID
782
+ */
783
+ findById(id: string): Promise<Role | null>;
784
+ /**
785
+ * Get a role by name
786
+ */
787
+ findByName(name: string): Promise<Role | null>;
788
+ /**
789
+ * Get a role with all permissions resolved
790
+ */
791
+ findByIdWithPermissions(id: string): Promise<RoleWithPermissions>;
792
+ /**
793
+ * Get a role by name with all permissions resolved
794
+ */
795
+ findByNameWithPermissions(name: string): Promise<RoleWithPermissions>;
796
+ /**
797
+ * Create a new role
798
+ */
799
+ create(dto: CreateRoleDto): Promise<Role>;
800
+ /**
801
+ * Update a role
802
+ */
803
+ update(id: string, dto: UpdateRoleDto): Promise<Role>;
804
+ /**
805
+ * Update role permissions
806
+ */
807
+ updatePermissions(id: string, permissions: string[]): Promise<Role>;
808
+ /**
809
+ * Delete a role (non-system roles only)
810
+ */
811
+ delete(id: string): Promise<void>;
812
+ /**
813
+ * Duplicate a role
814
+ */
815
+ duplicate(id: string, dto: DuplicateRoleDto): Promise<Role>;
816
+ /**
817
+ * Check if a user has a specific permission
818
+ */
819
+ hasPermission(userId: string, permission: string): Promise<boolean>;
820
+ /**
821
+ * Check if a role has a specific permission
822
+ */
823
+ roleHasPermission(roleName: string, permission: string): Promise<boolean>;
824
+ /**
825
+ * Check if a permission list includes a permission (with wildcard support)
826
+ */
827
+ checkPermission(rolePermissions: string[], permissionId: string): boolean;
828
+ /**
829
+ * Get all permissions a user has
830
+ */
831
+ getUserPermissions(userId: string): Promise<string[]>;
832
+ /**
833
+ * Assign a role to a user
834
+ */
835
+ assignRoleToUser(userId: string, roleName: string): Promise<void>;
836
+ /**
837
+ * Get all discovered permissions
838
+ */
839
+ getAllPermissions(): CategorizedPermissions;
840
+ /**
841
+ * Enable or disable permission caching
842
+ */
843
+ setCacheEnabled(enabled: boolean): void;
844
+ /**
845
+ * Set cache TTL
846
+ */
847
+ setCacheTTL(ttlMs: number): void;
848
+ /**
849
+ * Clear the permission cache
850
+ */
851
+ clearCache(): void;
852
+ /**
853
+ * Invalidate cache for a specific role
854
+ */
855
+ private invalidateRoleCache;
856
+ private getCachedPermission;
857
+ private setCachedPermission;
858
+ /**
859
+ * Resolve a role with all permissions marked
860
+ */
861
+ private resolveRolePermissions;
862
+ /**
863
+ * Get role ID (handles both string ID and _id from MongoDB)
864
+ */
865
+ private getRoleId;
866
+ /**
867
+ * Check if a role name is a system role
868
+ */
869
+ isSystemRole(roleName: string): boolean;
870
+ }
871
+
872
+ /**
873
+ * Guard that checks if the authenticated user has the required permission.
874
+ *
875
+ * Usage:
876
+ * ```typescript
877
+ * @Get()
878
+ * @UseGuards(DynamicAuthGuard, PermissionGuard)
879
+ * @RequirePermission({
880
+ * id: 'content.posts.find',
881
+ * name: 'List Posts',
882
+ * description: 'View list of posts',
883
+ * })
884
+ * async findAll() { ... }
885
+ * ```
886
+ *
887
+ * Supports dynamic permission IDs with placeholders:
888
+ * ```typescript
889
+ * @RequirePermission({
890
+ * id: 'content.{schema}.find',
891
+ * name: 'Find',
892
+ * })
893
+ * async find(@Param('schema') schema: string) { ... }
894
+ * ```
895
+ */
896
+ declare class PermissionGuard implements CanActivate {
897
+ private readonly reflector;
898
+ private readonly roleService;
899
+ private readonly logger;
900
+ constructor(reflector: Reflector, roleService: RoleService, logger: MagnetLogger);
901
+ canActivate(context: ExecutionContext): Promise<boolean>;
902
+ /**
903
+ * Get permission options from decorator or resolved permission
904
+ */
905
+ private getPermissionOptions;
906
+ /**
907
+ * Resolve dynamic permission placeholders
908
+ */
909
+ private resolvePermission;
910
+ }
911
+
912
+ export { AuthStrategyFactory as A, CreateUserDto as C, DiscoveryService as D, EventService as E, Hook as H, InjectPluginOptions as I, MagnetLogger as M, Plugin as P, RoleService as R, UserService as U, type ValidatePermissionIdsResult as V, type PluginDecoratorOptions as a, PermissionGuard as b, User as c, type PaginatedUserResult as d, PluginRegistryService as e, PermissionDiscoveryService as f, PermissionService as g, CreateRoleDto as h, DuplicateRoleDto as i, UpdateRoleDto as j, Role as k };