@magnet-cms/common 0.1.1 → 0.3.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.cjs +1898 -60
- package/dist/index.d.cts +3691 -547
- package/dist/index.d.ts +3691 -547
- package/dist/index.js +1796 -61
- package/package.json +4 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,300 +1,2303 @@
|
|
|
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
|
+
/**
|
|
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 {
|
|
82
|
+
key: string;
|
|
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;
|
|
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;
|
|
160
|
+
type: string;
|
|
161
|
+
channels: string[];
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Event payload map - maps event names to their payload types
|
|
165
|
+
*/
|
|
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;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Get payload type for an event name
|
|
252
|
+
*/
|
|
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;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Required event handler options (after defaults applied)
|
|
271
|
+
*/
|
|
272
|
+
interface RequiredEventHandlerOptions {
|
|
273
|
+
priority: number;
|
|
274
|
+
async: boolean;
|
|
275
|
+
name: string;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Registered handler with metadata
|
|
279
|
+
*/
|
|
280
|
+
interface RegisteredHandler<E extends EventName> {
|
|
281
|
+
handler: EventHandler<E>;
|
|
282
|
+
options: RequiredEventHandlerOptions;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Event history entry for debugging
|
|
286
|
+
*/
|
|
287
|
+
interface EventHistoryEntry {
|
|
288
|
+
event: EventName;
|
|
289
|
+
payload: BaseEventPayload;
|
|
290
|
+
timestamp: Date;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Event handler metadata (used by @OnEvent decorator)
|
|
294
|
+
*/
|
|
295
|
+
interface EventHandlerMetadata {
|
|
296
|
+
event: EventName;
|
|
297
|
+
options: EventHandlerOptions;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
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
|
|
312
|
+
*
|
|
313
|
+
* @example
|
|
314
|
+
* ```typescript
|
|
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)
|
|
320
|
+
* }
|
|
321
|
+
*
|
|
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)
|
|
326
|
+
* }
|
|
327
|
+
* }
|
|
328
|
+
* ```
|
|
329
|
+
*/
|
|
330
|
+
declare function OnEvent(event: EventName, options?: EventHandlerOptions): MethodDecorator;
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Base options shared by all field decorators
|
|
334
|
+
*/
|
|
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 */
|
|
349
|
+
description?: string;
|
|
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;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Text field options
|
|
367
|
+
*/
|
|
368
|
+
interface TextFieldOptions extends BaseFieldOptions {
|
|
369
|
+
minLength?: number;
|
|
370
|
+
maxLength?: number;
|
|
371
|
+
pattern?: string;
|
|
372
|
+
transform?: 'none' | 'lowercase' | 'uppercase' | 'trim';
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Number field options
|
|
376
|
+
*/
|
|
377
|
+
interface NumberFieldOptions extends BaseFieldOptions {
|
|
378
|
+
min?: number;
|
|
379
|
+
max?: number;
|
|
380
|
+
integer?: boolean;
|
|
381
|
+
step?: number;
|
|
382
|
+
default?: number;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Boolean field options
|
|
386
|
+
*/
|
|
387
|
+
interface BooleanFieldOptions extends BaseFieldOptions {
|
|
388
|
+
default?: boolean;
|
|
389
|
+
style?: 'switch' | 'checkbox';
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Date field options
|
|
393
|
+
*/
|
|
394
|
+
interface DateFieldOptions extends BaseFieldOptions {
|
|
395
|
+
min?: Date | string;
|
|
396
|
+
max?: Date | string;
|
|
397
|
+
default?: Date | string | 'now' | (() => Date);
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* DateTime field options
|
|
401
|
+
*/
|
|
402
|
+
interface DateTimeFieldOptions extends DateFieldOptions {
|
|
403
|
+
timezone?: string;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Rich text field options
|
|
407
|
+
*/
|
|
408
|
+
interface RichTextFieldOptions extends BaseFieldOptions {
|
|
409
|
+
toolbar?: 'minimal' | 'standard' | 'full';
|
|
410
|
+
maxLength?: number;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Markdown field options
|
|
414
|
+
*/
|
|
415
|
+
interface MarkdownFieldOptions extends BaseFieldOptions {
|
|
416
|
+
preview?: boolean;
|
|
417
|
+
maxLength?: number;
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Code field options
|
|
421
|
+
*/
|
|
422
|
+
interface CodeFieldOptions extends BaseFieldOptions {
|
|
423
|
+
language?: string;
|
|
424
|
+
lineNumbers?: boolean;
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* JSON field options
|
|
428
|
+
*/
|
|
429
|
+
interface JSONFieldOptions extends BaseFieldOptions {
|
|
430
|
+
/** Optional JSON schema for validation */
|
|
431
|
+
schema?: unknown;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Select option item
|
|
435
|
+
*/
|
|
436
|
+
interface SelectOptionItem {
|
|
437
|
+
label: string;
|
|
438
|
+
value: string | number;
|
|
439
|
+
}
|
|
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;
|
|
447
|
+
}
|
|
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;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Tags field options
|
|
458
|
+
*/
|
|
459
|
+
interface TagsFieldOptions extends BaseFieldOptions {
|
|
460
|
+
suggestions?: string[];
|
|
461
|
+
maxTags?: number;
|
|
462
|
+
allowCreate?: boolean;
|
|
463
|
+
}
|
|
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[];
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Image field options
|
|
477
|
+
*/
|
|
478
|
+
interface ImageFieldOptions extends BaseFieldOptions {
|
|
479
|
+
folder?: string;
|
|
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
|
+
|
|
4
676
|
type ResolverOptions = {
|
|
5
677
|
schema: Type;
|
|
6
678
|
};
|
|
7
|
-
type ResolverInput = (() => Type) | ResolverOptions;
|
|
8
|
-
type ResolveOptions = {
|
|
9
|
-
type: Type | [
|
|
10
|
-
isArray?: boolean;
|
|
11
|
-
description?: string;
|
|
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[];
|
|
12
1605
|
};
|
|
13
|
-
type
|
|
14
|
-
|
|
15
|
-
type
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
intl?: boolean;
|
|
22
|
-
hidden?: boolean;
|
|
23
|
-
readonly?: boolean;
|
|
1606
|
+
type SchemaProperty = {
|
|
1607
|
+
name: string;
|
|
1608
|
+
type: string;
|
|
1609
|
+
isArray: boolean;
|
|
1610
|
+
unique: boolean;
|
|
1611
|
+
required: boolean;
|
|
1612
|
+
validations: SchemaPropertyValidation[];
|
|
1613
|
+
ui?: UIDecoratorOptions;
|
|
24
1614
|
ref?: string;
|
|
25
1615
|
};
|
|
26
|
-
type
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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;
|
|
32
1625
|
};
|
|
33
1626
|
|
|
34
|
-
type
|
|
35
|
-
|
|
36
|
-
type UIBase = {
|
|
37
|
-
label?: string;
|
|
1627
|
+
type InitialConfig = {
|
|
1628
|
+
title?: string;
|
|
38
1629
|
description?: string;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
};
|
|
43
|
-
type UISelectItem = {
|
|
44
|
-
key: string;
|
|
45
|
-
value: string;
|
|
46
|
-
};
|
|
47
|
-
type UITab = UIBase & {
|
|
48
|
-
tab: string;
|
|
49
|
-
side?: never;
|
|
50
|
-
options?: UISelectItem[];
|
|
51
|
-
};
|
|
52
|
-
type UISide = UIBase & {
|
|
53
|
-
side: true;
|
|
54
|
-
tab?: never;
|
|
55
|
-
options?: UISelectItem[];
|
|
56
|
-
};
|
|
57
|
-
type UISelect = UIBase & {
|
|
58
|
-
type: 'select';
|
|
59
|
-
multi?: boolean;
|
|
60
|
-
options: UISelectItem[];
|
|
61
|
-
};
|
|
62
|
-
type UIMultiSelect = UIBase & {
|
|
63
|
-
type: 'multiSelect';
|
|
64
|
-
options: UISelectItem[];
|
|
65
|
-
};
|
|
66
|
-
type UICombobox = UIBase & {
|
|
67
|
-
type: 'combobox';
|
|
68
|
-
options: UISelectItem[];
|
|
69
|
-
};
|
|
70
|
-
type UITableColumn = {
|
|
71
|
-
key: string;
|
|
72
|
-
header: string;
|
|
73
|
-
type?: 'text' | 'badge' | 'status' | 'input' | 'code';
|
|
74
|
-
};
|
|
75
|
-
type UITable = UIBase & {
|
|
76
|
-
type: 'table';
|
|
77
|
-
columns?: UITableColumn[];
|
|
1630
|
+
env: string;
|
|
1631
|
+
schemas: SchemaMetadata[];
|
|
1632
|
+
settings: SchemaMetadata[];
|
|
78
1633
|
};
|
|
79
|
-
type UIDecoratorOptions = UITab | UISide | UISelect | UIMultiSelect | UICombobox | UITable;
|
|
80
1634
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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;
|
|
86
1840
|
};
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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<{
|
|
90
1918
|
name: string;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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;
|
|
107
2016
|
};
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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>[];
|
|
117
2033
|
};
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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;
|
|
125
2043
|
};
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
schemas: SchemaMetadata[];
|
|
132
|
-
settings: SchemaMetadata[];
|
|
2044
|
+
/**
|
|
2045
|
+
* Projection specification for field selection
|
|
2046
|
+
*/
|
|
2047
|
+
type ProjectionQuery<Schema> = {
|
|
2048
|
+
[K in keyof Schema]?: 0 | 1 | boolean;
|
|
133
2049
|
};
|
|
134
|
-
|
|
135
2050
|
/**
|
|
136
|
-
*
|
|
2051
|
+
* Query execution options
|
|
137
2052
|
*/
|
|
138
|
-
interface
|
|
139
|
-
/**
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
|
|
145
|
-
/** Optional additional user data */
|
|
146
|
-
[key: string]: unknown;
|
|
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;
|
|
147
2060
|
}
|
|
148
2061
|
/**
|
|
149
|
-
*
|
|
2062
|
+
* Paginated query result
|
|
150
2063
|
*/
|
|
151
|
-
interface
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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;
|
|
155
2073
|
}
|
|
2074
|
+
|
|
156
2075
|
/**
|
|
157
|
-
*
|
|
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
|
+
* ```
|
|
158
2087
|
*/
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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>;
|
|
165
2162
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
token_type?: string;
|
|
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;
|
|
174
2170
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
interface JwtAuthConfig {
|
|
179
|
-
/** JWT secret key */
|
|
180
|
-
secret: string;
|
|
181
|
-
/** Token expiration time (e.g., '7d', '1h') */
|
|
182
|
-
expiresIn?: string;
|
|
2171
|
+
interface ModelUpdateOptions {
|
|
2172
|
+
/** Skip database-level validation (useful for draft documents) */
|
|
2173
|
+
skipValidation?: boolean;
|
|
183
2174
|
}
|
|
184
2175
|
/**
|
|
185
|
-
*
|
|
2176
|
+
* Version document type for history/versioning
|
|
186
2177
|
*/
|
|
187
|
-
interface
|
|
188
|
-
/**
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
|
|
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';
|
|
194
2195
|
}
|
|
195
2196
|
/**
|
|
196
|
-
*
|
|
2197
|
+
* Native access wrapper - provides type-safe native operations
|
|
197
2198
|
*/
|
|
198
|
-
interface
|
|
199
|
-
/**
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
|
|
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;
|
|
213
2216
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
*
|
|
223
|
-
* async validate(payload: unknown): Promise<AuthUser | null> {
|
|
224
|
-
* // Validate Supabase JWT token
|
|
225
|
-
* }
|
|
226
|
-
*
|
|
227
|
-
* async login(credentials: LoginCredentials): Promise<AuthResult> {
|
|
228
|
-
* // Authenticate with Supabase
|
|
229
|
-
* }
|
|
230
|
-
*
|
|
231
|
-
* async register(data: RegisterData): Promise<AuthUser> {
|
|
232
|
-
* // Register user in Supabase
|
|
233
|
-
* }
|
|
234
|
-
*
|
|
235
|
-
* async validateCredentials(email: string, password: string): Promise<AuthUser | null> {
|
|
236
|
-
* // Validate user credentials
|
|
237
|
-
* }
|
|
238
|
-
* }
|
|
239
|
-
* ```
|
|
240
|
-
*/
|
|
241
|
-
declare abstract class AuthStrategy {
|
|
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>;
|
|
242
2225
|
/**
|
|
243
|
-
*
|
|
2226
|
+
* Set the locale for subsequent operations
|
|
2227
|
+
* @param locale The locale to use
|
|
2228
|
+
* @returns Cloned model instance with locale set
|
|
244
2229
|
*/
|
|
245
|
-
abstract
|
|
2230
|
+
abstract locale(locale: string): this;
|
|
246
2231
|
/**
|
|
247
|
-
*
|
|
2232
|
+
* Get current locale
|
|
248
2233
|
*/
|
|
249
|
-
|
|
2234
|
+
getLocale(): string;
|
|
250
2235
|
/**
|
|
251
|
-
*
|
|
252
|
-
* @param
|
|
253
|
-
* @returns
|
|
2236
|
+
* Set the version for subsequent operations
|
|
2237
|
+
* @param versionId The version ID or status ('draft', 'published', 'archived')
|
|
2238
|
+
* @returns Same instance (chainable)
|
|
254
2239
|
*/
|
|
255
|
-
|
|
2240
|
+
version(versionId: string): this;
|
|
256
2241
|
/**
|
|
257
|
-
*
|
|
258
|
-
* @param credentials - Login credentials (strategy-specific)
|
|
259
|
-
* @returns Authentication result with access token
|
|
2242
|
+
* Check if versioning is enabled for this model
|
|
260
2243
|
*/
|
|
261
|
-
|
|
2244
|
+
isVersioningEnabled(): boolean;
|
|
262
2245
|
/**
|
|
263
|
-
*
|
|
264
|
-
* @param
|
|
265
|
-
* @
|
|
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
|
|
266
2250
|
*/
|
|
267
|
-
|
|
2251
|
+
createVersion(documentId: string, data: Partial<Schema>): Promise<VersionDocument | null>;
|
|
268
2252
|
/**
|
|
269
|
-
*
|
|
270
|
-
* @param
|
|
271
|
-
* @param password - User password
|
|
272
|
-
* @returns User if valid, null otherwise
|
|
2253
|
+
* Find all versions of a document
|
|
2254
|
+
* @param documentId The document ID
|
|
273
2255
|
*/
|
|
274
|
-
|
|
2256
|
+
findVersions(documentId: string): Promise<VersionDocument[]>;
|
|
275
2257
|
/**
|
|
276
|
-
*
|
|
277
|
-
* @param
|
|
278
|
-
* @returns New authentication result
|
|
2258
|
+
* Find a specific version by ID
|
|
2259
|
+
* @param versionId The version ID
|
|
279
2260
|
*/
|
|
280
|
-
|
|
2261
|
+
findVersionById(versionId: string): Promise<VersionDocument | null>;
|
|
281
2262
|
/**
|
|
282
|
-
*
|
|
283
|
-
* @param
|
|
2263
|
+
* Restore a document to a specific version
|
|
2264
|
+
* @param versionId The version ID to restore
|
|
284
2265
|
*/
|
|
285
|
-
|
|
2266
|
+
restoreVersion(versionId: string): Promise<BaseSchema<Schema> | null>;
|
|
286
2267
|
/**
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
* @
|
|
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
|
+
* ```
|
|
291
2279
|
*/
|
|
292
|
-
|
|
2280
|
+
query(): QueryBuilder<Schema>;
|
|
293
2281
|
/**
|
|
294
|
-
* Get
|
|
295
|
-
*
|
|
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
|
|
296
2286
|
*/
|
|
297
|
-
|
|
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>;
|
|
298
2301
|
}
|
|
299
2302
|
|
|
300
2303
|
type MongooseConfig = {
|
|
@@ -313,20 +2316,101 @@ type DrizzleConfig = {
|
|
|
313
2316
|
driver?: 'pg' | 'neon' | 'mysql2' | 'better-sqlite3';
|
|
314
2317
|
/** Enable debug logging */
|
|
315
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
|
+
};
|
|
316
2332
|
};
|
|
317
2333
|
type DBConfig = MongooseConfig | DrizzleConfig;
|
|
318
|
-
|
|
319
|
-
|
|
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
|
+
*/
|
|
320
2384
|
abstract forFeature(schemas: Type | Type[]): DynamicModule;
|
|
321
|
-
|
|
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
|
+
*/
|
|
322
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;
|
|
323
2407
|
}
|
|
324
2408
|
|
|
325
2409
|
/**
|
|
326
2410
|
* Plugin metadata for the @Plugin decorator
|
|
327
2411
|
*/
|
|
328
2412
|
interface PluginMetadata {
|
|
329
|
-
/** Unique plugin identifier (e.g., '
|
|
2413
|
+
/** Unique plugin identifier (e.g., 'playground') */
|
|
330
2414
|
name: string;
|
|
331
2415
|
/** Human-readable description */
|
|
332
2416
|
description?: string;
|
|
@@ -686,11 +2770,116 @@ declare abstract class StorageAdapter {
|
|
|
686
2770
|
*/
|
|
687
2771
|
copy?(path: string, newPath: string): Promise<UploadResult>;
|
|
688
2772
|
/**
|
|
689
|
-
* Generate a signed URL for temporary access (for S3/R2)
|
|
690
|
-
* @param path - Storage path or key
|
|
691
|
-
* @param expiresIn - Expiration time in seconds
|
|
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.
|
|
692
2863
|
*/
|
|
693
|
-
|
|
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[];
|
|
694
2883
|
}
|
|
695
2884
|
|
|
696
2885
|
interface InternationalizationOptions {
|
|
@@ -709,6 +2898,14 @@ interface PlaygroundOptions {
|
|
|
709
2898
|
*/
|
|
710
2899
|
schemasPath?: string;
|
|
711
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
|
+
}
|
|
712
2909
|
declare class MagnetModuleOptions {
|
|
713
2910
|
db: DBConfig;
|
|
714
2911
|
jwt: {
|
|
@@ -721,14 +2918,47 @@ declare class MagnetModuleOptions {
|
|
|
721
2918
|
internationalization?: InternationalizationOptions;
|
|
722
2919
|
playground?: PlaygroundOptions;
|
|
723
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;
|
|
724
2927
|
/**
|
|
725
2928
|
* Plugins to load with the Magnet module
|
|
726
2929
|
*/
|
|
727
2930
|
plugins?: PluginConfig[];
|
|
728
|
-
|
|
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);
|
|
729
2959
|
}
|
|
730
2960
|
type MagnetModuleOptionsAsync = {
|
|
731
|
-
useFactory: (...args:
|
|
2961
|
+
useFactory: (...args: unknown[]) => Promise<MagnetModuleOptions> | MagnetModuleOptions;
|
|
732
2962
|
inject?: Type[];
|
|
733
2963
|
imports?: Type[];
|
|
734
2964
|
};
|
|
@@ -751,370 +2981,1148 @@ type DiscoveredSchema = {
|
|
|
751
2981
|
type Validations = {
|
|
752
2982
|
type: string;
|
|
753
2983
|
name: string;
|
|
754
|
-
constraints:
|
|
2984
|
+
constraints: unknown[];
|
|
755
2985
|
}[];
|
|
756
2986
|
|
|
757
2987
|
type VersionStatus = 'draft' | 'published' | 'archived';
|
|
758
2988
|
interface VersionConfig {
|
|
759
2989
|
/**
|
|
760
|
-
* Maximum number of versions to keep per document
|
|
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;
|
|
3109
|
+
/**
|
|
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)
|
|
3113
|
+
*/
|
|
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[];
|
|
3142
|
+
/**
|
|
3143
|
+
* Which channels to deliver to.
|
|
3144
|
+
* Defaults to `['platform']` when not specified.
|
|
3145
|
+
*/
|
|
3146
|
+
channels?: NotificationChannel[];
|
|
3147
|
+
/**
|
|
3148
|
+
* Notification category / type identifier.
|
|
3149
|
+
* Useful for filtering and icon mapping in the UI.
|
|
3150
|
+
*/
|
|
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;
|
|
3158
|
+
/**
|
|
3159
|
+
* Additional arbitrary metadata stored with the notification.
|
|
3160
|
+
* Not shown directly in UI but available for custom logic.
|
|
3161
|
+
*/
|
|
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 {
|
|
3219
|
+
/**
|
|
3220
|
+
* Unique identifier for this adapter
|
|
3221
|
+
*/
|
|
3222
|
+
abstract readonly name: string;
|
|
3223
|
+
/**
|
|
3224
|
+
* Retrieve a cached value by key.
|
|
3225
|
+
* @param key - Cache key
|
|
3226
|
+
* @returns The cached value, or null if not found or expired
|
|
3227
|
+
*/
|
|
3228
|
+
abstract get<T>(key: string): Promise<T | null>;
|
|
3229
|
+
/**
|
|
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.
|
|
3234
|
+
*/
|
|
3235
|
+
abstract set<T>(key: string, value: T, ttl?: number): Promise<void>;
|
|
3236
|
+
/**
|
|
3237
|
+
* Remove a value from the cache by key.
|
|
3238
|
+
* @param key - Cache key to delete
|
|
3239
|
+
*/
|
|
3240
|
+
abstract delete(key: string): Promise<void>;
|
|
3241
|
+
/**
|
|
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
|
|
3245
|
+
*/
|
|
3246
|
+
abstract deleteByPattern(pattern: string): Promise<void>;
|
|
3247
|
+
/**
|
|
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
|
|
3251
|
+
*/
|
|
3252
|
+
abstract has(key: string): Promise<boolean>;
|
|
3253
|
+
/**
|
|
3254
|
+
* Remove all entries from the cache.
|
|
3255
|
+
* For Redis, only clears keys within this adapter's key prefix.
|
|
3256
|
+
*/
|
|
3257
|
+
abstract clear(): Promise<void>;
|
|
3258
|
+
/**
|
|
3259
|
+
* Check the health of the cache backend.
|
|
3260
|
+
* @returns Health result with status and optional message
|
|
3261
|
+
*/
|
|
3262
|
+
abstract healthCheck(): Promise<CacheHealthResult>;
|
|
3263
|
+
/**
|
|
3264
|
+
* Optional cleanup/disconnect method.
|
|
3265
|
+
* Called when the module is destroyed.
|
|
3266
|
+
*/
|
|
3267
|
+
dispose?(): Promise<void>;
|
|
3268
|
+
}
|
|
3269
|
+
|
|
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;
|
|
3281
|
+
}
|
|
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;
|
|
3302
|
+
};
|
|
3303
|
+
/**
|
|
3304
|
+
* Admin panel configuration (enabled by default when omitted).
|
|
3305
|
+
* @example admin: false // API-only / headless
|
|
3306
|
+
* @example admin: { enabled: true, path: '/dashboard' }
|
|
3307
|
+
*/
|
|
3308
|
+
admin?: boolean | AdminConfig;
|
|
3309
|
+
/** RBAC (Role-Based Access Control) configuration */
|
|
3310
|
+
rbac?: RBACModuleOptions;
|
|
3311
|
+
/** Internationalization settings */
|
|
3312
|
+
internationalization?: InternationalizationOptions;
|
|
3313
|
+
/** Global Playground (schema builder) settings */
|
|
3314
|
+
playground?: PlaygroundOptions;
|
|
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 {
|
|
3440
|
+
/**
|
|
3441
|
+
* Whether to include timestamps (createdAt, updatedAt)
|
|
3442
|
+
* @default true
|
|
3443
|
+
*/
|
|
3444
|
+
timestamps?: boolean;
|
|
3445
|
+
}
|
|
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;
|
|
3484
|
+
|
|
3485
|
+
declare function Prop(options?: PropOptions): PropertyDecorator;
|
|
3486
|
+
|
|
3487
|
+
declare function Schema(options?: SchemaOptions): ClassDecorator;
|
|
3488
|
+
declare function getSchemaOptions(target: Function): SchemaOptions;
|
|
3489
|
+
|
|
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: {
|
|
3540
|
+
/**
|
|
3541
|
+
* Text setting field
|
|
761
3542
|
*/
|
|
762
|
-
|
|
3543
|
+
readonly Text: (options: SettingTextOptions) => PropertyDecorator;
|
|
763
3544
|
/**
|
|
764
|
-
*
|
|
3545
|
+
* Number setting field
|
|
765
3546
|
*/
|
|
766
|
-
|
|
767
|
-
/**
|
|
768
|
-
* Auto-publish drafts after a certain time
|
|
769
|
-
*/
|
|
770
|
-
autoPublish?: boolean;
|
|
771
|
-
/**
|
|
772
|
-
* Require approval before publishing
|
|
773
|
-
*/
|
|
774
|
-
requireApproval?: boolean;
|
|
775
|
-
};
|
|
776
|
-
}
|
|
777
|
-
interface VersionData<T> {
|
|
3547
|
+
readonly Number: (options: SettingNumberOptions) => PropertyDecorator;
|
|
778
3548
|
/**
|
|
779
|
-
*
|
|
3549
|
+
* Boolean setting field (toggle/switch)
|
|
780
3550
|
*/
|
|
781
|
-
|
|
3551
|
+
readonly Boolean: (options: SettingBooleanOptions) => PropertyDecorator;
|
|
782
3552
|
/**
|
|
783
|
-
*
|
|
3553
|
+
* Select setting field (dropdown)
|
|
784
3554
|
*/
|
|
785
|
-
|
|
3555
|
+
readonly Select: (options: SettingSelectOptions) => PropertyDecorator;
|
|
786
3556
|
/**
|
|
787
|
-
*
|
|
3557
|
+
* Secret setting field (encrypted, masked in UI)
|
|
788
3558
|
*/
|
|
789
|
-
|
|
3559
|
+
readonly Secret: (options: SettingSecretOptions) => PropertyDecorator;
|
|
790
3560
|
/**
|
|
791
|
-
*
|
|
3561
|
+
* Image setting field
|
|
792
3562
|
*/
|
|
793
|
-
|
|
3563
|
+
readonly Image: (options: SettingImageOptions) => PropertyDecorator;
|
|
794
3564
|
/**
|
|
795
|
-
*
|
|
3565
|
+
* JSON setting field
|
|
796
3566
|
*/
|
|
797
|
-
|
|
3567
|
+
readonly JSON: (options: SettingJSONOptions) => PropertyDecorator;
|
|
798
3568
|
/**
|
|
799
|
-
*
|
|
3569
|
+
* Textarea setting field (multi-line text)
|
|
800
3570
|
*/
|
|
801
|
-
|
|
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);
|
|
802
3691
|
/**
|
|
803
|
-
*
|
|
3692
|
+
* Convert to API response format
|
|
804
3693
|
*/
|
|
805
|
-
|
|
3694
|
+
toResponse(): ErrorResponse;
|
|
3695
|
+
/**
|
|
3696
|
+
* Convert to JSON for logging
|
|
3697
|
+
*/
|
|
3698
|
+
toJSON(): Record<string, unknown>;
|
|
806
3699
|
}
|
|
807
3700
|
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
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[];
|
|
813
3709
|
}
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
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);
|
|
817
3748
|
}
|
|
818
3749
|
|
|
819
3750
|
/**
|
|
820
|
-
*
|
|
3751
|
+
* Authentication required error
|
|
3752
|
+
* Thrown when a request requires authentication but none is provided
|
|
821
3753
|
*/
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
/** Greater than */
|
|
828
|
-
$gt?: T;
|
|
829
|
-
/** Greater than or equal to */
|
|
830
|
-
$gte?: T;
|
|
831
|
-
/** Less than */
|
|
832
|
-
$lt?: T;
|
|
833
|
-
/** Less than or equal to */
|
|
834
|
-
$lte?: T;
|
|
835
|
-
/** In array */
|
|
836
|
-
$in?: T[];
|
|
837
|
-
/** Not in array */
|
|
838
|
-
$nin?: T[];
|
|
839
|
-
/** Field exists */
|
|
840
|
-
$exists?: boolean;
|
|
841
|
-
/** Regular expression match */
|
|
842
|
-
$regex?: string | RegExp;
|
|
843
|
-
/** Regex options (i, m, s, x) */
|
|
844
|
-
$options?: string;
|
|
845
|
-
};
|
|
3754
|
+
declare class AuthenticationRequiredError extends MagnetError {
|
|
3755
|
+
readonly code = ErrorCode.AUTHENTICATION_REQUIRED;
|
|
3756
|
+
readonly httpStatus = 401;
|
|
3757
|
+
constructor(message?: string, metadata?: ErrorMetadata);
|
|
3758
|
+
}
|
|
846
3759
|
/**
|
|
847
|
-
*
|
|
3760
|
+
* Invalid credentials error
|
|
3761
|
+
* Thrown when email/password combination is incorrect
|
|
848
3762
|
*/
|
|
849
|
-
|
|
3763
|
+
declare class InvalidCredentialsError extends MagnetError {
|
|
3764
|
+
readonly code = ErrorCode.INVALID_CREDENTIALS;
|
|
3765
|
+
readonly httpStatus = 401;
|
|
3766
|
+
constructor(message?: string, metadata?: ErrorMetadata);
|
|
3767
|
+
}
|
|
850
3768
|
/**
|
|
851
|
-
*
|
|
3769
|
+
* Token expired error
|
|
3770
|
+
* Thrown when a JWT or refresh token has expired
|
|
852
3771
|
*/
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
/** Logical OR */
|
|
859
|
-
$or?: FilterQuery<Schema>[];
|
|
860
|
-
/** Logical NOR */
|
|
861
|
-
$nor?: FilterQuery<Schema>[];
|
|
862
|
-
};
|
|
3772
|
+
declare class TokenExpiredError extends MagnetError {
|
|
3773
|
+
readonly code = ErrorCode.TOKEN_EXPIRED;
|
|
3774
|
+
readonly httpStatus = 401;
|
|
3775
|
+
constructor(message?: string, metadata?: ErrorMetadata);
|
|
3776
|
+
}
|
|
863
3777
|
/**
|
|
864
|
-
*
|
|
3778
|
+
* Token invalid error
|
|
3779
|
+
* Thrown when a JWT or refresh token is malformed or invalid
|
|
865
3780
|
*/
|
|
866
|
-
|
|
3781
|
+
declare class TokenInvalidError extends MagnetError {
|
|
3782
|
+
readonly code = ErrorCode.TOKEN_INVALID;
|
|
3783
|
+
readonly httpStatus = 401;
|
|
3784
|
+
constructor(message?: string, metadata?: ErrorMetadata);
|
|
3785
|
+
}
|
|
867
3786
|
/**
|
|
868
|
-
*
|
|
3787
|
+
* Account locked error
|
|
3788
|
+
* Thrown when an account is temporarily locked due to too many failed attempts
|
|
869
3789
|
*/
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
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
|
+
}
|
|
873
3796
|
/**
|
|
874
|
-
*
|
|
3797
|
+
* Email not verified error
|
|
3798
|
+
* Thrown when an action requires email verification
|
|
875
3799
|
*/
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
3800
|
+
declare class EmailNotVerifiedError extends MagnetError {
|
|
3801
|
+
readonly code = ErrorCode.EMAIL_NOT_VERIFIED;
|
|
3802
|
+
readonly httpStatus = 403;
|
|
3803
|
+
constructor(message?: string, metadata?: ErrorMetadata);
|
|
3804
|
+
}
|
|
879
3805
|
/**
|
|
880
|
-
*
|
|
3806
|
+
* Permission denied error
|
|
3807
|
+
* Thrown when user lacks permission for an action
|
|
881
3808
|
*/
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
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);
|
|
889
4029
|
}
|
|
890
4030
|
/**
|
|
891
|
-
*
|
|
4031
|
+
* Unexpected error
|
|
4032
|
+
* Used as a fallback for unknown error types
|
|
892
4033
|
*/
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
/** Current page (if using skip/limit) */
|
|
899
|
-
page?: number;
|
|
900
|
-
/** Page size */
|
|
901
|
-
limit?: number;
|
|
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);
|
|
902
4039
|
}
|
|
903
4040
|
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
declare function Schema(options?: SchemaOptions): ClassDecorator;
|
|
911
|
-
declare function getSchemaOptions(target: Function): SchemaOptions;
|
|
912
|
-
|
|
913
|
-
declare function Setting(): ClassDecorator;
|
|
914
|
-
|
|
915
|
-
interface UIFieldMetadata {
|
|
916
|
-
propertyKey: string | symbol;
|
|
917
|
-
options: UIDecoratorOptions & {
|
|
918
|
-
designType: Function;
|
|
919
|
-
};
|
|
4041
|
+
/**
|
|
4042
|
+
* Context for error conversion
|
|
4043
|
+
*/
|
|
4044
|
+
interface ErrorContext {
|
|
4045
|
+
schema?: string;
|
|
4046
|
+
operation?: string;
|
|
920
4047
|
}
|
|
921
|
-
declare function UI(options: UIDecoratorOptions): PropertyDecorator;
|
|
922
|
-
|
|
923
|
-
declare const Validators: (...validators: PropertyDecorator[]) => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
|
|
924
|
-
|
|
925
|
-
declare const VERSION_METADATA_KEY = "version:metadata";
|
|
926
4048
|
/**
|
|
927
|
-
*
|
|
928
|
-
* @param
|
|
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
|
|
929
4053
|
*/
|
|
930
|
-
declare function
|
|
931
|
-
|
|
932
|
-
|
|
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;
|
|
933
4071
|
|
|
934
4072
|
declare class ValidationException extends Error {
|
|
935
|
-
readonly errors: ValidationError[];
|
|
936
|
-
constructor(errors: ValidationError[]);
|
|
4073
|
+
readonly errors: ValidationError$1[];
|
|
4074
|
+
constructor(errors: ValidationError$1[]);
|
|
937
4075
|
}
|
|
938
4076
|
|
|
939
4077
|
/**
|
|
940
|
-
*
|
|
941
|
-
*
|
|
4078
|
+
* Register the getter that returns the same `DatabaseAdapter` singleton used by
|
|
4079
|
+
* the adapter’s `forRoot()` / `getInstance()`.
|
|
942
4080
|
*
|
|
943
|
-
*
|
|
944
|
-
*
|
|
945
|
-
*
|
|
946
|
-
*
|
|
947
|
-
*
|
|
948
|
-
*
|
|
949
|
-
*
|
|
950
|
-
*
|
|
4081
|
+
* **Why:** With Nest’s compiled CJS output, feature modules are often
|
|
4082
|
+
* `require()`’d before the `AppModule` class decorator runs
|
|
4083
|
+
* `MagnetModule.forRoot()`, so `DatabaseModule.register()` has not executed yet
|
|
4084
|
+
* and core cannot resolve the adapter from registration alone.
|
|
4085
|
+
*
|
|
4086
|
+
* Official packages `@magnet-cms/adapter-db-drizzle` and
|
|
4087
|
+
* `@magnet-cms/adapter-db-mongoose` call this from their entry `index.ts`.
|
|
4088
|
+
* Custom third-party DB adapters should register here if they see the same
|
|
4089
|
+
* load-order failure.
|
|
951
4090
|
*/
|
|
952
|
-
declare
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
* @param filter Filter conditions to AND with existing filters
|
|
961
|
-
*/
|
|
962
|
-
abstract and(filter: FilterQuery<Schema>): this;
|
|
963
|
-
/**
|
|
964
|
-
* Add OR conditions
|
|
965
|
-
* @param filters Array of filter conditions for OR logic
|
|
966
|
-
*/
|
|
967
|
-
abstract or(filters: FilterQuery<Schema>[]): this;
|
|
968
|
-
/**
|
|
969
|
-
* Sort results by specified fields
|
|
970
|
-
* @param sort Sort specification with field names and directions
|
|
971
|
-
*/
|
|
972
|
-
abstract sort(sort: SortQuery<Schema>): this;
|
|
973
|
-
/**
|
|
974
|
-
* Limit the number of results
|
|
975
|
-
* @param count Maximum number of documents to return
|
|
976
|
-
*/
|
|
977
|
-
abstract limit(count: number): this;
|
|
978
|
-
/**
|
|
979
|
-
* Skip a number of results (for pagination)
|
|
980
|
-
* @param count Number of documents to skip
|
|
981
|
-
*/
|
|
982
|
-
abstract skip(count: number): this;
|
|
983
|
-
/**
|
|
984
|
-
* Select specific fields to return
|
|
985
|
-
* @param projection Field selection (1 to include, 0 to exclude)
|
|
986
|
-
*/
|
|
987
|
-
abstract select(projection: ProjectionQuery<Schema>): this;
|
|
988
|
-
/**
|
|
989
|
-
* Execute the query and return all matching documents
|
|
990
|
-
*/
|
|
991
|
-
abstract exec(): Promise<BaseSchema<Schema>[]>;
|
|
992
|
-
/**
|
|
993
|
-
* Execute the query and return a single document
|
|
994
|
-
*/
|
|
995
|
-
abstract execOne(): Promise<BaseSchema<Schema> | null>;
|
|
996
|
-
/**
|
|
997
|
-
* Count matching documents without fetching them
|
|
998
|
-
*/
|
|
999
|
-
abstract count(): Promise<number>;
|
|
1000
|
-
/**
|
|
1001
|
-
* Check if any matching documents exist
|
|
1002
|
-
*/
|
|
1003
|
-
abstract exists(): Promise<boolean>;
|
|
1004
|
-
/**
|
|
1005
|
-
* Execute with pagination info
|
|
1006
|
-
* @returns Data array with total count
|
|
1007
|
-
*/
|
|
1008
|
-
abstract paginate(): Promise<PaginatedResult<BaseSchema<Schema>>>;
|
|
1009
|
-
/**
|
|
1010
|
-
* Set the locale for query results
|
|
1011
|
-
* @param locale The locale to use
|
|
1012
|
-
*/
|
|
1013
|
-
abstract locale(locale: string): this;
|
|
1014
|
-
/**
|
|
1015
|
-
* Set the version filter for query
|
|
1016
|
-
* @param versionId The version ID or status
|
|
1017
|
-
*/
|
|
1018
|
-
abstract version(versionId: string): this;
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
type BaseSchema<T> = {
|
|
1022
|
-
id: string;
|
|
1023
|
-
} & T;
|
|
1024
|
-
interface ModelCreateOptions {
|
|
1025
|
-
/** Skip database-level validation (useful for draft documents) */
|
|
1026
|
-
skipValidation?: boolean;
|
|
1027
|
-
}
|
|
1028
|
-
interface ModelUpdateOptions {
|
|
1029
|
-
/** Skip database-level validation (useful for draft documents) */
|
|
1030
|
-
skipValidation?: boolean;
|
|
1031
|
-
}
|
|
1032
|
-
declare abstract class Model<Schema> {
|
|
1033
|
-
abstract create(data: Partial<BaseSchema<Schema>>, options?: ModelCreateOptions): Promise<BaseSchema<Schema>>;
|
|
1034
|
-
abstract find(): Promise<BaseSchema<Schema>[]>;
|
|
1035
|
-
abstract findById(id: string): Promise<BaseSchema<Schema> | null>;
|
|
1036
|
-
abstract findOne(query: Partial<BaseSchema<Schema>>): Promise<BaseSchema<Schema> | null>;
|
|
1037
|
-
abstract findMany(query: Partial<BaseSchema<Schema>>): Promise<BaseSchema<Schema>[]>;
|
|
1038
|
-
abstract update(query: Partial<BaseSchema<Schema>>, data: Partial<BaseSchema<Schema>>, options?: ModelUpdateOptions): Promise<BaseSchema<Schema>>;
|
|
1039
|
-
abstract delete(query: Partial<BaseSchema<Schema>>): Promise<boolean>;
|
|
1040
|
-
/**
|
|
1041
|
-
* Set the locale for subsequent operations
|
|
1042
|
-
* @param locale The locale to use
|
|
1043
|
-
*/
|
|
1044
|
-
abstract locale(locale: string): this;
|
|
1045
|
-
/**
|
|
1046
|
-
* Set the version for subsequent operations
|
|
1047
|
-
* @param versionId The version ID or status ('draft', 'published', 'archived')
|
|
1048
|
-
*/
|
|
1049
|
-
version(versionId: string): this;
|
|
1050
|
-
/**
|
|
1051
|
-
* Find all versions of a document
|
|
1052
|
-
* @param documentId The document ID
|
|
1053
|
-
*/
|
|
1054
|
-
findVersions(documentId: string): Promise<any[]>;
|
|
1055
|
-
/**
|
|
1056
|
-
* Find a specific version by ID
|
|
1057
|
-
* @param versionId The version ID
|
|
1058
|
-
*/
|
|
1059
|
-
findVersionById(versionId: string): Promise<any | null>;
|
|
1060
|
-
/**
|
|
1061
|
-
* Restore a version
|
|
1062
|
-
* @param versionId The version ID to restore
|
|
1063
|
-
*/
|
|
1064
|
-
restoreVersion(versionId: string): Promise<BaseSchema<Schema> | null>;
|
|
1065
|
-
/**
|
|
1066
|
-
* Create a query builder for advanced queries with sorting, pagination, and operators.
|
|
1067
|
-
* The query builder inherits the current locale/version context.
|
|
1068
|
-
*
|
|
1069
|
-
* @example
|
|
1070
|
-
* ```typescript
|
|
1071
|
-
* const results = await model.query()
|
|
1072
|
-
* .where({ status: 'active', age: { $gte: 18 } })
|
|
1073
|
-
* .sort({ createdAt: -1 })
|
|
1074
|
-
* .limit(10)
|
|
1075
|
-
* .exec()
|
|
1076
|
-
* ```
|
|
1077
|
-
*/
|
|
1078
|
-
query(): QueryBuilder<Schema>;
|
|
1079
|
-
/**
|
|
1080
|
-
* Get access to the native database model/collection.
|
|
1081
|
-
* Use with caution - bypasses Magnet abstractions like locale and versioning.
|
|
1082
|
-
*
|
|
1083
|
-
* @returns The underlying database model (e.g., Mongoose Model)
|
|
1084
|
-
*/
|
|
1085
|
-
native(): unknown;
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
declare class Mixed {
|
|
1089
|
-
static schemaName: 'Mixed';
|
|
1090
|
-
defaultOptions: Record<string, any>;
|
|
1091
|
-
}
|
|
4091
|
+
declare function registerDatabaseAdapterSingletonForFeature(getter: () => DatabaseAdapter): void;
|
|
4092
|
+
/**
|
|
4093
|
+
* @internal Used by `@magnet-cms/core` `DatabaseModule.forFeature` when
|
|
4094
|
+
* `DatabaseModule.register()` has not run yet.
|
|
4095
|
+
*/
|
|
4096
|
+
declare function getDatabaseAdapterSingletonForFeature(): DatabaseAdapter | null;
|
|
4097
|
+
/** @internal Clear between isolated tests if needed */
|
|
4098
|
+
declare function clearDatabaseAdapterSingletonForFeature(): void;
|
|
1092
4099
|
|
|
1093
4100
|
type SupportedAdapter = 'mongoose' | 'drizzle';
|
|
1094
4101
|
/**
|
|
1095
4102
|
* Detect the database adapter based on configuration or installed packages.
|
|
1096
4103
|
*
|
|
4104
|
+
* With the provider-based API, the adapter is typically auto-registered:
|
|
4105
|
+
* importing `@magnet-cms/adapter-db-mongoose` or `@magnet-cms/adapter-db-drizzle`
|
|
4106
|
+
* calls `setDatabaseAdapter()` as a module-level side effect, so detection
|
|
4107
|
+
* happens automatically before any `@Schema()` decorators evaluate.
|
|
4108
|
+
*
|
|
1097
4109
|
* Detection priority:
|
|
1098
|
-
* 1.
|
|
1099
|
-
* 2. Configuration-based: If `
|
|
1100
|
-
* 3.
|
|
4110
|
+
* 1. Cached value from `setDatabaseAdapter()` (set by adapter package import side effect)
|
|
4111
|
+
* 2. Configuration-based: If `connectionString` or `dialect` is present, use drizzle
|
|
4112
|
+
* 3. Configuration-based: If `uri` is present, use mongoose
|
|
4113
|
+
* 4. Package-based: Check which adapter packages are installed (mongoose > drizzle)
|
|
1101
4114
|
*
|
|
1102
4115
|
* @param dbConfig - Optional database configuration to determine adapter from
|
|
1103
4116
|
*/
|
|
1104
4117
|
declare function detectDatabaseAdapter(dbConfig?: DBConfig): SupportedAdapter;
|
|
1105
4118
|
/**
|
|
1106
4119
|
* Explicitly set the database adapter.
|
|
1107
|
-
* Call this at the very start of your application, before importing any schemas.
|
|
1108
4120
|
*
|
|
1109
|
-
*
|
|
1110
|
-
*
|
|
1111
|
-
*
|
|
1112
|
-
* import { setDatabaseAdapter } from '@magnet-cms/common'
|
|
1113
|
-
* setDatabaseAdapter('drizzle')
|
|
4121
|
+
* With the provider-based API, this is called automatically as a side effect
|
|
4122
|
+
* when importing an adapter package (e.g., `@magnet-cms/adapter-db-drizzle`).
|
|
4123
|
+
* Manual calls are no longer needed in typical user code.
|
|
1114
4124
|
*
|
|
1115
|
-
*
|
|
1116
|
-
* import { MagnetModule } from '@magnet-cms/core'
|
|
1117
|
-
* ```
|
|
4125
|
+
* @internal Called by adapter package index.ts as module-level side effect
|
|
1118
4126
|
*/
|
|
1119
4127
|
declare function setDatabaseAdapter(adapter: SupportedAdapter): void;
|
|
1120
4128
|
/**
|
|
@@ -1122,11 +4130,140 @@ declare function setDatabaseAdapter(adapter: SupportedAdapter): void;
|
|
|
1122
4130
|
*/
|
|
1123
4131
|
declare function clearAdapterCache(): void;
|
|
1124
4132
|
|
|
1125
|
-
|
|
4133
|
+
/**
|
|
4134
|
+
* Get model injection token for any adapter
|
|
4135
|
+
* @param schema Schema class or schema name
|
|
4136
|
+
* @returns Injection token string
|
|
4137
|
+
*/
|
|
4138
|
+
declare function getModelToken(schema: Type | string): string;
|
|
4139
|
+
/**
|
|
4140
|
+
* Get adapter injection token
|
|
4141
|
+
* @returns Injection token for the database adapter
|
|
4142
|
+
*/
|
|
4143
|
+
declare function getAdapterToken(): string;
|
|
4144
|
+
declare function registerModel(token: string, model: unknown): void;
|
|
4145
|
+
declare function getRegisteredModel<T>(token: string): T | undefined;
|
|
1126
4146
|
|
|
1127
4147
|
declare const getSchemaToken: (schema: Type) => string;
|
|
1128
4148
|
declare const getSettingToken: (setting: Type) => string;
|
|
1129
4149
|
|
|
4150
|
+
/**
|
|
4151
|
+
* Type guard utilities for safe type narrowing
|
|
4152
|
+
* Use these instead of type assertions (as any, as unknown as T)
|
|
4153
|
+
*/
|
|
4154
|
+
/**
|
|
4155
|
+
* Check if value is a non-null object
|
|
4156
|
+
*/
|
|
4157
|
+
declare function isObject(value: unknown): value is Record<string, unknown>;
|
|
4158
|
+
/**
|
|
4159
|
+
* Check if value has a specific property
|
|
4160
|
+
*/
|
|
4161
|
+
declare function hasProperty<K extends string>(value: unknown, key: K): value is Record<K, unknown>;
|
|
4162
|
+
/**
|
|
4163
|
+
* Check if value has multiple properties
|
|
4164
|
+
*/
|
|
4165
|
+
declare function hasProperties<K extends string>(value: unknown, keys: K[]): value is Record<K, unknown>;
|
|
4166
|
+
/**
|
|
4167
|
+
* Check if value is a string
|
|
4168
|
+
*/
|
|
4169
|
+
declare function isString(value: unknown): value is string;
|
|
4170
|
+
/**
|
|
4171
|
+
* Check if value is a number
|
|
4172
|
+
*/
|
|
4173
|
+
declare function isNumber(value: unknown): value is number;
|
|
4174
|
+
/**
|
|
4175
|
+
* Check if value is a boolean
|
|
4176
|
+
*/
|
|
4177
|
+
declare function isBoolean(value: unknown): value is boolean;
|
|
4178
|
+
/**
|
|
4179
|
+
* Check if value is an array
|
|
4180
|
+
*/
|
|
4181
|
+
declare function isArray(value: unknown): value is unknown[];
|
|
4182
|
+
/**
|
|
4183
|
+
* Check if value is a string array
|
|
4184
|
+
*/
|
|
4185
|
+
declare function isStringArray(value: unknown): value is string[];
|
|
4186
|
+
/**
|
|
4187
|
+
* Check if value is a function
|
|
4188
|
+
*/
|
|
4189
|
+
declare function isFunction(value: unknown): value is Function;
|
|
4190
|
+
/**
|
|
4191
|
+
* Check if value is a valid document with ID
|
|
4192
|
+
*/
|
|
4193
|
+
declare function isDocument(value: unknown): value is {
|
|
4194
|
+
id: string;
|
|
4195
|
+
[key: string]: unknown;
|
|
4196
|
+
};
|
|
4197
|
+
/**
|
|
4198
|
+
* Check if error is a MongoDB CastError
|
|
4199
|
+
*/
|
|
4200
|
+
declare function isCastError(error: unknown): error is {
|
|
4201
|
+
name: 'CastError';
|
|
4202
|
+
path: string;
|
|
4203
|
+
value: unknown;
|
|
4204
|
+
};
|
|
4205
|
+
/**
|
|
4206
|
+
* Check if error is a MongoDB duplicate key error
|
|
4207
|
+
*/
|
|
4208
|
+
declare function isDuplicateKeyError(error: unknown): error is {
|
|
4209
|
+
code: 11000;
|
|
4210
|
+
keyValue: Record<string, unknown>;
|
|
4211
|
+
};
|
|
4212
|
+
/**
|
|
4213
|
+
* Check if error is a Mongoose validation error
|
|
4214
|
+
*/
|
|
4215
|
+
declare function isValidationError(error: unknown): error is {
|
|
4216
|
+
name: 'ValidationError';
|
|
4217
|
+
errors: Record<string, unknown>;
|
|
4218
|
+
};
|
|
4219
|
+
/**
|
|
4220
|
+
* Check if error is a PostgreSQL unique constraint violation
|
|
4221
|
+
*/
|
|
4222
|
+
declare function isPostgresUniqueError(error: unknown): error is {
|
|
4223
|
+
code: string;
|
|
4224
|
+
detail?: string;
|
|
4225
|
+
};
|
|
4226
|
+
/**
|
|
4227
|
+
* Check if an object has a method
|
|
4228
|
+
*/
|
|
4229
|
+
declare function hasMethod<K extends string>(value: unknown, methodName: K): value is Record<K, Function>;
|
|
4230
|
+
/**
|
|
4231
|
+
* Check if value has setLocale method (for i18n documents)
|
|
4232
|
+
*/
|
|
4233
|
+
declare function hasSetLocale<T>(value: T): value is T & {
|
|
4234
|
+
setLocale: (locale: string) => T;
|
|
4235
|
+
};
|
|
4236
|
+
/**
|
|
4237
|
+
* Check if value has toString method that returns string
|
|
4238
|
+
*/
|
|
4239
|
+
declare function hasToString(value: unknown): value is {
|
|
4240
|
+
toString(): string;
|
|
4241
|
+
};
|
|
4242
|
+
/**
|
|
4243
|
+
* Assert value is defined (not null or undefined)
|
|
4244
|
+
* Throws if value is null or undefined
|
|
4245
|
+
*/
|
|
4246
|
+
declare function assertDefined<T>(value: T | null | undefined, message?: string): asserts value is T;
|
|
4247
|
+
/**
|
|
4248
|
+
* Assert condition is true
|
|
4249
|
+
* Throws if condition is false
|
|
4250
|
+
*/
|
|
4251
|
+
declare function assert(condition: boolean, message?: string): asserts condition;
|
|
4252
|
+
/**
|
|
4253
|
+
* Safely get a string ID from a document that might have _id or id
|
|
4254
|
+
* Returns undefined if no valid ID found
|
|
4255
|
+
*/
|
|
4256
|
+
declare function getDocumentId(doc: unknown): string | undefined;
|
|
4257
|
+
/**
|
|
4258
|
+
* Type guard for checking if an object matches a record with string values
|
|
4259
|
+
*/
|
|
4260
|
+
declare function isStringRecord(value: unknown): value is Record<string, string>;
|
|
4261
|
+
|
|
4262
|
+
/**
|
|
4263
|
+
* Check if value is a version document
|
|
4264
|
+
*/
|
|
4265
|
+
declare function isVersionDocument(value: unknown): value is VersionDocument;
|
|
4266
|
+
|
|
1130
4267
|
declare const RESOLVER_METADATA_KEY = "magnet:resolver";
|
|
1131
4268
|
declare const RESOLVE_METADATA_KEY = "magnet:resolve";
|
|
1132
4269
|
declare const SCHEMA_METADATA_KEY = "magnet:schema";
|
|
@@ -1134,11 +4271,18 @@ declare const SCHEMA_OPTIONS_METADATA_KEY = "magnet:schema:options";
|
|
|
1134
4271
|
declare const BASE_SCHEMA_METADATA_KEY = "magnet:schema:base";
|
|
1135
4272
|
declare const PROP_METADATA_KEY = "magnet:schema:prop";
|
|
1136
4273
|
declare const UI_METADATA_KEY = "magnet:schema:ui";
|
|
4274
|
+
declare const FIELD_METADATA_KEY = "magnet:schema:field";
|
|
1137
4275
|
declare const SETTING_METADATA_KEY = "magnet:setting";
|
|
4276
|
+
declare const SETTINGS_OPTIONS_METADATA_KEY = "magnet:settings:options";
|
|
4277
|
+
declare const SETTING_FIELD_METADATA_KEY = "magnet:settings:field";
|
|
4278
|
+
declare const EXTEND_USER_METADATA_KEY = "magnet:extend:user";
|
|
4279
|
+
declare const PERMISSION_METADATA_KEY = "magnet:permission";
|
|
4280
|
+
declare const PERMISSION_OPTIONS_METADATA_KEY = "magnet:permission:options";
|
|
4281
|
+
declare const RESOLVED_PERMISSION_KEY = "magnet:permission:resolved";
|
|
1138
4282
|
declare const INJECT_MODEL = "magnet:inject:model";
|
|
1139
4283
|
declare const DESIGN_TYPE = "design:type";
|
|
1140
4284
|
declare const DESIGN_META = "design:metadata";
|
|
1141
4285
|
declare const DESIGN_PARAM_TYPES = "design:paramtypes";
|
|
1142
4286
|
declare const DESIGN_RETURN_TYPE = "design:returntype";
|
|
1143
4287
|
|
|
1144
|
-
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 DrizzleConfig, 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 SupabaseAuthConfig, type SupabaseStorageConfig, type SupportedAdapter, 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 UploadOptions, type UploadResult, VERSION_METADATA_KEY, ValidationException, type Validations, Validators, Version, type VersionConfig, type VersionData, type VersionStatus, clearAdapterCache, detectDatabaseAdapter, getModelToken, getSchemaOptions, getSchemaToken, getSettingToken, setDatabaseAdapter };
|
|
4288
|
+
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, clearDatabaseAdapterSingletonForFeature, createFieldDecorator, detectDatabaseAdapter, fromDrizzleError, fromMongooseError, getAdapterToken, getDatabaseAdapterSingletonForFeature, 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, registerDatabaseAdapterSingletonForFeature, registerModel, setDatabaseAdapter, wrapError };
|