@magnet-cms/common 0.1.0 → 0.2.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/dist/index.d.ts CHANGED
@@ -1,494 +1,2627 @@
1
- import { Type, DynamicModule, ValidationError } from '@nestjs/common';
1
+ import { Type, OnModuleDestroy, DynamicModule, ValidationError as ValidationError$1 } from '@nestjs/common';
2
2
  import { Readable } from 'node:stream';
3
3
 
4
- type ResolverOptions = {
5
- schema: Type;
6
- };
7
- type ResolverInput = (() => Type) | ResolverOptions;
8
- type ResolveOptions = {
9
- type: Type | [Type];
10
- isArray?: boolean;
11
- description?: string;
12
- };
13
- type ResolveInput = (() => Type | [Type]) | ResolveOptions;
14
- type PropOptions = {
15
- type?: Type | [Type];
16
- description?: string;
17
- required?: boolean;
18
- unique?: boolean;
19
- default?: any;
20
- nullable?: boolean;
21
- intl?: boolean;
22
- hidden?: boolean;
23
- readonly?: boolean;
24
- };
25
- type BaseSchemaOptions = {
26
- timestamps?: boolean;
27
- };
28
- type SchemaOptions = {
29
- versioning?: boolean;
30
- i18n?: boolean;
31
- };
32
-
33
- type UIPresentationFields = 'tab' | 'collapsible' | 'row' | 'customUI';
34
- type UITypes = 'array' | 'blocks' | 'checkbox' | 'code' | 'combobox' | 'date' | 'email' | 'fileUpload' | 'group' | 'json' | 'multiSelect' | 'number' | 'phone' | 'point' | 'quantity' | 'radio' | 'relationship' | 'richText' | 'select' | 'switch' | 'table' | 'text' | 'textarea' | 'upload';
35
- type UIBase = {
36
- label?: string;
37
- description?: string;
38
- type?: UITypes;
39
- row?: boolean;
40
- collapsible?: boolean;
41
- };
42
- type UISelectItem = {
43
- key: string;
44
- value: string;
45
- };
46
- type UITab = UIBase & {
47
- tab: string;
48
- side?: never;
49
- options?: UISelectItem[];
50
- };
51
- type UISide = UIBase & {
52
- side: true;
53
- tab?: never;
54
- options?: UISelectItem[];
55
- };
56
- type UISelect = UIBase & {
57
- type: 'select';
58
- multi?: boolean;
59
- options: UISelectItem[];
60
- };
61
- type UIMultiSelect = UIBase & {
62
- type: 'multiSelect';
63
- options: UISelectItem[];
64
- };
65
- type UICombobox = UIBase & {
66
- type: 'combobox';
67
- options: UISelectItem[];
68
- };
69
- type UITableColumn = {
4
+ /**
5
+ * Event System Type Definitions
6
+ *
7
+ * Type-safe event system for decoupled communication between modules.
8
+ * Used by: Activity logging, Webhooks, Auth events, RBAC events, etc.
9
+ */
10
+ /**
11
+ * All event names in the system
12
+ * Adding new events requires updating this union
13
+ */
14
+ type EventName = 'content.created' | 'content.updated' | 'content.deleted' | 'content.published' | 'content.unpublished' | 'content.version.created' | 'content.version.restored' | 'user.created' | 'user.updated' | 'user.deleted' | 'user.registered' | 'user.login' | 'user.logout' | 'user.logout_all' | 'user.password_changed' | 'user.password_reset_requested' | 'user.password_reset' | 'user.password_reset_completed' | 'user.email_verification_requested' | 'user.email_verified' | 'user.session_revoked' | 'auth.token_refreshed' | 'auth.session_created' | 'auth.session_revoked' | 'auth.failed_login_attempt' | 'role.created' | 'role.updated' | 'role.deleted' | 'role.permissions_updated' | 'role.user_assigned' | 'settings.updated' | 'settings.group_updated' | 'media.uploaded' | 'media.deleted' | 'media.folder_created' | 'media.folder_deleted' | 'api_key.created' | 'api_key.revoked' | 'api_key.used' | 'webhook.created' | 'webhook.updated' | 'webhook.deleted' | 'webhook.delivery_success' | 'webhook.delivery_failed' | 'plugin.initialized' | 'plugin.destroyed' | 'notification.created' | 'system.startup' | 'system.shutdown';
15
+ /**
16
+ * Base event payload with common fields
17
+ */
18
+ interface BaseEventPayload {
19
+ /** Timestamp when event was emitted */
20
+ timestamp: Date;
21
+ /** User who triggered the event (if applicable) */
22
+ userId?: string;
23
+ /** IP address of the request (if applicable) */
24
+ ipAddress?: string;
25
+ /** Request ID for tracing */
26
+ requestId?: string;
27
+ }
28
+ /**
29
+ * Content event payload
30
+ */
31
+ interface ContentEventPayload extends BaseEventPayload {
32
+ schema: string;
33
+ documentId: string;
34
+ locale?: string;
35
+ }
36
+ /**
37
+ * Content version event payload
38
+ */
39
+ interface ContentVersionEventPayload extends ContentEventPayload {
40
+ version: number;
41
+ previousVersion?: number;
42
+ }
43
+ /**
44
+ * Field change record
45
+ */
46
+ interface FieldChange {
47
+ field: string;
48
+ oldValue: unknown;
49
+ newValue: unknown;
50
+ }
51
+ /**
52
+ * User event payload
53
+ */
54
+ interface UserEventPayload extends BaseEventPayload {
55
+ targetUserId: string;
56
+ email?: string;
57
+ }
58
+ /**
59
+ * Auth event payload
60
+ */
61
+ interface AuthEventPayload extends BaseEventPayload {
62
+ userId: string;
63
+ }
64
+ /**
65
+ * Failed login event payload
66
+ */
67
+ interface FailedLoginEventPayload extends BaseEventPayload {
68
+ email: string;
69
+ reason: 'invalid_password' | 'user_not_found' | 'account_locked' | 'email_not_verified';
70
+ }
71
+ /**
72
+ * Role event payload
73
+ */
74
+ interface RoleEventPayload extends BaseEventPayload {
75
+ roleId: string;
76
+ roleName: string;
77
+ }
78
+ /**
79
+ * Settings event payload
80
+ */
81
+ interface SettingsEventPayload extends BaseEventPayload {
70
82
  key: string;
71
- header: string;
72
- type?: 'text' | 'badge' | 'status' | 'input' | 'code';
73
- };
74
- type UITable = UIBase & {
75
- type: 'table';
76
- columns?: UITableColumn[];
77
- };
78
- type UIDecoratorOptions = UITab | UISide | UISelect | UIMultiSelect | UICombobox | UITable;
79
-
80
- type MethodMetadata = {
81
- name: string;
82
- returnType: {
83
- type: Type;
84
- isArray: boolean;
85
- };
86
- params: {
87
- arg: string;
88
- type: string;
89
- name: string;
90
- }[];
91
- httpMethod: string;
92
- routePath: string;
93
- guards?: Type[];
94
- interceptors?: Type[];
95
- pipes?: Type[];
96
- };
97
- type ControllerMetadata = {
98
- name: string;
99
- basePath: string;
100
- methods: MethodMetadata[];
101
- };
102
- type SchemaPropertyValidation = {
103
- type: string;
104
- name: string;
105
- constraints: number[];
106
- };
107
- type SchemaProperty = {
83
+ oldValue: unknown;
84
+ newValue: unknown;
85
+ }
86
+ /**
87
+ * Settings group event payload
88
+ */
89
+ interface SettingsGroupEventPayload extends BaseEventPayload {
90
+ group: string;
91
+ changes: Array<{
92
+ key: string;
93
+ oldValue: unknown;
94
+ newValue: unknown;
95
+ }>;
96
+ }
97
+ /**
98
+ * Media event payload
99
+ */
100
+ interface MediaEventPayload extends BaseEventPayload {
101
+ fileId: string;
102
+ filename: string;
103
+ mimeType: string;
104
+ size: number;
105
+ folder?: string;
106
+ }
107
+ /**
108
+ * Media folder event payload
109
+ */
110
+ interface MediaFolderEventPayload extends BaseEventPayload {
111
+ folderId: string;
112
+ folderName: string;
113
+ parentFolder?: string;
114
+ }
115
+ /**
116
+ * API Key event payload
117
+ */
118
+ interface ApiKeyEventPayload extends BaseEventPayload {
119
+ apiKeyId: string;
108
120
  name: string;
121
+ }
122
+ /**
123
+ * Webhook event payload
124
+ */
125
+ interface WebhookEventPayload extends BaseEventPayload {
126
+ webhookId: string;
127
+ url: string;
128
+ events: string[];
129
+ }
130
+ /**
131
+ * Webhook delivery event payload
132
+ */
133
+ interface WebhookDeliveryEventPayload extends BaseEventPayload {
134
+ webhookId: string;
135
+ deliveryId: string;
136
+ event: string;
137
+ statusCode?: number;
138
+ duration?: number;
139
+ }
140
+ /**
141
+ * Plugin event payload
142
+ */
143
+ interface PluginEventPayload extends BaseEventPayload {
144
+ pluginName: string;
145
+ version: string;
146
+ }
147
+ /**
148
+ * System event payload
149
+ */
150
+ interface SystemEventPayload extends BaseEventPayload {
151
+ version: string;
152
+ environment: string;
153
+ }
154
+ /**
155
+ * Notification created event payload
156
+ */
157
+ interface NotificationEventPayload extends BaseEventPayload {
158
+ notificationId: string;
159
+ targetUserId: string;
109
160
  type: string;
110
- isArray: boolean;
111
- unique: boolean;
112
- required: boolean;
113
- validations: SchemaPropertyValidation[];
114
- ui: UIDecoratorOptions;
115
- };
116
- type SchemaMetadata = {
117
- name: string;
118
- properties: SchemaProperty[];
119
- options?: SchemaOptions;
120
- };
121
-
122
- type InitialConfig = {
123
- title?: string;
124
- description?: string;
125
- env: string;
126
- schemas: SchemaMetadata[];
127
- settings: SchemaMetadata[];
128
- };
129
-
161
+ channels: string[];
162
+ }
130
163
  /**
131
- * Authenticated user returned from auth strategies
164
+ * Event payload map - maps event names to their payload types
132
165
  */
133
- interface AuthUser {
134
- /** Unique user identifier */
135
- id: string;
136
- /** User email address */
137
- email: string;
138
- /** User role for authorization */
139
- role: string;
140
- /** Optional additional user data */
141
- [key: string]: unknown;
166
+ interface EventPayloadMap {
167
+ 'content.created': ContentEventPayload;
168
+ 'content.updated': ContentEventPayload & {
169
+ changes: FieldChange[];
170
+ };
171
+ 'content.deleted': ContentEventPayload;
172
+ 'content.published': ContentEventPayload;
173
+ 'content.unpublished': ContentEventPayload;
174
+ 'content.version.created': ContentVersionEventPayload;
175
+ 'content.version.restored': ContentVersionEventPayload;
176
+ 'user.created': UserEventPayload;
177
+ 'user.updated': UserEventPayload & {
178
+ changes: string[];
179
+ };
180
+ 'user.deleted': UserEventPayload;
181
+ 'user.registered': UserEventPayload & {
182
+ name?: string;
183
+ };
184
+ 'user.login': UserEventPayload & {
185
+ sessionId?: string;
186
+ };
187
+ 'user.logout': UserEventPayload & {
188
+ sessionId?: string;
189
+ };
190
+ 'user.logout_all': UserEventPayload;
191
+ 'user.password_changed': UserEventPayload;
192
+ 'user.password_reset_requested': UserEventPayload & {
193
+ token?: string;
194
+ plainToken?: string;
195
+ };
196
+ 'user.password_reset': UserEventPayload;
197
+ 'user.password_reset_completed': UserEventPayload;
198
+ 'user.email_verification_requested': UserEventPayload & {
199
+ name?: string;
200
+ verificationToken?: string;
201
+ };
202
+ 'user.email_verified': UserEventPayload;
203
+ 'user.session_revoked': UserEventPayload & {
204
+ sessionId: string;
205
+ };
206
+ 'auth.token_refreshed': AuthEventPayload;
207
+ 'auth.session_created': AuthEventPayload & {
208
+ sessionId: string;
209
+ };
210
+ 'auth.session_revoked': AuthEventPayload & {
211
+ sessionId: string;
212
+ reason: string;
213
+ };
214
+ 'auth.failed_login_attempt': FailedLoginEventPayload;
215
+ 'role.created': RoleEventPayload;
216
+ 'role.updated': RoleEventPayload;
217
+ 'role.deleted': RoleEventPayload;
218
+ 'role.permissions_updated': RoleEventPayload & {
219
+ permissions: string[];
220
+ };
221
+ 'role.user_assigned': RoleEventPayload & {
222
+ assignedUserId: string;
223
+ };
224
+ 'settings.updated': SettingsEventPayload;
225
+ 'settings.group_updated': SettingsGroupEventPayload;
226
+ 'media.uploaded': MediaEventPayload;
227
+ 'media.deleted': MediaEventPayload;
228
+ 'media.folder_created': MediaFolderEventPayload;
229
+ 'media.folder_deleted': MediaFolderEventPayload;
230
+ 'api_key.created': ApiKeyEventPayload;
231
+ 'api_key.revoked': ApiKeyEventPayload & {
232
+ reason?: string;
233
+ };
234
+ 'api_key.used': ApiKeyEventPayload & {
235
+ endpoint: string;
236
+ };
237
+ 'webhook.created': WebhookEventPayload;
238
+ 'webhook.updated': WebhookEventPayload;
239
+ 'webhook.deleted': WebhookEventPayload;
240
+ 'webhook.delivery_success': WebhookDeliveryEventPayload;
241
+ 'webhook.delivery_failed': WebhookDeliveryEventPayload & {
242
+ error: string;
243
+ };
244
+ 'plugin.initialized': PluginEventPayload;
245
+ 'plugin.destroyed': PluginEventPayload;
246
+ 'notification.created': NotificationEventPayload;
247
+ 'system.startup': SystemEventPayload;
248
+ 'system.shutdown': SystemEventPayload;
142
249
  }
143
250
  /**
144
- * Login credentials (strategy-specific)
251
+ * Get payload type for an event name
145
252
  */
146
- interface LoginCredentials {
147
- email: string;
148
- password: string;
149
- [key: string]: unknown;
253
+ type EventPayload<E extends EventName> = EventPayloadMap[E];
254
+ /**
255
+ * Event handler function type
256
+ */
257
+ type EventHandler<E extends EventName> = (payload: EventPayload<E>) => Promise<void> | void;
258
+ /**
259
+ * Event handler options
260
+ */
261
+ interface EventHandlerOptions {
262
+ /** Priority (lower runs first, default 100) */
263
+ priority?: number;
264
+ /** Whether handler should run async (non-blocking) */
265
+ async?: boolean;
266
+ /** Handler name for debugging */
267
+ name?: string;
150
268
  }
151
269
  /**
152
- * Registration data (strategy-specific)
270
+ * Required event handler options (after defaults applied)
153
271
  */
154
- interface RegisterData {
155
- email: string;
156
- password: string;
272
+ interface RequiredEventHandlerOptions {
273
+ priority: number;
274
+ async: boolean;
157
275
  name: string;
158
- role?: string;
159
- [key: string]: unknown;
160
276
  }
161
277
  /**
162
- * Authentication result containing access token
278
+ * Registered handler with metadata
163
279
  */
164
- interface AuthResult {
165
- access_token: string;
166
- refresh_token?: string;
167
- expires_in?: number;
168
- token_type?: string;
280
+ interface RegisteredHandler<E extends EventName> {
281
+ handler: EventHandler<E>;
282
+ options: RequiredEventHandlerOptions;
169
283
  }
170
284
  /**
171
- * JWT-specific configuration
285
+ * Event history entry for debugging
172
286
  */
173
- interface JwtAuthConfig {
174
- /** JWT secret key */
175
- secret: string;
176
- /** Token expiration time (e.g., '7d', '1h') */
177
- expiresIn?: string;
287
+ interface EventHistoryEntry {
288
+ event: EventName;
289
+ payload: BaseEventPayload;
290
+ timestamp: Date;
178
291
  }
179
292
  /**
180
- * Auth configuration for MagnetModuleOptions
293
+ * Event handler metadata (used by @OnEvent decorator)
181
294
  */
182
- interface AuthConfig {
183
- /** Strategy name to use (default: 'jwt') */
184
- strategy?: string;
185
- /** JWT-specific configuration */
186
- jwt?: JwtAuthConfig;
187
- /** Allow extensible config for custom strategies */
188
- [key: string]: unknown;
295
+ interface EventHandlerMetadata {
296
+ event: EventName;
297
+ options: EventHandlerOptions;
189
298
  }
299
+
190
300
  /**
191
- * Abstract base class for authentication strategies.
192
- * Similar to StorageAdapter, custom strategies must extend this class.
301
+ * Metadata key for event handler registration
302
+ */
303
+ declare const EVENT_HANDLER_METADATA = "magnet:event_handler";
304
+ /**
305
+ * Decorator to mark a method as an event handler
306
+ *
307
+ * Event handlers are automatically discovered and registered with the EventService
308
+ * on module initialization.
309
+ *
310
+ * @param event - The event name to listen for
311
+ * @param options - Optional handler configuration
193
312
  *
194
313
  * @example
195
314
  * ```typescript
196
- * export class SupabaseAuthStrategy extends AuthStrategy {
197
- * readonly name = 'supabase'
198
- *
199
- * async validate(payload: unknown): Promise<AuthUser | null> {
200
- * // Validate Supabase JWT token
201
- * }
202
- *
203
- * async login(credentials: LoginCredentials): Promise<AuthResult> {
204
- * // Authenticate with Supabase
205
- * }
206
- *
207
- * async register(data: RegisterData): Promise<AuthUser> {
208
- * // Register user in Supabase
315
+ * @Injectable()
316
+ * export class ActivityService {
317
+ * @OnEvent('content.created', { priority: 10 })
318
+ * async logContentCreated(payload: EventPayload<'content.created'>): Promise<void> {
319
+ * await this.createActivityLog(payload)
209
320
  * }
210
321
  *
211
- * async validateCredentials(email: string, password: string): Promise<AuthUser | null> {
212
- * // Validate user credentials
322
+ * // Async handlers run in the background and don't block the request
323
+ * @OnEvent('user.login', { priority: 50, async: true })
324
+ * async sendWelcomeEmail(payload: EventPayload<'user.login'>): Promise<void> {
325
+ * await this.emailService.sendWelcome(payload.targetUserId)
213
326
  * }
214
327
  * }
215
328
  * ```
216
329
  */
217
- declare abstract class AuthStrategy {
218
- /**
219
- * Unique identifier for this strategy
220
- */
221
- abstract readonly name: string;
222
- /**
223
- * Initialize the auth strategy (optional setup)
224
- */
225
- initialize?(): Promise<void>;
226
- /**
227
- * Validate a token/payload and return the authenticated user
228
- * @param payload - Strategy-specific payload (e.g., JWT payload, session data)
229
- * @returns Authenticated user or null if invalid
230
- */
231
- abstract validate(payload: unknown): Promise<AuthUser | null>;
232
- /**
233
- * Authenticate user with credentials and return tokens
234
- * @param credentials - Login credentials (strategy-specific)
235
- * @returns Authentication result with access token
236
- */
237
- abstract login(credentials: LoginCredentials): Promise<AuthResult>;
238
- /**
239
- * Register a new user
240
- * @param data - Registration data
241
- * @returns The created user
242
- */
243
- abstract register(data: RegisterData): Promise<AuthUser>;
244
- /**
245
- * Validate user credentials (used internally by login)
246
- * @param email - User email
247
- * @param password - User password
248
- * @returns User if valid, null otherwise
249
- */
250
- abstract validateCredentials(email: string, password: string): Promise<AuthUser | null>;
251
- /**
252
- * Refresh an access token (optional)
253
- * @param refreshToken - The refresh token
254
- * @returns New authentication result
255
- */
256
- refresh?(refreshToken: string): Promise<AuthResult>;
257
- /**
258
- * Logout/invalidate tokens (optional)
259
- * @param token - The token to invalidate
260
- */
261
- logout?(token: string): Promise<void>;
262
- /**
263
- * Get the Passport strategy name (for guards)
264
- * Returns the name to use with AuthGuard()
265
- */
266
- getPassportStrategyName(): string;
267
- }
268
-
269
- type MongooseConfig = {
270
- uri: string;
271
- };
272
- type TypeORMConfig = {
273
- type: 'mysql' | 'postgres' | 'sqlite' | 'mariadb' | 'mssql' | 'oracle' | 'mongodb';
274
- host: string;
275
- port: number;
276
- username: string;
277
- password: string;
278
- database: string;
279
- };
280
- type DBConfig = MongooseConfig | TypeORMConfig;
281
- declare abstract class DatabaseAdapter {
282
- abstract connect(options: MagnetModuleOptions): DynamicModule;
283
- abstract forFeature(schemas: Type | Type[]): DynamicModule;
284
- abstract model<T>(modelInstance: any): any;
285
- abstract token(schema: string): string;
286
- }
330
+ declare function OnEvent(event: EventName, options?: EventHandlerOptions): MethodDecorator;
287
331
 
288
332
  /**
289
- * Plugin metadata for the @Plugin decorator
333
+ * Base options shared by all field decorators
290
334
  */
291
- interface PluginMetadata {
292
- /** Unique plugin identifier (e.g., 'content-builder') */
293
- name: string;
294
- /** Human-readable description */
335
+ interface BaseFieldOptions {
336
+ /** Field is required */
337
+ required?: boolean;
338
+ /** Field must be unique */
339
+ unique?: boolean;
340
+ /** Default value */
341
+ default?: unknown;
342
+ /** Admin UI tab placement */
343
+ tab?: string;
344
+ /** Admin UI group within tab */
345
+ group?: string;
346
+ /** Field label in admin UI */
347
+ label?: string;
348
+ /** Field description/help text */
295
349
  description?: string;
296
- /** Semver version */
297
- version?: string;
298
- /** Plugin dependencies (other plugin names) */
299
- dependencies?: string[];
300
- /** NestJS module to be auto-imported (optional for backwards compatibility) */
301
- module?: Type<unknown>;
350
+ /** Field placeholder text */
351
+ placeholder?: string;
352
+ /** Hide field in admin UI */
353
+ hidden?: boolean;
354
+ /** Make field read-only in admin UI */
355
+ readonly?: boolean;
356
+ /** Field display order */
357
+ order?: number;
358
+ /** Show field in sidebar (instead of main content area) */
359
+ side?: boolean;
360
+ /** Display fields in a row layout */
361
+ row?: boolean;
362
+ /** Enable internationalization for this field */
363
+ intl?: boolean;
302
364
  }
303
365
  /**
304
- * Route definition for plugin frontend
366
+ * Text field options
305
367
  */
306
- interface PluginRouteDefinition {
307
- /** Route path (e.g., '/playground') */
308
- path: string;
309
- /** Component identifier for lazy loading */
310
- componentId: string;
311
- /** Whether route requires authentication */
312
- requiresAuth?: boolean;
313
- /** Required permissions */
314
- permissions?: string[];
315
- /** Child routes */
316
- children?: PluginRouteDefinition[];
368
+ interface TextFieldOptions extends BaseFieldOptions {
369
+ minLength?: number;
370
+ maxLength?: number;
371
+ pattern?: string;
372
+ transform?: 'none' | 'lowercase' | 'uppercase' | 'trim';
317
373
  }
318
374
  /**
319
- * Sidebar item for plugin frontend
375
+ * Number field options
320
376
  */
321
- interface PluginSidebarItem {
322
- /** Unique identifier */
323
- id: string;
324
- /** Display title */
325
- title: string;
326
- /** Route path */
327
- url: string;
328
- /** Lucide icon name (e.g., 'Boxes', 'Settings') */
329
- icon: string;
330
- /** Position in sidebar (lower = higher) */
331
- order?: number;
332
- /** Child items */
333
- items?: PluginSidebarItem[];
334
- /** Badge to show */
335
- badge?: string | number;
377
+ interface NumberFieldOptions extends BaseFieldOptions {
378
+ min?: number;
379
+ max?: number;
380
+ integer?: boolean;
381
+ step?: number;
382
+ default?: number;
336
383
  }
337
384
  /**
338
- * Settings page for plugin
385
+ * Boolean field options
339
386
  */
340
- interface PluginSettingsPage {
341
- /** Settings group identifier */
342
- groupId: string;
343
- /** Display title */
344
- title: string;
345
- /** Description */
346
- description?: string;
347
- /** Component identifier */
348
- componentId: string;
387
+ interface BooleanFieldOptions extends BaseFieldOptions {
388
+ default?: boolean;
389
+ style?: 'switch' | 'checkbox';
349
390
  }
350
391
  /**
351
- * Frontend manifest exposed by plugins via discovery
392
+ * Date field options
352
393
  */
353
- interface PluginFrontendManifest {
354
- /** Plugin identifier */
355
- pluginName: string;
356
- /** Routes to register */
357
- routes?: PluginRouteDefinition[];
358
- /** Sidebar items */
359
- sidebar?: PluginSidebarItem[];
360
- /** Settings pages */
361
- settings?: PluginSettingsPage[];
362
- /** Required permissions */
363
- permissions?: string[];
394
+ interface DateFieldOptions extends BaseFieldOptions {
395
+ min?: Date | string;
396
+ max?: Date | string;
397
+ default?: Date | string | 'now' | (() => Date);
364
398
  }
365
399
  /**
366
- * Enriched plugin manifest with bundle URL for runtime loading
367
- * Returned by GET /plugins/manifests endpoint
400
+ * DateTime field options
368
401
  */
369
- interface EnrichedPluginManifest extends PluginFrontendManifest {
370
- /** URL to load the plugin's frontend bundle */
371
- bundleUrl: string;
402
+ interface DateTimeFieldOptions extends DateFieldOptions {
403
+ timezone?: string;
372
404
  }
373
405
  /**
374
- * Plugin configuration passed to MagnetModule.forRoot
406
+ * Rich text field options
375
407
  */
376
- interface PluginConfig {
377
- /** The plugin class decorated with @Plugin */
378
- plugin: Type<unknown>;
379
- /** Plugin-specific options */
380
- options?: Record<string, unknown>;
381
- /** Whether the plugin is enabled (default: true) */
382
- enabled?: boolean;
408
+ interface RichTextFieldOptions extends BaseFieldOptions {
409
+ toolbar?: 'minimal' | 'standard' | 'full';
410
+ maxLength?: number;
383
411
  }
384
412
  /**
385
- * Hook definition for plugins
413
+ * Markdown field options
386
414
  */
387
- interface PluginHook {
388
- instance: unknown;
389
- methodName: string | symbol;
415
+ interface MarkdownFieldOptions extends BaseFieldOptions {
416
+ preview?: boolean;
417
+ maxLength?: number;
390
418
  }
391
419
  /**
392
- * Options for PluginModule.forRoot
420
+ * Code field options
393
421
  */
394
- interface PluginModuleOptions {
395
- plugins: PluginConfig[];
422
+ interface CodeFieldOptions extends BaseFieldOptions {
423
+ language?: string;
424
+ lineNumbers?: boolean;
396
425
  }
397
426
  /**
398
- * Registered plugin info returned from API
427
+ * JSON field options
399
428
  */
400
- interface RegisteredPluginInfo {
401
- name: string;
402
- description?: string;
403
- version?: string;
404
- dependencies?: string[];
405
- frontend?: PluginFrontendManifest;
406
- options?: Record<string, unknown>;
429
+ interface JSONFieldOptions extends BaseFieldOptions {
430
+ /** Optional JSON schema for validation */
431
+ schema?: unknown;
407
432
  }
408
433
  /**
409
- * Interface for plugin lifecycle hooks.
410
- * Plugins can implement these methods to respond to lifecycle events.
411
- *
412
- * @example
413
- * ```ts
414
- * @Plugin({ name: 'my-plugin', module: MyPluginModule })
415
- * export class MyPlugin implements PluginLifecycle {
416
- * onPluginInit() {
417
- * console.log('Plugin initialized')
418
- * }
419
- *
420
- * onPluginDestroy() {
421
- * console.log('Plugin destroyed')
422
- * }
423
- * }
424
- * ```
434
+ * Select option item
425
435
  */
426
- interface PluginLifecycle {
427
- /**
428
- * Called after the plugin module is initialized.
429
- * Use this for plugin-specific setup that needs other services.
430
- */
431
- onPluginInit?(): void | Promise<void>;
432
- /**
433
- * Called when the application is shutting down.
434
- * Use this for cleanup operations.
435
- */
436
- onPluginDestroy?(): void | Promise<void>;
436
+ interface SelectOptionItem {
437
+ label: string;
438
+ value: string | number;
437
439
  }
438
-
439
- interface LocalStorageConfig {
440
- /** Directory where files will be stored (e.g., './uploads') */
441
- uploadDir: string;
442
- /** Public URL path for serving files (e.g., '/media') */
443
- publicPath: string;
444
- /** Maximum file size in bytes (default: 50MB) */
445
- maxFileSize?: number;
446
- /** Allowed MIME types (default: all) */
447
- allowedMimeTypes?: string[];
440
+ /**
441
+ * Select field options
442
+ */
443
+ interface SelectFieldOptions extends BaseFieldOptions {
444
+ options: ReadonlyArray<SelectOptionItem> | ReadonlyArray<string | number>;
445
+ default?: string | number | (string | number)[];
446
+ multiple?: boolean;
448
447
  }
449
- interface S3StorageConfig {
450
- /** S3 bucket name */
451
- bucket: string;
452
- /** AWS region */
453
- region: string;
454
- /** AWS access key ID */
455
- accessKeyId: string;
456
- /** AWS secret access key */
457
- secretAccessKey: string;
458
- /** Custom endpoint URL (for R2, MinIO, etc.) */
459
- endpoint?: string;
460
- /** Public URL for serving files (CDN URL) */
461
- publicUrl?: string;
462
- /** Enable path-style access (required for some S3-compatible services) */
463
- forcePathStyle?: boolean;
448
+ /**
449
+ * Enum field options - generic preserves enum type
450
+ */
451
+ interface EnumFieldOptions<E extends Record<string, string | number> = Record<string, string | number>> extends BaseFieldOptions {
452
+ enum: E;
453
+ default?: E[keyof E];
454
+ multiple?: boolean;
464
455
  }
465
- interface R2StorageConfig extends S3StorageConfig {
466
- /** Cloudflare account ID */
467
- accountId: string;
456
+ /**
457
+ * Tags field options
458
+ */
459
+ interface TagsFieldOptions extends BaseFieldOptions {
460
+ suggestions?: string[];
461
+ maxTags?: number;
462
+ allowCreate?: boolean;
468
463
  }
469
- interface StorageConfig {
470
- /** Storage adapter to use */
471
- adapter: 'local' | 's3' | 'r2';
472
- /** Local storage configuration */
473
- local?: LocalStorageConfig;
474
- /** S3 storage configuration */
475
- s3?: S3StorageConfig;
476
- /** R2 storage configuration */
477
- r2?: R2StorageConfig;
464
+ /**
465
+ * Relationship field options
466
+ */
467
+ interface RelationshipFieldOptions extends BaseFieldOptions {
468
+ /** Reference schema name */
469
+ ref: string;
470
+ /** Allow multiple selections */
471
+ multiple?: boolean;
472
+ /** Fields to display in selection */
473
+ displayFields?: string[];
478
474
  }
479
- interface UploadOptions {
480
- /** Target folder for the file */
475
+ /**
476
+ * Image field options
477
+ */
478
+ interface ImageFieldOptions extends BaseFieldOptions {
481
479
  folder?: string;
482
- /** Custom filename (auto-generated if not provided) */
483
- filename?: string;
484
- /** MIME type of the file */
485
- mimeType?: string;
486
- /** Tags for categorization */
487
- tags?: string[];
488
- /** Alt text for accessibility */
489
- alt?: string;
490
- /** Custom metadata fields */
491
- customFields?: Record<string, unknown>;
480
+ maxSize?: number;
481
+ formats?: ReadonlyArray<'jpg' | 'jpeg' | 'png' | 'gif' | 'webp' | 'svg'>;
482
+ dimensions?: {
483
+ minWidth?: number;
484
+ maxWidth?: number;
485
+ minHeight?: number;
486
+ maxHeight?: number;
487
+ };
488
+ }
489
+ /**
490
+ * File field options
491
+ */
492
+ interface FileFieldOptions extends BaseFieldOptions {
493
+ folder?: string;
494
+ maxSize?: number;
495
+ accept?: string[];
496
+ }
497
+ /**
498
+ * Gallery field options
499
+ */
500
+ interface GalleryFieldOptions extends ImageFieldOptions {
501
+ maxItems?: number;
502
+ }
503
+ /**
504
+ * Slug field options
505
+ */
506
+ interface SlugFieldOptions extends BaseFieldOptions {
507
+ /** Field to generate slug from */
508
+ from: string;
509
+ unique?: boolean;
510
+ }
511
+ /**
512
+ * Email field options
513
+ */
514
+ interface EmailFieldOptions extends BaseFieldOptions {
515
+ pattern?: string;
516
+ }
517
+ /**
518
+ * URL field options
519
+ */
520
+ interface URLFieldOptions extends BaseFieldOptions {
521
+ protocols?: string[];
522
+ }
523
+ /**
524
+ * Phone field options
525
+ */
526
+ interface PhoneFieldOptions extends BaseFieldOptions {
527
+ defaultCountry?: string;
528
+ }
529
+ /**
530
+ * Address field options
531
+ */
532
+ interface AddressFieldOptions extends BaseFieldOptions {
533
+ provider?: 'google' | 'mapbox' | 'none';
534
+ }
535
+ /**
536
+ * Color field options
537
+ */
538
+ interface ColorFieldOptions extends BaseFieldOptions {
539
+ format?: 'hex' | 'rgb' | 'hsl';
540
+ presets?: string[];
541
+ }
542
+ /**
543
+ * Object field options
544
+ */
545
+ interface ObjectFieldOptions extends BaseFieldOptions {
546
+ /** Optional schema for validation */
547
+ schema?: unknown;
548
+ }
549
+ /**
550
+ * All field type identifiers
551
+ */
552
+ type FieldTypeId = 'text' | 'number' | 'boolean' | 'date' | 'datetime' | 'richtext' | 'markdown' | 'code' | 'json' | 'select' | 'enum' | 'tags' | 'image' | 'file' | 'gallery' | 'slug' | 'email' | 'url' | 'phone' | 'address' | 'color' | 'object' | 'array' | 'blocks' | 'relationship' | 'textarea';
553
+ /**
554
+ * Field type definition for array items
555
+ */
556
+ interface ArrayItemType {
557
+ type: FieldTypeId;
558
+ options?: BaseFieldOptions;
559
+ }
560
+ /**
561
+ * Array field options - generic preserves item type
562
+ */
563
+ interface ArrayFieldOptions extends BaseFieldOptions {
564
+ of: ArrayItemType;
565
+ minItems?: number;
566
+ maxItems?: number;
567
+ }
568
+ /**
569
+ * Block type definition
570
+ */
571
+ interface BlockTypeDefinition {
572
+ name: string;
573
+ label: string;
574
+ fields: Record<string, FieldTypeId>;
575
+ }
576
+ /**
577
+ * Blocks field options
578
+ */
579
+ interface BlocksFieldOptions extends BaseFieldOptions {
580
+ types: string[];
581
+ maxBlocks?: number;
582
+ }
583
+ /**
584
+ * Textarea field options
585
+ */
586
+ interface TextareaFieldOptions extends BaseFieldOptions {
587
+ minLength?: number;
588
+ maxLength?: number;
589
+ rows?: number;
590
+ }
591
+ /**
592
+ * Field metadata stored via reflection
593
+ */
594
+ interface FieldMetadata<T extends BaseFieldOptions = BaseFieldOptions> {
595
+ /** Field type identifier */
596
+ type: FieldTypeId;
597
+ /** Typed options for this field */
598
+ options: T;
599
+ /** Property key */
600
+ propertyKey: string | symbol;
601
+ /** Target class */
602
+ target: Type<unknown>;
603
+ /** Design type from TypeScript metadata */
604
+ designType?: unknown;
605
+ }
606
+ /**
607
+ * Map of field type IDs to their option interfaces
608
+ */
609
+ interface FieldOptionsMap {
610
+ text: TextFieldOptions;
611
+ number: NumberFieldOptions;
612
+ boolean: BooleanFieldOptions;
613
+ date: DateFieldOptions;
614
+ datetime: DateTimeFieldOptions;
615
+ richtext: RichTextFieldOptions;
616
+ markdown: MarkdownFieldOptions;
617
+ code: CodeFieldOptions;
618
+ json: JSONFieldOptions;
619
+ select: SelectFieldOptions;
620
+ enum: EnumFieldOptions;
621
+ tags: TagsFieldOptions;
622
+ image: ImageFieldOptions;
623
+ file: FileFieldOptions;
624
+ gallery: GalleryFieldOptions;
625
+ slug: SlugFieldOptions;
626
+ email: EmailFieldOptions;
627
+ url: URLFieldOptions;
628
+ phone: PhoneFieldOptions;
629
+ address: AddressFieldOptions;
630
+ color: ColorFieldOptions;
631
+ object: ObjectFieldOptions;
632
+ array: ArrayFieldOptions;
633
+ blocks: BlocksFieldOptions;
634
+ relationship: RelationshipFieldOptions;
635
+ textarea: TextareaFieldOptions;
636
+ }
637
+ /**
638
+ * Type guard to check if a value is a FieldMetadata
639
+ */
640
+ declare function isFieldMetadata(value: unknown): value is FieldMetadata;
641
+ /**
642
+ * Type guard to check if field type is valid
643
+ */
644
+ declare function isValidFieldType(type: unknown): type is FieldTypeId;
645
+
646
+ /**
647
+ * Type-safe field decorator factory.
648
+ *
649
+ * Creates a property decorator that:
650
+ * 1. Stores field metadata under FIELD_METADATA_KEY
651
+ * 2. Emits legacy Prop metadata for backwards compatibility
652
+ * 3. Emits legacy UI metadata for backwards compatibility
653
+ * 4. Applies the adapter-specific Prop decorator
654
+ *
655
+ * @param type - The field type identifier
656
+ * @param defaultOptions - Default options to merge with user-provided options
657
+ * @returns A function that creates a PropertyDecorator
658
+ */
659
+ declare function createFieldDecorator<T extends BaseFieldOptions>(type: FieldTypeId, defaultOptions?: Partial<T>): (options?: T) => PropertyDecorator;
660
+ /**
661
+ * Get all field metadata for a class.
662
+ *
663
+ * @param target - The class constructor
664
+ * @returns Array of field metadata entries
665
+ */
666
+ declare function getFieldMetadata(target: Type<unknown>): FieldMetadata[];
667
+ /**
668
+ * Get field metadata for a specific property.
669
+ *
670
+ * @param target - The class constructor
671
+ * @param propertyKey - The property name
672
+ * @returns The field metadata or undefined
673
+ */
674
+ declare function getFieldMetadataForProperty(target: Type<unknown>, propertyKey: string | symbol): FieldMetadata | undefined;
675
+
676
+ type ResolverOptions = {
677
+ schema: Type;
678
+ };
679
+ type ResolverInput = (() => Type) | ResolverOptions;
680
+ type ResolveOptions = {
681
+ type: Type | Type[];
682
+ isArray?: boolean;
683
+ description?: string;
684
+ };
685
+ type ResolveInput = (() => Type | Type[]) | (() => Type)[] | ResolveOptions;
686
+ /**
687
+ * Property default value - can be a primitive, object, array, or factory function
688
+ */
689
+ type PropDefaultValue = string | number | boolean | null | Record<string, unknown> | unknown[] | (() => unknown);
690
+ type PropOptions = {
691
+ type?: Type | Type[];
692
+ description?: string;
693
+ required?: boolean;
694
+ unique?: boolean;
695
+ default?: PropDefaultValue;
696
+ nullable?: boolean;
697
+ intl?: boolean;
698
+ hidden?: boolean;
699
+ readonly?: boolean;
700
+ ref?: string;
701
+ };
702
+ type BaseSchemaOptions = {
703
+ timestamps?: boolean;
704
+ };
705
+ type SchemaIndexOption = {
706
+ keys: Record<string, 1 | -1>;
707
+ unique?: boolean;
708
+ };
709
+ type SchemaOptions = {
710
+ versioning?: boolean;
711
+ i18n?: boolean;
712
+ /**
713
+ * Whether the schema is visible in the Content Manager.
714
+ * Set to false for system schemas that have dedicated admin pages.
715
+ * @default true
716
+ */
717
+ visible?: boolean;
718
+ /**
719
+ * Compound indexes (adapter-specific).
720
+ * Mongoose: schema.index(keys, { unique })
721
+ */
722
+ indexes?: SchemaIndexOption[];
723
+ };
724
+
725
+ /**
726
+ * Map field type and options to legacy Prop decorator options.
727
+ * This ensures backwards compatibility with existing adapters.
728
+ */
729
+ declare function mapFieldTypeToProp(type: FieldTypeId, options: BaseFieldOptions): PropOptions;
730
+
731
+ type UIPresentationFields = 'tab' | 'collapsible' | 'row' | 'customUI';
732
+ type UITypes = 'array' | 'blocks' | 'checkbox' | 'code' | 'combobox' | 'date' | 'email' | 'fileUpload' | 'group' | 'json' | 'multiSelect' | 'number' | 'phone' | 'point' | 'quantity' | 'radio' | 'relationship' | 'richText' | 'select' | 'switch' | 'table' | 'text' | 'textarea' | 'upload';
733
+ type UIBase = {
734
+ label?: string;
735
+ description?: string;
736
+ placeholder?: string;
737
+ type?: UITypes;
738
+ row?: boolean;
739
+ collapsible?: boolean;
740
+ };
741
+ type UISelectItem = {
742
+ key: string;
743
+ value: string;
744
+ };
745
+ type UITab = UIBase & {
746
+ tab: string;
747
+ side?: never;
748
+ options?: UISelectItem[];
749
+ };
750
+ type UISide = UIBase & {
751
+ side: true;
752
+ tab?: never;
753
+ options?: UISelectItem[];
754
+ };
755
+ type UISelect = UIBase & {
756
+ type: 'select';
757
+ multi?: boolean;
758
+ options: UISelectItem[];
759
+ };
760
+ type UIMultiSelect = UIBase & {
761
+ type: 'multiSelect';
762
+ options: UISelectItem[];
763
+ };
764
+ type UICombobox = UIBase & {
765
+ type: 'combobox';
766
+ options: UISelectItem[];
767
+ };
768
+ type UITableColumn = {
769
+ key: string;
770
+ header: string;
771
+ type?: 'text' | 'badge' | 'status' | 'input' | 'code';
772
+ };
773
+ type UITable = UIBase & {
774
+ type: 'table';
775
+ columns?: UITableColumn[];
776
+ };
777
+ type UIDecoratorOptions = UITab | UISide | UISelect | UIMultiSelect | UICombobox | UITable;
778
+
779
+ /**
780
+ * Map field type and options to legacy UI decorator options.
781
+ * This ensures backwards compatibility with existing admin UI.
782
+ */
783
+ declare function mapFieldTypeToUI(type: FieldTypeId, options: BaseFieldOptions): UIDecoratorOptions;
784
+
785
+ /**
786
+ * Field decorator namespace with full type safety.
787
+ *
788
+ * Each decorator combines @Prop and @UI functionality into a single,
789
+ * semantic decorator. Validation remains explicit via Field.Validators().
790
+ *
791
+ * @example
792
+ * ```typescript
793
+ * @Schema({ slug: 'posts' })
794
+ * export class Post {
795
+ * @Field.Text({ required: true, tab: 'General' })
796
+ * @Field.Validators(IsString(), Length(1, 200))
797
+ * title: string
798
+ *
799
+ * @Field.Slug({ from: 'title', unique: true })
800
+ * slug: string
801
+ *
802
+ * @Field.RichText({ toolbar: 'full' })
803
+ * content?: string
804
+ *
805
+ * @Field.Relationship({ ref: 'users', multiple: false })
806
+ * author: string
807
+ * }
808
+ * ```
809
+ */
810
+ declare const Field: {
811
+ /**
812
+ * Text field - single line text input
813
+ *
814
+ * @example
815
+ * ```typescript
816
+ * @Field.Text({ required: true, maxLength: 200 })
817
+ * title: string
818
+ * ```
819
+ */
820
+ readonly Text: (options?: TextFieldOptions | undefined) => PropertyDecorator;
821
+ /**
822
+ * Number field - numeric input
823
+ *
824
+ * @example
825
+ * ```typescript
826
+ * @Field.Number({ min: 0, max: 100, integer: true })
827
+ * quantity: number
828
+ * ```
829
+ */
830
+ readonly Number: (options?: NumberFieldOptions | undefined) => PropertyDecorator;
831
+ /**
832
+ * Boolean field - true/false toggle
833
+ *
834
+ * @example
835
+ * ```typescript
836
+ * @Field.Boolean({ default: false, style: 'switch' })
837
+ * isPublished: boolean
838
+ * ```
839
+ */
840
+ readonly Boolean: (options?: BooleanFieldOptions | undefined) => PropertyDecorator;
841
+ /**
842
+ * Date field - date picker (without time)
843
+ *
844
+ * @example
845
+ * ```typescript
846
+ * @Field.Date({ min: '2024-01-01' })
847
+ * publishDate: Date
848
+ * ```
849
+ */
850
+ readonly Date: (options?: DateFieldOptions | undefined) => PropertyDecorator;
851
+ /**
852
+ * DateTime field - date and time picker
853
+ *
854
+ * @example
855
+ * ```typescript
856
+ * @Field.DateTime({ timezone: 'UTC' })
857
+ * scheduledAt: Date
858
+ * ```
859
+ */
860
+ readonly DateTime: (options?: DateTimeFieldOptions | undefined) => PropertyDecorator;
861
+ /**
862
+ * RichText field - WYSIWYG editor
863
+ *
864
+ * @example
865
+ * ```typescript
866
+ * @Field.RichText({ toolbar: 'full' })
867
+ * content: string
868
+ * ```
869
+ */
870
+ readonly RichText: (options?: RichTextFieldOptions | undefined) => PropertyDecorator;
871
+ /**
872
+ * Markdown field - markdown editor with preview
873
+ *
874
+ * @example
875
+ * ```typescript
876
+ * @Field.Markdown({ preview: true })
877
+ * description: string
878
+ * ```
879
+ */
880
+ readonly Markdown: (options?: MarkdownFieldOptions | undefined) => PropertyDecorator;
881
+ /**
882
+ * Code field - code editor with syntax highlighting
883
+ *
884
+ * @example
885
+ * ```typescript
886
+ * @Field.Code({ language: 'typescript' })
887
+ * snippet: string
888
+ * ```
889
+ */
890
+ readonly Code: (options?: CodeFieldOptions | undefined) => PropertyDecorator;
891
+ /**
892
+ * JSON field - JSON editor
893
+ *
894
+ * @example
895
+ * ```typescript
896
+ * @Field.JSON()
897
+ * metadata: Record<string, unknown>
898
+ * ```
899
+ */
900
+ readonly JSON: (options?: JSONFieldOptions | undefined) => PropertyDecorator;
901
+ /**
902
+ * Textarea field - multi-line text input
903
+ *
904
+ * @example
905
+ * ```typescript
906
+ * @Field.Textarea({ rows: 5 })
907
+ * summary: string
908
+ * ```
909
+ */
910
+ readonly Textarea: (options?: TextareaFieldOptions | undefined) => PropertyDecorator;
911
+ /**
912
+ * Select field - dropdown selection
913
+ *
914
+ * @example
915
+ * ```typescript
916
+ * @Field.Select({
917
+ * options: [
918
+ * { label: 'Draft', value: 'draft' },
919
+ * { label: 'Published', value: 'published' }
920
+ * ],
921
+ * default: 'draft'
922
+ * })
923
+ * status: string
924
+ * ```
925
+ */
926
+ readonly Select: (options: SelectFieldOptions) => PropertyDecorator;
927
+ /**
928
+ * Enum field - dropdown from TypeScript enum
929
+ *
930
+ * @example
931
+ * ```typescript
932
+ * enum Status { Draft = 'draft', Published = 'published' }
933
+ *
934
+ * @Field.Enum({ enum: Status, default: Status.Draft })
935
+ * status: Status
936
+ * ```
937
+ */
938
+ readonly Enum: <E extends Record<string, string | number>>(options: EnumFieldOptions<E>) => PropertyDecorator;
939
+ /**
940
+ * Tags field - multi-value tag input
941
+ *
942
+ * @example
943
+ * ```typescript
944
+ * @Field.Tags({ suggestions: ['tech', 'news'], maxTags: 5 })
945
+ * tags: string[]
946
+ * ```
947
+ */
948
+ readonly Tags: (options?: TagsFieldOptions | undefined) => PropertyDecorator;
949
+ /**
950
+ * Image field - single image upload
951
+ *
952
+ * @example
953
+ * ```typescript
954
+ * @Field.Image({ folder: 'covers', formats: ['jpg', 'png', 'webp'] })
955
+ * coverImage: string
956
+ * ```
957
+ */
958
+ readonly Image: (options?: ImageFieldOptions | undefined) => PropertyDecorator;
959
+ /**
960
+ * File field - single file upload
961
+ *
962
+ * @example
963
+ * ```typescript
964
+ * @Field.File({ folder: 'documents', accept: ['application/pdf'] })
965
+ * attachment: string
966
+ * ```
967
+ */
968
+ readonly File: (options?: FileFieldOptions | undefined) => PropertyDecorator;
969
+ /**
970
+ * Gallery field - multiple image upload
971
+ *
972
+ * @example
973
+ * ```typescript
974
+ * @Field.Gallery({ maxItems: 10 })
975
+ * images: string[]
976
+ * ```
977
+ */
978
+ readonly Gallery: (options?: GalleryFieldOptions | undefined) => PropertyDecorator;
979
+ /**
980
+ * Slug field - auto-generated URL-friendly string
981
+ *
982
+ * @example
983
+ * ```typescript
984
+ * @Field.Slug({ from: 'title', unique: true })
985
+ * slug: string
986
+ * ```
987
+ */
988
+ readonly Slug: (options?: SlugFieldOptions | undefined) => PropertyDecorator;
989
+ /**
990
+ * Email field - email input with validation pattern
991
+ *
992
+ * @example
993
+ * ```typescript
994
+ * @Field.Email({ required: true })
995
+ * @Field.Validators(IsEmail())
996
+ * email: string
997
+ * ```
998
+ */
999
+ readonly Email: (options?: EmailFieldOptions | undefined) => PropertyDecorator;
1000
+ /**
1001
+ * URL field - URL input
1002
+ *
1003
+ * @example
1004
+ * ```typescript
1005
+ * @Field.URL({ protocols: ['https'] })
1006
+ * @Field.Validators(IsUrl())
1007
+ * website: string
1008
+ * ```
1009
+ */
1010
+ readonly URL: (options?: URLFieldOptions | undefined) => PropertyDecorator;
1011
+ /**
1012
+ * Phone field - phone number input
1013
+ *
1014
+ * @example
1015
+ * ```typescript
1016
+ * @Field.Phone({ defaultCountry: 'US' })
1017
+ * phone: string
1018
+ * ```
1019
+ */
1020
+ readonly Phone: (options?: PhoneFieldOptions | undefined) => PropertyDecorator;
1021
+ /**
1022
+ * Address field - address input with optional geocoding
1023
+ *
1024
+ * @example
1025
+ * ```typescript
1026
+ * @Field.Address({ provider: 'google' })
1027
+ * address: string
1028
+ * ```
1029
+ */
1030
+ readonly Address: (options?: AddressFieldOptions | undefined) => PropertyDecorator;
1031
+ /**
1032
+ * Color field - color picker
1033
+ *
1034
+ * @example
1035
+ * ```typescript
1036
+ * @Field.Color({ format: 'hex', presets: ['#ff0000', '#00ff00'] })
1037
+ * brandColor: string
1038
+ * ```
1039
+ */
1040
+ readonly Color: (options?: ColorFieldOptions | undefined) => PropertyDecorator;
1041
+ /**
1042
+ * Object field - nested object structure
1043
+ *
1044
+ * @example
1045
+ * ```typescript
1046
+ * @Field.Object()
1047
+ * metadata: { key: string; value: string }
1048
+ * ```
1049
+ */
1050
+ readonly Object: (options?: ObjectFieldOptions | undefined) => PropertyDecorator;
1051
+ /**
1052
+ * Array field - array of items
1053
+ *
1054
+ * @example
1055
+ * ```typescript
1056
+ * @Field.Array({ of: { type: 'text' }, maxItems: 10 })
1057
+ * items: string[]
1058
+ * ```
1059
+ */
1060
+ readonly Array: (options: ArrayFieldOptions) => PropertyDecorator;
1061
+ /**
1062
+ * Blocks field - flexible content blocks
1063
+ *
1064
+ * @example
1065
+ * ```typescript
1066
+ * @Field.Blocks({ types: ['paragraph', 'image', 'quote'] })
1067
+ * content: Block[]
1068
+ * ```
1069
+ */
1070
+ readonly Blocks: (options?: BlocksFieldOptions | undefined) => PropertyDecorator;
1071
+ /**
1072
+ * Relationship field - reference to another schema
1073
+ *
1074
+ * @example
1075
+ * ```typescript
1076
+ * @Field.Relationship({ ref: 'users', multiple: false })
1077
+ * author: string
1078
+ *
1079
+ * @Field.Relationship({ ref: 'categories', multiple: true })
1080
+ * categories: string[]
1081
+ * ```
1082
+ */
1083
+ readonly Relationship: (options?: RelationshipFieldOptions | undefined) => PropertyDecorator;
1084
+ /**
1085
+ * Validators - apply class-validator decorators
1086
+ *
1087
+ * This is an alias for the existing @Validators decorator,
1088
+ * keeping validation explicit and using familiar class-validator syntax.
1089
+ *
1090
+ * @example
1091
+ * ```typescript
1092
+ * @Field.Text({ required: true })
1093
+ * @Field.Validators(IsString(), Length(1, 200), IsNotEmpty())
1094
+ * title: string
1095
+ * ```
1096
+ */
1097
+ readonly Validators: (...validators: PropertyDecorator[]) => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
1098
+ };
1099
+ /**
1100
+ * Type for the Field namespace
1101
+ */
1102
+ type FieldNamespace = typeof Field;
1103
+
1104
+ /**
1105
+ * Role-Based Access Control (RBAC) Type Definitions
1106
+ *
1107
+ * Type-safe permission and role management system.
1108
+ * Used by: Permission guards, Role service, Admin UI permission matrix
1109
+ */
1110
+ /**
1111
+ * Permission source - where the permission was discovered from
1112
+ */
1113
+ type PermissionSource = 'schema' | 'controller' | 'plugin' | 'manual';
1114
+ /**
1115
+ * Permission definition - represents a single permission in the system
1116
+ */
1117
+ interface PermissionDefinition {
1118
+ /** Unique permission identifier (e.g., 'content.posts.create') */
1119
+ id: string;
1120
+ /** Human-readable name */
1121
+ name: string;
1122
+ /** Description for admin UI */
1123
+ description?: string;
1124
+ /** Group for organization (e.g., 'Content', 'Users', 'Settings') */
1125
+ group?: string;
1126
+ /** Schema name if auto-generated from schema */
1127
+ schema?: string;
1128
+ /** API identifier (e.g., 'api::posts', 'plugin::playground') */
1129
+ apiId?: string;
1130
+ /** Source of this permission */
1131
+ source?: PermissionSource;
1132
+ /** Controller name if discovered from controller */
1133
+ controller?: string;
1134
+ /** Method name if discovered from controller */
1135
+ method?: string;
1136
+ /** Plugin name if from plugin */
1137
+ plugin?: string;
1138
+ }
1139
+ /**
1140
+ * Permission item with checked state (for UI)
1141
+ */
1142
+ interface PermissionItem {
1143
+ /** Permission identifier */
1144
+ id: string;
1145
+ /** Human-readable name */
1146
+ name: string;
1147
+ /** Description */
1148
+ description: string;
1149
+ /** Whether this permission is enabled */
1150
+ checked?: boolean;
1151
+ }
1152
+ /**
1153
+ * Permission group for UI display
1154
+ */
1155
+ interface PermissionGroup {
1156
+ /** Group identifier */
1157
+ id: string;
1158
+ /** Display name */
1159
+ name: string;
1160
+ /** API identifier */
1161
+ apiId?: string;
1162
+ /** Permissions in this group */
1163
+ permissions: PermissionItem[];
1164
+ }
1165
+ /**
1166
+ * Permissions categorized by type
1167
+ */
1168
+ interface CategorizedPermissions {
1169
+ /** Permissions for collection types (schemas) */
1170
+ collectionTypes: PermissionGroup[];
1171
+ /** Permissions from controllers (@RequirePermission) - grouped by controller */
1172
+ controllers: PermissionGroup[];
1173
+ /** Permissions from plugins */
1174
+ plugins: PermissionGroup[];
1175
+ /** System permissions (users, settings, etc.) */
1176
+ system: PermissionGroup[];
1177
+ }
1178
+ /**
1179
+ * Role definition
1180
+ */
1181
+ interface Role {
1182
+ /** Unique role identifier */
1183
+ id: string;
1184
+ /** Role slug (e.g., 'admin', 'authenticated', 'editor') */
1185
+ name: string;
1186
+ /** Human-readable name */
1187
+ displayName: string;
1188
+ /** Role description */
1189
+ description?: string;
1190
+ /** Array of permission IDs */
1191
+ permissions: string[];
1192
+ /** Whether this is a system role (cannot be deleted) */
1193
+ isSystem: boolean;
1194
+ /** When the role was created */
1195
+ createdAt: Date;
1196
+ /** When the role was last updated */
1197
+ updatedAt?: Date;
1198
+ }
1199
+ /**
1200
+ * Role with resolved permission details for UI
1201
+ */
1202
+ interface RoleWithPermissions extends Role {
1203
+ /** Collection type permissions */
1204
+ collectionTypes: PermissionGroup[];
1205
+ /** Controller permissions (grouped by controller) */
1206
+ controllers: PermissionGroup[];
1207
+ /** Plugin permissions */
1208
+ plugins: PermissionGroup[];
1209
+ /** System permissions */
1210
+ system: PermissionGroup[];
1211
+ }
1212
+ /**
1213
+ * Default system role names
1214
+ */
1215
+ type SystemRoleName = 'admin' | 'authenticated' | 'public';
1216
+ /**
1217
+ * System role configuration
1218
+ */
1219
+ interface SystemRoleConfig {
1220
+ name: SystemRoleName;
1221
+ displayName: string;
1222
+ description: string;
1223
+ permissions: string[];
1224
+ }
1225
+ /**
1226
+ * Options for @RequirePermission decorator
1227
+ */
1228
+ interface PermissionOptions {
1229
+ /** Permission identifier (e.g., 'content.posts.create') */
1230
+ id: string;
1231
+ /** Human-readable name */
1232
+ name: string;
1233
+ /** Description for admin UI */
1234
+ description?: string;
1235
+ /** Group for organization */
1236
+ group?: string;
1237
+ }
1238
+ /**
1239
+ * Resolved permission after template substitution
1240
+ */
1241
+ interface ResolvedPermission extends PermissionOptions {
1242
+ /** Original template (if any) */
1243
+ template?: string;
1244
+ }
1245
+ /**
1246
+ * Create role request
1247
+ */
1248
+ interface CreateRoleDto {
1249
+ /** Role slug (lowercase, no spaces) */
1250
+ name: string;
1251
+ /** Human-readable name */
1252
+ displayName: string;
1253
+ /** Role description */
1254
+ description?: string;
1255
+ /** Initial permissions */
1256
+ permissions?: string[];
1257
+ }
1258
+ /**
1259
+ * Update role request
1260
+ */
1261
+ interface UpdateRoleDto {
1262
+ /** Human-readable name */
1263
+ displayName?: string;
1264
+ /** Role description */
1265
+ description?: string;
1266
+ }
1267
+ /**
1268
+ * Update role permissions request
1269
+ */
1270
+ interface UpdatePermissionsDto {
1271
+ /** Array of permission IDs to set */
1272
+ permissions: string[];
1273
+ }
1274
+ /**
1275
+ * Duplicate role request
1276
+ */
1277
+ interface DuplicateRoleDto {
1278
+ /** Name for the new role */
1279
+ name: string;
1280
+ /** Display name for the new role */
1281
+ displayName?: string;
1282
+ }
1283
+ /**
1284
+ * Assign role to user request
1285
+ */
1286
+ interface AssignRoleDto {
1287
+ /** Role name to assign */
1288
+ roleName: string;
1289
+ }
1290
+ /**
1291
+ * Permission check result
1292
+ */
1293
+ interface PermissionCheckResult {
1294
+ /** Whether permission is granted */
1295
+ granted: boolean;
1296
+ /** The permission that was checked */
1297
+ permission: string;
1298
+ /** User's role name */
1299
+ role?: string;
1300
+ /** Reason if denied */
1301
+ reason?: string;
1302
+ }
1303
+ /**
1304
+ * Role audit log entry
1305
+ */
1306
+ interface RoleAuditEntry {
1307
+ /** Action performed */
1308
+ action: 'created' | 'updated' | 'permissions_updated' | 'deleted' | 'duplicated';
1309
+ /** When the action occurred */
1310
+ timestamp: Date;
1311
+ /** User who performed the action */
1312
+ userId?: string;
1313
+ /** User name for display */
1314
+ userName?: string;
1315
+ /** Changed permissions (for permissions_updated) */
1316
+ permissions?: {
1317
+ added: string[];
1318
+ removed: string[];
1319
+ };
1320
+ }
1321
+ /**
1322
+ * RBAC module options
1323
+ */
1324
+ interface RBACModuleOptions {
1325
+ /** Whether RBAC is enabled */
1326
+ enabled?: boolean;
1327
+ /** Default role for new users */
1328
+ defaultRole?: string;
1329
+ /** Whether to allow public (unauthenticated) access */
1330
+ allowPublicAccess?: boolean;
1331
+ /** Whether to cache permission checks */
1332
+ cachePermissions?: boolean;
1333
+ /** Cache TTL in seconds */
1334
+ cacheTTL?: number;
1335
+ }
1336
+
1337
+ /**
1338
+ * Decorator to mark controller methods with required permissions
1339
+ *
1340
+ * The guard will check if the authenticated user's role has the specified permission.
1341
+ * Supports dynamic placeholders like `{schema}` which are resolved at runtime.
1342
+ *
1343
+ * @param options - Permission configuration
1344
+ *
1345
+ * @example
1346
+ * ```typescript
1347
+ * // Static permission
1348
+ * @Post()
1349
+ * @RequirePermission({
1350
+ * id: 'content.posts.create',
1351
+ * name: 'Create Posts',
1352
+ * description: 'Create new blog posts',
1353
+ * group: 'Content'
1354
+ * })
1355
+ * async create(@Body() data: CreatePostDto) { ... }
1356
+ *
1357
+ * // Dynamic permission with schema placeholder
1358
+ * @Get(':schema')
1359
+ * @RequirePermission({
1360
+ * id: 'content.{schema}.find',
1361
+ * name: 'Find',
1362
+ * description: 'List entries',
1363
+ * })
1364
+ * async list(@Param('schema') schema: string) { ... }
1365
+ * ```
1366
+ */
1367
+ declare function RequirePermission(options: PermissionOptions): MethodDecorator;
1368
+ /**
1369
+ * Decorator to mark methods that check permissions manually
1370
+ *
1371
+ * This decorator only stores the permission ID for metadata discovery.
1372
+ * The actual permission check must be done in the method implementation.
1373
+ *
1374
+ * @param permission - Permission ID to check
1375
+ *
1376
+ * @example
1377
+ * ```typescript
1378
+ * @Get('sensitive-data')
1379
+ * @HasPermission('admin.sensitive.read')
1380
+ * async getSensitiveData(): Promise<SensitiveData> {
1381
+ * // Permission is checked by guard
1382
+ * return this.service.getSensitiveData()
1383
+ * }
1384
+ * ```
1385
+ */
1386
+ declare function HasPermission(permission: string): MethodDecorator;
1387
+ /**
1388
+ * Decorator to provide additional permission metadata
1389
+ *
1390
+ * Can be combined with @RequirePermission for extra configuration.
1391
+ *
1392
+ * @param options - Additional permission options
1393
+ */
1394
+ declare function PermissionMeta(options: Partial<PermissionOptions>): MethodDecorator;
1395
+ /**
1396
+ * Helper to extract permission metadata from a method
1397
+ */
1398
+ declare function getPermissionMetadata(target: object, propertyKey: string | symbol): PermissionOptions | undefined;
1399
+ /**
1400
+ * Helper to check if a method has permission decorator
1401
+ */
1402
+ declare function hasPermissionDecorator(target: object, propertyKey: string | symbol): boolean;
1403
+
1404
+ type SettingType = 'string' | 'boolean' | 'number' | 'object' | 'array';
1405
+ /**
1406
+ * Settings object type for nested settings
1407
+ */
1408
+ interface SettingObject {
1409
+ [key: string]: SettingValue;
1410
+ }
1411
+ /**
1412
+ * Settings value types - union of all possible setting values
1413
+ * This replaces `any` in settings-related code
1414
+ */
1415
+ type SettingValue = string | number | boolean | string[] | number[] | SettingObject | null;
1416
+ interface SchemaSetting {
1417
+ key: string;
1418
+ value: SettingValue;
1419
+ type: SettingType | string;
1420
+ }
1421
+ interface SettingsFeatureOptions<T = unknown> {
1422
+ group: string;
1423
+ schema: new () => T;
1424
+ }
1425
+ /**
1426
+ * Settings update payload for a single setting
1427
+ */
1428
+ interface SettingsUpdatePayload {
1429
+ group: string;
1430
+ key: string;
1431
+ value: SettingValue;
1432
+ }
1433
+ /**
1434
+ * Settings bulk update payload
1435
+ */
1436
+ interface SettingsBulkUpdatePayload {
1437
+ settings: Array<{
1438
+ key: string;
1439
+ value: SettingValue;
1440
+ }>;
1441
+ }
1442
+ /**
1443
+ * Settings record type for typed settings groups
1444
+ */
1445
+ type SettingsRecord = Record<string, SettingValue>;
1446
+ /**
1447
+ * Section variant for special styling (e.g., danger zone)
1448
+ */
1449
+ type SettingSectionVariant = 'default' | 'danger';
1450
+ /**
1451
+ * Section definition for grouping settings fields visually
1452
+ */
1453
+ interface SettingSectionDefinition {
1454
+ /** Unique section identifier */
1455
+ name: string;
1456
+ /** Display label for the section */
1457
+ label: string;
1458
+ /** Icon identifier (lucide icon name) */
1459
+ icon?: string;
1460
+ /** Description of the section */
1461
+ description?: string;
1462
+ /** Display order within the settings group */
1463
+ order?: number;
1464
+ /** Visual variant for the section */
1465
+ variant?: SettingSectionVariant;
1466
+ }
1467
+ /**
1468
+ * Options for the @Settings() class decorator
1469
+ */
1470
+ interface SettingsDecoratorOptions {
1471
+ /** Unique group identifier for this settings class */
1472
+ group: string;
1473
+ /** Display label in admin UI */
1474
+ label: string;
1475
+ /** Icon identifier for admin UI */
1476
+ icon?: string;
1477
+ /** Description of what these settings control */
1478
+ description?: string;
1479
+ /** Display order in settings list */
1480
+ order?: number;
1481
+ /** Section definitions for grouping fields visually */
1482
+ sections?: SettingSectionDefinition[];
1483
+ }
1484
+ /**
1485
+ * Base options for Setting field decorators
1486
+ */
1487
+ interface SettingFieldBaseOptions {
1488
+ /** Display label in admin UI */
1489
+ label: string;
1490
+ /** Help text/description */
1491
+ description?: string;
1492
+ /** Default value */
1493
+ default?: SettingValue;
1494
+ /** Display order */
1495
+ order?: number;
1496
+ /** Hide from admin UI */
1497
+ hidden?: boolean;
1498
+ /** Make read-only in admin UI */
1499
+ readonly?: boolean;
1500
+ /** Section this field belongs to (references section name) */
1501
+ section?: string;
1502
+ }
1503
+ /**
1504
+ * Text setting field options
1505
+ */
1506
+ interface SettingTextOptions extends SettingFieldBaseOptions {
1507
+ default?: string;
1508
+ minLength?: number;
1509
+ maxLength?: number;
1510
+ placeholder?: string;
1511
+ }
1512
+ /**
1513
+ * Number setting field options
1514
+ */
1515
+ interface SettingNumberOptions extends SettingFieldBaseOptions {
1516
+ default?: number;
1517
+ min?: number;
1518
+ max?: number;
1519
+ step?: number;
1520
+ }
1521
+ /**
1522
+ * Boolean setting field options
1523
+ */
1524
+ interface SettingBooleanOptions extends SettingFieldBaseOptions {
1525
+ default?: boolean;
1526
+ }
1527
+ /**
1528
+ * Select setting field options
1529
+ */
1530
+ interface SettingSelectOptions extends SettingFieldBaseOptions {
1531
+ options: ReadonlyArray<{
1532
+ label: string;
1533
+ value: string;
1534
+ }> | ReadonlyArray<string>;
1535
+ default?: string | string[];
1536
+ /** Enable multi-select mode */
1537
+ multiple?: boolean;
1538
+ }
1539
+ /**
1540
+ * Secret setting field options (for API keys, passwords, etc.)
1541
+ */
1542
+ interface SettingSecretOptions extends SettingFieldBaseOptions {
1543
+ /** Mask value in UI (show only last 4 characters) */
1544
+ masked?: boolean;
1545
+ }
1546
+ /**
1547
+ * Image setting field options
1548
+ */
1549
+ interface SettingImageOptions extends SettingFieldBaseOptions {
1550
+ folder?: string;
1551
+ maxSize?: number;
1552
+ }
1553
+ /**
1554
+ * JSON setting field options
1555
+ */
1556
+ interface SettingJSONOptions extends SettingFieldBaseOptions {
1557
+ default?: SettingObject;
1558
+ }
1559
+ /**
1560
+ * Setting field type identifiers
1561
+ */
1562
+ type SettingFieldTypeId = 'text' | 'number' | 'boolean' | 'select' | 'secret' | 'image' | 'json' | 'textarea';
1563
+ /**
1564
+ * Setting field metadata stored via reflection
1565
+ */
1566
+ interface SettingFieldMetadata<T extends SettingFieldBaseOptions = SettingFieldBaseOptions> {
1567
+ /** Field type identifier */
1568
+ type: SettingFieldTypeId;
1569
+ /** Typed options for this field */
1570
+ options: T;
1571
+ /** Property key */
1572
+ propertyKey: string | symbol;
1573
+ }
1574
+ /**
1575
+ * Type guard to check if a value is SettingFieldMetadata
1576
+ */
1577
+ declare function isSettingFieldMetadata(value: unknown): value is SettingFieldMetadata;
1578
+
1579
+ type MethodMetadata = {
1580
+ name: string;
1581
+ returnType: {
1582
+ type: Type;
1583
+ isArray: boolean;
1584
+ };
1585
+ params: {
1586
+ arg: string;
1587
+ type: string;
1588
+ name: string;
1589
+ }[];
1590
+ httpMethod: string;
1591
+ routePath: string;
1592
+ guards?: Type[];
1593
+ interceptors?: Type[];
1594
+ pipes?: Type[];
1595
+ };
1596
+ type ControllerMetadata = {
1597
+ name: string;
1598
+ basePath: string;
1599
+ methods: MethodMetadata[];
1600
+ };
1601
+ type SchemaPropertyValidation = {
1602
+ type: string;
1603
+ name: string;
1604
+ constraints?: unknown[];
1605
+ };
1606
+ type SchemaProperty = {
1607
+ name: string;
1608
+ type: string;
1609
+ isArray: boolean;
1610
+ unique: boolean;
1611
+ required: boolean;
1612
+ validations: SchemaPropertyValidation[];
1613
+ ui?: UIDecoratorOptions;
1614
+ ref?: string;
1615
+ };
1616
+ type SchemaMetadata = {
1617
+ name: string;
1618
+ className?: string;
1619
+ apiName?: string;
1620
+ displayName?: string;
1621
+ properties: SchemaProperty[];
1622
+ options?: SchemaOptions;
1623
+ /** Settings-specific options (only present for settings schemas) */
1624
+ settingsOptions?: SettingsDecoratorOptions;
1625
+ };
1626
+
1627
+ type InitialConfig = {
1628
+ title?: string;
1629
+ description?: string;
1630
+ env: string;
1631
+ schemas: SchemaMetadata[];
1632
+ settings: SchemaMetadata[];
1633
+ };
1634
+
1635
+ /**
1636
+ * Authenticated user returned from auth strategies
1637
+ */
1638
+ interface AuthUser {
1639
+ /** Unique user identifier */
1640
+ id: string;
1641
+ /** User email address */
1642
+ email: string;
1643
+ /** User role for authorization */
1644
+ role: string;
1645
+ /** Optional additional user data */
1646
+ [key: string]: unknown;
1647
+ }
1648
+ /**
1649
+ * Login credentials (strategy-specific)
1650
+ */
1651
+ interface LoginCredentials {
1652
+ email: string;
1653
+ password: string;
1654
+ [key: string]: unknown;
1655
+ }
1656
+ /**
1657
+ * Registration data (strategy-specific)
1658
+ */
1659
+ interface RegisterData {
1660
+ email: string;
1661
+ password: string;
1662
+ name: string;
1663
+ role?: string;
1664
+ [key: string]: unknown;
1665
+ }
1666
+ /**
1667
+ * Authentication result containing access token
1668
+ */
1669
+ interface AuthResult {
1670
+ access_token: string;
1671
+ refresh_token?: string;
1672
+ expires_in?: number;
1673
+ token_type?: string;
1674
+ }
1675
+ /**
1676
+ * JWT-specific configuration
1677
+ */
1678
+ interface JwtAuthConfig {
1679
+ /** JWT secret key */
1680
+ secret: string;
1681
+ /** Token expiration time (e.g., '7d', '1h') */
1682
+ expiresIn?: string;
1683
+ }
1684
+ /**
1685
+ * Supabase-specific auth configuration
1686
+ */
1687
+ interface SupabaseAuthConfig {
1688
+ /** Supabase project URL */
1689
+ supabaseUrl: string;
1690
+ /** Supabase anon/public key */
1691
+ supabaseKey: string;
1692
+ /** Default role for new users */
1693
+ defaultRole?: string;
1694
+ }
1695
+ /**
1696
+ * Auth configuration for MagnetModuleOptions
1697
+ */
1698
+ interface AuthConfig {
1699
+ /** Strategy name to use (default: 'jwt') */
1700
+ strategy?: string;
1701
+ /** JWT-specific configuration */
1702
+ jwt?: JwtAuthConfig;
1703
+ /** Supabase-specific configuration (when strategy: 'supabase') */
1704
+ supabaseUrl?: string;
1705
+ /** Supabase anon/public key */
1706
+ supabaseKey?: string;
1707
+ /** Supabase service role key (required for admin operations like listUsers) */
1708
+ supabaseServiceKey?: string;
1709
+ /** Default role for new Supabase users */
1710
+ defaultRole?: string;
1711
+ /** Allow extensible config for custom strategies */
1712
+ [key: string]: unknown;
1713
+ }
1714
+ /**
1715
+ * Information about the active authentication strategy, including
1716
+ * whether it's an external provider and what OAuth providers it has configured.
1717
+ *
1718
+ * Returned by `AuthStrategy.getAuthInfo()` for external adapters (Supabase, Clerk, etc.).
1719
+ */
1720
+ interface ExternalAuthInfo {
1721
+ /** Strategy identifier (e.g., 'supabase', 'clerk', 'jwt') */
1722
+ strategy: string;
1723
+ /** Whether authentication is handled by an external provider */
1724
+ isExternal: boolean;
1725
+ /** List of OAuth provider names configured in the external service (e.g., ['google', 'github']) */
1726
+ providers: string[];
1727
+ /** Additional provider-specific settings (e.g., disable_signup, autoconfirm) */
1728
+ providerSettings?: Record<string, unknown>;
1729
+ }
1730
+ /**
1731
+ * Abstract base class for authentication strategies.
1732
+ * Similar to StorageAdapter, custom strategies must extend this class.
1733
+ *
1734
+ * @example
1735
+ * ```typescript
1736
+ * export class SupabaseAuthStrategy extends AuthStrategy {
1737
+ * readonly name = 'supabase'
1738
+ *
1739
+ * async validate(payload: unknown): Promise<AuthUser | null> {
1740
+ * // Validate Supabase JWT token
1741
+ * }
1742
+ *
1743
+ * async login(credentials: LoginCredentials): Promise<AuthResult> {
1744
+ * // Authenticate with Supabase
1745
+ * }
1746
+ *
1747
+ * async register(data: RegisterData): Promise<AuthUser> {
1748
+ * // Register user in Supabase
1749
+ * }
1750
+ *
1751
+ * async validateCredentials(email: string, password: string): Promise<AuthUser | null> {
1752
+ * // Validate user credentials
1753
+ * }
1754
+ * }
1755
+ * ```
1756
+ */
1757
+ declare abstract class AuthStrategy {
1758
+ /**
1759
+ * Unique identifier for this strategy
1760
+ */
1761
+ abstract readonly name: string;
1762
+ /**
1763
+ * Initialize the auth strategy (optional setup)
1764
+ */
1765
+ initialize?(): Promise<void>;
1766
+ /**
1767
+ * Validate a token/payload and return the authenticated user
1768
+ * @param payload - Strategy-specific payload (e.g., JWT payload, session data)
1769
+ * @returns Authenticated user or null if invalid
1770
+ */
1771
+ abstract validate(payload: unknown): Promise<AuthUser | null>;
1772
+ /**
1773
+ * Authenticate user with credentials and return tokens
1774
+ * @param credentials - Login credentials (strategy-specific)
1775
+ * @returns Authentication result with access token
1776
+ */
1777
+ abstract login(credentials: LoginCredentials): Promise<AuthResult>;
1778
+ /**
1779
+ * Register a new user
1780
+ * @param data - Registration data
1781
+ * @returns The created user
1782
+ */
1783
+ abstract register(data: RegisterData): Promise<AuthUser>;
1784
+ /**
1785
+ * Validate user credentials (used internally by login)
1786
+ * @param email - User email
1787
+ * @param password - User password
1788
+ * @returns User if valid, null otherwise
1789
+ */
1790
+ abstract validateCredentials(email: string, password: string): Promise<AuthUser | null>;
1791
+ /**
1792
+ * Refresh an access token (optional)
1793
+ * @param refreshToken - The refresh token
1794
+ * @returns New authentication result
1795
+ */
1796
+ refresh?(refreshToken: string): Promise<AuthResult>;
1797
+ /**
1798
+ * Logout/invalidate tokens (optional)
1799
+ * @param token - The token to invalidate
1800
+ */
1801
+ logout?(token: string): Promise<void>;
1802
+ /**
1803
+ * Check if any users exist in the system (optional)
1804
+ * Strategies that manage their own user storage should implement this.
1805
+ * If not implemented, AuthService will fall back to checking the local database.
1806
+ * @returns true if users exist, false otherwise
1807
+ */
1808
+ hasUsers?(): Promise<boolean>;
1809
+ /**
1810
+ * Get information about the auth strategy and its configured providers (optional).
1811
+ * External adapters (Supabase, Clerk) implement this to report which OAuth
1812
+ * providers are configured on their side. If not implemented, the strategy
1813
+ * is assumed to be built-in (JWT).
1814
+ * @returns Auth info including strategy name, external flag, and provider list
1815
+ */
1816
+ getAuthInfo?(): Promise<ExternalAuthInfo>;
1817
+ /**
1818
+ * Get the Passport strategy name (for guards)
1819
+ * Returns the name to use with AuthGuard()
1820
+ */
1821
+ getPassportStrategyName(): string;
1822
+ }
1823
+
1824
+ /**
1825
+ * SMTP configuration for Nodemailer adapter
1826
+ */
1827
+ interface NodemailerConfig {
1828
+ /** SMTP server hostname */
1829
+ host: string;
1830
+ /** SMTP server port (default: 587) */
1831
+ port?: number;
1832
+ /** Use TLS (default: true for port 465, false otherwise) */
1833
+ secure?: boolean;
1834
+ /** SMTP authentication credentials */
1835
+ auth: {
1836
+ /** SMTP username */
1837
+ user: string;
1838
+ /** SMTP password */
1839
+ pass: string;
1840
+ };
1841
+ /** Connection timeout in milliseconds */
1842
+ connectionTimeout?: number;
1843
+ /** Greeting timeout in milliseconds */
1844
+ greetingTimeout?: number;
1845
+ /** Socket timeout in milliseconds */
1846
+ socketTimeout?: number;
1847
+ }
1848
+ /**
1849
+ * Resend API configuration
1850
+ */
1851
+ interface ResendConfig {
1852
+ /** Resend API key */
1853
+ apiKey: string;
1854
+ }
1855
+ /**
1856
+ * Email adapter name type — extensible for custom adapters
1857
+ */
1858
+ type EmailAdapterName = 'nodemailer' | 'resend' | (string & {});
1859
+ /**
1860
+ * Email system configuration for MagnetModuleOptions
1861
+ */
1862
+ interface EmailConfig {
1863
+ /** Which email adapter to use */
1864
+ adapter: EmailAdapterName;
1865
+ /** Nodemailer SMTP configuration (when adapter is 'nodemailer') */
1866
+ nodemailer?: NodemailerConfig;
1867
+ /** Resend API configuration (when adapter is 'resend') */
1868
+ resend?: ResendConfig;
1869
+ /** Default email settings */
1870
+ defaults?: {
1871
+ /** Default sender email address */
1872
+ from?: string;
1873
+ /** Default reply-to address */
1874
+ replyTo?: string;
1875
+ };
1876
+ }
1877
+ /**
1878
+ * Email attachment
1879
+ */
1880
+ interface EmailAttachment {
1881
+ /** Attachment filename */
1882
+ filename: string;
1883
+ /** Attachment content (Buffer, string, or URL) */
1884
+ content: Buffer | string;
1885
+ /** MIME type of the attachment */
1886
+ contentType?: string;
1887
+ /** Content disposition (default: 'attachment') */
1888
+ disposition?: 'attachment' | 'inline';
1889
+ /** Content ID for inline attachments */
1890
+ cid?: string;
1891
+ }
1892
+ /**
1893
+ * Options for sending an email
1894
+ */
1895
+ interface SendEmailOptions {
1896
+ /** Recipient email address(es) */
1897
+ to: string | string[];
1898
+ /** Sender email address (overrides default) */
1899
+ from?: string;
1900
+ /** Email subject line */
1901
+ subject: string;
1902
+ /** HTML body content */
1903
+ html?: string;
1904
+ /** Plain text body content */
1905
+ text?: string;
1906
+ /** Reply-to address (overrides default) */
1907
+ replyTo?: string;
1908
+ /** CC recipients */
1909
+ cc?: string | string[];
1910
+ /** BCC recipients */
1911
+ bcc?: string | string[];
1912
+ /** Email attachments */
1913
+ attachments?: EmailAttachment[];
1914
+ /** Custom headers */
1915
+ headers?: Record<string, string>;
1916
+ /** Tags for categorization (supported by some providers) */
1917
+ tags?: Array<{
1918
+ name: string;
1919
+ value: string;
1920
+ }>;
1921
+ }
1922
+ /**
1923
+ * Result of sending an email
1924
+ */
1925
+ interface SendEmailResult {
1926
+ /** Provider-assigned message ID */
1927
+ id?: string;
1928
+ /** Whether the email was accepted for delivery */
1929
+ accepted: boolean;
1930
+ /** List of accepted recipient addresses */
1931
+ acceptedAddresses?: string[];
1932
+ /** List of rejected recipient addresses */
1933
+ rejectedAddresses?: string[];
1934
+ /** Error message if sending failed */
1935
+ error?: string;
1936
+ }
1937
+ /**
1938
+ * Abstract base class for email adapters.
1939
+ *
1940
+ * All email providers must extend this class and implement the abstract methods.
1941
+ * Follows the same pattern as `StorageAdapter` and `DatabaseAdapter`.
1942
+ *
1943
+ * @example
1944
+ * ```typescript
1945
+ * export class NodemailerEmailAdapter extends EmailAdapter {
1946
+ * readonly name = 'nodemailer'
1947
+ *
1948
+ * async send(options: SendEmailOptions): Promise<SendEmailResult> {
1949
+ * // Send via SMTP using Nodemailer
1950
+ * }
1951
+ *
1952
+ * async sendBatch(emails: SendEmailOptions[]): Promise<SendEmailResult[]> {
1953
+ * return Promise.all(emails.map(email => this.send(email)))
1954
+ * }
1955
+ *
1956
+ * async verify(): Promise<boolean> {
1957
+ * // Test SMTP connection
1958
+ * }
1959
+ * }
1960
+ * ```
1961
+ */
1962
+ declare abstract class EmailAdapter {
1963
+ /**
1964
+ * Unique identifier for this adapter
1965
+ */
1966
+ abstract readonly name: string;
1967
+ /**
1968
+ * Send a single email
1969
+ * @param options - Email send options (to, subject, html, etc.)
1970
+ * @returns Result with delivery status
1971
+ */
1972
+ abstract send(options: SendEmailOptions): Promise<SendEmailResult>;
1973
+ /**
1974
+ * Send multiple emails in batch
1975
+ * @param emails - Array of email options
1976
+ * @returns Array of results (one per email)
1977
+ */
1978
+ abstract sendBatch(emails: SendEmailOptions[]): Promise<SendEmailResult[]>;
1979
+ /**
1980
+ * Verify the adapter connection/configuration
1981
+ * @returns true if the adapter is properly configured and can send emails
1982
+ */
1983
+ abstract verify(): Promise<boolean>;
1984
+ /**
1985
+ * Optional cleanup/disconnect method
1986
+ */
1987
+ dispose?(): Promise<void>;
1988
+ }
1989
+
1990
+ /**
1991
+ * Query operator types for MongoDB-style queries
1992
+ */
1993
+ type QueryOperator<T> = {
1994
+ /** Equal to */
1995
+ $eq?: T;
1996
+ /** Not equal to */
1997
+ $ne?: T;
1998
+ /** Greater than */
1999
+ $gt?: T;
2000
+ /** Greater than or equal to */
2001
+ $gte?: T;
2002
+ /** Less than */
2003
+ $lt?: T;
2004
+ /** Less than or equal to */
2005
+ $lte?: T;
2006
+ /** In array */
2007
+ $in?: T[];
2008
+ /** Not in array */
2009
+ $nin?: T[];
2010
+ /** Field exists */
2011
+ $exists?: boolean;
2012
+ /** Regular expression match */
2013
+ $regex?: string | RegExp;
2014
+ /** Regex options (i, m, s, x) */
2015
+ $options?: string;
2016
+ };
2017
+ /**
2018
+ * Filter value that supports both direct values and operators
2019
+ */
2020
+ type FilterValue<T> = T | QueryOperator<T>;
2021
+ /**
2022
+ * Full filter query type with logical operators
2023
+ */
2024
+ type FilterQuery<Schema> = {
2025
+ [K in keyof Schema]?: FilterValue<Schema[K]>;
2026
+ } & {
2027
+ /** Logical AND */
2028
+ $and?: FilterQuery<Schema>[];
2029
+ /** Logical OR */
2030
+ $or?: FilterQuery<Schema>[];
2031
+ /** Logical NOR */
2032
+ $nor?: FilterQuery<Schema>[];
2033
+ };
2034
+ /**
2035
+ * Sort direction
2036
+ */
2037
+ type SortDirection = 1 | -1 | 'asc' | 'desc';
2038
+ /**
2039
+ * Sort specification
2040
+ */
2041
+ type SortQuery<Schema> = {
2042
+ [K in keyof Schema]?: SortDirection;
2043
+ };
2044
+ /**
2045
+ * Projection specification for field selection
2046
+ */
2047
+ type ProjectionQuery<Schema> = {
2048
+ [K in keyof Schema]?: 0 | 1 | boolean;
2049
+ };
2050
+ /**
2051
+ * Query execution options
2052
+ */
2053
+ interface QueryOptions {
2054
+ /** Maximum number of documents to return */
2055
+ limit?: number;
2056
+ /** Number of documents to skip */
2057
+ skip?: number;
2058
+ /** Return plain objects instead of documents */
2059
+ lean?: boolean;
2060
+ }
2061
+ /**
2062
+ * Paginated query result
2063
+ */
2064
+ interface PaginatedResult<T> {
2065
+ /** Result data */
2066
+ data: T[];
2067
+ /** Total count of matching documents */
2068
+ total: number;
2069
+ /** Current page (if using skip/limit) */
2070
+ page?: number;
2071
+ /** Page size */
2072
+ limit?: number;
2073
+ }
2074
+
2075
+ /**
2076
+ * Abstract query builder for fluent database queries.
2077
+ * Provides chainable methods for filtering, sorting, pagination, and projection.
2078
+ *
2079
+ * @example
2080
+ * ```typescript
2081
+ * const users = await userModel.query()
2082
+ * .where({ status: 'active' })
2083
+ * .sort({ createdAt: -1 })
2084
+ * .limit(10)
2085
+ * .exec()
2086
+ * ```
2087
+ */
2088
+ declare abstract class QueryBuilder<Schema> {
2089
+ /**
2090
+ * Add filter conditions to the query
2091
+ * @param filter Filter conditions with optional operators
2092
+ */
2093
+ abstract where(filter: FilterQuery<Schema>): this;
2094
+ /**
2095
+ * Add additional AND conditions
2096
+ * @param filter Filter conditions to AND with existing filters
2097
+ */
2098
+ abstract and(filter: FilterQuery<Schema>): this;
2099
+ /**
2100
+ * Add OR conditions
2101
+ * @param filters Array of filter conditions for OR logic
2102
+ */
2103
+ abstract or(filters: FilterQuery<Schema>[]): this;
2104
+ /**
2105
+ * Sort results by specified fields
2106
+ * @param sort Sort specification with field names and directions
2107
+ */
2108
+ abstract sort(sort: SortQuery<Schema>): this;
2109
+ /**
2110
+ * Limit the number of results
2111
+ * @param count Maximum number of documents to return
2112
+ */
2113
+ abstract limit(count: number): this;
2114
+ /**
2115
+ * Skip a number of results (for pagination)
2116
+ * @param count Number of documents to skip
2117
+ */
2118
+ abstract skip(count: number): this;
2119
+ /**
2120
+ * Execute with pagination info
2121
+ * @param page Page number (1-indexed)
2122
+ * @param perPage Items per page
2123
+ * @returns Data array with pagination metadata
2124
+ */
2125
+ abstract paginate(page?: number, perPage?: number): Promise<PaginatedResult<BaseSchema<Schema>>>;
2126
+ /**
2127
+ * Select specific fields to return (inclusion)
2128
+ * @param projection Field selection (1 to include, 0 to exclude)
2129
+ */
2130
+ abstract select(projection: ProjectionQuery<Schema>): this;
2131
+ /**
2132
+ * Exclude specific fields from results
2133
+ * @param fields Array of field names to exclude
2134
+ */
2135
+ exclude(fields: (keyof Schema | string)[]): this;
2136
+ /**
2137
+ * Set the locale for query results
2138
+ * @param locale The locale to use
2139
+ */
2140
+ abstract locale(locale: string): this;
2141
+ /**
2142
+ * Set the version filter for query
2143
+ * @param versionId The version ID or status
2144
+ */
2145
+ abstract version(versionId: string): this;
2146
+ /**
2147
+ * Execute the query and return all matching documents
2148
+ */
2149
+ abstract exec(): Promise<BaseSchema<Schema>[]>;
2150
+ /**
2151
+ * Execute the query and return a single document
2152
+ */
2153
+ abstract execOne(): Promise<BaseSchema<Schema> | null>;
2154
+ /**
2155
+ * Count matching documents without fetching them
2156
+ */
2157
+ abstract count(): Promise<number>;
2158
+ /**
2159
+ * Check if any matching documents exist
2160
+ */
2161
+ abstract exists(): Promise<boolean>;
2162
+ }
2163
+
2164
+ type BaseSchema<T> = {
2165
+ id: string;
2166
+ } & T;
2167
+ interface ModelCreateOptions {
2168
+ /** Skip database-level validation (useful for draft documents) */
2169
+ skipValidation?: boolean;
2170
+ }
2171
+ interface ModelUpdateOptions {
2172
+ /** Skip database-level validation (useful for draft documents) */
2173
+ skipValidation?: boolean;
2174
+ }
2175
+ /**
2176
+ * Version document type for history/versioning
2177
+ */
2178
+ interface VersionDocument {
2179
+ /** ID of the original document */
2180
+ documentId: string;
2181
+ /** Unique version identifier */
2182
+ versionId: string;
2183
+ /** Name of the schema/collection */
2184
+ schemaName: string;
2185
+ /** Version status */
2186
+ status: 'draft' | 'published' | 'archived';
2187
+ /** Snapshot of the document data at this version */
2188
+ data: Record<string, unknown>;
2189
+ /** When this version was created */
2190
+ createdAt: Date;
2191
+ /** Who created this version */
2192
+ createdBy?: string;
2193
+ /** Type of change that created this version */
2194
+ changeType?: 'create' | 'update' | 'restore';
2195
+ }
2196
+ /**
2197
+ * Native access wrapper - provides type-safe native operations
2198
+ */
2199
+ interface NativeAccess<T> {
2200
+ /**
2201
+ * Raw database/ORM instance (type varies by adapter)
2202
+ * For Mongoose: Model<Document>
2203
+ * For Drizzle: { db, table }
2204
+ */
2205
+ readonly raw: unknown;
2206
+ /**
2207
+ * Execute raw query (adapter-specific syntax)
2208
+ * @param query - The raw query string
2209
+ * @param params - Query parameters
2210
+ */
2211
+ rawQuery<R = unknown>(query: string, params?: unknown[]): Promise<R>;
2212
+ /**
2213
+ * Get adapter name for adapter-specific code
2214
+ */
2215
+ readonly adapterName: AdapterName;
2216
+ }
2217
+ declare abstract class Model<Schema> {
2218
+ abstract create(data: Partial<BaseSchema<Schema>>, options?: ModelCreateOptions): Promise<BaseSchema<Schema>>;
2219
+ abstract find(): Promise<BaseSchema<Schema>[]>;
2220
+ abstract findById(id: string): Promise<BaseSchema<Schema> | null>;
2221
+ abstract findOne(query: Partial<BaseSchema<Schema>>): Promise<BaseSchema<Schema> | null>;
2222
+ abstract findMany(query: Partial<BaseSchema<Schema>>): Promise<BaseSchema<Schema>[]>;
2223
+ abstract update(query: Partial<BaseSchema<Schema>>, data: Partial<BaseSchema<Schema>>, options?: ModelUpdateOptions): Promise<BaseSchema<Schema>>;
2224
+ abstract delete(query: Partial<BaseSchema<Schema>>): Promise<boolean>;
2225
+ /**
2226
+ * Set the locale for subsequent operations
2227
+ * @param locale The locale to use
2228
+ * @returns Cloned model instance with locale set
2229
+ */
2230
+ abstract locale(locale: string): this;
2231
+ /**
2232
+ * Get current locale
2233
+ */
2234
+ getLocale(): string;
2235
+ /**
2236
+ * Set the version for subsequent operations
2237
+ * @param versionId The version ID or status ('draft', 'published', 'archived')
2238
+ * @returns Same instance (chainable)
2239
+ */
2240
+ version(versionId: string): this;
2241
+ /**
2242
+ * Check if versioning is enabled for this model
2243
+ */
2244
+ isVersioningEnabled(): boolean;
2245
+ /**
2246
+ * Create a version snapshot of a document
2247
+ * @param documentId The document ID
2248
+ * @param data The data to version
2249
+ * @returns Version record or null if versioning disabled
2250
+ */
2251
+ createVersion(documentId: string, data: Partial<Schema>): Promise<VersionDocument | null>;
2252
+ /**
2253
+ * Find all versions of a document
2254
+ * @param documentId The document ID
2255
+ */
2256
+ findVersions(documentId: string): Promise<VersionDocument[]>;
2257
+ /**
2258
+ * Find a specific version by ID
2259
+ * @param versionId The version ID
2260
+ */
2261
+ findVersionById(versionId: string): Promise<VersionDocument | null>;
2262
+ /**
2263
+ * Restore a document to a specific version
2264
+ * @param versionId The version ID to restore
2265
+ */
2266
+ restoreVersion(versionId: string): Promise<BaseSchema<Schema> | null>;
2267
+ /**
2268
+ * Create a query builder for advanced queries with sorting, pagination, and operators.
2269
+ * The query builder inherits the current locale/version context.
2270
+ *
2271
+ * @example
2272
+ * ```typescript
2273
+ * const results = await model.query()
2274
+ * .where({ status: 'active', age: { $gte: 18 } })
2275
+ * .sort({ createdAt: -1 })
2276
+ * .limit(10)
2277
+ * .exec()
2278
+ * ```
2279
+ */
2280
+ query(): QueryBuilder<Schema>;
2281
+ /**
2282
+ * Get access to the native database model/collection.
2283
+ * Use with caution - bypasses Magnet abstractions like locale and versioning.
2284
+ *
2285
+ * @returns Typed native access object
2286
+ */
2287
+ native(): NativeAccess<Schema>;
2288
+ /**
2289
+ * Get schema name
2290
+ */
2291
+ getSchemaName(): string;
2292
+ /**
2293
+ * Get schema metadata
2294
+ */
2295
+ getMetadata(): SchemaMetadata;
2296
+ }
2297
+
2298
+ declare class Mixed {
2299
+ static schemaName: 'Mixed';
2300
+ defaultOptions: Record<string, unknown>;
2301
+ }
2302
+
2303
+ type MongooseConfig = {
2304
+ uri: string;
2305
+ };
2306
+ /**
2307
+ * Drizzle ORM configuration for SQL databases.
2308
+ * Supports PostgreSQL, MySQL, and SQLite through Drizzle ORM.
2309
+ */
2310
+ type DrizzleConfig = {
2311
+ /** Database connection string */
2312
+ connectionString: string;
2313
+ /** SQL dialect to use */
2314
+ dialect: 'postgresql' | 'mysql' | 'sqlite';
2315
+ /** Database driver to use (auto-detected if not specified) */
2316
+ driver?: 'pg' | 'neon' | 'mysql2' | 'better-sqlite3';
2317
+ /** Enable debug logging */
2318
+ debug?: boolean;
2319
+ /**
2320
+ * Migration configuration. If omitted, falls back to legacy CREATE TABLE IF NOT EXISTS behavior.
2321
+ */
2322
+ migrations?: {
2323
+ /** Migration mode — 'auto' for development, 'manual' for production */
2324
+ mode?: 'auto' | 'manual';
2325
+ /** Directory where migration files are stored (default: './migrations') */
2326
+ directory?: string;
2327
+ /** Table name for tracking applied migrations (default: '_magnet_migrations') */
2328
+ tableName?: string;
2329
+ /** Whether to run each migration in a transaction (default: true) */
2330
+ transactional?: boolean;
2331
+ };
2332
+ };
2333
+ type DBConfig = MongooseConfig | DrizzleConfig;
2334
+ /**
2335
+ * Database model instance type - the native model from the adapter
2336
+ * This could be a Mongoose Model, Drizzle table, or other adapter-specific type
2337
+ */
2338
+ type DatabaseModelInstance = unknown;
2339
+ /**
2340
+ * Model class constructor returned by adapter.model()
2341
+ */
2342
+ type ModelClass<T> = new () => Model<T>;
2343
+ /**
2344
+ * Supported adapter names
2345
+ */
2346
+ type AdapterName = 'mongoose' | 'drizzle' | 'prisma' | 'typeorm';
2347
+ /**
2348
+ * Features an adapter may support
2349
+ */
2350
+ type AdapterFeature = 'transactions' | 'nested-transactions' | 'json-queries' | 'full-text-search' | 'geospatial' | 'change-streams' | 'migrations';
2351
+ /**
2352
+ * Database types supported by adapters
2353
+ */
2354
+ type DatabaseType = 'mongodb' | 'postgresql' | 'mysql' | 'sqlite' | 'mssql';
2355
+ /**
2356
+ * Adapter capability declaration
2357
+ */
2358
+ interface AdapterCapabilities {
2359
+ /** Supported database types */
2360
+ databases: DatabaseType[];
2361
+ /** Supported features */
2362
+ features: AdapterFeature[];
2363
+ /** Whether adapter handles its own versioning */
2364
+ handlesVersioning: boolean;
2365
+ /** Whether adapter supports lazy table/collection creation */
2366
+ supportsLazyCreation: boolean;
2367
+ }
2368
+ /**
2369
+ * Database adapter contract - all adapters MUST implement this interface
2370
+ */
2371
+ declare abstract class DatabaseAdapter implements OnModuleDestroy {
2372
+ /**
2373
+ * Adapter identifier
2374
+ */
2375
+ abstract readonly name: AdapterName;
2376
+ /**
2377
+ * Connect to database and return NestJS dynamic module.
2378
+ * @param config - Database configuration (MongooseConfig or DrizzleConfig)
2379
+ */
2380
+ abstract connect(config: DBConfig): DynamicModule;
2381
+ /**
2382
+ * Register schemas as features
2383
+ */
2384
+ abstract forFeature(schemas: Type | Type[]): DynamicModule;
2385
+ /**
2386
+ * Create a Model class for the given native model instance
2387
+ * @param modelInstance - The native model instance from the database driver
2388
+ * @returns A Model class constructor that can be instantiated
2389
+ */
2390
+ abstract model<T>(modelInstance: DatabaseModelInstance): ModelClass<T>;
2391
+ /**
2392
+ * Get injection token for a schema
2393
+ */
2394
+ abstract token(schema: string): string;
2395
+ /**
2396
+ * Cleanup on module destroy
2397
+ */
2398
+ abstract onModuleDestroy(): Promise<void>;
2399
+ /**
2400
+ * Check if adapter supports a feature
2401
+ */
2402
+ abstract supports(feature: AdapterFeature): boolean;
2403
+ /**
2404
+ * Get adapter capabilities
2405
+ */
2406
+ abstract getCapabilities(): AdapterCapabilities;
2407
+ }
2408
+
2409
+ /**
2410
+ * Plugin metadata for the @Plugin decorator
2411
+ */
2412
+ interface PluginMetadata {
2413
+ /** Unique plugin identifier (e.g., 'playground') */
2414
+ name: string;
2415
+ /** Human-readable description */
2416
+ description?: string;
2417
+ /** Semver version */
2418
+ version?: string;
2419
+ /** Plugin dependencies (other plugin names) */
2420
+ dependencies?: string[];
2421
+ /** NestJS module to be auto-imported (optional for backwards compatibility) */
2422
+ module?: Type<unknown>;
2423
+ }
2424
+ /**
2425
+ * Route definition for plugin frontend
2426
+ */
2427
+ interface PluginRouteDefinition {
2428
+ /** Route path (e.g., '/playground') */
2429
+ path: string;
2430
+ /** Component identifier for lazy loading */
2431
+ componentId: string;
2432
+ /** Whether route requires authentication */
2433
+ requiresAuth?: boolean;
2434
+ /** Required permissions */
2435
+ permissions?: string[];
2436
+ /** Child routes */
2437
+ children?: PluginRouteDefinition[];
2438
+ }
2439
+ /**
2440
+ * Sidebar item for plugin frontend
2441
+ */
2442
+ interface PluginSidebarItem {
2443
+ /** Unique identifier */
2444
+ id: string;
2445
+ /** Display title */
2446
+ title: string;
2447
+ /** Route path */
2448
+ url: string;
2449
+ /** Lucide icon name (e.g., 'Boxes', 'Settings') */
2450
+ icon: string;
2451
+ /** Position in sidebar (lower = higher) */
2452
+ order?: number;
2453
+ /** Child items */
2454
+ items?: PluginSidebarItem[];
2455
+ /** Badge to show */
2456
+ badge?: string | number;
2457
+ }
2458
+ /**
2459
+ * Settings page for plugin
2460
+ */
2461
+ interface PluginSettingsPage {
2462
+ /** Settings group identifier */
2463
+ groupId: string;
2464
+ /** Display title */
2465
+ title: string;
2466
+ /** Description */
2467
+ description?: string;
2468
+ /** Component identifier */
2469
+ componentId: string;
2470
+ }
2471
+ /**
2472
+ * Frontend manifest exposed by plugins via discovery
2473
+ */
2474
+ interface PluginFrontendManifest {
2475
+ /** Plugin identifier */
2476
+ pluginName: string;
2477
+ /** Routes to register */
2478
+ routes?: PluginRouteDefinition[];
2479
+ /** Sidebar items */
2480
+ sidebar?: PluginSidebarItem[];
2481
+ /** Settings pages */
2482
+ settings?: PluginSettingsPage[];
2483
+ /** Required permissions */
2484
+ permissions?: string[];
2485
+ }
2486
+ /**
2487
+ * Enriched plugin manifest with bundle URL for runtime loading
2488
+ * Returned by GET /plugins/manifests endpoint
2489
+ */
2490
+ interface EnrichedPluginManifest extends PluginFrontendManifest {
2491
+ /** URL to load the plugin's frontend bundle */
2492
+ bundleUrl: string;
2493
+ }
2494
+ /**
2495
+ * Plugin configuration passed to MagnetModule.forRoot
2496
+ */
2497
+ interface PluginConfig {
2498
+ /** The plugin class decorated with @Plugin */
2499
+ plugin: Type<unknown>;
2500
+ /** Plugin-specific options */
2501
+ options?: Record<string, unknown>;
2502
+ /** Whether the plugin is enabled (default: true) */
2503
+ enabled?: boolean;
2504
+ }
2505
+ /**
2506
+ * Hook definition for plugins
2507
+ */
2508
+ interface PluginHook {
2509
+ instance: unknown;
2510
+ methodName: string | symbol;
2511
+ }
2512
+ /**
2513
+ * Options for PluginModule.forRoot
2514
+ */
2515
+ interface PluginModuleOptions {
2516
+ plugins: PluginConfig[];
2517
+ }
2518
+ /**
2519
+ * Registered plugin info returned from API
2520
+ */
2521
+ interface RegisteredPluginInfo {
2522
+ name: string;
2523
+ description?: string;
2524
+ version?: string;
2525
+ dependencies?: string[];
2526
+ frontend?: PluginFrontendManifest;
2527
+ options?: Record<string, unknown>;
2528
+ }
2529
+ /**
2530
+ * Interface for plugin lifecycle hooks.
2531
+ * Plugins can implement these methods to respond to lifecycle events.
2532
+ *
2533
+ * @example
2534
+ * ```ts
2535
+ * @Plugin({ name: 'my-plugin', module: MyPluginModule })
2536
+ * export class MyPlugin implements PluginLifecycle {
2537
+ * onPluginInit() {
2538
+ * console.log('Plugin initialized')
2539
+ * }
2540
+ *
2541
+ * onPluginDestroy() {
2542
+ * console.log('Plugin destroyed')
2543
+ * }
2544
+ * }
2545
+ * ```
2546
+ */
2547
+ interface PluginLifecycle {
2548
+ /**
2549
+ * Called after the plugin module is initialized.
2550
+ * Use this for plugin-specific setup that needs other services.
2551
+ */
2552
+ onPluginInit?(): void | Promise<void>;
2553
+ /**
2554
+ * Called when the application is shutting down.
2555
+ * Use this for cleanup operations.
2556
+ */
2557
+ onPluginDestroy?(): void | Promise<void>;
2558
+ }
2559
+
2560
+ interface LocalStorageConfig {
2561
+ /** Directory where files will be stored (e.g., './uploads') */
2562
+ uploadDir: string;
2563
+ /** Public URL path for serving files (e.g., '/media') */
2564
+ publicPath: string;
2565
+ /** Maximum file size in bytes (default: 50MB) */
2566
+ maxFileSize?: number;
2567
+ /** Allowed MIME types (default: all) */
2568
+ allowedMimeTypes?: string[];
2569
+ }
2570
+ interface S3StorageConfig {
2571
+ /** S3 bucket name */
2572
+ bucket: string;
2573
+ /** AWS region */
2574
+ region: string;
2575
+ /** AWS access key ID */
2576
+ accessKeyId: string;
2577
+ /** AWS secret access key */
2578
+ secretAccessKey: string;
2579
+ /** Custom endpoint URL (for R2, MinIO, etc.) */
2580
+ endpoint?: string;
2581
+ /** Public URL for serving files (CDN URL) */
2582
+ publicUrl?: string;
2583
+ /** Enable path-style access (required for some S3-compatible services) */
2584
+ forcePathStyle?: boolean;
2585
+ }
2586
+ interface R2StorageConfig extends S3StorageConfig {
2587
+ /** Cloudflare account ID */
2588
+ accountId: string;
2589
+ }
2590
+ interface SupabaseStorageConfig {
2591
+ /** Supabase project URL */
2592
+ supabaseUrl: string;
2593
+ /** Supabase service role key (required for storage operations) */
2594
+ supabaseKey: string;
2595
+ /** Storage bucket name */
2596
+ bucket: string;
2597
+ /** Public URL for the bucket (optional, uses Supabase URL if not provided) */
2598
+ publicUrl?: string;
2599
+ }
2600
+ interface StorageConfig {
2601
+ /** Storage adapter to use */
2602
+ adapter: 'local' | 's3' | 'r2' | 'supabase';
2603
+ /** Local storage configuration */
2604
+ local?: LocalStorageConfig;
2605
+ /** S3 storage configuration */
2606
+ s3?: S3StorageConfig;
2607
+ /** R2 storage configuration */
2608
+ r2?: R2StorageConfig;
2609
+ /** Supabase storage configuration */
2610
+ supabase?: SupabaseStorageConfig;
2611
+ }
2612
+ interface UploadOptions {
2613
+ /** Target folder for the file */
2614
+ folder?: string;
2615
+ /** Custom filename (auto-generated if not provided) */
2616
+ filename?: string;
2617
+ /** MIME type of the file */
2618
+ mimeType?: string;
2619
+ /** Tags for categorization */
2620
+ tags?: string[];
2621
+ /** Alt text for accessibility */
2622
+ alt?: string;
2623
+ /** Custom metadata fields */
2624
+ customFields?: Record<string, unknown>;
492
2625
  }
493
2626
  interface UploadResult {
494
2627
  /** Unique identifier for the uploaded file */
@@ -564,489 +2697,1549 @@ interface PaginatedMedia<T = UploadResult> {
564
2697
  /** Total number of pages */
565
2698
  totalPages: number;
566
2699
  }
567
- declare abstract class StorageAdapter {
2700
+ declare abstract class StorageAdapter {
2701
+ /**
2702
+ * Initialize the storage adapter (create directories, check connections)
2703
+ */
2704
+ abstract initialize(): Promise<void>;
2705
+ /**
2706
+ * Upload a file to storage
2707
+ * @param file - File buffer or readable stream
2708
+ * @param originalFilename - Original filename from user
2709
+ * @param options - Upload options
2710
+ */
2711
+ abstract upload(file: Buffer | Readable, originalFilename: string, options?: UploadOptions): Promise<UploadResult>;
2712
+ /**
2713
+ * Upload a file using chunked/streaming upload (for large files)
2714
+ * @param stream - Readable stream of the file
2715
+ * @param originalFilename - Original filename from user
2716
+ * @param totalSize - Total size of the file in bytes
2717
+ * @param options - Upload options
2718
+ */
2719
+ abstract uploadChunked(stream: Readable, originalFilename: string, totalSize: number, options?: UploadOptions): Promise<UploadResult>;
2720
+ /**
2721
+ * Delete a file from storage
2722
+ * @param path - Storage path or key of the file
2723
+ */
2724
+ abstract delete(path: string): Promise<boolean>;
2725
+ /**
2726
+ * Delete multiple files from storage
2727
+ * @param paths - Array of storage paths or keys
2728
+ */
2729
+ abstract deleteMany(paths: string[]): Promise<{
2730
+ deleted: number;
2731
+ failed: string[];
2732
+ }>;
2733
+ /**
2734
+ * Get the public URL for a file
2735
+ * @param path - Storage path or key
2736
+ * @param transform - Optional transform options for images
2737
+ */
2738
+ abstract getUrl(path: string, transform?: TransformOptions): string;
2739
+ /**
2740
+ * Get a readable stream for a file
2741
+ * @param path - Storage path or key
2742
+ */
2743
+ abstract getStream(path: string): Promise<Readable>;
2744
+ /**
2745
+ * Get the file as a buffer
2746
+ * @param path - Storage path or key
2747
+ */
2748
+ abstract getBuffer(path: string): Promise<Buffer>;
2749
+ /**
2750
+ * Check if a file exists
2751
+ * @param path - Storage path or key
2752
+ */
2753
+ abstract exists(path: string): Promise<boolean>;
2754
+ /**
2755
+ * Get a transformed version of an image
2756
+ * @param path - Storage path or key
2757
+ * @param options - Transform options
2758
+ */
2759
+ abstract transform(path: string, options: TransformOptions): Promise<Buffer>;
2760
+ /**
2761
+ * Move/rename a file
2762
+ * @param path - Current storage path or key
2763
+ * @param newPath - New storage path or key
2764
+ */
2765
+ move?(path: string, newPath: string): Promise<UploadResult>;
2766
+ /**
2767
+ * Copy a file
2768
+ * @param path - Source storage path or key
2769
+ * @param newPath - Destination storage path or key
2770
+ */
2771
+ copy?(path: string, newPath: string): Promise<UploadResult>;
2772
+ /**
2773
+ * Generate a signed URL for temporary access (for S3/R2)
2774
+ * @param path - Storage path or key
2775
+ * @param expiresIn - Expiration time in seconds
2776
+ */
2777
+ signedUrl?(path: string, expiresIn?: number): Promise<string>;
2778
+ }
2779
+
2780
+ type VaultAdapterType = 'db' | 'hashicorp' | 'supabase';
2781
+ /**
2782
+ * Token-based authentication for HashiCorp Vault.
2783
+ * Token is read from VAULT_TOKEN env var.
2784
+ */
2785
+ interface VaultTokenAuth {
2786
+ type: 'token';
2787
+ token: string;
2788
+ }
2789
+ /**
2790
+ * AppRole-based authentication for HashiCorp Vault.
2791
+ */
2792
+ interface VaultAppRoleAuth {
2793
+ type: 'appRole';
2794
+ roleId: string;
2795
+ secretId?: string;
2796
+ }
2797
+ type VaultAuthConfig = VaultTokenAuth | VaultAppRoleAuth;
2798
+ /**
2799
+ * Configuration for the HashiCorp Vault adapter.
2800
+ */
2801
+ interface HashiCorpVaultConfig {
2802
+ /** Vault server URL (e.g., 'https://vault.example.com:8200'). Defaults to VAULT_ADDR env var. */
2803
+ url?: string;
2804
+ /** Authentication configuration. Defaults to VAULT_TOKEN env var. */
2805
+ auth?: VaultAuthConfig;
2806
+ /** Secrets engine mount path (default: 'secret') */
2807
+ mountPath?: string;
2808
+ /** Vault Enterprise namespace (optional) */
2809
+ namespace?: string;
2810
+ }
2811
+ /**
2812
+ * Configuration for the Supabase Vault adapter.
2813
+ */
2814
+ interface SupabaseVaultConfig {
2815
+ /** Supabase project URL */
2816
+ supabaseUrl: string;
2817
+ /** Supabase service role key (required for vault operations) */
2818
+ supabaseServiceKey: string;
2819
+ }
2820
+ /**
2821
+ * Top-level vault configuration passed to MagnetModuleOptions.
2822
+ */
2823
+ interface VaultConfig {
2824
+ /** Vault adapter to use (default: 'db') */
2825
+ adapter?: VaultAdapterType;
2826
+ /** Cache TTL in seconds (default: 300) */
2827
+ cacheTtl?: number;
2828
+ /** HashiCorp Vault adapter configuration */
2829
+ hashicorp?: HashiCorpVaultConfig;
2830
+ /** Supabase Vault adapter configuration */
2831
+ supabase?: SupabaseVaultConfig;
2832
+ }
2833
+ /**
2834
+ * Abstract base class for vault adapters.
2835
+ *
2836
+ * All adapters encrypt secrets at rest. Implementations determine
2837
+ * the storage backend (app DB, HashiCorp Vault, Supabase Vault).
2838
+ */
2839
+ declare abstract class VaultAdapter {
2840
+ /**
2841
+ * Retrieve a secret value by key.
2842
+ * @returns The decrypted string value or null if not found
2843
+ */
2844
+ abstract get(key: string): Promise<string | null>;
2845
+ /**
2846
+ * Store or update a secret.
2847
+ *
2848
+ * @param key - Secret identifier
2849
+ * @param value - Plaintext value to encrypt and store
2850
+ * @param description - Optional human-readable description (stored unencrypted)
2851
+ */
2852
+ abstract set(key: string, value: string, description?: string): Promise<void>;
2853
+ /**
2854
+ * Delete a secret by key.
2855
+ */
2856
+ abstract delete(key: string): Promise<void>;
2857
+ /**
2858
+ * List all secrets with their metadata, optionally filtered by prefix.
2859
+ */
2860
+ abstract list(prefix?: string): Promise<VaultSecretMeta[]>;
2861
+ /**
2862
+ * Check the health of the vault backend.
2863
+ */
2864
+ abstract healthCheck(): Promise<boolean>;
2865
+ }
2866
+ /** Lightweight metadata returned by list() — does not include the secret value. */
2867
+ interface VaultSecretMeta {
2868
+ name: string;
2869
+ description?: string;
2870
+ /** ISO date string when the secret was last updated (adapter-dependent) */
2871
+ lastUpdated?: string;
2872
+ }
2873
+ interface VaultStatusResponse {
2874
+ /** Whether the vault adapter is healthy */
2875
+ healthy: boolean;
2876
+ /** The adapter type in use */
2877
+ adapter: VaultAdapterType;
2878
+ /** Whether VAULT_MASTER_KEY is set (db adapter only) */
2879
+ masterKeyConfigured?: boolean;
2880
+ }
2881
+ interface VaultSecretListResponse {
2882
+ secrets: VaultSecretMeta[];
2883
+ }
2884
+
2885
+ interface InternationalizationOptions {
2886
+ locales: string[];
2887
+ defaultLocale: string;
2888
+ }
2889
+ interface PlaygroundOptions {
2890
+ /**
2891
+ * Path to the directory where module folders will be created
2892
+ * @example './src/modules'
2893
+ */
2894
+ modulesPath?: string;
2895
+ /**
2896
+ * @deprecated Use modulesPath instead
2897
+ * Path to the directory where schema files will be saved
2898
+ */
2899
+ schemasPath?: string;
2900
+ }
2901
+ interface AdminConfig {
2902
+ /** Enable static admin serving (default true when omitted) */
2903
+ enabled?: boolean;
2904
+ /** Path to serve admin UI (default: '/admin') */
2905
+ path?: string;
2906
+ /** Custom path to admin dist folder */
2907
+ distPath?: string;
2908
+ }
2909
+ declare class MagnetModuleOptions {
2910
+ db: DBConfig;
2911
+ jwt: {
2912
+ secret: string;
2913
+ };
2914
+ /**
2915
+ * Auth configuration (optional, uses JWT by default)
2916
+ */
2917
+ auth?: AuthConfig;
2918
+ internationalization?: InternationalizationOptions;
2919
+ playground?: PlaygroundOptions;
2920
+ storage?: StorageConfig;
2921
+ /**
2922
+ * Email adapter configuration
2923
+ * @example
2924
+ * email: { adapter: 'nodemailer', nodemailer: { host: 'smtp.example.com', port: 587, auth: { user: 'user', pass: 'pass' } } }
2925
+ */
2926
+ email?: EmailConfig;
2927
+ /**
2928
+ * Plugins to load with the Magnet module
2929
+ */
2930
+ plugins?: PluginConfig[];
2931
+ /**
2932
+ * Admin panel configuration (enabled by default when omitted).
2933
+ * @example
2934
+ * // Explicit enable (same as omitting `admin`)
2935
+ * admin: true
2936
+ *
2937
+ * // Custom path
2938
+ * admin: { enabled: true, path: '/dashboard' }
2939
+ *
2940
+ * // Disable (for API-only mode)
2941
+ * admin: false
2942
+ */
2943
+ admin?: boolean | AdminConfig;
2944
+ /**
2945
+ * RBAC (Role-Based Access Control) configuration
2946
+ * @example
2947
+ * rbac: { enabled: true, defaultRole: 'authenticated' }
2948
+ */
2949
+ rbac?: RBACModuleOptions;
2950
+ /**
2951
+ * Vault configuration for encrypted secrets management.
2952
+ * Uses the built-in DB adapter by default (requires VAULT_MASTER_KEY env var).
2953
+ * @example
2954
+ * vault: { adapter: 'db' }
2955
+ * vault: { adapter: 'hashicorp', hashicorp: { url: 'https://vault.example.com:8200' } }
2956
+ */
2957
+ vault?: VaultConfig;
2958
+ constructor({ db, jwt, auth, internationalization, playground, storage, email, plugins, admin, rbac, vault, }: MagnetModuleOptions);
2959
+ }
2960
+ type MagnetModuleOptionsAsync = {
2961
+ useFactory: (...args: unknown[]) => Promise<MagnetModuleOptions> | MagnetModuleOptions;
2962
+ inject?: Type[];
2963
+ imports?: Type[];
2964
+ };
2965
+
2966
+ type DiscoveredController = {
2967
+ path: string;
2968
+ schema: string;
2969
+ methods: DiscoveredMethod[];
2970
+ };
2971
+ type DiscoveredMethod = {
2972
+ name: string;
2973
+ method: string;
2974
+ };
2975
+ type DiscoveredSchema = {
2976
+ name: string;
2977
+ tableName: string;
2978
+ target: string | object;
2979
+ };
2980
+
2981
+ type Validations = {
2982
+ type: string;
2983
+ name: string;
2984
+ constraints: unknown[];
2985
+ }[];
2986
+
2987
+ type VersionStatus = 'draft' | 'published' | 'archived';
2988
+ interface VersionConfig {
2989
+ /**
2990
+ * Maximum number of versions to keep per document
2991
+ */
2992
+ max?: number;
2993
+ /**
2994
+ * Enable drafts mode for this schema
2995
+ */
2996
+ drafts?: boolean | {
2997
+ /**
2998
+ * Auto-publish drafts after a certain time
2999
+ */
3000
+ autoPublish?: boolean;
3001
+ /**
3002
+ * Require approval before publishing
3003
+ */
3004
+ requireApproval?: boolean;
3005
+ };
3006
+ }
3007
+ interface VersionData<T> {
3008
+ /**
3009
+ * Document ID this version belongs to
3010
+ */
3011
+ documentId: string;
3012
+ /**
3013
+ * Version ID
3014
+ */
3015
+ versionId: string;
3016
+ /**
3017
+ * Version status
3018
+ */
3019
+ status: VersionStatus;
3020
+ /**
3021
+ * Version data
3022
+ */
3023
+ data: T;
3024
+ /**
3025
+ * Version created at
3026
+ */
3027
+ createdAt: Date;
3028
+ /**
3029
+ * Version created by
3030
+ */
3031
+ createdBy?: string;
3032
+ /**
3033
+ * Version notes
3034
+ */
3035
+ notes?: string;
3036
+ }
3037
+
3038
+ /** Log severity levels, ordered from most critical to most verbose. */
3039
+ type LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'verbose';
3040
+ /** Structured metadata attached to a log entry. */
3041
+ interface LogMetadata {
3042
+ operation?: string;
3043
+ schema?: string;
3044
+ resourceId?: string;
3045
+ duration?: number;
3046
+ method?: string;
3047
+ path?: string;
3048
+ statusCode?: number;
3049
+ [key: string]: unknown;
3050
+ }
3051
+ /** Serialized error information for structured logging. */
3052
+ interface ErrorLogData {
3053
+ name: string;
3054
+ message: string;
3055
+ code?: string;
3056
+ stack?: string;
3057
+ }
3058
+ /** A single structured log entry. */
3059
+ interface LogEntry {
3060
+ level: LogLevel;
3061
+ message: string;
3062
+ timestamp: string;
3063
+ context: string;
3064
+ requestId?: string;
3065
+ userId?: string;
3066
+ metadata?: LogMetadata;
3067
+ error?: ErrorLogData;
3068
+ }
3069
+ /** Configuration for MagnetLogger, read from environment variables. */
3070
+ interface LoggerConfig {
3071
+ /** Minimum log level to output. Default: 'info' */
3072
+ level: LogLevel;
3073
+ /** Output format. Default: 'pretty' */
3074
+ format: 'json' | 'pretty';
3075
+ /** Whether to include timestamps. Default: true */
3076
+ timestamps: boolean;
3077
+ /** Whether to include error stack traces. Default: true */
3078
+ stackTraces: boolean;
3079
+ /** Field names to redact from metadata. */
3080
+ redactFields: string[];
3081
+ }
3082
+
3083
+ /**
3084
+ * Notification System Type Definitions
3085
+ *
3086
+ * Shared types used by core backend and admin client for the notifications system.
3087
+ */
3088
+ /**
3089
+ * Available notification delivery channels.
3090
+ * - `platform`: Persists notification in DB, shown in admin drawer.
3091
+ * - `email`: Sends an email to the user (requires an adapter registered).
3092
+ */
3093
+ type NotificationChannel = 'platform' | 'email';
3094
+ /**
3095
+ * Result of delivering a notification via a single channel.
3096
+ */
3097
+ interface NotificationChannelResult {
3098
+ channel: NotificationChannel;
3099
+ success: boolean;
3100
+ error?: string;
3101
+ }
3102
+ /**
3103
+ * Interface that any notification channel adapter must implement.
3104
+ * Register adapters in `NotificationModule.forRoot({ adapters: [...] })`.
3105
+ */
3106
+ interface NotificationChannelAdapter {
3107
+ /** Which channel this adapter handles */
3108
+ readonly channel: NotificationChannel;
568
3109
  /**
569
- * Initialize the storage adapter (create directories, check connections)
3110
+ * Deliver a notification to a recipient.
3111
+ * @param payload - Notification data to send
3112
+ * @param recipient - Target user info (userId always present; email populated when available)
570
3113
  */
571
- abstract initialize(): Promise<void>;
3114
+ send(payload: NotificationSendPayload, recipient: NotificationRecipient): Promise<NotificationChannelResult>;
3115
+ }
3116
+ /**
3117
+ * Minimal notification data passed to channel adapters for delivery.
3118
+ */
3119
+ interface NotificationSendPayload {
3120
+ id: string;
3121
+ type: string;
3122
+ title: string;
3123
+ message: string;
3124
+ href?: string;
3125
+ metadata?: Record<string, unknown>;
3126
+ createdAt: Date;
3127
+ }
3128
+ /**
3129
+ * Recipient info resolved when delivering a notification.
3130
+ */
3131
+ interface NotificationRecipient {
3132
+ userId: string;
3133
+ email?: string;
3134
+ name?: string;
3135
+ }
3136
+ /**
3137
+ * DTO used to send a notification through NotificationService.notify().
3138
+ */
3139
+ interface NotifyDto {
3140
+ /** Target user ID. Can be a single user or a list for bulk delivery. */
3141
+ userId: string | string[];
572
3142
  /**
573
- * Upload a file to storage
574
- * @param file - File buffer or readable stream
575
- * @param originalFilename - Original filename from user
576
- * @param options - Upload options
3143
+ * Which channels to deliver to.
3144
+ * Defaults to `['platform']` when not specified.
577
3145
  */
578
- abstract upload(file: Buffer | Readable, originalFilename: string, options?: UploadOptions): Promise<UploadResult>;
3146
+ channels?: NotificationChannel[];
579
3147
  /**
580
- * Upload a file using chunked/streaming upload (for large files)
581
- * @param stream - Readable stream of the file
582
- * @param originalFilename - Original filename from user
583
- * @param totalSize - Total size of the file in bytes
584
- * @param options - Upload options
3148
+ * Notification category / type identifier.
3149
+ * Useful for filtering and icon mapping in the UI.
585
3150
  */
586
- abstract uploadChunked(stream: Readable, originalFilename: string, totalSize: number, options?: UploadOptions): Promise<UploadResult>;
3151
+ type: string;
3152
+ /** Short title shown in the notification list. */
3153
+ title: string;
3154
+ /** Longer description or body of the notification. */
3155
+ message: string;
3156
+ /** Optional link the user will be taken to when clicking the notification. */
3157
+ href?: string;
587
3158
  /**
588
- * Delete a file from storage
589
- * @param path - Storage path or key of the file
3159
+ * Additional arbitrary metadata stored with the notification.
3160
+ * Not shown directly in UI but available for custom logic.
590
3161
  */
591
- abstract delete(path: string): Promise<boolean>;
3162
+ metadata?: Record<string, unknown>;
3163
+ }
3164
+ /**
3165
+ * Options for querying a user's notifications.
3166
+ */
3167
+ interface NotificationQueryOptions {
3168
+ /** Filter to only unread notifications. */
3169
+ unreadOnly?: boolean;
3170
+ /** Maximum number of results. Defaults to 20. */
3171
+ limit?: number;
3172
+ /** Number of results to skip for pagination. */
3173
+ offset?: number;
3174
+ }
3175
+ /**
3176
+ * Paginated response for notification lists.
3177
+ */
3178
+ interface PaginatedNotifications<T> {
3179
+ items: T[];
3180
+ total: number;
3181
+ unreadCount: number;
3182
+ limit: number;
3183
+ offset: number;
3184
+ }
3185
+
3186
+ /**
3187
+ * Result of a cache health check
3188
+ */
3189
+ interface CacheHealthResult {
3190
+ /** Whether the cache adapter is healthy and reachable */
3191
+ healthy: boolean;
3192
+ /** Optional message with details about the health status */
3193
+ message?: string;
3194
+ }
3195
+ /**
3196
+ * Abstract base class for cache adapters.
3197
+ *
3198
+ * All cache providers must extend this class and implement the abstract methods.
3199
+ * Follows the same pattern as `StorageAdapter`, `EmailAdapter`, and `DatabaseAdapter`.
3200
+ *
3201
+ * @example
3202
+ * ```typescript
3203
+ * export class MemoryCacheAdapter extends CacheAdapter {
3204
+ * readonly name = 'memory'
3205
+ *
3206
+ * async get<T>(key: string): Promise<T | null> {
3207
+ * // Return cached value or null
3208
+ * }
3209
+ *
3210
+ * async set<T>(key: string, value: T, ttl?: number): Promise<void> {
3211
+ * // Store value with optional TTL in seconds
3212
+ * }
3213
+ *
3214
+ * // ... other methods
3215
+ * }
3216
+ * ```
3217
+ */
3218
+ declare abstract class CacheAdapter {
592
3219
  /**
593
- * Delete multiple files from storage
594
- * @param paths - Array of storage paths or keys
3220
+ * Unique identifier for this adapter
595
3221
  */
596
- abstract deleteMany(paths: string[]): Promise<{
597
- deleted: number;
598
- failed: string[];
599
- }>;
3222
+ abstract readonly name: string;
600
3223
  /**
601
- * Get the public URL for a file
602
- * @param path - Storage path or key
603
- * @param transform - Optional transform options for images
3224
+ * Retrieve a cached value by key.
3225
+ * @param key - Cache key
3226
+ * @returns The cached value, or null if not found or expired
604
3227
  */
605
- abstract getUrl(path: string, transform?: TransformOptions): string;
3228
+ abstract get<T>(key: string): Promise<T | null>;
606
3229
  /**
607
- * Get a readable stream for a file
608
- * @param path - Storage path or key
3230
+ * Store a value in the cache.
3231
+ * @param key - Cache key
3232
+ * @param value - Value to cache (must be JSON-serializable)
3233
+ * @param ttl - Time-to-live in seconds. If omitted, uses adapter default.
609
3234
  */
610
- abstract getStream(path: string): Promise<Readable>;
3235
+ abstract set<T>(key: string, value: T, ttl?: number): Promise<void>;
611
3236
  /**
612
- * Get the file as a buffer
613
- * @param path - Storage path or key
3237
+ * Remove a value from the cache by key.
3238
+ * @param key - Cache key to delete
614
3239
  */
615
- abstract getBuffer(path: string): Promise<Buffer>;
3240
+ abstract delete(key: string): Promise<void>;
616
3241
  /**
617
- * Check if a file exists
618
- * @param path - Storage path or key
3242
+ * Remove all cache entries matching a glob pattern.
3243
+ * Supports `*` wildcards (e.g., `content:posts:*` removes all post entries).
3244
+ * @param pattern - Glob pattern to match keys against
619
3245
  */
620
- abstract exists(path: string): Promise<boolean>;
3246
+ abstract deleteByPattern(pattern: string): Promise<void>;
621
3247
  /**
622
- * Get a transformed version of an image
623
- * @param path - Storage path or key
624
- * @param options - Transform options
3248
+ * Check if a key exists in the cache (and has not expired).
3249
+ * @param key - Cache key to check
3250
+ * @returns true if the key exists and is not expired
625
3251
  */
626
- abstract transform(path: string, options: TransformOptions): Promise<Buffer>;
3252
+ abstract has(key: string): Promise<boolean>;
627
3253
  /**
628
- * Move/rename a file
629
- * @param path - Current storage path or key
630
- * @param newPath - New storage path or key
3254
+ * Remove all entries from the cache.
3255
+ * For Redis, only clears keys within this adapter's key prefix.
631
3256
  */
632
- move?(path: string, newPath: string): Promise<UploadResult>;
3257
+ abstract clear(): Promise<void>;
633
3258
  /**
634
- * Copy a file
635
- * @param path - Source storage path or key
636
- * @param newPath - Destination storage path or key
3259
+ * Check the health of the cache backend.
3260
+ * @returns Health result with status and optional message
637
3261
  */
638
- copy?(path: string, newPath: string): Promise<UploadResult>;
3262
+ abstract healthCheck(): Promise<CacheHealthResult>;
639
3263
  /**
640
- * Generate a signed URL for temporary access (for S3/R2)
641
- * @param path - Storage path or key
642
- * @param expiresIn - Expiration time in seconds
3264
+ * Optional cleanup/disconnect method.
3265
+ * Called when the module is destroyed.
643
3266
  */
644
- signedUrl?(path: string, expiresIn?: number): Promise<string>;
3267
+ dispose?(): Promise<void>;
645
3268
  }
646
3269
 
647
- interface InternationalizationOptions {
648
- locales: string[];
649
- defaultLocale: string;
650
- }
651
- interface PlaygroundOptions {
652
- /**
653
- * Path to the directory where module folders will be created
654
- * @example './src/modules'
655
- */
656
- modulesPath?: string;
657
- /**
658
- * @deprecated Use modulesPath instead
659
- * Path to the directory where schema files will be saved
660
- */
661
- schemasPath?: string;
3270
+ /**
3271
+ * Declares a required or optional environment variable for an adapter/plugin.
3272
+ * Used by MagnetModule to validate all env vars before NestJS bootstraps.
3273
+ */
3274
+ interface EnvVarRequirement {
3275
+ /** Environment variable name (e.g., 'DATABASE_URL') */
3276
+ name: string;
3277
+ /** Whether this env var is required for the adapter to function */
3278
+ required: boolean;
3279
+ /** Human-readable description shown in error messages */
3280
+ description?: string;
662
3281
  }
663
- declare class MagnetModuleOptions {
664
- db: DBConfig;
665
- jwt: {
666
- secret: string;
3282
+ /**
3283
+ * Global configuration options passed as the second argument to MagnetModule.forRoot().
3284
+ * Contains cross-cutting settings that don't belong to any specific adapter.
3285
+ *
3286
+ * @example
3287
+ * ```typescript
3288
+ * MagnetModule.forRoot([...providers], {
3289
+ * jwt: { secret: 'my-secret' },
3290
+ * admin: true,
3291
+ * rbac: { enabled: true },
3292
+ * })
3293
+ * ```
3294
+ */
3295
+ interface MagnetGlobalOptions {
3296
+ /** JWT configuration for authentication */
3297
+ jwt?: {
3298
+ /** JWT signing secret. Auto-resolved from JWT_SECRET env var if not provided. */
3299
+ secret?: string;
3300
+ /** Token expiration time (e.g., '7d', '1h'). Default: '7d' */
3301
+ expiresIn?: string;
667
3302
  };
668
3303
  /**
669
- * Auth configuration (optional, uses JWT by default)
3304
+ * Admin panel configuration (enabled by default when omitted).
3305
+ * @example admin: false // API-only / headless
3306
+ * @example admin: { enabled: true, path: '/dashboard' }
670
3307
  */
671
- auth?: AuthConfig;
3308
+ admin?: boolean | AdminConfig;
3309
+ /** RBAC (Role-Based Access Control) configuration */
3310
+ rbac?: RBACModuleOptions;
3311
+ /** Internationalization settings */
672
3312
  internationalization?: InternationalizationOptions;
3313
+ /** Global Playground (schema builder) settings */
673
3314
  playground?: PlaygroundOptions;
674
- storage?: StorageConfig;
3315
+ }
3316
+ /**
3317
+ * Base interface for all Magnet providers.
3318
+ * Every adapter and plugin declares its environment variable requirements.
3319
+ */
3320
+ interface BaseMagnetProvider {
3321
+ /** Environment variables this provider needs */
3322
+ envVars: EnvVarRequirement[];
3323
+ }
3324
+ /**
3325
+ * Database adapter provider.
3326
+ * Returned by database adapter `.forRoot()` methods.
3327
+ */
3328
+ interface DatabaseMagnetProvider extends BaseMagnetProvider {
3329
+ type: 'database';
3330
+ /** The database adapter instance */
3331
+ adapter: DatabaseAdapter;
3332
+ /** Resolved database configuration */
3333
+ config: DBConfig;
3334
+ }
3335
+ /**
3336
+ * Storage adapter provider.
3337
+ * Returned by storage adapter `.forRoot()` methods.
3338
+ */
3339
+ interface StorageMagnetProvider extends BaseMagnetProvider {
3340
+ type: 'storage';
3341
+ /** The storage adapter instance */
3342
+ adapter: StorageAdapter;
3343
+ /** Adapter-specific resolved configuration */
3344
+ config?: Record<string, unknown>;
3345
+ }
3346
+ /**
3347
+ * Email adapter provider.
3348
+ * Returned by email adapter `.forRoot()` methods.
3349
+ */
3350
+ interface EmailMagnetProvider extends BaseMagnetProvider {
3351
+ type: 'email';
3352
+ /** The email adapter instance */
3353
+ adapter: EmailAdapter;
3354
+ /** Default email settings */
3355
+ defaults?: {
3356
+ from?: string;
3357
+ replyTo?: string;
3358
+ };
3359
+ }
3360
+ /**
3361
+ * Vault adapter provider.
3362
+ * Returned by vault adapter `.forRoot()` methods.
3363
+ *
3364
+ * Supports two patterns:
3365
+ * - Direct `adapter` for adapters that don't need NestJS DI (e.g., HashiCorp)
3366
+ * - `adapterFactory` for adapters that need ModuleRef (e.g., built-in DB vault)
3367
+ */
3368
+ interface VaultMagnetProvider extends BaseMagnetProvider {
3369
+ type: 'vault';
3370
+ /** Direct adapter instance (for adapters that don't need DI) */
3371
+ adapter?: VaultAdapter;
3372
+ /** Factory function for adapters that need NestJS ModuleRef */
3373
+ adapterFactory?: (moduleRef: unknown) => VaultAdapter;
3374
+ /** Vault configuration */
3375
+ config?: {
3376
+ cacheTtl?: number;
3377
+ };
3378
+ }
3379
+ /**
3380
+ * Auth strategy provider.
3381
+ * Returned by auth adapter `.forRoot()` methods.
3382
+ */
3383
+ interface AuthMagnetProvider extends BaseMagnetProvider {
3384
+ type: 'auth';
3385
+ /** Auth configuration including strategy name */
3386
+ config: AuthConfig;
3387
+ }
3388
+ /**
3389
+ * Plugin provider.
3390
+ * Returned by plugin `.forRoot()` methods.
3391
+ */
3392
+ interface PluginMagnetProvider extends BaseMagnetProvider {
3393
+ type: 'plugin';
3394
+ /** The @Plugin() decorated class */
3395
+ plugin: Type<unknown>;
3396
+ /** Plugin-specific options (injected via PLUGIN_OPTIONS token) */
3397
+ options?: Record<string, unknown>;
3398
+ }
3399
+ /**
3400
+ * Cache adapter provider.
3401
+ * Returned by cache adapter `.forRoot()` methods.
3402
+ *
3403
+ * When not provided, CacheModule defaults to the built-in MemoryCacheAdapter.
3404
+ *
3405
+ * @example
3406
+ * ```typescript
3407
+ * MagnetModule.forRoot([
3408
+ * RedisCacheAdapter.forRoot(), // or omit for in-memory default
3409
+ * ])
3410
+ * ```
3411
+ */
3412
+ interface CacheMagnetProvider extends BaseMagnetProvider {
3413
+ type: 'cache';
3414
+ /** The cache adapter instance */
3415
+ adapter: CacheAdapter;
3416
+ }
3417
+ /**
3418
+ * Discriminated union of all provider types.
3419
+ * Each adapter/plugin `.forRoot()` returns one of these variants.
3420
+ *
3421
+ * @example
3422
+ * ```typescript
3423
+ * const providers: MagnetProvider[] = [
3424
+ * MongooseDatabaseAdapter.forRoot(),
3425
+ * StripePlugin.forRoot({ currency: 'usd' }),
3426
+ * ]
3427
+ * MagnetModule.forRoot(providers, { admin: true })
3428
+ * ```
3429
+ */
3430
+ type MagnetProvider = DatabaseMagnetProvider | StorageMagnetProvider | EmailMagnetProvider | VaultMagnetProvider | AuthMagnetProvider | PluginMagnetProvider | CacheMagnetProvider;
3431
+
3432
+ declare function Resolver(optionsOrFn: ResolverInput): ClassDecorator;
3433
+
3434
+ declare function Resolve(optionsOrFn: ResolveInput): MethodDecorator;
3435
+
3436
+ /**
3437
+ * Options for the @ExtendUser decorator
3438
+ */
3439
+ interface ExtendUserOptions {
675
3440
  /**
676
- * Plugins to load with the Magnet module
3441
+ * Whether to include timestamps (createdAt, updatedAt)
3442
+ * @default true
677
3443
  */
678
- plugins?: PluginConfig[];
679
- constructor({ db, jwt, auth, internationalization, playground, storage, plugins, }: MagnetModuleOptions);
3444
+ timestamps?: boolean;
680
3445
  }
681
- type MagnetModuleOptionsAsync = {
682
- useFactory: (...args: any[]) => Promise<MagnetModuleOptions> | MagnetModuleOptions;
683
- inject?: Type[];
684
- imports?: Type[];
685
- };
3446
+ /**
3447
+ * Marks a class as a User extension.
3448
+ *
3449
+ * The decorated class will inherit base User fields (id, email, password, role, etc.)
3450
+ * and can add additional custom fields using Field decorators.
3451
+ *
3452
+ * @example
3453
+ * ```typescript
3454
+ * @ExtendUser()
3455
+ * export class User {
3456
+ * // Base fields inherited: id, email, password, role, createdAt, updatedAt
3457
+ *
3458
+ * @Field.Text({ required: true })
3459
+ * @Field.Validators(IsString(), Length(1, 50))
3460
+ * firstName: string
3461
+ *
3462
+ * @Field.Text({ required: true })
3463
+ * @Field.Validators(IsString(), Length(1, 50))
3464
+ * lastName: string
3465
+ *
3466
+ * @Field.Image({ folder: 'avatars' })
3467
+ * avatar?: string
3468
+ *
3469
+ * get fullName() {
3470
+ * return `${this.firstName} ${this.lastName}`
3471
+ * }
3472
+ * }
3473
+ * ```
3474
+ */
3475
+ declare function ExtendUser(options?: ExtendUserOptions): ClassDecorator;
3476
+ /**
3477
+ * Check if a class is marked as a User extension
3478
+ */
3479
+ declare function isUserExtension(target: Function): boolean;
3480
+ /**
3481
+ * Get ExtendUser options from a class
3482
+ */
3483
+ declare function getExtendUserOptions(target: Function): ExtendUserOptions | undefined;
686
3484
 
687
- type DiscoveredController = {
688
- path: string;
689
- schema: string;
690
- methods: DiscoveredMethod[];
691
- };
692
- type DiscoveredMethod = {
693
- name: string;
694
- method: string;
695
- };
696
- type DiscoveredSchema = {
697
- name: string;
698
- tableName: string;
699
- target: string | object;
700
- };
3485
+ declare function Prop(options?: PropOptions): PropertyDecorator;
701
3486
 
702
- type Validations = {
703
- type: string;
704
- name: string;
705
- constraints: any[];
706
- }[];
3487
+ declare function Schema(options?: SchemaOptions): ClassDecorator;
3488
+ declare function getSchemaOptions(target: Function): SchemaOptions;
707
3489
 
708
- type VersionStatus = 'draft' | 'published' | 'archived';
709
- interface VersionConfig {
3490
+ declare function Setting(): ClassDecorator;
3491
+
3492
+ /**
3493
+ * Enhanced Settings class decorator.
3494
+ *
3495
+ * Marks a class as a settings schema with group, label, and icon configuration.
3496
+ *
3497
+ * @example
3498
+ * ```typescript
3499
+ * @Settings({ group: 'general', label: 'General Settings', icon: 'settings' })
3500
+ * export class GeneralSettings {
3501
+ * @SettingField.Text({ label: 'Site Name' })
3502
+ * siteName: string = 'My Site'
3503
+ *
3504
+ * @SettingField.Boolean({ label: 'Maintenance Mode' })
3505
+ * maintenanceMode: boolean = false
3506
+ * }
3507
+ * ```
3508
+ */
3509
+ declare function Settings(options: SettingsDecoratorOptions): ClassDecorator;
3510
+ /**
3511
+ * Get settings options from a class
3512
+ */
3513
+ declare function getSettingsOptions(target: Function): SettingsDecoratorOptions | undefined;
3514
+ /**
3515
+ * Get all setting field metadata from a class
3516
+ */
3517
+ declare function getSettingFields(target: Function): SettingFieldMetadata[];
3518
+ /**
3519
+ * SettingField decorator namespace.
3520
+ *
3521
+ * Provides type-safe field decorators for settings classes.
3522
+ *
3523
+ * @example
3524
+ * ```typescript
3525
+ * @Settings({ group: 'email', label: 'Email Settings', icon: 'mail' })
3526
+ * export class EmailSettings {
3527
+ * @SettingField.Select({
3528
+ * label: 'Provider',
3529
+ * options: ['smtp', 'sendgrid', 'resend'],
3530
+ * default: 'smtp'
3531
+ * })
3532
+ * provider: string = 'smtp'
3533
+ *
3534
+ * @SettingField.Secret({ label: 'API Key', masked: true })
3535
+ * apiKey?: string
3536
+ * }
3537
+ * ```
3538
+ */
3539
+ declare const SettingField: {
710
3540
  /**
711
- * Maximum number of versions to keep per document
3541
+ * Text setting field
712
3542
  */
713
- max?: number;
3543
+ readonly Text: (options: SettingTextOptions) => PropertyDecorator;
714
3544
  /**
715
- * Enable drafts mode for this schema
3545
+ * Number setting field
716
3546
  */
717
- drafts?: boolean | {
718
- /**
719
- * Auto-publish drafts after a certain time
720
- */
721
- autoPublish?: boolean;
722
- /**
723
- * Require approval before publishing
724
- */
725
- requireApproval?: boolean;
726
- };
727
- }
728
- interface VersionData<T> {
3547
+ readonly Number: (options: SettingNumberOptions) => PropertyDecorator;
729
3548
  /**
730
- * Document ID this version belongs to
3549
+ * Boolean setting field (toggle/switch)
731
3550
  */
732
- documentId: string;
3551
+ readonly Boolean: (options: SettingBooleanOptions) => PropertyDecorator;
733
3552
  /**
734
- * Version ID
3553
+ * Select setting field (dropdown)
735
3554
  */
736
- versionId: string;
3555
+ readonly Select: (options: SettingSelectOptions) => PropertyDecorator;
737
3556
  /**
738
- * Version status
3557
+ * Secret setting field (encrypted, masked in UI)
739
3558
  */
740
- status: VersionStatus;
3559
+ readonly Secret: (options: SettingSecretOptions) => PropertyDecorator;
741
3560
  /**
742
- * Version data
3561
+ * Image setting field
743
3562
  */
744
- data: T;
3563
+ readonly Image: (options: SettingImageOptions) => PropertyDecorator;
745
3564
  /**
746
- * Version created at
3565
+ * JSON setting field
747
3566
  */
748
- createdAt: Date;
3567
+ readonly JSON: (options: SettingJSONOptions) => PropertyDecorator;
749
3568
  /**
750
- * Version created by
3569
+ * Textarea setting field (multi-line text)
751
3570
  */
752
- createdBy?: string;
3571
+ readonly Textarea: (options: SettingTextOptions) => PropertyDecorator;
3572
+ };
3573
+ /**
3574
+ * Type for the SettingField namespace
3575
+ */
3576
+ type SettingFieldNamespace = typeof SettingField;
3577
+
3578
+ interface UIFieldMetadata {
3579
+ propertyKey: string | symbol;
3580
+ options: UIDecoratorOptions & {
3581
+ designType: Function;
3582
+ };
3583
+ }
3584
+ declare function UI(options: UIDecoratorOptions): PropertyDecorator;
3585
+
3586
+ declare const Validators: (...validators: PropertyDecorator[]) => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
3587
+
3588
+ declare const VERSION_METADATA_KEY = "version:metadata";
3589
+ /**
3590
+ * Decorator to enable versioning for a schema
3591
+ * @param config Version configuration
3592
+ */
3593
+ declare function Version(config?: VersionConfig): ClassDecorator;
3594
+
3595
+ declare function InjectModel(model: Type): ParameterDecorator;
3596
+
3597
+ /**
3598
+ * Error codes for programmatic error handling
3599
+ * Organized by category for easy identification
3600
+ */
3601
+ declare enum ErrorCode {
3602
+ VALIDATION_FAILED = 1000,
3603
+ REQUIRED_FIELD_MISSING = 1001,
3604
+ INVALID_FORMAT = 1002,
3605
+ VALUE_OUT_OF_RANGE = 1003,
3606
+ UNIQUE_CONSTRAINT_VIOLATION = 1004,
3607
+ AUTHENTICATION_REQUIRED = 2000,
3608
+ INVALID_CREDENTIALS = 2001,
3609
+ TOKEN_EXPIRED = 2002,
3610
+ TOKEN_INVALID = 2003,
3611
+ ACCOUNT_LOCKED = 2004,
3612
+ EMAIL_NOT_VERIFIED = 2005,
3613
+ PERMISSION_DENIED = 3000,
3614
+ INSUFFICIENT_PERMISSIONS = 3001,
3615
+ ROLE_NOT_FOUND = 3002,
3616
+ PERMISSION_NOT_FOUND = 3003,
3617
+ RESOURCE_NOT_FOUND = 4000,
3618
+ SCHEMA_NOT_FOUND = 4001,
3619
+ DOCUMENT_NOT_FOUND = 4002,
3620
+ USER_NOT_FOUND = 4003,
3621
+ FILE_NOT_FOUND = 4004,
3622
+ VERSION_NOT_FOUND = 4005,
3623
+ DATABASE_ERROR = 5000,
3624
+ CONNECTION_FAILED = 5001,
3625
+ QUERY_FAILED = 5002,
3626
+ TRANSACTION_FAILED = 5003,
3627
+ DUPLICATE_KEY = 5004,
3628
+ PLUGIN_ERROR = 6000,
3629
+ PLUGIN_NOT_FOUND = 6001,
3630
+ PLUGIN_INITIALIZATION_FAILED = 6002,
3631
+ HOOK_EXECUTION_FAILED = 6003,
3632
+ EXTERNAL_SERVICE_ERROR = 7000,
3633
+ STORAGE_ERROR = 7001,
3634
+ EMAIL_SERVICE_ERROR = 7002,
3635
+ WEBHOOK_DELIVERY_FAILED = 7003,
3636
+ INTERNAL_ERROR = 9000,
3637
+ CONFIGURATION_ERROR = 9001,
3638
+ UNEXPECTED_ERROR = 9999
3639
+ }
3640
+ /**
3641
+ * Operation types for error metadata
3642
+ */
3643
+ type OperationType = 'create' | 'read' | 'update' | 'delete' | 'publish';
3644
+ /**
3645
+ * Error metadata for additional context
3646
+ */
3647
+ interface ErrorMetadata {
3648
+ /** Schema/collection name */
3649
+ schema?: string;
3650
+ /** Field name that caused the error */
3651
+ field?: string;
3652
+ /** Document/resource ID */
3653
+ resourceId?: string;
3654
+ /** Operation being performed */
3655
+ operation?: OperationType;
3656
+ /** Additional context */
3657
+ context?: Record<string, unknown>;
3658
+ }
3659
+ /**
3660
+ * Validation error detail
3661
+ */
3662
+ interface ValidationErrorDetail {
3663
+ field: string;
3664
+ message: string;
3665
+ constraint?: string;
3666
+ value?: unknown;
3667
+ }
3668
+ /**
3669
+ * Standard error response structure for API consumers
3670
+ */
3671
+ interface ErrorResponse {
3672
+ error: {
3673
+ code: ErrorCode;
3674
+ message: string;
3675
+ name: string;
3676
+ timestamp: string;
3677
+ metadata?: ErrorMetadata;
3678
+ details?: ValidationErrorDetail[];
3679
+ };
3680
+ }
3681
+ /**
3682
+ * Base error class for all Magnet errors
3683
+ * Provides consistent error handling with codes, metadata, and serialization
3684
+ */
3685
+ declare abstract class MagnetError extends Error {
3686
+ abstract readonly code: ErrorCode;
3687
+ abstract readonly httpStatus: number;
3688
+ readonly timestamp: Date;
3689
+ readonly metadata: ErrorMetadata;
3690
+ constructor(message: string, metadata?: ErrorMetadata);
753
3691
  /**
754
- * Version notes
3692
+ * Convert to API response format
755
3693
  */
756
- notes?: string;
3694
+ toResponse(): ErrorResponse;
3695
+ /**
3696
+ * Convert to JSON for logging
3697
+ */
3698
+ toJSON(): Record<string, unknown>;
757
3699
  }
758
3700
 
759
- type SettingType = 'string' | 'boolean' | 'number' | 'object' | 'array';
760
- interface SchemaSetting {
761
- key: string;
3701
+ /**
3702
+ * Interface for class-validator error format
3703
+ */
3704
+ interface ClassValidatorError {
3705
+ property: string;
3706
+ value?: unknown;
3707
+ constraints?: Record<string, string>;
3708
+ children?: ClassValidatorError[];
3709
+ }
3710
+ /**
3711
+ * Validation error with field-level details
3712
+ * Used for form validation and input validation failures
3713
+ */
3714
+ declare class ValidationError extends MagnetError {
3715
+ readonly code = ErrorCode.VALIDATION_FAILED;
3716
+ readonly httpStatus = 400;
3717
+ readonly details: ValidationErrorDetail[];
3718
+ constructor(message: string, details: ValidationErrorDetail[], metadata?: ErrorMetadata);
3719
+ /**
3720
+ * Create ValidationError from class-validator errors
3721
+ */
3722
+ static fromClassValidator(errors: ClassValidatorError[]): ValidationError;
3723
+ toResponse(): ErrorResponse;
3724
+ }
3725
+ /**
3726
+ * Required field missing error
3727
+ */
3728
+ declare class RequiredFieldError extends MagnetError {
3729
+ readonly code = ErrorCode.REQUIRED_FIELD_MISSING;
3730
+ readonly httpStatus = 400;
3731
+ constructor(field: string, metadata?: ErrorMetadata);
3732
+ }
3733
+ /**
3734
+ * Invalid format error (e.g., invalid email, invalid URL)
3735
+ */
3736
+ declare class InvalidFormatError extends MagnetError {
3737
+ readonly code = ErrorCode.INVALID_FORMAT;
3738
+ readonly httpStatus = 400;
3739
+ constructor(field: string, expectedFormat: string, metadata?: ErrorMetadata);
3740
+ }
3741
+ /**
3742
+ * Value out of range error
3743
+ */
3744
+ declare class ValueOutOfRangeError extends MagnetError {
3745
+ readonly code = ErrorCode.VALUE_OUT_OF_RANGE;
3746
+ readonly httpStatus = 400;
3747
+ constructor(field: string, min?: number, max?: number, metadata?: ErrorMetadata);
3748
+ }
3749
+
3750
+ /**
3751
+ * Authentication required error
3752
+ * Thrown when a request requires authentication but none is provided
3753
+ */
3754
+ declare class AuthenticationRequiredError extends MagnetError {
3755
+ readonly code = ErrorCode.AUTHENTICATION_REQUIRED;
3756
+ readonly httpStatus = 401;
3757
+ constructor(message?: string, metadata?: ErrorMetadata);
3758
+ }
3759
+ /**
3760
+ * Invalid credentials error
3761
+ * Thrown when email/password combination is incorrect
3762
+ */
3763
+ declare class InvalidCredentialsError extends MagnetError {
3764
+ readonly code = ErrorCode.INVALID_CREDENTIALS;
3765
+ readonly httpStatus = 401;
3766
+ constructor(message?: string, metadata?: ErrorMetadata);
3767
+ }
3768
+ /**
3769
+ * Token expired error
3770
+ * Thrown when a JWT or refresh token has expired
3771
+ */
3772
+ declare class TokenExpiredError extends MagnetError {
3773
+ readonly code = ErrorCode.TOKEN_EXPIRED;
3774
+ readonly httpStatus = 401;
3775
+ constructor(message?: string, metadata?: ErrorMetadata);
3776
+ }
3777
+ /**
3778
+ * Token invalid error
3779
+ * Thrown when a JWT or refresh token is malformed or invalid
3780
+ */
3781
+ declare class TokenInvalidError extends MagnetError {
3782
+ readonly code = ErrorCode.TOKEN_INVALID;
3783
+ readonly httpStatus = 401;
3784
+ constructor(message?: string, metadata?: ErrorMetadata);
3785
+ }
3786
+ /**
3787
+ * Account locked error
3788
+ * Thrown when an account is temporarily locked due to too many failed attempts
3789
+ */
3790
+ declare class AccountLockedError extends MagnetError {
3791
+ readonly code = ErrorCode.ACCOUNT_LOCKED;
3792
+ readonly httpStatus = 423;
3793
+ readonly unlockAt?: Date;
3794
+ constructor(message?: string, unlockAt?: Date, metadata?: ErrorMetadata);
3795
+ }
3796
+ /**
3797
+ * Email not verified error
3798
+ * Thrown when an action requires email verification
3799
+ */
3800
+ declare class EmailNotVerifiedError extends MagnetError {
3801
+ readonly code = ErrorCode.EMAIL_NOT_VERIFIED;
3802
+ readonly httpStatus = 403;
3803
+ constructor(message?: string, metadata?: ErrorMetadata);
3804
+ }
3805
+ /**
3806
+ * Permission denied error
3807
+ * Thrown when user lacks permission for an action
3808
+ */
3809
+ declare class PermissionDeniedError extends MagnetError {
3810
+ readonly code = ErrorCode.PERMISSION_DENIED;
3811
+ readonly httpStatus = 403;
3812
+ readonly requiredPermission?: string;
3813
+ constructor(message?: string, requiredPermission?: string, metadata?: ErrorMetadata);
3814
+ }
3815
+ /**
3816
+ * Insufficient permissions error
3817
+ * Thrown when user has some permissions but not enough
3818
+ */
3819
+ declare class InsufficientPermissionsError extends MagnetError {
3820
+ readonly code = ErrorCode.INSUFFICIENT_PERMISSIONS;
3821
+ readonly httpStatus = 403;
3822
+ readonly requiredPermissions: string[];
3823
+ constructor(requiredPermissions: string[], metadata?: ErrorMetadata);
3824
+ }
3825
+ /**
3826
+ * Role not found error
3827
+ */
3828
+ declare class RoleNotFoundError extends MagnetError {
3829
+ readonly code = ErrorCode.ROLE_NOT_FOUND;
3830
+ readonly httpStatus = 404;
3831
+ constructor(roleName: string, metadata?: ErrorMetadata);
3832
+ }
3833
+ /**
3834
+ * Permission not found error
3835
+ * Thrown when assigning invalid permission IDs to a role
3836
+ */
3837
+ declare class PermissionNotFoundError extends MagnetError {
3838
+ readonly code = ErrorCode.PERMISSION_NOT_FOUND;
3839
+ readonly httpStatus = 400;
3840
+ readonly invalidPermissionIds: string[];
3841
+ constructor(invalidPermissionIds: string[], metadata?: ErrorMetadata);
3842
+ }
3843
+
3844
+ /**
3845
+ * Resource not found error
3846
+ * Generic error for any resource type
3847
+ */
3848
+ declare class ResourceNotFoundError extends MagnetError {
3849
+ readonly code = ErrorCode.RESOURCE_NOT_FOUND;
3850
+ readonly httpStatus = 404;
3851
+ constructor(resourceType: string, identifier: string, metadata?: ErrorMetadata);
3852
+ }
3853
+ /**
3854
+ * Schema not found error
3855
+ * Thrown when a schema/collection doesn't exist
3856
+ */
3857
+ declare class SchemaNotFoundError extends MagnetError {
3858
+ readonly code = ErrorCode.SCHEMA_NOT_FOUND;
3859
+ readonly httpStatus = 404;
3860
+ constructor(schemaName: string, metadata?: ErrorMetadata);
3861
+ }
3862
+ /**
3863
+ * Document not found error
3864
+ * Thrown when a document doesn't exist in a schema
3865
+ */
3866
+ declare class DocumentNotFoundError extends MagnetError {
3867
+ readonly code = ErrorCode.DOCUMENT_NOT_FOUND;
3868
+ readonly httpStatus = 404;
3869
+ constructor(schema: string, id: string, metadata?: ErrorMetadata);
3870
+ }
3871
+ /**
3872
+ * User not found error
3873
+ */
3874
+ declare class UserNotFoundError extends MagnetError {
3875
+ readonly code = ErrorCode.USER_NOT_FOUND;
3876
+ readonly httpStatus = 404;
3877
+ constructor(identifier: string, metadata?: ErrorMetadata);
3878
+ }
3879
+ /**
3880
+ * File not found error
3881
+ */
3882
+ declare class FileNotFoundError extends MagnetError {
3883
+ readonly code = ErrorCode.FILE_NOT_FOUND;
3884
+ readonly httpStatus = 404;
3885
+ constructor(path: string, metadata?: ErrorMetadata);
3886
+ }
3887
+ /**
3888
+ * Version not found error
3889
+ * Thrown when a specific version of a document doesn't exist
3890
+ */
3891
+ declare class VersionNotFoundError extends MagnetError {
3892
+ readonly code = ErrorCode.VERSION_NOT_FOUND;
3893
+ readonly httpStatus = 404;
3894
+ constructor(schema: string, documentId: string, versionId: string, metadata?: ErrorMetadata);
3895
+ }
3896
+
3897
+ /**
3898
+ * Generic database error
3899
+ * Used when a database operation fails
3900
+ */
3901
+ declare class DatabaseError extends MagnetError {
3902
+ readonly code = ErrorCode.DATABASE_ERROR;
3903
+ readonly httpStatus = 500;
3904
+ readonly originalError?: unknown;
3905
+ constructor(message: string, originalError?: unknown, metadata?: ErrorMetadata);
3906
+ }
3907
+ /**
3908
+ * Database connection failed error
3909
+ */
3910
+ declare class ConnectionFailedError extends MagnetError {
3911
+ readonly code = ErrorCode.CONNECTION_FAILED;
3912
+ readonly httpStatus = 503;
3913
+ constructor(message?: string, metadata?: ErrorMetadata);
3914
+ }
3915
+ /**
3916
+ * Query failed error
3917
+ */
3918
+ declare class QueryFailedError extends MagnetError {
3919
+ readonly code = ErrorCode.QUERY_FAILED;
3920
+ readonly httpStatus = 500;
3921
+ readonly query?: string;
3922
+ constructor(message: string, query?: string, metadata?: ErrorMetadata);
3923
+ }
3924
+ /**
3925
+ * Transaction failed error
3926
+ */
3927
+ declare class TransactionFailedError extends MagnetError {
3928
+ readonly code = ErrorCode.TRANSACTION_FAILED;
3929
+ readonly httpStatus = 500;
3930
+ constructor(message?: string, metadata?: ErrorMetadata);
3931
+ }
3932
+ /**
3933
+ * Duplicate key error
3934
+ * Thrown when attempting to insert a duplicate value for a unique field
3935
+ */
3936
+ declare class DuplicateKeyError extends MagnetError {
3937
+ readonly code = ErrorCode.DUPLICATE_KEY;
3938
+ readonly httpStatus = 409;
3939
+ constructor(field: string, value: unknown, metadata?: ErrorMetadata);
3940
+ }
3941
+
3942
+ /**
3943
+ * Generic plugin error
3944
+ */
3945
+ declare class PluginError extends MagnetError {
3946
+ readonly code = ErrorCode.PLUGIN_ERROR;
3947
+ readonly httpStatus = 500;
3948
+ constructor(pluginName: string, message: string, metadata?: ErrorMetadata);
3949
+ }
3950
+ /**
3951
+ * Plugin not found error
3952
+ */
3953
+ declare class PluginNotFoundError extends MagnetError {
3954
+ readonly code = ErrorCode.PLUGIN_NOT_FOUND;
3955
+ readonly httpStatus = 404;
3956
+ constructor(pluginName: string, metadata?: ErrorMetadata);
3957
+ }
3958
+ /**
3959
+ * Plugin initialization error
3960
+ * Thrown when a plugin fails to initialize
3961
+ */
3962
+ declare class PluginInitializationError extends MagnetError {
3963
+ readonly code = ErrorCode.PLUGIN_INITIALIZATION_FAILED;
3964
+ readonly httpStatus = 500;
3965
+ constructor(pluginName: string, reason: string, metadata?: ErrorMetadata);
3966
+ }
3967
+ /**
3968
+ * Hook execution error
3969
+ * Thrown when a plugin hook fails to execute
3970
+ */
3971
+ declare class HookExecutionError extends MagnetError {
3972
+ readonly code = ErrorCode.HOOK_EXECUTION_FAILED;
3973
+ readonly httpStatus = 500;
3974
+ constructor(hookName: string, pluginName: string, reason: string, metadata?: ErrorMetadata);
3975
+ }
3976
+
3977
+ /**
3978
+ * Generic external service error
3979
+ */
3980
+ declare class ExternalServiceError extends MagnetError {
3981
+ readonly code = ErrorCode.EXTERNAL_SERVICE_ERROR;
3982
+ readonly httpStatus = 502;
3983
+ constructor(serviceName: string, message: string, metadata?: ErrorMetadata);
3984
+ }
3985
+ /**
3986
+ * Storage service error
3987
+ */
3988
+ declare class StorageError extends MagnetError {
3989
+ readonly code = ErrorCode.STORAGE_ERROR;
3990
+ readonly httpStatus = 502;
3991
+ constructor(message: string, metadata?: ErrorMetadata);
3992
+ }
3993
+ /**
3994
+ * Email service error
3995
+ */
3996
+ declare class EmailServiceError extends MagnetError {
3997
+ readonly code = ErrorCode.EMAIL_SERVICE_ERROR;
3998
+ readonly httpStatus = 502;
3999
+ constructor(message: string, metadata?: ErrorMetadata);
4000
+ }
4001
+ /**
4002
+ * Webhook delivery error
4003
+ */
4004
+ declare class WebhookDeliveryError extends MagnetError {
4005
+ readonly code = ErrorCode.WEBHOOK_DELIVERY_FAILED;
4006
+ readonly httpStatus = 502;
4007
+ readonly webhookUrl: string;
4008
+ readonly statusCode?: number;
4009
+ constructor(webhookUrl: string, reason: string, statusCode?: number, metadata?: ErrorMetadata);
4010
+ }
4011
+
4012
+ /**
4013
+ * Internal error
4014
+ * Used for unexpected server errors
4015
+ */
4016
+ declare class InternalError extends MagnetError {
4017
+ readonly code = ErrorCode.INTERNAL_ERROR;
4018
+ readonly httpStatus = 500;
4019
+ constructor(message?: string, metadata?: ErrorMetadata);
4020
+ }
4021
+ /**
4022
+ * Configuration error
4023
+ * Used when application configuration is invalid
4024
+ */
4025
+ declare class ConfigurationError extends MagnetError {
4026
+ readonly code = ErrorCode.CONFIGURATION_ERROR;
4027
+ readonly httpStatus = 500;
4028
+ constructor(message: string, metadata?: ErrorMetadata);
4029
+ }
4030
+ /**
4031
+ * Unexpected error
4032
+ * Used as a fallback for unknown error types
4033
+ */
4034
+ declare class UnexpectedError extends MagnetError {
4035
+ readonly code = ErrorCode.UNEXPECTED_ERROR;
4036
+ readonly httpStatus = 500;
4037
+ readonly originalError?: unknown;
4038
+ constructor(message?: string, originalError?: unknown, metadata?: ErrorMetadata);
4039
+ }
4040
+
4041
+ /**
4042
+ * Context for error conversion
4043
+ */
4044
+ interface ErrorContext {
4045
+ schema?: string;
4046
+ operation?: string;
4047
+ }
4048
+ /**
4049
+ * Convert MongoDB/Mongoose errors to typed Magnet errors
4050
+ * @param error - The original error from Mongoose
4051
+ * @param context - Optional context about the operation
4052
+ * @returns A typed MagnetError
4053
+ */
4054
+ declare function fromMongooseError(error: unknown, context?: ErrorContext): MagnetError;
4055
+ /**
4056
+ * Convert Drizzle/PostgreSQL errors to typed Magnet errors
4057
+ * @param error - The original error from Drizzle
4058
+ * @param context - Optional context about the operation
4059
+ * @returns A typed MagnetError
4060
+ */
4061
+ declare function fromDrizzleError(error: unknown, context?: ErrorContext): MagnetError;
4062
+ /**
4063
+ * Check if an error is a MagnetError
4064
+ */
4065
+ declare function isMagnetError(error: unknown): error is MagnetError;
4066
+ /**
4067
+ * Wrap an unknown error as a MagnetError
4068
+ * If already a MagnetError, returns it unchanged
4069
+ */
4070
+ declare function wrapError(error: unknown, fallbackMessage?: string): MagnetError;
4071
+
4072
+ declare class ValidationException extends Error {
4073
+ readonly errors: ValidationError$1[];
4074
+ constructor(errors: ValidationError$1[]);
4075
+ }
4076
+
4077
+ type SupportedAdapter = 'mongoose' | 'drizzle';
4078
+ /**
4079
+ * Detect the database adapter based on configuration or installed packages.
4080
+ *
4081
+ * With the provider-based API, the adapter is typically auto-registered:
4082
+ * importing `@magnet-cms/adapter-db-mongoose` or `@magnet-cms/adapter-db-drizzle`
4083
+ * calls `setDatabaseAdapter()` as a module-level side effect, so detection
4084
+ * happens automatically before any `@Schema()` decorators evaluate.
4085
+ *
4086
+ * Detection priority:
4087
+ * 1. Cached value from `setDatabaseAdapter()` (set by adapter package import side effect)
4088
+ * 2. Configuration-based: If `connectionString` or `dialect` is present, use drizzle
4089
+ * 3. Configuration-based: If `uri` is present, use mongoose
4090
+ * 4. Package-based: Check which adapter packages are installed (mongoose > drizzle)
4091
+ *
4092
+ * @param dbConfig - Optional database configuration to determine adapter from
4093
+ */
4094
+ declare function detectDatabaseAdapter(dbConfig?: DBConfig): SupportedAdapter;
4095
+ /**
4096
+ * Explicitly set the database adapter.
4097
+ *
4098
+ * With the provider-based API, this is called automatically as a side effect
4099
+ * when importing an adapter package (e.g., `@magnet-cms/adapter-db-drizzle`).
4100
+ * Manual calls are no longer needed in typical user code.
4101
+ *
4102
+ * @internal Called by adapter package index.ts as module-level side effect
4103
+ */
4104
+ declare function setDatabaseAdapter(adapter: SupportedAdapter): void;
4105
+ /**
4106
+ * Clear the cached adapter (useful for testing)
4107
+ */
4108
+ declare function clearAdapterCache(): void;
4109
+
4110
+ /**
4111
+ * Get model injection token for any adapter
4112
+ * @param schema Schema class or schema name
4113
+ * @returns Injection token string
4114
+ */
4115
+ declare function getModelToken(schema: Type | string): string;
4116
+ /**
4117
+ * Get adapter injection token
4118
+ * @returns Injection token for the database adapter
4119
+ */
4120
+ declare function getAdapterToken(): string;
4121
+ declare function registerModel(token: string, model: unknown): void;
4122
+ declare function getRegisteredModel<T>(token: string): T | undefined;
4123
+
4124
+ declare const getSchemaToken: (schema: Type) => string;
4125
+ declare const getSettingToken: (setting: Type) => string;
4126
+
4127
+ /**
4128
+ * Type guard utilities for safe type narrowing
4129
+ * Use these instead of type assertions (as any, as unknown as T)
4130
+ */
4131
+ /**
4132
+ * Check if value is a non-null object
4133
+ */
4134
+ declare function isObject(value: unknown): value is Record<string, unknown>;
4135
+ /**
4136
+ * Check if value has a specific property
4137
+ */
4138
+ declare function hasProperty<K extends string>(value: unknown, key: K): value is Record<K, unknown>;
4139
+ /**
4140
+ * Check if value has multiple properties
4141
+ */
4142
+ declare function hasProperties<K extends string>(value: unknown, keys: K[]): value is Record<K, unknown>;
4143
+ /**
4144
+ * Check if value is a string
4145
+ */
4146
+ declare function isString(value: unknown): value is string;
4147
+ /**
4148
+ * Check if value is a number
4149
+ */
4150
+ declare function isNumber(value: unknown): value is number;
4151
+ /**
4152
+ * Check if value is a boolean
4153
+ */
4154
+ declare function isBoolean(value: unknown): value is boolean;
4155
+ /**
4156
+ * Check if value is an array
4157
+ */
4158
+ declare function isArray(value: unknown): value is unknown[];
4159
+ /**
4160
+ * Check if value is a string array
4161
+ */
4162
+ declare function isStringArray(value: unknown): value is string[];
4163
+ /**
4164
+ * Check if value is a function
4165
+ */
4166
+ declare function isFunction(value: unknown): value is Function;
4167
+ /**
4168
+ * Check if value is a valid document with ID
4169
+ */
4170
+ declare function isDocument(value: unknown): value is {
4171
+ id: string;
4172
+ [key: string]: unknown;
4173
+ };
4174
+ /**
4175
+ * Check if error is a MongoDB CastError
4176
+ */
4177
+ declare function isCastError(error: unknown): error is {
4178
+ name: 'CastError';
4179
+ path: string;
762
4180
  value: unknown;
763
- type: SettingType | string;
764
- }
765
- interface SettingsFeatureOptions<T = unknown> {
766
- group: string;
767
- schema: new () => T;
768
- }
769
-
4181
+ };
770
4182
  /**
771
- * Query operator types for MongoDB-style queries
4183
+ * Check if error is a MongoDB duplicate key error
772
4184
  */
773
- type QueryOperator<T> = {
774
- /** Equal to */
775
- $eq?: T;
776
- /** Not equal to */
777
- $ne?: T;
778
- /** Greater than */
779
- $gt?: T;
780
- /** Greater than or equal to */
781
- $gte?: T;
782
- /** Less than */
783
- $lt?: T;
784
- /** Less than or equal to */
785
- $lte?: T;
786
- /** In array */
787
- $in?: T[];
788
- /** Not in array */
789
- $nin?: T[];
790
- /** Field exists */
791
- $exists?: boolean;
792
- /** Regular expression match */
793
- $regex?: string | RegExp;
794
- /** Regex options (i, m, s, x) */
795
- $options?: string;
4185
+ declare function isDuplicateKeyError(error: unknown): error is {
4186
+ code: 11000;
4187
+ keyValue: Record<string, unknown>;
796
4188
  };
797
4189
  /**
798
- * Filter value that supports both direct values and operators
4190
+ * Check if error is a Mongoose validation error
799
4191
  */
800
- type FilterValue<T> = T | QueryOperator<T>;
4192
+ declare function isValidationError(error: unknown): error is {
4193
+ name: 'ValidationError';
4194
+ errors: Record<string, unknown>;
4195
+ };
801
4196
  /**
802
- * Full filter query type with logical operators
4197
+ * Check if error is a PostgreSQL unique constraint violation
803
4198
  */
804
- type FilterQuery<Schema> = {
805
- [K in keyof Schema]?: FilterValue<Schema[K]>;
806
- } & {
807
- /** Logical AND */
808
- $and?: FilterQuery<Schema>[];
809
- /** Logical OR */
810
- $or?: FilterQuery<Schema>[];
811
- /** Logical NOR */
812
- $nor?: FilterQuery<Schema>[];
4199
+ declare function isPostgresUniqueError(error: unknown): error is {
4200
+ code: string;
4201
+ detail?: string;
813
4202
  };
814
4203
  /**
815
- * Sort direction
4204
+ * Check if an object has a method
816
4205
  */
817
- type SortDirection = 1 | -1 | 'asc' | 'desc';
4206
+ declare function hasMethod<K extends string>(value: unknown, methodName: K): value is Record<K, Function>;
818
4207
  /**
819
- * Sort specification
4208
+ * Check if value has setLocale method (for i18n documents)
820
4209
  */
821
- type SortQuery<Schema> = {
822
- [K in keyof Schema]?: SortDirection;
4210
+ declare function hasSetLocale<T>(value: T): value is T & {
4211
+ setLocale: (locale: string) => T;
823
4212
  };
824
4213
  /**
825
- * Projection specification for field selection
4214
+ * Check if value has toString method that returns string
826
4215
  */
827
- type ProjectionQuery<Schema> = {
828
- [K in keyof Schema]?: 0 | 1 | boolean;
4216
+ declare function hasToString(value: unknown): value is {
4217
+ toString(): string;
829
4218
  };
830
4219
  /**
831
- * Query execution options
4220
+ * Assert value is defined (not null or undefined)
4221
+ * Throws if value is null or undefined
832
4222
  */
833
- interface QueryOptions {
834
- /** Maximum number of documents to return */
835
- limit?: number;
836
- /** Number of documents to skip */
837
- skip?: number;
838
- /** Return plain objects instead of documents */
839
- lean?: boolean;
840
- }
4223
+ declare function assertDefined<T>(value: T | null | undefined, message?: string): asserts value is T;
841
4224
  /**
842
- * Paginated query result
4225
+ * Assert condition is true
4226
+ * Throws if condition is false
843
4227
  */
844
- interface PaginatedResult<T> {
845
- /** Result data */
846
- data: T[];
847
- /** Total count of matching documents */
848
- total: number;
849
- /** Current page (if using skip/limit) */
850
- page?: number;
851
- /** Page size */
852
- limit?: number;
853
- }
854
-
855
- declare function Resolver(optionsOrFn: ResolverInput): ClassDecorator;
856
-
857
- declare function Resolve(optionsOrFn: ResolveInput): MethodDecorator;
858
-
859
- declare function Prop(options?: PropOptions): PropertyDecorator;
860
-
861
- declare function Schema(options?: SchemaOptions): ClassDecorator;
862
- declare function getSchemaOptions(target: Function): SchemaOptions;
863
-
864
- declare function Setting(): ClassDecorator;
865
-
866
- interface UIFieldMetadata {
867
- propertyKey: string | symbol;
868
- options: UIDecoratorOptions & {
869
- designType: Function;
870
- };
871
- }
872
- declare function UI(options: UIDecoratorOptions): PropertyDecorator;
873
-
874
- declare const Validators: (...validators: PropertyDecorator[]) => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
875
-
876
- declare const VERSION_METADATA_KEY = "version:metadata";
4228
+ declare function assert(condition: boolean, message?: string): asserts condition;
877
4229
  /**
878
- * Decorator to enable versioning for a schema
879
- * @param config Version configuration
4230
+ * Safely get a string ID from a document that might have _id or id
4231
+ * Returns undefined if no valid ID found
880
4232
  */
881
- declare function Version(config?: VersionConfig): ClassDecorator;
882
-
883
- declare function InjectModel(model: Type): ParameterDecorator;
884
-
885
- declare class ValidationException extends Error {
886
- readonly errors: ValidationError[];
887
- constructor(errors: ValidationError[]);
888
- }
889
-
4233
+ declare function getDocumentId(doc: unknown): string | undefined;
890
4234
  /**
891
- * Abstract query builder for fluent database queries.
892
- * Provides chainable methods for filtering, sorting, pagination, and projection.
893
- *
894
- * @example
895
- * ```typescript
896
- * const users = await userModel.query()
897
- * .where({ status: 'active' })
898
- * .sort({ createdAt: -1 })
899
- * .limit(10)
900
- * .exec()
901
- * ```
4235
+ * Type guard for checking if an object matches a record with string values
902
4236
  */
903
- declare abstract class QueryBuilder<Schema> {
904
- /**
905
- * Add filter conditions to the query
906
- * @param filter Filter conditions with optional operators
907
- */
908
- abstract where(filter: FilterQuery<Schema>): this;
909
- /**
910
- * Add additional AND conditions
911
- * @param filter Filter conditions to AND with existing filters
912
- */
913
- abstract and(filter: FilterQuery<Schema>): this;
914
- /**
915
- * Add OR conditions
916
- * @param filters Array of filter conditions for OR logic
917
- */
918
- abstract or(filters: FilterQuery<Schema>[]): this;
919
- /**
920
- * Sort results by specified fields
921
- * @param sort Sort specification with field names and directions
922
- */
923
- abstract sort(sort: SortQuery<Schema>): this;
924
- /**
925
- * Limit the number of results
926
- * @param count Maximum number of documents to return
927
- */
928
- abstract limit(count: number): this;
929
- /**
930
- * Skip a number of results (for pagination)
931
- * @param count Number of documents to skip
932
- */
933
- abstract skip(count: number): this;
934
- /**
935
- * Select specific fields to return
936
- * @param projection Field selection (1 to include, 0 to exclude)
937
- */
938
- abstract select(projection: ProjectionQuery<Schema>): this;
939
- /**
940
- * Execute the query and return all matching documents
941
- */
942
- abstract exec(): Promise<BaseSchema<Schema>[]>;
943
- /**
944
- * Execute the query and return a single document
945
- */
946
- abstract execOne(): Promise<BaseSchema<Schema> | null>;
947
- /**
948
- * Count matching documents without fetching them
949
- */
950
- abstract count(): Promise<number>;
951
- /**
952
- * Check if any matching documents exist
953
- */
954
- abstract exists(): Promise<boolean>;
955
- /**
956
- * Execute with pagination info
957
- * @returns Data array with total count
958
- */
959
- abstract paginate(): Promise<PaginatedResult<BaseSchema<Schema>>>;
960
- /**
961
- * Set the locale for query results
962
- * @param locale The locale to use
963
- */
964
- abstract locale(locale: string): this;
965
- /**
966
- * Set the version filter for query
967
- * @param versionId The version ID or status
968
- */
969
- abstract version(versionId: string): this;
970
- }
971
-
972
- type BaseSchema<T> = {
973
- id: string;
974
- } & T;
975
- interface ModelCreateOptions {
976
- /** Skip database-level validation (useful for draft documents) */
977
- skipValidation?: boolean;
978
- }
979
- interface ModelUpdateOptions {
980
- /** Skip database-level validation (useful for draft documents) */
981
- skipValidation?: boolean;
982
- }
983
- declare abstract class Model<Schema> {
984
- abstract create(data: Partial<BaseSchema<Schema>>, options?: ModelCreateOptions): Promise<BaseSchema<Schema>>;
985
- abstract find(): Promise<BaseSchema<Schema>[]>;
986
- abstract findById(id: string): Promise<BaseSchema<Schema> | null>;
987
- abstract findOne(query: Partial<BaseSchema<Schema>>): Promise<BaseSchema<Schema> | null>;
988
- abstract findMany(query: Partial<BaseSchema<Schema>>): Promise<BaseSchema<Schema>[]>;
989
- abstract update(query: Partial<BaseSchema<Schema>>, data: Partial<BaseSchema<Schema>>, options?: ModelUpdateOptions): Promise<BaseSchema<Schema>>;
990
- abstract delete(query: Partial<BaseSchema<Schema>>): Promise<boolean>;
991
- /**
992
- * Set the locale for subsequent operations
993
- * @param locale The locale to use
994
- */
995
- abstract locale(locale: string): this;
996
- /**
997
- * Set the version for subsequent operations
998
- * @param versionId The version ID or status ('draft', 'published', 'archived')
999
- */
1000
- version(versionId: string): this;
1001
- /**
1002
- * Find all versions of a document
1003
- * @param documentId The document ID
1004
- */
1005
- findVersions(documentId: string): Promise<any[]>;
1006
- /**
1007
- * Find a specific version by ID
1008
- * @param versionId The version ID
1009
- */
1010
- findVersionById(versionId: string): Promise<any | null>;
1011
- /**
1012
- * Restore a version
1013
- * @param versionId The version ID to restore
1014
- */
1015
- restoreVersion(versionId: string): Promise<BaseSchema<Schema> | null>;
1016
- /**
1017
- * Create a query builder for advanced queries with sorting, pagination, and operators.
1018
- * The query builder inherits the current locale/version context.
1019
- *
1020
- * @example
1021
- * ```typescript
1022
- * const results = await model.query()
1023
- * .where({ status: 'active', age: { $gte: 18 } })
1024
- * .sort({ createdAt: -1 })
1025
- * .limit(10)
1026
- * .exec()
1027
- * ```
1028
- */
1029
- query(): QueryBuilder<Schema>;
1030
- /**
1031
- * Get access to the native database model/collection.
1032
- * Use with caution - bypasses Magnet abstractions like locale and versioning.
1033
- *
1034
- * @returns The underlying database model (e.g., Mongoose Model)
1035
- */
1036
- native(): unknown;
1037
- }
1038
-
1039
- declare class Mixed {
1040
- static schemaName: 'Mixed';
1041
- defaultOptions: Record<string, any>;
1042
- }
1043
-
1044
- declare function detectDatabaseAdapter(): 'mongoose' | 'typeorm';
1045
-
1046
- declare function getModelToken(schema: Type): string;
4237
+ declare function isStringRecord(value: unknown): value is Record<string, string>;
1047
4238
 
1048
- declare const getSchemaToken: (schema: Type) => string;
1049
- declare const getSettingToken: (setting: Type) => string;
4239
+ /**
4240
+ * Check if value is a version document
4241
+ */
4242
+ declare function isVersionDocument(value: unknown): value is VersionDocument;
1050
4243
 
1051
4244
  declare const RESOLVER_METADATA_KEY = "magnet:resolver";
1052
4245
  declare const RESOLVE_METADATA_KEY = "magnet:resolve";
@@ -1055,11 +4248,18 @@ declare const SCHEMA_OPTIONS_METADATA_KEY = "magnet:schema:options";
1055
4248
  declare const BASE_SCHEMA_METADATA_KEY = "magnet:schema:base";
1056
4249
  declare const PROP_METADATA_KEY = "magnet:schema:prop";
1057
4250
  declare const UI_METADATA_KEY = "magnet:schema:ui";
4251
+ declare const FIELD_METADATA_KEY = "magnet:schema:field";
1058
4252
  declare const SETTING_METADATA_KEY = "magnet:setting";
4253
+ declare const SETTINGS_OPTIONS_METADATA_KEY = "magnet:settings:options";
4254
+ declare const SETTING_FIELD_METADATA_KEY = "magnet:settings:field";
4255
+ declare const EXTEND_USER_METADATA_KEY = "magnet:extend:user";
4256
+ declare const PERMISSION_METADATA_KEY = "magnet:permission";
4257
+ declare const PERMISSION_OPTIONS_METADATA_KEY = "magnet:permission:options";
4258
+ declare const RESOLVED_PERMISSION_KEY = "magnet:permission:resolved";
1059
4259
  declare const INJECT_MODEL = "magnet:inject:model";
1060
4260
  declare const DESIGN_TYPE = "design:type";
1061
4261
  declare const DESIGN_META = "design:metadata";
1062
4262
  declare const DESIGN_PARAM_TYPES = "design:paramtypes";
1063
4263
  declare const DESIGN_RETURN_TYPE = "design:returntype";
1064
4264
 
1065
- export { type AuthConfig, type AuthResult, AuthStrategy, type AuthUser, BASE_SCHEMA_METADATA_KEY, type BaseSchema, type BaseSchemaOptions, type ControllerMetadata, type DBConfig, DESIGN_META, DESIGN_PARAM_TYPES, DESIGN_RETURN_TYPE, DESIGN_TYPE, DatabaseAdapter, type DiscoveredController, type DiscoveredMethod, type DiscoveredSchema, type EnrichedPluginManifest, type FilterQuery, type FilterValue, INJECT_MODEL, type InitialConfig, InjectModel, type InternationalizationOptions, type JwtAuthConfig, type LocalStorageConfig, type LoginCredentials, MagnetModuleOptions, type MagnetModuleOptionsAsync, type MediaQueryOptions, type MethodMetadata, Mixed, Model, type ModelCreateOptions, type ModelUpdateOptions, type MongooseConfig, PROP_METADATA_KEY, type PaginatedMedia, type PaginatedResult, type PlaygroundOptions, type PluginConfig, type PluginFrontendManifest, type PluginHook, type PluginLifecycle, type PluginMetadata, type PluginModuleOptions, type PluginRouteDefinition, type PluginSettingsPage, type PluginSidebarItem, type ProjectionQuery, Prop, type PropOptions, QueryBuilder, type QueryOperator, type QueryOptions, type R2StorageConfig, RESOLVER_METADATA_KEY, RESOLVE_METADATA_KEY, type RegisterData, type RegisteredPluginInfo, Resolve, type ResolveInput, type ResolveOptions, Resolver, type ResolverInput, type ResolverOptions, type S3StorageConfig, SCHEMA_METADATA_KEY, SCHEMA_OPTIONS_METADATA_KEY, SETTING_METADATA_KEY, Schema, type SchemaMetadata, type SchemaOptions, type SchemaProperty, type SchemaPropertyValidation, type SchemaSetting, Setting, type SettingType, type SettingsFeatureOptions, type SortDirection, type SortQuery, StorageAdapter, type StorageConfig, type TransformOptions, type TypeORMConfig, UI, type UIBase, type UICombobox, type UIDecoratorOptions, type UIFieldMetadata, type UIMultiSelect, type UIPresentationFields, type UISelect, type UISelectItem, type UISide, type UITab, type UITable, type UITableColumn, type UITypes, UI_METADATA_KEY, type UploadOptions, type UploadResult, VERSION_METADATA_KEY, ValidationException, type Validations, Validators, Version, type VersionConfig, type VersionData, type VersionStatus, detectDatabaseAdapter, getModelToken, getSchemaOptions, getSchemaToken, getSettingToken };
4265
+ export { AccountLockedError, type AdapterCapabilities, type AdapterFeature, type AdapterName, type AddressFieldOptions, type AdminConfig, type ApiKeyEventPayload, type ArrayFieldOptions, type ArrayItemType, type AssignRoleDto, type AuthConfig, type AuthEventPayload, type AuthMagnetProvider, type AuthResult, AuthStrategy, type AuthUser, AuthenticationRequiredError, BASE_SCHEMA_METADATA_KEY, type BaseEventPayload, type BaseFieldOptions, type BaseSchema, type BaseSchemaOptions, type BlockTypeDefinition, type BlocksFieldOptions, type BooleanFieldOptions, CacheAdapter, type CacheHealthResult, type CacheMagnetProvider, type CategorizedPermissions, type CodeFieldOptions, type ColorFieldOptions, ConfigurationError, ConnectionFailedError, type ContentEventPayload, type ContentVersionEventPayload, type ControllerMetadata, type CreateRoleDto, type DBConfig, DESIGN_META, DESIGN_PARAM_TYPES, DESIGN_RETURN_TYPE, DESIGN_TYPE, DatabaseAdapter, DatabaseError, type DatabaseMagnetProvider, type DatabaseModelInstance, type DatabaseType, type DateFieldOptions, type DateTimeFieldOptions, type DiscoveredController, type DiscoveredMethod, type DiscoveredSchema, DocumentNotFoundError, type DrizzleConfig, DuplicateKeyError, type DuplicateRoleDto, EVENT_HANDLER_METADATA, EXTEND_USER_METADATA_KEY, EmailAdapter, type EmailAdapterName, type EmailAttachment, type EmailConfig, type EmailFieldOptions, type EmailMagnetProvider, EmailNotVerifiedError, EmailServiceError, type EnrichedPluginManifest, type EnumFieldOptions, type EnvVarRequirement, ErrorCode, type ErrorLogData, type ErrorMetadata, type ErrorResponse, type EventHandler, type EventHandlerMetadata, type EventHandlerOptions, type EventHistoryEntry, type EventName, type EventPayload, type EventPayloadMap, ExtendUser, type ExtendUserOptions, type ExternalAuthInfo, ExternalServiceError, FIELD_METADATA_KEY, type FailedLoginEventPayload, Field, type FieldChange, type FieldMetadata, type FieldNamespace, type FieldOptionsMap, type FieldTypeId, type FileFieldOptions, FileNotFoundError, type FilterQuery, type FilterValue, type GalleryFieldOptions, HasPermission, type HashiCorpVaultConfig, HookExecutionError, INJECT_MODEL, type ImageFieldOptions, type InitialConfig, InjectModel, InsufficientPermissionsError, InternalError, type InternationalizationOptions, InvalidCredentialsError, InvalidFormatError, type JSONFieldOptions, type JwtAuthConfig, type LocalStorageConfig, type LogEntry, type LogLevel, type LogMetadata, type LoggerConfig, type LoginCredentials, MagnetError, type MagnetGlobalOptions, MagnetModuleOptions, type MagnetModuleOptionsAsync, type MagnetProvider, type MarkdownFieldOptions, type MediaEventPayload, type MediaFolderEventPayload, type MediaQueryOptions, type MethodMetadata, Mixed, Model, type ModelClass, type ModelCreateOptions, type ModelUpdateOptions, type MongooseConfig, type NativeAccess, type NodemailerConfig, type NotificationChannel, type NotificationChannelAdapter, type NotificationChannelResult, type NotificationEventPayload, type NotificationQueryOptions, type NotificationRecipient, type NotificationSendPayload, type NotifyDto, type NumberFieldOptions, type ObjectFieldOptions, OnEvent, type OperationType, PERMISSION_METADATA_KEY, PERMISSION_OPTIONS_METADATA_KEY, PROP_METADATA_KEY, type PaginatedMedia, type PaginatedNotifications, type PaginatedResult, type PermissionCheckResult, type PermissionDefinition, PermissionDeniedError, type PermissionGroup, type PermissionItem, PermissionMeta, PermissionNotFoundError, type PermissionOptions, type PermissionSource, type PhoneFieldOptions, type PlaygroundOptions, type PluginConfig, PluginError, type PluginEventPayload, type PluginFrontendManifest, type PluginHook, PluginInitializationError, type PluginLifecycle, type PluginMagnetProvider, type PluginMetadata, type PluginModuleOptions, PluginNotFoundError, type PluginRouteDefinition, type PluginSettingsPage, type PluginSidebarItem, type ProjectionQuery, Prop, type PropDefaultValue, type PropOptions, QueryBuilder, QueryFailedError, type QueryOperator, type QueryOptions, type R2StorageConfig, type RBACModuleOptions, RESOLVED_PERMISSION_KEY, RESOLVER_METADATA_KEY, RESOLVE_METADATA_KEY, type RegisterData, type RegisteredHandler, type RegisteredPluginInfo, type RelationshipFieldOptions, RequirePermission, type RequiredEventHandlerOptions, RequiredFieldError, type ResendConfig, Resolve, type ResolveInput, type ResolveOptions, type ResolvedPermission, Resolver, type ResolverInput, type ResolverOptions, ResourceNotFoundError, type RichTextFieldOptions, type Role, type RoleAuditEntry, type RoleEventPayload, RoleNotFoundError, type RoleWithPermissions, type S3StorageConfig, SCHEMA_METADATA_KEY, SCHEMA_OPTIONS_METADATA_KEY, SETTINGS_OPTIONS_METADATA_KEY, SETTING_FIELD_METADATA_KEY, SETTING_METADATA_KEY, Schema, type SchemaIndexOption, type SchemaMetadata, SchemaNotFoundError, type SchemaOptions, type SchemaProperty, type SchemaPropertyValidation, type SchemaSetting, type SelectFieldOptions, type SelectOptionItem, type SendEmailOptions, type SendEmailResult, Setting, type SettingBooleanOptions, SettingField, type SettingFieldBaseOptions, type SettingFieldMetadata, type SettingFieldNamespace, type SettingFieldTypeId, type SettingImageOptions, type SettingJSONOptions, type SettingNumberOptions, type SettingObject, type SettingSecretOptions, type SettingSectionDefinition, type SettingSectionVariant, type SettingSelectOptions, type SettingTextOptions, type SettingType, type SettingValue, Settings, type SettingsBulkUpdatePayload, type SettingsDecoratorOptions, type SettingsEventPayload, type SettingsFeatureOptions, type SettingsGroupEventPayload, type SettingsRecord, type SettingsUpdatePayload, type SlugFieldOptions, type SortDirection, type SortQuery, StorageAdapter, type StorageConfig, StorageError, type StorageMagnetProvider, type SupabaseAuthConfig, type SupabaseStorageConfig, type SupabaseVaultConfig, type SupportedAdapter, type SystemEventPayload, type SystemRoleConfig, type SystemRoleName, type TagsFieldOptions, type TextFieldOptions, type TextareaFieldOptions, TokenExpiredError, TokenInvalidError, TransactionFailedError, type TransformOptions, UI, type UIBase, type UICombobox, type UIDecoratorOptions, type UIFieldMetadata, type UIMultiSelect, type UIPresentationFields, type UISelect, type UISelectItem, type UISide, type UITab, type UITable, type UITableColumn, type UITypes, UI_METADATA_KEY, type URLFieldOptions, UnexpectedError, type UpdatePermissionsDto, type UpdateRoleDto, type UploadOptions, type UploadResult, type UserEventPayload, UserNotFoundError, VERSION_METADATA_KEY, ValidationError, type ValidationErrorDetail, ValidationException, type Validations, Validators, ValueOutOfRangeError, VaultAdapter, type VaultAdapterType, type VaultAppRoleAuth, type VaultAuthConfig, type VaultConfig, type VaultMagnetProvider, type VaultSecretListResponse, type VaultSecretMeta, type VaultStatusResponse, type VaultTokenAuth, Version, type VersionConfig, type VersionData, type VersionDocument, VersionNotFoundError, type VersionStatus, WebhookDeliveryError, type WebhookDeliveryEventPayload, type WebhookEventPayload, assert, assertDefined, clearAdapterCache, createFieldDecorator, detectDatabaseAdapter, fromDrizzleError, fromMongooseError, getAdapterToken, getDocumentId, getExtendUserOptions, getFieldMetadata, getFieldMetadataForProperty, getModelToken, getPermissionMetadata, getRegisteredModel, getSchemaOptions, getSchemaToken, getSettingFields, getSettingToken, getSettingsOptions, hasMethod, hasPermissionDecorator, hasProperties, hasProperty, hasSetLocale, hasToString, isArray, isBoolean, isCastError, isDocument, isDuplicateKeyError, isFieldMetadata, isFunction, isMagnetError, isNumber, isObject, isPostgresUniqueError, isSettingFieldMetadata, isString, isStringArray, isStringRecord, isUserExtension, isValidFieldType, isValidationError, isVersionDocument, mapFieldTypeToProp, mapFieldTypeToUI, registerModel, setDatabaseAdapter, wrapError };