@magnet-cms/common 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import 'reflect-metadata';
2
+ import { SetMetadata, applyDecorators } from '@nestjs/common';
2
3
  import { existsSync } from 'node:fs';
3
4
  import { join } from 'node:path';
4
- import { applyDecorators } from '@nestjs/common';
5
5
 
6
6
  var __defProp = Object.defineProperty;
7
7
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
@@ -11,6 +11,21 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
11
11
  if (typeof require !== "undefined") return require.apply(this, arguments);
12
12
  throw Error('Dynamic require of "' + x + '" is not supported');
13
13
  });
14
+ var EVENT_HANDLER_METADATA = "magnet:event_handler";
15
+ function OnEvent(event, options = {}) {
16
+ return (target, propertyKey, descriptor) => {
17
+ const metadata = {
18
+ event,
19
+ options
20
+ };
21
+ SetMetadata(EVENT_HANDLER_METADATA, metadata)(target, propertyKey, descriptor);
22
+ return descriptor;
23
+ };
24
+ }
25
+ __name(OnEvent, "OnEvent");
26
+ var Validators = /* @__PURE__ */ __name((...validators) => {
27
+ return applyDecorators(...validators);
28
+ }, "Validators");
14
29
 
15
30
  // src/constants.ts
16
31
  var RESOLVER_METADATA_KEY = "magnet:resolver";
@@ -20,12 +35,904 @@ var SCHEMA_OPTIONS_METADATA_KEY = "magnet:schema:options";
20
35
  var BASE_SCHEMA_METADATA_KEY = "magnet:schema:base";
21
36
  var PROP_METADATA_KEY = "magnet:schema:prop";
22
37
  var UI_METADATA_KEY = "magnet:schema:ui";
38
+ var FIELD_METADATA_KEY = "magnet:schema:field";
23
39
  var SETTING_METADATA_KEY = "magnet:setting";
40
+ var SETTINGS_OPTIONS_METADATA_KEY = "magnet:settings:options";
41
+ var SETTING_FIELD_METADATA_KEY = "magnet:settings:field";
42
+ var EXTEND_USER_METADATA_KEY = "magnet:extend:user";
43
+ var PERMISSION_METADATA_KEY = "magnet:permission";
44
+ var PERMISSION_OPTIONS_METADATA_KEY = "magnet:permission:options";
45
+ var RESOLVED_PERMISSION_KEY = "magnet:permission:resolved";
24
46
  var INJECT_MODEL = "magnet:inject:model";
25
47
  var DESIGN_TYPE = "design:type";
26
48
  var DESIGN_META = "design:metadata";
27
49
  var DESIGN_PARAM_TYPES = "design:paramtypes";
28
50
  var DESIGN_RETURN_TYPE = "design:returntype";
51
+ var cachedAdapter = null;
52
+ function isPackageInstalled(packageName) {
53
+ try {
54
+ return existsSync(join(__require.resolve(packageName), "../../"));
55
+ } catch {
56
+ return false;
57
+ }
58
+ }
59
+ __name(isPackageInstalled, "isPackageInstalled");
60
+ function detectDatabaseAdapter(dbConfig) {
61
+ if (dbConfig) {
62
+ if ("connectionString" in dbConfig || "dialect" in dbConfig) {
63
+ cachedAdapter = "drizzle";
64
+ return cachedAdapter;
65
+ }
66
+ if ("uri" in dbConfig) {
67
+ cachedAdapter = "mongoose";
68
+ return cachedAdapter;
69
+ }
70
+ }
71
+ if (cachedAdapter) return cachedAdapter;
72
+ if (isPackageInstalled("@magnet-cms/adapter-db-mongoose")) {
73
+ cachedAdapter = "mongoose";
74
+ } else if (isPackageInstalled("@magnet-cms/adapter-db-drizzle")) {
75
+ cachedAdapter = "drizzle";
76
+ } else {
77
+ throw new Error("\u274C No supported database adapter found. Install @magnet-cms/adapter-db-mongoose or @magnet-cms/adapter-db-drizzle.");
78
+ }
79
+ return cachedAdapter;
80
+ }
81
+ __name(detectDatabaseAdapter, "detectDatabaseAdapter");
82
+ function setDatabaseAdapter(adapter) {
83
+ cachedAdapter = adapter;
84
+ }
85
+ __name(setDatabaseAdapter, "setDatabaseAdapter");
86
+ function clearAdapterCache() {
87
+ cachedAdapter = null;
88
+ }
89
+ __name(clearAdapterCache, "clearAdapterCache");
90
+
91
+ // src/utils/get-model-token.util.ts
92
+ function getModelToken(schema) {
93
+ const name = typeof schema === "string" ? schema : schema.name;
94
+ return `MAGNET_MODEL_${name.toUpperCase()}`;
95
+ }
96
+ __name(getModelToken, "getModelToken");
97
+ function getAdapterToken() {
98
+ return "MAGNET_DATABASE_ADAPTER";
99
+ }
100
+ __name(getAdapterToken, "getAdapterToken");
101
+ var globalModelRegistry = /* @__PURE__ */ new Map();
102
+ function registerModel(token, model) {
103
+ globalModelRegistry.set(token, model);
104
+ }
105
+ __name(registerModel, "registerModel");
106
+ function getRegisteredModel(token) {
107
+ return globalModelRegistry.get(token);
108
+ }
109
+ __name(getRegisteredModel, "getRegisteredModel");
110
+
111
+ // src/utils/get-schema-token.util.ts
112
+ var getSchemaToken = /* @__PURE__ */ __name((schema) => {
113
+ return `${schema.name}Schema`;
114
+ }, "getSchemaToken");
115
+ var getSettingToken = /* @__PURE__ */ __name((setting) => {
116
+ return `${setting.name}Setting`;
117
+ }, "getSettingToken");
118
+
119
+ // src/utils/type-guards.ts
120
+ function isObject(value) {
121
+ return typeof value === "object" && value !== null && !Array.isArray(value);
122
+ }
123
+ __name(isObject, "isObject");
124
+ function hasProperty(value, key) {
125
+ return isObject(value) && key in value;
126
+ }
127
+ __name(hasProperty, "hasProperty");
128
+ function hasProperties(value, keys) {
129
+ return isObject(value) && keys.every((key) => key in value);
130
+ }
131
+ __name(hasProperties, "hasProperties");
132
+ function isString(value) {
133
+ return typeof value === "string";
134
+ }
135
+ __name(isString, "isString");
136
+ function isNumber(value) {
137
+ return typeof value === "number" && !Number.isNaN(value);
138
+ }
139
+ __name(isNumber, "isNumber");
140
+ function isBoolean(value) {
141
+ return typeof value === "boolean";
142
+ }
143
+ __name(isBoolean, "isBoolean");
144
+ function isArray(value) {
145
+ return Array.isArray(value);
146
+ }
147
+ __name(isArray, "isArray");
148
+ function isStringArray(value) {
149
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
150
+ }
151
+ __name(isStringArray, "isStringArray");
152
+ function isFunction(value) {
153
+ return typeof value === "function";
154
+ }
155
+ __name(isFunction, "isFunction");
156
+ function isDocument(value) {
157
+ return isObject(value) && hasProperty(value, "id") && typeof value.id === "string";
158
+ }
159
+ __name(isDocument, "isDocument");
160
+ function isCastError(error) {
161
+ return isObject(error) && hasProperty(error, "name") && error.name === "CastError" && hasProperty(error, "path") && typeof error.path === "string";
162
+ }
163
+ __name(isCastError, "isCastError");
164
+ function isDuplicateKeyError(error) {
165
+ return isObject(error) && hasProperty(error, "code") && error.code === 11e3;
166
+ }
167
+ __name(isDuplicateKeyError, "isDuplicateKeyError");
168
+ function isValidationError(error) {
169
+ return isObject(error) && hasProperty(error, "name") && error.name === "ValidationError" && hasProperty(error, "errors");
170
+ }
171
+ __name(isValidationError, "isValidationError");
172
+ function isPostgresUniqueError(error) {
173
+ return isObject(error) && hasProperty(error, "code") && error.code === "23505";
174
+ }
175
+ __name(isPostgresUniqueError, "isPostgresUniqueError");
176
+ function hasMethod(value, methodName) {
177
+ return isObject(value) && hasProperty(value, methodName) && typeof value[methodName] === "function";
178
+ }
179
+ __name(hasMethod, "hasMethod");
180
+ function hasSetLocale(value) {
181
+ return isObject(value) && hasMethod(value, "setLocale");
182
+ }
183
+ __name(hasSetLocale, "hasSetLocale");
184
+ function hasToString(value) {
185
+ return isObject(value) && hasMethod(value, "toString");
186
+ }
187
+ __name(hasToString, "hasToString");
188
+ function assertDefined(value, message) {
189
+ if (value === null || value === void 0) {
190
+ throw new Error(message ?? "Value is null or undefined");
191
+ }
192
+ }
193
+ __name(assertDefined, "assertDefined");
194
+ function assert(condition, message) {
195
+ if (!condition) {
196
+ throw new Error(message ?? "Assertion failed");
197
+ }
198
+ }
199
+ __name(assert, "assert");
200
+ function getDocumentId(doc) {
201
+ if (!isObject(doc)) return void 0;
202
+ if (hasProperty(doc, "id") && typeof doc.id === "string") {
203
+ return doc.id;
204
+ }
205
+ if (hasProperty(doc, "_id")) {
206
+ if (typeof doc._id === "string") {
207
+ return doc._id;
208
+ }
209
+ if (hasToString(doc._id)) {
210
+ return doc._id.toString();
211
+ }
212
+ }
213
+ return void 0;
214
+ }
215
+ __name(getDocumentId, "getDocumentId");
216
+ function isStringRecord(value) {
217
+ if (!isObject(value)) return false;
218
+ return Object.values(value).every((v) => typeof v === "string");
219
+ }
220
+ __name(isStringRecord, "isStringRecord");
221
+ function isVersionDocument(value) {
222
+ return isObject(value) && hasProperty(value, "documentId") && typeof value.documentId === "string" && hasProperty(value, "versionId") && typeof value.versionId === "string" && hasProperty(value, "schemaName") && typeof value.schemaName === "string" && hasProperty(value, "status") && hasProperty(value, "data") && isObject(value.data);
223
+ }
224
+ __name(isVersionDocument, "isVersionDocument");
225
+
226
+ // src/decorators/field/field.prop-mapper.ts
227
+ function isPropDefaultValue(value) {
228
+ if (value === null) return true;
229
+ if (typeof value === "string") return true;
230
+ if (typeof value === "number") return true;
231
+ if (typeof value === "boolean") return true;
232
+ if (typeof value === "function") return true;
233
+ if (Array.isArray(value)) return true;
234
+ if (typeof value === "object") return true;
235
+ return false;
236
+ }
237
+ __name(isPropDefaultValue, "isPropDefaultValue");
238
+ function mapFieldTypeToProp(type, options) {
239
+ const propOptions = {
240
+ required: options.required,
241
+ unique: options.unique,
242
+ default: isPropDefaultValue(options.default) ? options.default : void 0,
243
+ hidden: options.hidden,
244
+ readonly: options.readonly,
245
+ description: options.description
246
+ };
247
+ switch (type) {
248
+ case "text":
249
+ case "email":
250
+ case "url":
251
+ case "phone":
252
+ case "address":
253
+ case "color":
254
+ case "slug":
255
+ case "textarea":
256
+ case "markdown":
257
+ case "code":
258
+ propOptions.type = String;
259
+ break;
260
+ case "number":
261
+ propOptions.type = Number;
262
+ break;
263
+ case "boolean":
264
+ propOptions.type = Boolean;
265
+ break;
266
+ case "date":
267
+ case "datetime":
268
+ propOptions.type = Date;
269
+ break;
270
+ case "richtext":
271
+ propOptions.type = String;
272
+ break;
273
+ case "json":
274
+ case "object":
275
+ propOptions.type = Object;
276
+ break;
277
+ case "select":
278
+ case "enum":
279
+ propOptions.type = String;
280
+ break;
281
+ case "tags":
282
+ propOptions.type = [
283
+ String
284
+ ];
285
+ break;
286
+ case "image":
287
+ case "file":
288
+ propOptions.type = String;
289
+ break;
290
+ case "gallery":
291
+ propOptions.type = [
292
+ String
293
+ ];
294
+ break;
295
+ case "array":
296
+ propOptions.type = Array;
297
+ break;
298
+ case "blocks":
299
+ propOptions.type = Array;
300
+ break;
301
+ case "relationship": {
302
+ const relOptions = options;
303
+ propOptions.ref = relOptions.ref;
304
+ if (relOptions.multiple) {
305
+ propOptions.type = [
306
+ String
307
+ ];
308
+ } else {
309
+ propOptions.type = String;
310
+ }
311
+ break;
312
+ }
313
+ default: {
314
+ const _exhaustiveCheck = type;
315
+ throw new Error(`Unknown field type: ${_exhaustiveCheck}`);
316
+ }
317
+ }
318
+ return Object.fromEntries(Object.entries(propOptions).filter(([, value]) => value !== void 0));
319
+ }
320
+ __name(mapFieldTypeToProp, "mapFieldTypeToProp");
321
+
322
+ // src/decorators/field/field.ui-mapper.ts
323
+ function mapFieldTypeToUIType(type) {
324
+ const typeMap = {
325
+ text: "text",
326
+ number: "number",
327
+ boolean: "switch",
328
+ date: "date",
329
+ datetime: "date",
330
+ richtext: "richText",
331
+ markdown: "textarea",
332
+ code: "code",
333
+ json: "json",
334
+ select: "select",
335
+ enum: "select",
336
+ tags: "multiSelect",
337
+ image: "upload",
338
+ file: "fileUpload",
339
+ gallery: "upload",
340
+ slug: "text",
341
+ email: "email",
342
+ url: "text",
343
+ phone: "phone",
344
+ address: "text",
345
+ color: "text",
346
+ object: "json",
347
+ array: "array",
348
+ blocks: "blocks",
349
+ relationship: "relationship",
350
+ textarea: "textarea"
351
+ };
352
+ return typeMap[type];
353
+ }
354
+ __name(mapFieldTypeToUIType, "mapFieldTypeToUIType");
355
+ function convertToUISelectItems(options) {
356
+ return options.map((opt) => {
357
+ if (typeof opt === "object" && opt !== null && "label" in opt && "value" in opt) {
358
+ return {
359
+ key: String(opt.value),
360
+ value: opt.label
361
+ };
362
+ }
363
+ return {
364
+ key: String(opt),
365
+ value: String(opt)
366
+ };
367
+ });
368
+ }
369
+ __name(convertToUISelectItems, "convertToUISelectItems");
370
+ function convertEnumToUISelectItems(enumObj) {
371
+ return Object.entries(enumObj).filter(([key]) => Number.isNaN(Number(key))).map(([key, value]) => ({
372
+ key: String(value),
373
+ value: key
374
+ }));
375
+ }
376
+ __name(convertEnumToUISelectItems, "convertEnumToUISelectItems");
377
+ function toUIDecoratorOptions(internal) {
378
+ if (internal.side) {
379
+ return {
380
+ type: internal.type,
381
+ label: internal.label,
382
+ description: internal.description,
383
+ side: true,
384
+ options: internal.options
385
+ };
386
+ }
387
+ const result = {
388
+ type: internal.type,
389
+ label: internal.label,
390
+ description: internal.description,
391
+ tab: internal.tab ?? "General"
392
+ };
393
+ if (internal.options) {
394
+ result.options = internal.options;
395
+ }
396
+ return result;
397
+ }
398
+ __name(toUIDecoratorOptions, "toUIDecoratorOptions");
399
+ function mapFieldTypeToUI(type, options) {
400
+ const uiType = mapFieldTypeToUIType(type);
401
+ const internal = {
402
+ type: uiType,
403
+ label: options.label,
404
+ description: options.description,
405
+ tab: options.tab,
406
+ side: options.side ? true : void 0
407
+ };
408
+ switch (type) {
409
+ case "select": {
410
+ const selectOpts = options;
411
+ return toUIDecoratorOptions({
412
+ ...internal,
413
+ type: selectOpts.multiple ? "multiSelect" : "select",
414
+ options: convertToUISelectItems(selectOpts.options)
415
+ });
416
+ }
417
+ case "enum": {
418
+ const enumOpts = options;
419
+ return toUIDecoratorOptions({
420
+ ...internal,
421
+ type: enumOpts.multiple ? "multiSelect" : "select",
422
+ options: convertEnumToUISelectItems(enumOpts.enum)
423
+ });
424
+ }
425
+ case "boolean": {
426
+ const boolOpts = options;
427
+ return toUIDecoratorOptions({
428
+ ...internal,
429
+ type: boolOpts.style === "checkbox" ? "checkbox" : "switch"
430
+ });
431
+ }
432
+ case "richtext": {
433
+ return toUIDecoratorOptions({
434
+ ...internal,
435
+ type: "richText"
436
+ });
437
+ }
438
+ case "code": {
439
+ return toUIDecoratorOptions({
440
+ ...internal,
441
+ type: "code"
442
+ });
443
+ }
444
+ case "tags": {
445
+ const tagsOpts = options;
446
+ return toUIDecoratorOptions({
447
+ ...internal,
448
+ type: "multiSelect",
449
+ options: tagsOpts.suggestions?.map((s) => ({
450
+ key: s,
451
+ value: s
452
+ })) ?? []
453
+ });
454
+ }
455
+ default:
456
+ return toUIDecoratorOptions(internal);
457
+ }
458
+ }
459
+ __name(mapFieldTypeToUI, "mapFieldTypeToUI");
460
+
461
+ // src/decorators/field/field.factory.ts
462
+ function createFieldDecorator(type, defaultOptions = {}) {
463
+ return (options) => {
464
+ const mergedOptions = {
465
+ ...defaultOptions,
466
+ ...options
467
+ };
468
+ return (target, propertyKey) => {
469
+ const designType = Reflect.getMetadata(DESIGN_TYPE, target, propertyKey);
470
+ const metadata = {
471
+ type,
472
+ options: mergedOptions,
473
+ propertyKey,
474
+ target: target.constructor,
475
+ designType
476
+ };
477
+ const existingFields = Reflect.getMetadata(FIELD_METADATA_KEY, target.constructor) ?? [];
478
+ const filteredFields = existingFields.filter((f) => f.propertyKey !== propertyKey);
479
+ Reflect.defineMetadata(FIELD_METADATA_KEY, [
480
+ ...filteredFields,
481
+ metadata
482
+ ], target.constructor);
483
+ emitLegacyPropMetadata(target, propertyKey, type, mergedOptions);
484
+ emitLegacyUIMetadata(target, propertyKey, type, mergedOptions, designType);
485
+ applyAdapterProp(target, propertyKey, type, mergedOptions);
486
+ };
487
+ };
488
+ }
489
+ __name(createFieldDecorator, "createFieldDecorator");
490
+ function emitLegacyPropMetadata(target, propertyKey, type, options) {
491
+ const propOptions = mapFieldTypeToProp(type, options);
492
+ const existingProps = Reflect.getMetadata(PROP_METADATA_KEY, target) ?? [];
493
+ const filteredProps = existingProps.filter((p) => p.propertyKey !== propertyKey);
494
+ Reflect.defineMetadata(PROP_METADATA_KEY, [
495
+ ...filteredProps,
496
+ {
497
+ propertyKey,
498
+ options: propOptions
499
+ }
500
+ ], target);
501
+ }
502
+ __name(emitLegacyPropMetadata, "emitLegacyPropMetadata");
503
+ function emitLegacyUIMetadata(target, propertyKey, type, options, designType) {
504
+ const uiOptions = mapFieldTypeToUI(type, options);
505
+ const existingUI = Reflect.getMetadata(UI_METADATA_KEY, target) ?? [];
506
+ const filteredUI = existingUI.filter((u) => u.propertyKey !== propertyKey);
507
+ Reflect.defineMetadata(UI_METADATA_KEY, [
508
+ ...filteredUI,
509
+ {
510
+ propertyKey,
511
+ options: {
512
+ ...uiOptions,
513
+ designType
514
+ }
515
+ }
516
+ ], target);
517
+ }
518
+ __name(emitLegacyUIMetadata, "emitLegacyUIMetadata");
519
+ function applyAdapterProp(target, propertyKey, type, options) {
520
+ try {
521
+ const adapter = detectDatabaseAdapter();
522
+ const propOptions = mapFieldTypeToProp(type, options);
523
+ const { Prop: Prop2 } = __require(`@magnet-cms/adapter-db-${adapter}`);
524
+ Prop2(propOptions)(target, propertyKey);
525
+ } catch {
526
+ }
527
+ }
528
+ __name(applyAdapterProp, "applyAdapterProp");
529
+ function getFieldMetadata(target) {
530
+ return Reflect.getMetadata(FIELD_METADATA_KEY, target) ?? [];
531
+ }
532
+ __name(getFieldMetadata, "getFieldMetadata");
533
+ function getFieldMetadataForProperty(target, propertyKey) {
534
+ const fields = getFieldMetadata(target);
535
+ return fields.find((f) => f.propertyKey === propertyKey);
536
+ }
537
+ __name(getFieldMetadataForProperty, "getFieldMetadataForProperty");
538
+
539
+ // src/types/field.types.ts
540
+ function isFieldMetadata(value) {
541
+ if (typeof value !== "object" || value === null) {
542
+ return false;
543
+ }
544
+ const metadata = value;
545
+ return typeof metadata.type === "string" && typeof metadata.options === "object" && metadata.options !== null && "propertyKey" in metadata;
546
+ }
547
+ __name(isFieldMetadata, "isFieldMetadata");
548
+ function isValidFieldType(type) {
549
+ const validTypes = [
550
+ "text",
551
+ "number",
552
+ "boolean",
553
+ "date",
554
+ "datetime",
555
+ "richtext",
556
+ "markdown",
557
+ "code",
558
+ "json",
559
+ "select",
560
+ "enum",
561
+ "tags",
562
+ "image",
563
+ "file",
564
+ "gallery",
565
+ "slug",
566
+ "email",
567
+ "url",
568
+ "phone",
569
+ "address",
570
+ "color",
571
+ "object",
572
+ "array",
573
+ "blocks",
574
+ "relationship",
575
+ "textarea"
576
+ ];
577
+ return typeof type === "string" && validTypes.includes(type);
578
+ }
579
+ __name(isValidFieldType, "isValidFieldType");
580
+
581
+ // src/decorators/field/index.ts
582
+ var Field = {
583
+ // ============================================
584
+ // PRIMITIVES
585
+ // ============================================
586
+ /**
587
+ * Text field - single line text input
588
+ *
589
+ * @example
590
+ * ```typescript
591
+ * @Field.Text({ required: true, maxLength: 200 })
592
+ * title: string
593
+ * ```
594
+ */
595
+ Text: createFieldDecorator("text"),
596
+ /**
597
+ * Number field - numeric input
598
+ *
599
+ * @example
600
+ * ```typescript
601
+ * @Field.Number({ min: 0, max: 100, integer: true })
602
+ * quantity: number
603
+ * ```
604
+ */
605
+ Number: createFieldDecorator("number"),
606
+ /**
607
+ * Boolean field - true/false toggle
608
+ *
609
+ * @example
610
+ * ```typescript
611
+ * @Field.Boolean({ default: false, style: 'switch' })
612
+ * isPublished: boolean
613
+ * ```
614
+ */
615
+ Boolean: createFieldDecorator("boolean", {
616
+ style: "switch"
617
+ }),
618
+ /**
619
+ * Date field - date picker (without time)
620
+ *
621
+ * @example
622
+ * ```typescript
623
+ * @Field.Date({ min: '2024-01-01' })
624
+ * publishDate: Date
625
+ * ```
626
+ */
627
+ Date: createFieldDecorator("date"),
628
+ /**
629
+ * DateTime field - date and time picker
630
+ *
631
+ * @example
632
+ * ```typescript
633
+ * @Field.DateTime({ timezone: 'UTC' })
634
+ * scheduledAt: Date
635
+ * ```
636
+ */
637
+ DateTime: createFieldDecorator("datetime"),
638
+ // ============================================
639
+ // RICH CONTENT
640
+ // ============================================
641
+ /**
642
+ * RichText field - WYSIWYG editor
643
+ *
644
+ * @example
645
+ * ```typescript
646
+ * @Field.RichText({ toolbar: 'full' })
647
+ * content: string
648
+ * ```
649
+ */
650
+ RichText: createFieldDecorator("richtext", {
651
+ toolbar: "standard"
652
+ }),
653
+ /**
654
+ * Markdown field - markdown editor with preview
655
+ *
656
+ * @example
657
+ * ```typescript
658
+ * @Field.Markdown({ preview: true })
659
+ * description: string
660
+ * ```
661
+ */
662
+ Markdown: createFieldDecorator("markdown", {
663
+ preview: true
664
+ }),
665
+ /**
666
+ * Code field - code editor with syntax highlighting
667
+ *
668
+ * @example
669
+ * ```typescript
670
+ * @Field.Code({ language: 'typescript' })
671
+ * snippet: string
672
+ * ```
673
+ */
674
+ Code: createFieldDecorator("code"),
675
+ /**
676
+ * JSON field - JSON editor
677
+ *
678
+ * @example
679
+ * ```typescript
680
+ * @Field.JSON()
681
+ * metadata: Record<string, unknown>
682
+ * ```
683
+ */
684
+ JSON: createFieldDecorator("json"),
685
+ /**
686
+ * Textarea field - multi-line text input
687
+ *
688
+ * @example
689
+ * ```typescript
690
+ * @Field.Textarea({ rows: 5 })
691
+ * summary: string
692
+ * ```
693
+ */
694
+ Textarea: createFieldDecorator("textarea"),
695
+ // ============================================
696
+ // SELECTION
697
+ // ============================================
698
+ /**
699
+ * Select field - dropdown selection
700
+ *
701
+ * @example
702
+ * ```typescript
703
+ * @Field.Select({
704
+ * options: [
705
+ * { label: 'Draft', value: 'draft' },
706
+ * { label: 'Published', value: 'published' }
707
+ * ],
708
+ * default: 'draft'
709
+ * })
710
+ * status: string
711
+ * ```
712
+ */
713
+ Select: /* @__PURE__ */ __name((options) => createFieldDecorator("select")(options), "Select"),
714
+ /**
715
+ * Enum field - dropdown from TypeScript enum
716
+ *
717
+ * @example
718
+ * ```typescript
719
+ * enum Status { Draft = 'draft', Published = 'published' }
720
+ *
721
+ * @Field.Enum({ enum: Status, default: Status.Draft })
722
+ * status: Status
723
+ * ```
724
+ */
725
+ Enum: /* @__PURE__ */ __name((options) => createFieldDecorator("enum")(options), "Enum"),
726
+ /**
727
+ * Tags field - multi-value tag input
728
+ *
729
+ * @example
730
+ * ```typescript
731
+ * @Field.Tags({ suggestions: ['tech', 'news'], maxTags: 5 })
732
+ * tags: string[]
733
+ * ```
734
+ */
735
+ Tags: createFieldDecorator("tags"),
736
+ // ============================================
737
+ // MEDIA
738
+ // ============================================
739
+ /**
740
+ * Image field - single image upload
741
+ *
742
+ * @example
743
+ * ```typescript
744
+ * @Field.Image({ folder: 'covers', formats: ['jpg', 'png', 'webp'] })
745
+ * coverImage: string
746
+ * ```
747
+ */
748
+ Image: createFieldDecorator("image"),
749
+ /**
750
+ * File field - single file upload
751
+ *
752
+ * @example
753
+ * ```typescript
754
+ * @Field.File({ folder: 'documents', accept: ['application/pdf'] })
755
+ * attachment: string
756
+ * ```
757
+ */
758
+ File: createFieldDecorator("file"),
759
+ /**
760
+ * Gallery field - multiple image upload
761
+ *
762
+ * @example
763
+ * ```typescript
764
+ * @Field.Gallery({ maxItems: 10 })
765
+ * images: string[]
766
+ * ```
767
+ */
768
+ Gallery: createFieldDecorator("gallery"),
769
+ // ============================================
770
+ // SPECIAL
771
+ // ============================================
772
+ /**
773
+ * Slug field - auto-generated URL-friendly string
774
+ *
775
+ * @example
776
+ * ```typescript
777
+ * @Field.Slug({ from: 'title', unique: true })
778
+ * slug: string
779
+ * ```
780
+ */
781
+ Slug: createFieldDecorator("slug"),
782
+ /**
783
+ * Email field - email input with validation pattern
784
+ *
785
+ * @example
786
+ * ```typescript
787
+ * @Field.Email({ required: true })
788
+ * @Field.Validators(IsEmail())
789
+ * email: string
790
+ * ```
791
+ */
792
+ Email: createFieldDecorator("email", {
793
+ pattern: "^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$"
794
+ }),
795
+ /**
796
+ * URL field - URL input
797
+ *
798
+ * @example
799
+ * ```typescript
800
+ * @Field.URL({ protocols: ['https'] })
801
+ * @Field.Validators(IsUrl())
802
+ * website: string
803
+ * ```
804
+ */
805
+ URL: createFieldDecorator("url"),
806
+ /**
807
+ * Phone field - phone number input
808
+ *
809
+ * @example
810
+ * ```typescript
811
+ * @Field.Phone({ defaultCountry: 'US' })
812
+ * phone: string
813
+ * ```
814
+ */
815
+ Phone: createFieldDecorator("phone"),
816
+ /**
817
+ * Address field - address input with optional geocoding
818
+ *
819
+ * @example
820
+ * ```typescript
821
+ * @Field.Address({ provider: 'google' })
822
+ * address: string
823
+ * ```
824
+ */
825
+ Address: createFieldDecorator("address"),
826
+ /**
827
+ * Color field - color picker
828
+ *
829
+ * @example
830
+ * ```typescript
831
+ * @Field.Color({ format: 'hex', presets: ['#ff0000', '#00ff00'] })
832
+ * brandColor: string
833
+ * ```
834
+ */
835
+ Color: createFieldDecorator("color", {
836
+ format: "hex"
837
+ }),
838
+ // ============================================
839
+ // COMPOSITION
840
+ // ============================================
841
+ /**
842
+ * Object field - nested object structure
843
+ *
844
+ * @example
845
+ * ```typescript
846
+ * @Field.Object()
847
+ * metadata: { key: string; value: string }
848
+ * ```
849
+ */
850
+ Object: createFieldDecorator("object"),
851
+ /**
852
+ * Array field - array of items
853
+ *
854
+ * @example
855
+ * ```typescript
856
+ * @Field.Array({ of: { type: 'text' }, maxItems: 10 })
857
+ * items: string[]
858
+ * ```
859
+ */
860
+ Array: /* @__PURE__ */ __name((options) => createFieldDecorator("array")(options), "Array"),
861
+ /**
862
+ * Blocks field - flexible content blocks
863
+ *
864
+ * @example
865
+ * ```typescript
866
+ * @Field.Blocks({ types: ['paragraph', 'image', 'quote'] })
867
+ * content: Block[]
868
+ * ```
869
+ */
870
+ Blocks: createFieldDecorator("blocks"),
871
+ /**
872
+ * Relationship field - reference to another schema
873
+ *
874
+ * @example
875
+ * ```typescript
876
+ * @Field.Relationship({ ref: 'users', multiple: false })
877
+ * author: string
878
+ *
879
+ * @Field.Relationship({ ref: 'categories', multiple: true })
880
+ * categories: string[]
881
+ * ```
882
+ */
883
+ Relationship: createFieldDecorator("relationship"),
884
+ // ============================================
885
+ // VALIDATION
886
+ // ============================================
887
+ /**
888
+ * Validators - apply class-validator decorators
889
+ *
890
+ * This is an alias for the existing @Validators decorator,
891
+ * keeping validation explicit and using familiar class-validator syntax.
892
+ *
893
+ * @example
894
+ * ```typescript
895
+ * @Field.Text({ required: true })
896
+ * @Field.Validators(IsString(), Length(1, 200), IsNotEmpty())
897
+ * title: string
898
+ * ```
899
+ */
900
+ Validators
901
+ };
902
+ function RequirePermission(options) {
903
+ return (target, propertyKey, descriptor) => {
904
+ SetMetadata(PERMISSION_METADATA_KEY, options)(target, propertyKey, descriptor);
905
+ return descriptor;
906
+ };
907
+ }
908
+ __name(RequirePermission, "RequirePermission");
909
+ function HasPermission(permission) {
910
+ return (target, propertyKey, descriptor) => {
911
+ const options = {
912
+ id: permission,
913
+ name: permission.split(".").pop() ?? permission,
914
+ description: `Requires ${permission} permission`
915
+ };
916
+ SetMetadata(PERMISSION_METADATA_KEY, options)(target, propertyKey, descriptor);
917
+ return descriptor;
918
+ };
919
+ }
920
+ __name(HasPermission, "HasPermission");
921
+ function PermissionMeta(options) {
922
+ return (target, propertyKey, descriptor) => {
923
+ SetMetadata(PERMISSION_OPTIONS_METADATA_KEY, options)(target, propertyKey, descriptor);
924
+ return descriptor;
925
+ };
926
+ }
927
+ __name(PermissionMeta, "PermissionMeta");
928
+ function getPermissionMetadata(target, propertyKey) {
929
+ return Reflect.getMetadata(PERMISSION_METADATA_KEY, target, propertyKey);
930
+ }
931
+ __name(getPermissionMetadata, "getPermissionMetadata");
932
+ function hasPermissionDecorator(target, propertyKey) {
933
+ return Reflect.hasMetadata(PERMISSION_METADATA_KEY, target, propertyKey);
934
+ }
935
+ __name(hasPermissionDecorator, "hasPermissionDecorator");
29
936
 
30
937
  // src/decorators/resolver/resolver.decorator.ts
31
938
  function Resolver(optionsOrFn) {
@@ -81,41 +988,36 @@ function Resolve(optionsOrFn) {
81
988
  };
82
989
  }
83
990
  __name(Resolve, "Resolve");
84
- var cachedAdapter = null;
85
- function isPackageInstalled(packageName) {
86
- try {
87
- return existsSync(join(__require.resolve(packageName), "../../"));
88
- } catch {
89
- return false;
90
- }
991
+
992
+ // src/decorators/schema/extend-user.decorator.ts
993
+ function ExtendUser(options = {}) {
994
+ const mergedOptions = {
995
+ timestamps: true,
996
+ ...options
997
+ };
998
+ return (target) => {
999
+ Reflect.defineMetadata(EXTEND_USER_METADATA_KEY, mergedOptions, target);
1000
+ Reflect.defineMetadata(SCHEMA_METADATA_KEY, true, target);
1001
+ try {
1002
+ const adapter = detectDatabaseAdapter();
1003
+ const { Schema: Schema2 } = __require(`@magnet-cms/adapter-db-${adapter}`);
1004
+ Schema2({
1005
+ collection: "users",
1006
+ timestamps: mergedOptions.timestamps
1007
+ })(target);
1008
+ } catch {
1009
+ }
1010
+ };
91
1011
  }
92
- __name(isPackageInstalled, "isPackageInstalled");
93
- function detectDatabaseAdapter() {
94
- if (cachedAdapter) return cachedAdapter;
95
- if (isPackageInstalled("@magnet-cms/adapter-mongoose")) {
96
- cachedAdapter = "mongoose";
97
- } else if (isPackageInstalled("@magnet-cms/adapter-typeorm")) {
98
- cachedAdapter = "typeorm";
99
- } else {
100
- throw new Error("\u274C No supported database adapter found. Install @magnet-cms/adapter-mongoose or @magnet-cms/adapter-typeorm.");
101
- }
102
- return cachedAdapter;
1012
+ __name(ExtendUser, "ExtendUser");
1013
+ function isUserExtension(target) {
1014
+ return Reflect.hasMetadata(EXTEND_USER_METADATA_KEY, target);
103
1015
  }
104
- __name(detectDatabaseAdapter, "detectDatabaseAdapter");
105
-
106
- // src/utils/get-model-token.util.ts
107
- function getModelToken(schema) {
108
- return `Magnet${schema.name}Model`;
1016
+ __name(isUserExtension, "isUserExtension");
1017
+ function getExtendUserOptions(target) {
1018
+ return Reflect.getMetadata(EXTEND_USER_METADATA_KEY, target);
109
1019
  }
110
- __name(getModelToken, "getModelToken");
111
-
112
- // src/utils/get-schema-token.util.ts
113
- var getSchemaToken = /* @__PURE__ */ __name((schema) => {
114
- return `${schema.name}Schema`;
115
- }, "getSchemaToken");
116
- var getSettingToken = /* @__PURE__ */ __name((setting) => {
117
- return `${setting.name}Setting`;
118
- }, "getSettingToken");
1020
+ __name(getExtendUserOptions, "getExtendUserOptions");
119
1021
 
120
1022
  // src/decorators/schema/prop.decorator.ts
121
1023
  function Prop(options) {
@@ -129,7 +1031,7 @@ function Prop(options) {
129
1031
  options
130
1032
  }
131
1033
  ], target);
132
- const { Prop: Prop2 } = __require(`@magnet-cms/adapter-${adapter}`);
1034
+ const { Prop: Prop2 } = __require(`@magnet-cms/adapter-db-${adapter}`);
133
1035
  return Prop2(options)(target, propertyKey);
134
1036
  };
135
1037
  }
@@ -138,7 +1040,8 @@ __name(Prop, "Prop");
138
1040
  // src/decorators/schema/schema.decorator.ts
139
1041
  var defaultSchemaOptions = {
140
1042
  versioning: true,
141
- i18n: true
1043
+ i18n: true,
1044
+ visible: true
142
1045
  };
143
1046
  function Schema(options = {}) {
144
1047
  return (target) => {
@@ -149,7 +1052,7 @@ function Schema(options = {}) {
149
1052
  };
150
1053
  Reflect.defineMetadata(SCHEMA_METADATA_KEY, true, target);
151
1054
  Reflect.defineMetadata(SCHEMA_OPTIONS_METADATA_KEY, mergedOptions, target);
152
- const { Schema: Schema2 } = __require(`@magnet-cms/adapter-${adapter}`);
1055
+ const { Schema: Schema2 } = __require(`@magnet-cms/adapter-db-${adapter}`);
153
1056
  return Schema2()(target);
154
1057
  };
155
1058
  }
@@ -167,6 +1070,81 @@ function Setting() {
167
1070
  }
168
1071
  __name(Setting, "Setting");
169
1072
 
1073
+ // src/decorators/schema/settings.decorator.ts
1074
+ function Settings(options) {
1075
+ return (target) => {
1076
+ Reflect.defineMetadata(SETTING_METADATA_KEY, true, target);
1077
+ Reflect.defineMetadata(SETTINGS_OPTIONS_METADATA_KEY, options, target);
1078
+ };
1079
+ }
1080
+ __name(Settings, "Settings");
1081
+ function getSettingsOptions(target) {
1082
+ return Reflect.getMetadata(SETTINGS_OPTIONS_METADATA_KEY, target);
1083
+ }
1084
+ __name(getSettingsOptions, "getSettingsOptions");
1085
+ function getSettingFields(target) {
1086
+ return Reflect.getMetadata(SETTING_FIELD_METADATA_KEY, target) ?? [];
1087
+ }
1088
+ __name(getSettingFields, "getSettingFields");
1089
+ function createSettingFieldDecorator(type, defaultOptions = {}) {
1090
+ return (options) => {
1091
+ const mergedOptions = {
1092
+ ...defaultOptions,
1093
+ ...options
1094
+ };
1095
+ return (target, propertyKey) => {
1096
+ const metadata = {
1097
+ type,
1098
+ options: mergedOptions,
1099
+ propertyKey
1100
+ };
1101
+ const existingFields = Reflect.getMetadata(SETTING_FIELD_METADATA_KEY, target.constructor) ?? [];
1102
+ const filteredFields = existingFields.filter((f) => f.propertyKey !== propertyKey);
1103
+ Reflect.defineMetadata(SETTING_FIELD_METADATA_KEY, [
1104
+ ...filteredFields,
1105
+ metadata
1106
+ ], target.constructor);
1107
+ };
1108
+ };
1109
+ }
1110
+ __name(createSettingFieldDecorator, "createSettingFieldDecorator");
1111
+ var SettingField = {
1112
+ /**
1113
+ * Text setting field
1114
+ */
1115
+ Text: createSettingFieldDecorator("text"),
1116
+ /**
1117
+ * Number setting field
1118
+ */
1119
+ Number: createSettingFieldDecorator("number"),
1120
+ /**
1121
+ * Boolean setting field (toggle/switch)
1122
+ */
1123
+ Boolean: createSettingFieldDecorator("boolean"),
1124
+ /**
1125
+ * Select setting field (dropdown)
1126
+ */
1127
+ Select: createSettingFieldDecorator("select"),
1128
+ /**
1129
+ * Secret setting field (encrypted, masked in UI)
1130
+ */
1131
+ Secret: createSettingFieldDecorator("secret", {
1132
+ masked: true
1133
+ }),
1134
+ /**
1135
+ * Image setting field
1136
+ */
1137
+ Image: createSettingFieldDecorator("image"),
1138
+ /**
1139
+ * JSON setting field
1140
+ */
1141
+ JSON: createSettingFieldDecorator("json"),
1142
+ /**
1143
+ * Textarea setting field (multi-line text)
1144
+ */
1145
+ Textarea: createSettingFieldDecorator("textarea")
1146
+ };
1147
+
170
1148
  // src/decorators/schema/ui.decorator.ts
171
1149
  function UI(options) {
172
1150
  return (target, propertyKey) => {
@@ -185,9 +1163,6 @@ function UI(options) {
185
1163
  };
186
1164
  }
187
1165
  __name(UI, "UI");
188
- var Validators = /* @__PURE__ */ __name((...validators) => {
189
- return applyDecorators(...validators);
190
- }, "Validators");
191
1166
 
192
1167
  // src/decorators/schema/version.decorator.ts
193
1168
  var VERSION_METADATA_KEY = "version:metadata";
@@ -205,12 +1180,643 @@ function InjectModel(model) {
205
1180
  if (propertyKey !== void 0) {
206
1181
  Reflect.defineMetadata(INJECT_MODEL, model, target, propertyKey);
207
1182
  }
208
- const { InjectModel: InjectModel2 } = __require(`@magnet-cms/adapter-${adapter}`);
1183
+ const { InjectModel: InjectModel2 } = __require(`@magnet-cms/adapter-db-${adapter}`);
209
1184
  return InjectModel2(model)(target, propertyKey, parameterIndex);
210
1185
  };
211
1186
  }
212
1187
  __name(InjectModel, "InjectModel");
213
1188
 
1189
+ // src/errors/base.error.ts
1190
+ var ErrorCode = /* @__PURE__ */ function(ErrorCode2) {
1191
+ ErrorCode2[ErrorCode2["VALIDATION_FAILED"] = 1e3] = "VALIDATION_FAILED";
1192
+ ErrorCode2[ErrorCode2["REQUIRED_FIELD_MISSING"] = 1001] = "REQUIRED_FIELD_MISSING";
1193
+ ErrorCode2[ErrorCode2["INVALID_FORMAT"] = 1002] = "INVALID_FORMAT";
1194
+ ErrorCode2[ErrorCode2["VALUE_OUT_OF_RANGE"] = 1003] = "VALUE_OUT_OF_RANGE";
1195
+ ErrorCode2[ErrorCode2["UNIQUE_CONSTRAINT_VIOLATION"] = 1004] = "UNIQUE_CONSTRAINT_VIOLATION";
1196
+ ErrorCode2[ErrorCode2["AUTHENTICATION_REQUIRED"] = 2e3] = "AUTHENTICATION_REQUIRED";
1197
+ ErrorCode2[ErrorCode2["INVALID_CREDENTIALS"] = 2001] = "INVALID_CREDENTIALS";
1198
+ ErrorCode2[ErrorCode2["TOKEN_EXPIRED"] = 2002] = "TOKEN_EXPIRED";
1199
+ ErrorCode2[ErrorCode2["TOKEN_INVALID"] = 2003] = "TOKEN_INVALID";
1200
+ ErrorCode2[ErrorCode2["ACCOUNT_LOCKED"] = 2004] = "ACCOUNT_LOCKED";
1201
+ ErrorCode2[ErrorCode2["EMAIL_NOT_VERIFIED"] = 2005] = "EMAIL_NOT_VERIFIED";
1202
+ ErrorCode2[ErrorCode2["PERMISSION_DENIED"] = 3e3] = "PERMISSION_DENIED";
1203
+ ErrorCode2[ErrorCode2["INSUFFICIENT_PERMISSIONS"] = 3001] = "INSUFFICIENT_PERMISSIONS";
1204
+ ErrorCode2[ErrorCode2["ROLE_NOT_FOUND"] = 3002] = "ROLE_NOT_FOUND";
1205
+ ErrorCode2[ErrorCode2["PERMISSION_NOT_FOUND"] = 3003] = "PERMISSION_NOT_FOUND";
1206
+ ErrorCode2[ErrorCode2["RESOURCE_NOT_FOUND"] = 4e3] = "RESOURCE_NOT_FOUND";
1207
+ ErrorCode2[ErrorCode2["SCHEMA_NOT_FOUND"] = 4001] = "SCHEMA_NOT_FOUND";
1208
+ ErrorCode2[ErrorCode2["DOCUMENT_NOT_FOUND"] = 4002] = "DOCUMENT_NOT_FOUND";
1209
+ ErrorCode2[ErrorCode2["USER_NOT_FOUND"] = 4003] = "USER_NOT_FOUND";
1210
+ ErrorCode2[ErrorCode2["FILE_NOT_FOUND"] = 4004] = "FILE_NOT_FOUND";
1211
+ ErrorCode2[ErrorCode2["VERSION_NOT_FOUND"] = 4005] = "VERSION_NOT_FOUND";
1212
+ ErrorCode2[ErrorCode2["DATABASE_ERROR"] = 5e3] = "DATABASE_ERROR";
1213
+ ErrorCode2[ErrorCode2["CONNECTION_FAILED"] = 5001] = "CONNECTION_FAILED";
1214
+ ErrorCode2[ErrorCode2["QUERY_FAILED"] = 5002] = "QUERY_FAILED";
1215
+ ErrorCode2[ErrorCode2["TRANSACTION_FAILED"] = 5003] = "TRANSACTION_FAILED";
1216
+ ErrorCode2[ErrorCode2["DUPLICATE_KEY"] = 5004] = "DUPLICATE_KEY";
1217
+ ErrorCode2[ErrorCode2["PLUGIN_ERROR"] = 6e3] = "PLUGIN_ERROR";
1218
+ ErrorCode2[ErrorCode2["PLUGIN_NOT_FOUND"] = 6001] = "PLUGIN_NOT_FOUND";
1219
+ ErrorCode2[ErrorCode2["PLUGIN_INITIALIZATION_FAILED"] = 6002] = "PLUGIN_INITIALIZATION_FAILED";
1220
+ ErrorCode2[ErrorCode2["HOOK_EXECUTION_FAILED"] = 6003] = "HOOK_EXECUTION_FAILED";
1221
+ ErrorCode2[ErrorCode2["EXTERNAL_SERVICE_ERROR"] = 7e3] = "EXTERNAL_SERVICE_ERROR";
1222
+ ErrorCode2[ErrorCode2["STORAGE_ERROR"] = 7001] = "STORAGE_ERROR";
1223
+ ErrorCode2[ErrorCode2["EMAIL_SERVICE_ERROR"] = 7002] = "EMAIL_SERVICE_ERROR";
1224
+ ErrorCode2[ErrorCode2["WEBHOOK_DELIVERY_FAILED"] = 7003] = "WEBHOOK_DELIVERY_FAILED";
1225
+ ErrorCode2[ErrorCode2["INTERNAL_ERROR"] = 9e3] = "INTERNAL_ERROR";
1226
+ ErrorCode2[ErrorCode2["CONFIGURATION_ERROR"] = 9001] = "CONFIGURATION_ERROR";
1227
+ ErrorCode2[ErrorCode2["UNEXPECTED_ERROR"] = 9999] = "UNEXPECTED_ERROR";
1228
+ return ErrorCode2;
1229
+ }({});
1230
+ var MagnetError = class extends Error {
1231
+ static {
1232
+ __name(this, "MagnetError");
1233
+ }
1234
+ timestamp;
1235
+ metadata;
1236
+ constructor(message, metadata = {}) {
1237
+ super(message);
1238
+ this.name = this.constructor.name;
1239
+ this.timestamp = /* @__PURE__ */ new Date();
1240
+ this.metadata = metadata;
1241
+ if (Error.captureStackTrace) {
1242
+ Error.captureStackTrace(this, this.constructor);
1243
+ }
1244
+ }
1245
+ /**
1246
+ * Convert to API response format
1247
+ */
1248
+ toResponse() {
1249
+ return {
1250
+ error: {
1251
+ code: this.code,
1252
+ message: this.message,
1253
+ name: this.name,
1254
+ timestamp: this.timestamp.toISOString(),
1255
+ metadata: this.metadata
1256
+ }
1257
+ };
1258
+ }
1259
+ /**
1260
+ * Convert to JSON for logging
1261
+ */
1262
+ toJSON() {
1263
+ return {
1264
+ name: this.name,
1265
+ code: this.code,
1266
+ message: this.message,
1267
+ httpStatus: this.httpStatus,
1268
+ timestamp: this.timestamp.toISOString(),
1269
+ metadata: this.metadata,
1270
+ stack: this.stack
1271
+ };
1272
+ }
1273
+ };
1274
+
1275
+ // src/errors/validation.error.ts
1276
+ var ValidationError = class _ValidationError extends MagnetError {
1277
+ static {
1278
+ __name(this, "ValidationError");
1279
+ }
1280
+ code = ErrorCode.VALIDATION_FAILED;
1281
+ httpStatus = 400;
1282
+ details;
1283
+ constructor(message, details, metadata) {
1284
+ super(message, metadata);
1285
+ this.details = details;
1286
+ }
1287
+ /**
1288
+ * Create ValidationError from class-validator errors
1289
+ */
1290
+ static fromClassValidator(errors) {
1291
+ const details = errors.flatMap((error) => Object.entries(error.constraints ?? {}).map(([constraint, message]) => ({
1292
+ field: error.property,
1293
+ message,
1294
+ constraint,
1295
+ value: error.value
1296
+ })));
1297
+ return new _ValidationError(`Validation failed for ${details.length} field(s)`, details);
1298
+ }
1299
+ toResponse() {
1300
+ return {
1301
+ error: {
1302
+ ...super.toResponse().error,
1303
+ details: this.details
1304
+ }
1305
+ };
1306
+ }
1307
+ };
1308
+ var RequiredFieldError = class extends MagnetError {
1309
+ static {
1310
+ __name(this, "RequiredFieldError");
1311
+ }
1312
+ code = ErrorCode.REQUIRED_FIELD_MISSING;
1313
+ httpStatus = 400;
1314
+ constructor(field, metadata) {
1315
+ super(`Required field '${field}' is missing`, {
1316
+ ...metadata,
1317
+ field
1318
+ });
1319
+ }
1320
+ };
1321
+ var InvalidFormatError = class extends MagnetError {
1322
+ static {
1323
+ __name(this, "InvalidFormatError");
1324
+ }
1325
+ code = ErrorCode.INVALID_FORMAT;
1326
+ httpStatus = 400;
1327
+ constructor(field, expectedFormat, metadata) {
1328
+ super(`Field '${field}' has invalid format. Expected: ${expectedFormat}`, {
1329
+ ...metadata,
1330
+ field
1331
+ });
1332
+ }
1333
+ };
1334
+ var ValueOutOfRangeError = class extends MagnetError {
1335
+ static {
1336
+ __name(this, "ValueOutOfRangeError");
1337
+ }
1338
+ code = ErrorCode.VALUE_OUT_OF_RANGE;
1339
+ httpStatus = 400;
1340
+ constructor(field, min, max, metadata) {
1341
+ const rangeMsg = min !== void 0 && max !== void 0 ? `between ${min} and ${max}` : min !== void 0 ? `at least ${min}` : max !== void 0 ? `at most ${max}` : "within valid range";
1342
+ super(`Field '${field}' must be ${rangeMsg}`, {
1343
+ ...metadata,
1344
+ field
1345
+ });
1346
+ }
1347
+ };
1348
+
1349
+ // src/errors/auth.error.ts
1350
+ var AuthenticationRequiredError = class extends MagnetError {
1351
+ static {
1352
+ __name(this, "AuthenticationRequiredError");
1353
+ }
1354
+ code = ErrorCode.AUTHENTICATION_REQUIRED;
1355
+ httpStatus = 401;
1356
+ constructor(message = "Authentication required", metadata) {
1357
+ super(message, metadata);
1358
+ }
1359
+ };
1360
+ var InvalidCredentialsError = class extends MagnetError {
1361
+ static {
1362
+ __name(this, "InvalidCredentialsError");
1363
+ }
1364
+ code = ErrorCode.INVALID_CREDENTIALS;
1365
+ httpStatus = 401;
1366
+ constructor(message = "Invalid email or password", metadata) {
1367
+ super(message, metadata);
1368
+ }
1369
+ };
1370
+ var TokenExpiredError = class extends MagnetError {
1371
+ static {
1372
+ __name(this, "TokenExpiredError");
1373
+ }
1374
+ code = ErrorCode.TOKEN_EXPIRED;
1375
+ httpStatus = 401;
1376
+ constructor(message = "Token has expired", metadata) {
1377
+ super(message, metadata);
1378
+ }
1379
+ };
1380
+ var TokenInvalidError = class extends MagnetError {
1381
+ static {
1382
+ __name(this, "TokenInvalidError");
1383
+ }
1384
+ code = ErrorCode.TOKEN_INVALID;
1385
+ httpStatus = 401;
1386
+ constructor(message = "Token is invalid", metadata) {
1387
+ super(message, metadata);
1388
+ }
1389
+ };
1390
+ var AccountLockedError = class extends MagnetError {
1391
+ static {
1392
+ __name(this, "AccountLockedError");
1393
+ }
1394
+ code = ErrorCode.ACCOUNT_LOCKED;
1395
+ httpStatus = 423;
1396
+ unlockAt;
1397
+ constructor(message = "Account is temporarily locked", unlockAt, metadata) {
1398
+ super(message, metadata);
1399
+ this.unlockAt = unlockAt;
1400
+ }
1401
+ };
1402
+ var EmailNotVerifiedError = class extends MagnetError {
1403
+ static {
1404
+ __name(this, "EmailNotVerifiedError");
1405
+ }
1406
+ code = ErrorCode.EMAIL_NOT_VERIFIED;
1407
+ httpStatus = 403;
1408
+ constructor(message = "Email address not verified", metadata) {
1409
+ super(message, metadata);
1410
+ }
1411
+ };
1412
+ var PermissionDeniedError = class extends MagnetError {
1413
+ static {
1414
+ __name(this, "PermissionDeniedError");
1415
+ }
1416
+ code = ErrorCode.PERMISSION_DENIED;
1417
+ httpStatus = 403;
1418
+ requiredPermission;
1419
+ constructor(message = "You do not have permission to perform this action", requiredPermission, metadata) {
1420
+ super(message, metadata);
1421
+ this.requiredPermission = requiredPermission;
1422
+ }
1423
+ };
1424
+ var InsufficientPermissionsError = class extends MagnetError {
1425
+ static {
1426
+ __name(this, "InsufficientPermissionsError");
1427
+ }
1428
+ code = ErrorCode.INSUFFICIENT_PERMISSIONS;
1429
+ httpStatus = 403;
1430
+ requiredPermissions;
1431
+ constructor(requiredPermissions, metadata) {
1432
+ super(`Insufficient permissions. Required: ${requiredPermissions.join(", ")}`, metadata);
1433
+ this.requiredPermissions = requiredPermissions;
1434
+ }
1435
+ };
1436
+ var RoleNotFoundError = class extends MagnetError {
1437
+ static {
1438
+ __name(this, "RoleNotFoundError");
1439
+ }
1440
+ code = ErrorCode.ROLE_NOT_FOUND;
1441
+ httpStatus = 404;
1442
+ constructor(roleName, metadata) {
1443
+ super(`Role '${roleName}' not found`, metadata);
1444
+ }
1445
+ };
1446
+ var PermissionNotFoundError = class extends MagnetError {
1447
+ static {
1448
+ __name(this, "PermissionNotFoundError");
1449
+ }
1450
+ code = ErrorCode.PERMISSION_NOT_FOUND;
1451
+ httpStatus = 400;
1452
+ invalidPermissionIds;
1453
+ constructor(invalidPermissionIds, metadata) {
1454
+ super(`Invalid permission(s): ${invalidPermissionIds.join(", ")}. These permissions are not registered in the system.`, {
1455
+ ...metadata,
1456
+ context: {
1457
+ ...metadata?.context,
1458
+ invalidPermissionIds
1459
+ }
1460
+ });
1461
+ this.invalidPermissionIds = invalidPermissionIds;
1462
+ }
1463
+ };
1464
+
1465
+ // src/errors/resource.error.ts
1466
+ var ResourceNotFoundError = class extends MagnetError {
1467
+ static {
1468
+ __name(this, "ResourceNotFoundError");
1469
+ }
1470
+ code = ErrorCode.RESOURCE_NOT_FOUND;
1471
+ httpStatus = 404;
1472
+ constructor(resourceType, identifier, metadata) {
1473
+ super(`${resourceType} with identifier '${identifier}' not found`, {
1474
+ ...metadata,
1475
+ resourceId: identifier
1476
+ });
1477
+ }
1478
+ };
1479
+ var SchemaNotFoundError = class extends MagnetError {
1480
+ static {
1481
+ __name(this, "SchemaNotFoundError");
1482
+ }
1483
+ code = ErrorCode.SCHEMA_NOT_FOUND;
1484
+ httpStatus = 404;
1485
+ constructor(schemaName, metadata) {
1486
+ super(`Schema '${schemaName}' not found`, {
1487
+ ...metadata,
1488
+ schema: schemaName
1489
+ });
1490
+ }
1491
+ };
1492
+ var DocumentNotFoundError = class extends MagnetError {
1493
+ static {
1494
+ __name(this, "DocumentNotFoundError");
1495
+ }
1496
+ code = ErrorCode.DOCUMENT_NOT_FOUND;
1497
+ httpStatus = 404;
1498
+ constructor(schema, id, metadata) {
1499
+ super(`Document '${id}' not found in ${schema}`, {
1500
+ ...metadata,
1501
+ schema,
1502
+ resourceId: id
1503
+ });
1504
+ }
1505
+ };
1506
+ var UserNotFoundError = class extends MagnetError {
1507
+ static {
1508
+ __name(this, "UserNotFoundError");
1509
+ }
1510
+ code = ErrorCode.USER_NOT_FOUND;
1511
+ httpStatus = 404;
1512
+ constructor(identifier, metadata) {
1513
+ super(`User '${identifier}' not found`, {
1514
+ ...metadata,
1515
+ resourceId: identifier
1516
+ });
1517
+ }
1518
+ };
1519
+ var FileNotFoundError = class extends MagnetError {
1520
+ static {
1521
+ __name(this, "FileNotFoundError");
1522
+ }
1523
+ code = ErrorCode.FILE_NOT_FOUND;
1524
+ httpStatus = 404;
1525
+ constructor(path, metadata) {
1526
+ super(`File '${path}' not found`, {
1527
+ ...metadata,
1528
+ resourceId: path
1529
+ });
1530
+ }
1531
+ };
1532
+ var VersionNotFoundError = class extends MagnetError {
1533
+ static {
1534
+ __name(this, "VersionNotFoundError");
1535
+ }
1536
+ code = ErrorCode.VERSION_NOT_FOUND;
1537
+ httpStatus = 404;
1538
+ constructor(schema, documentId, versionId, metadata) {
1539
+ super(`Version '${versionId}' not found for document '${documentId}' in ${schema}`, {
1540
+ ...metadata,
1541
+ schema,
1542
+ resourceId: documentId,
1543
+ context: {
1544
+ versionId
1545
+ }
1546
+ });
1547
+ }
1548
+ };
1549
+
1550
+ // src/errors/database.error.ts
1551
+ var DatabaseError = class extends MagnetError {
1552
+ static {
1553
+ __name(this, "DatabaseError");
1554
+ }
1555
+ code = ErrorCode.DATABASE_ERROR;
1556
+ httpStatus = 500;
1557
+ originalError;
1558
+ constructor(message, originalError, metadata) {
1559
+ super(message, metadata);
1560
+ this.originalError = originalError;
1561
+ }
1562
+ };
1563
+ var ConnectionFailedError = class extends MagnetError {
1564
+ static {
1565
+ __name(this, "ConnectionFailedError");
1566
+ }
1567
+ code = ErrorCode.CONNECTION_FAILED;
1568
+ httpStatus = 503;
1569
+ constructor(message = "Database connection failed", metadata) {
1570
+ super(message, metadata);
1571
+ }
1572
+ };
1573
+ var QueryFailedError = class extends MagnetError {
1574
+ static {
1575
+ __name(this, "QueryFailedError");
1576
+ }
1577
+ code = ErrorCode.QUERY_FAILED;
1578
+ httpStatus = 500;
1579
+ query;
1580
+ constructor(message, query, metadata) {
1581
+ super(message, metadata);
1582
+ this.query = query;
1583
+ }
1584
+ };
1585
+ var TransactionFailedError = class extends MagnetError {
1586
+ static {
1587
+ __name(this, "TransactionFailedError");
1588
+ }
1589
+ code = ErrorCode.TRANSACTION_FAILED;
1590
+ httpStatus = 500;
1591
+ constructor(message = "Transaction failed", metadata) {
1592
+ super(message, metadata);
1593
+ }
1594
+ };
1595
+ var DuplicateKeyError = class extends MagnetError {
1596
+ static {
1597
+ __name(this, "DuplicateKeyError");
1598
+ }
1599
+ code = ErrorCode.DUPLICATE_KEY;
1600
+ httpStatus = 409;
1601
+ constructor(field, value, metadata) {
1602
+ super(`A record with ${field} '${String(value)}' already exists`, {
1603
+ ...metadata,
1604
+ field
1605
+ });
1606
+ }
1607
+ };
1608
+
1609
+ // src/errors/plugin.error.ts
1610
+ var PluginError = class extends MagnetError {
1611
+ static {
1612
+ __name(this, "PluginError");
1613
+ }
1614
+ code = ErrorCode.PLUGIN_ERROR;
1615
+ httpStatus = 500;
1616
+ constructor(pluginName, message, metadata) {
1617
+ super(`Plugin '${pluginName}': ${message}`, metadata);
1618
+ }
1619
+ };
1620
+ var PluginNotFoundError = class extends MagnetError {
1621
+ static {
1622
+ __name(this, "PluginNotFoundError");
1623
+ }
1624
+ code = ErrorCode.PLUGIN_NOT_FOUND;
1625
+ httpStatus = 404;
1626
+ constructor(pluginName, metadata) {
1627
+ super(`Plugin '${pluginName}' not found`, metadata);
1628
+ }
1629
+ };
1630
+ var PluginInitializationError = class extends MagnetError {
1631
+ static {
1632
+ __name(this, "PluginInitializationError");
1633
+ }
1634
+ code = ErrorCode.PLUGIN_INITIALIZATION_FAILED;
1635
+ httpStatus = 500;
1636
+ constructor(pluginName, reason, metadata) {
1637
+ super(`Failed to initialize plugin '${pluginName}': ${reason}`, metadata);
1638
+ }
1639
+ };
1640
+ var HookExecutionError = class extends MagnetError {
1641
+ static {
1642
+ __name(this, "HookExecutionError");
1643
+ }
1644
+ code = ErrorCode.HOOK_EXECUTION_FAILED;
1645
+ httpStatus = 500;
1646
+ constructor(hookName, pluginName, reason, metadata) {
1647
+ super(`Hook '${hookName}' in plugin '${pluginName}' failed: ${reason}`, metadata);
1648
+ }
1649
+ };
1650
+
1651
+ // src/errors/external.error.ts
1652
+ var ExternalServiceError = class extends MagnetError {
1653
+ static {
1654
+ __name(this, "ExternalServiceError");
1655
+ }
1656
+ code = ErrorCode.EXTERNAL_SERVICE_ERROR;
1657
+ httpStatus = 502;
1658
+ constructor(serviceName, message, metadata) {
1659
+ super(`External service '${serviceName}' error: ${message}`, metadata);
1660
+ }
1661
+ };
1662
+ var StorageError = class extends MagnetError {
1663
+ static {
1664
+ __name(this, "StorageError");
1665
+ }
1666
+ code = ErrorCode.STORAGE_ERROR;
1667
+ httpStatus = 502;
1668
+ constructor(message, metadata) {
1669
+ super(`Storage error: ${message}`, metadata);
1670
+ }
1671
+ };
1672
+ var EmailServiceError = class extends MagnetError {
1673
+ static {
1674
+ __name(this, "EmailServiceError");
1675
+ }
1676
+ code = ErrorCode.EMAIL_SERVICE_ERROR;
1677
+ httpStatus = 502;
1678
+ constructor(message, metadata) {
1679
+ super(`Email service error: ${message}`, metadata);
1680
+ }
1681
+ };
1682
+ var WebhookDeliveryError = class extends MagnetError {
1683
+ static {
1684
+ __name(this, "WebhookDeliveryError");
1685
+ }
1686
+ code = ErrorCode.WEBHOOK_DELIVERY_FAILED;
1687
+ httpStatus = 502;
1688
+ webhookUrl;
1689
+ statusCode;
1690
+ constructor(webhookUrl, reason, statusCode, metadata) {
1691
+ super(`Webhook delivery to '${webhookUrl}' failed: ${reason}`, metadata);
1692
+ this.webhookUrl = webhookUrl;
1693
+ this.statusCode = statusCode;
1694
+ }
1695
+ };
1696
+
1697
+ // src/errors/internal.error.ts
1698
+ var InternalError = class extends MagnetError {
1699
+ static {
1700
+ __name(this, "InternalError");
1701
+ }
1702
+ code = ErrorCode.INTERNAL_ERROR;
1703
+ httpStatus = 500;
1704
+ constructor(message = "An internal error occurred", metadata) {
1705
+ super(message, metadata);
1706
+ }
1707
+ };
1708
+ var ConfigurationError = class extends MagnetError {
1709
+ static {
1710
+ __name(this, "ConfigurationError");
1711
+ }
1712
+ code = ErrorCode.CONFIGURATION_ERROR;
1713
+ httpStatus = 500;
1714
+ constructor(message, metadata) {
1715
+ super(`Configuration error: ${message}`, metadata);
1716
+ }
1717
+ };
1718
+ var UnexpectedError = class extends MagnetError {
1719
+ static {
1720
+ __name(this, "UnexpectedError");
1721
+ }
1722
+ code = ErrorCode.UNEXPECTED_ERROR;
1723
+ httpStatus = 500;
1724
+ originalError;
1725
+ constructor(message = "An unexpected error occurred", originalError, metadata) {
1726
+ super(message, metadata);
1727
+ this.originalError = originalError;
1728
+ }
1729
+ };
1730
+
1731
+ // src/errors/factory.ts
1732
+ function fromMongooseError(error, context) {
1733
+ if (isCastError(error) && error.path === "_id") {
1734
+ return new DocumentNotFoundError(context?.schema ?? "document", String(error.value), {
1735
+ operation: context?.operation
1736
+ });
1737
+ }
1738
+ if (isDuplicateKeyError(error)) {
1739
+ const keyValue = error.keyValue;
1740
+ const field = Object.keys(keyValue)[0] ?? "field";
1741
+ const value = keyValue[field];
1742
+ return new DuplicateKeyError(field, value, {
1743
+ schema: context?.schema
1744
+ });
1745
+ }
1746
+ if (isValidationError(error)) {
1747
+ const details = Object.entries(error.errors).map(([field, err]) => {
1748
+ const errorObj = err;
1749
+ return {
1750
+ field,
1751
+ message: String(errorObj.message ?? "Validation failed")
1752
+ };
1753
+ });
1754
+ return new ValidationError("Validation failed", details, {
1755
+ schema: context?.schema
1756
+ });
1757
+ }
1758
+ return new DatabaseError(error instanceof Error ? error.message : "Database operation failed", error, {
1759
+ schema: context?.schema
1760
+ });
1761
+ }
1762
+ __name(fromMongooseError, "fromMongooseError");
1763
+ function extractPostgresUniqueInfo(error) {
1764
+ if (!error.detail) {
1765
+ return null;
1766
+ }
1767
+ const match = error.detail.match(/Key \((\w+)\)=\(([^)]+)\)/);
1768
+ const field = match?.[1];
1769
+ const value = match?.[2];
1770
+ if (field && value) {
1771
+ return {
1772
+ field,
1773
+ value
1774
+ };
1775
+ }
1776
+ return null;
1777
+ }
1778
+ __name(extractPostgresUniqueInfo, "extractPostgresUniqueInfo");
1779
+ function fromDrizzleError(error, context) {
1780
+ if (isPostgresUniqueError(error)) {
1781
+ const info = extractPostgresUniqueInfo(error);
1782
+ if (info) {
1783
+ return new DuplicateKeyError(info.field, info.value, {
1784
+ schema: context?.schema
1785
+ });
1786
+ }
1787
+ }
1788
+ if (error instanceof Error && error.message.includes("unique constraint")) {
1789
+ const match = error.message.match(/Key \((\w+)\)=\(([^)]+)\)/);
1790
+ const field = match?.[1];
1791
+ const value = match?.[2];
1792
+ if (field && value) {
1793
+ return new DuplicateKeyError(field, value, {
1794
+ schema: context?.schema
1795
+ });
1796
+ }
1797
+ }
1798
+ if (error instanceof Error && error.message.includes("no result")) {
1799
+ return new DocumentNotFoundError(context?.schema ?? "document", "unknown", {
1800
+ operation: "read"
1801
+ });
1802
+ }
1803
+ return new DatabaseError(error instanceof Error ? error.message : "Database operation failed", error, {
1804
+ schema: context?.schema
1805
+ });
1806
+ }
1807
+ __name(fromDrizzleError, "fromDrizzleError");
1808
+ function isMagnetError(error) {
1809
+ return error instanceof MagnetError;
1810
+ }
1811
+ __name(isMagnetError, "isMagnetError");
1812
+ function wrapError(error, fallbackMessage = "An error occurred") {
1813
+ if (isMagnetError(error)) {
1814
+ return error;
1815
+ }
1816
+ return new DatabaseError(error instanceof Error ? error.message : fallbackMessage, error);
1817
+ }
1818
+ __name(wrapError, "wrapError");
1819
+
214
1820
  // src/exceptions/validation.exception.ts
215
1821
  var ValidationException = class extends Error {
216
1822
  static {
@@ -228,13 +1834,35 @@ var Model = class {
228
1834
  __name(this, "Model");
229
1835
  }
230
1836
  /**
1837
+ * Get current locale
1838
+ */
1839
+ getLocale() {
1840
+ return "en";
1841
+ }
1842
+ /**
231
1843
  * Set the version for subsequent operations
232
1844
  * @param versionId The version ID or status ('draft', 'published', 'archived')
1845
+ * @returns Same instance (chainable)
233
1846
  */
234
1847
  version(versionId) {
235
1848
  return this;
236
1849
  }
237
1850
  /**
1851
+ * Check if versioning is enabled for this model
1852
+ */
1853
+ isVersioningEnabled() {
1854
+ return false;
1855
+ }
1856
+ /**
1857
+ * Create a version snapshot of a document
1858
+ * @param documentId The document ID
1859
+ * @param data The data to version
1860
+ * @returns Version record or null if versioning disabled
1861
+ */
1862
+ createVersion(documentId, data) {
1863
+ return Promise.resolve(null);
1864
+ }
1865
+ /**
238
1866
  * Find all versions of a document
239
1867
  * @param documentId The document ID
240
1868
  */
@@ -249,12 +1877,13 @@ var Model = class {
249
1877
  return Promise.resolve(null);
250
1878
  }
251
1879
  /**
252
- * Restore a version
1880
+ * Restore a document to a specific version
253
1881
  * @param versionId The version ID to restore
254
1882
  */
255
1883
  restoreVersion(versionId) {
256
1884
  return Promise.resolve(null);
257
1885
  }
1886
+ // ============= Query Builder =============
258
1887
  /**
259
1888
  * Create a query builder for advanced queries with sorting, pagination, and operators.
260
1889
  * The query builder inherits the current locale/version context.
@@ -271,15 +1900,29 @@ var Model = class {
271
1900
  query() {
272
1901
  throw new Error("QueryBuilder not implemented by this adapter");
273
1902
  }
1903
+ // ============= Native Access =============
274
1904
  /**
275
1905
  * Get access to the native database model/collection.
276
1906
  * Use with caution - bypasses Magnet abstractions like locale and versioning.
277
1907
  *
278
- * @returns The underlying database model (e.g., Mongoose Model)
1908
+ * @returns Typed native access object
279
1909
  */
280
1910
  native() {
281
1911
  throw new Error("Native access not implemented by this adapter");
282
1912
  }
1913
+ // ============= Metadata =============
1914
+ /**
1915
+ * Get schema name
1916
+ */
1917
+ getSchemaName() {
1918
+ throw new Error("getSchemaName not implemented by this adapter");
1919
+ }
1920
+ /**
1921
+ * Get schema metadata
1922
+ */
1923
+ getMetadata() {
1924
+ throw new Error("getMetadata not implemented by this adapter");
1925
+ }
283
1926
  };
284
1927
 
285
1928
  // src/model/mixed.model.ts
@@ -296,6 +1939,17 @@ var QueryBuilder = class {
296
1939
  static {
297
1940
  __name(this, "QueryBuilder");
298
1941
  }
1942
+ /**
1943
+ * Exclude specific fields from results
1944
+ * @param fields Array of field names to exclude
1945
+ */
1946
+ exclude(fields) {
1947
+ const projection = {};
1948
+ for (const field of fields) {
1949
+ projection[field] = 0;
1950
+ }
1951
+ return this.select(projection);
1952
+ }
299
1953
  };
300
1954
 
301
1955
  // src/types/auth.types.ts
@@ -312,6 +1966,13 @@ var AuthStrategy = class {
312
1966
  }
313
1967
  };
314
1968
 
1969
+ // src/types/email.types.ts
1970
+ var EmailAdapter = class {
1971
+ static {
1972
+ __name(this, "EmailAdapter");
1973
+ }
1974
+ };
1975
+
315
1976
  // src/types/config.types.ts
316
1977
  var MagnetModuleOptions = class {
317
1978
  static {
@@ -327,17 +1988,54 @@ var MagnetModuleOptions = class {
327
1988
  playground;
328
1989
  storage;
329
1990
  /**
1991
+ * Email adapter configuration
1992
+ * @example
1993
+ * email: { adapter: 'nodemailer', nodemailer: { host: 'smtp.example.com', port: 587, auth: { user: 'user', pass: 'pass' } } }
1994
+ */
1995
+ email;
1996
+ /**
330
1997
  * Plugins to load with the Magnet module
331
1998
  */
332
1999
  plugins;
333
- constructor({ db, jwt, auth, internationalization, playground, storage, plugins }) {
2000
+ /**
2001
+ * Admin panel configuration (enabled by default when omitted).
2002
+ * @example
2003
+ * // Explicit enable (same as omitting `admin`)
2004
+ * admin: true
2005
+ *
2006
+ * // Custom path
2007
+ * admin: { enabled: true, path: '/dashboard' }
2008
+ *
2009
+ * // Disable (for API-only mode)
2010
+ * admin: false
2011
+ */
2012
+ admin;
2013
+ /**
2014
+ * RBAC (Role-Based Access Control) configuration
2015
+ * @example
2016
+ * rbac: { enabled: true, defaultRole: 'authenticated' }
2017
+ */
2018
+ rbac;
2019
+ /**
2020
+ * Vault configuration for encrypted secrets management.
2021
+ * Uses the built-in DB adapter by default (requires VAULT_MASTER_KEY env var).
2022
+ * @example
2023
+ * vault: { adapter: 'db' }
2024
+ * vault: { adapter: 'hashicorp', hashicorp: { url: 'https://vault.example.com:8200' } }
2025
+ */
2026
+ vault;
2027
+ constructor({ db, jwt, auth, internationalization, playground, storage, email, plugins, admin, rbac, vault }) {
334
2028
  this.db = db;
335
2029
  this.jwt = jwt;
336
2030
  this.auth = auth;
337
2031
  this.internationalization = internationalization;
338
2032
  this.playground = playground;
339
2033
  this.storage = storage;
2034
+ this.email = email;
340
2035
  this.plugins = plugins;
2036
+ this.admin = admin;
2037
+ this.rbac = rbac;
2038
+ this.vault = vault;
341
2039
  }
342
2040
  };
343
2041
 
@@ -348,6 +2046,16 @@ var DatabaseAdapter = class {
348
2046
  }
349
2047
  };
350
2048
 
2049
+ // src/types/settings.types.ts
2050
+ function isSettingFieldMetadata(value) {
2051
+ if (typeof value !== "object" || value === null) {
2052
+ return false;
2053
+ }
2054
+ const metadata = value;
2055
+ return typeof metadata.type === "string" && typeof metadata.options === "object" && metadata.options !== null && "propertyKey" in metadata;
2056
+ }
2057
+ __name(isSettingFieldMetadata, "isSettingFieldMetadata");
2058
+
351
2059
  // src/types/storage.types.ts
352
2060
  var StorageAdapter = class {
353
2061
  static {
@@ -355,4 +2063,18 @@ var StorageAdapter = class {
355
2063
  }
356
2064
  };
357
2065
 
358
- export { AuthStrategy, BASE_SCHEMA_METADATA_KEY, DESIGN_META, DESIGN_PARAM_TYPES, DESIGN_RETURN_TYPE, DESIGN_TYPE, DatabaseAdapter, INJECT_MODEL, InjectModel, MagnetModuleOptions, Mixed, Model, PROP_METADATA_KEY, Prop, QueryBuilder, RESOLVER_METADATA_KEY, RESOLVE_METADATA_KEY, Resolve, Resolver, SCHEMA_METADATA_KEY, SCHEMA_OPTIONS_METADATA_KEY, SETTING_METADATA_KEY, Schema, Setting, StorageAdapter, UI, UI_METADATA_KEY, VERSION_METADATA_KEY, ValidationException, Validators, Version, detectDatabaseAdapter, getModelToken, getSchemaOptions, getSchemaToken, getSettingToken };
2066
+ // src/types/vault.types.ts
2067
+ var VaultAdapter = class {
2068
+ static {
2069
+ __name(this, "VaultAdapter");
2070
+ }
2071
+ };
2072
+
2073
+ // src/types/cache.types.ts
2074
+ var CacheAdapter = class {
2075
+ static {
2076
+ __name(this, "CacheAdapter");
2077
+ }
2078
+ };
2079
+
2080
+ export { AccountLockedError, AuthStrategy, AuthenticationRequiredError, BASE_SCHEMA_METADATA_KEY, CacheAdapter, ConfigurationError, ConnectionFailedError, DESIGN_META, DESIGN_PARAM_TYPES, DESIGN_RETURN_TYPE, DESIGN_TYPE, DatabaseAdapter, DatabaseError, DocumentNotFoundError, DuplicateKeyError, EVENT_HANDLER_METADATA, EXTEND_USER_METADATA_KEY, EmailAdapter, EmailNotVerifiedError, EmailServiceError, ErrorCode, ExtendUser, ExternalServiceError, FIELD_METADATA_KEY, Field, FileNotFoundError, HasPermission, HookExecutionError, INJECT_MODEL, InjectModel, InsufficientPermissionsError, InternalError, InvalidCredentialsError, InvalidFormatError, MagnetError, MagnetModuleOptions, Mixed, Model, OnEvent, PERMISSION_METADATA_KEY, PERMISSION_OPTIONS_METADATA_KEY, PROP_METADATA_KEY, PermissionDeniedError, PermissionMeta, PermissionNotFoundError, PluginError, PluginInitializationError, PluginNotFoundError, Prop, QueryBuilder, QueryFailedError, RESOLVED_PERMISSION_KEY, RESOLVER_METADATA_KEY, RESOLVE_METADATA_KEY, RequirePermission, RequiredFieldError, Resolve, Resolver, ResourceNotFoundError, RoleNotFoundError, SCHEMA_METADATA_KEY, SCHEMA_OPTIONS_METADATA_KEY, SETTINGS_OPTIONS_METADATA_KEY, SETTING_FIELD_METADATA_KEY, SETTING_METADATA_KEY, Schema, SchemaNotFoundError, Setting, SettingField, Settings, StorageAdapter, StorageError, TokenExpiredError, TokenInvalidError, TransactionFailedError, UI, UI_METADATA_KEY, UnexpectedError, UserNotFoundError, VERSION_METADATA_KEY, ValidationError, ValidationException, Validators, ValueOutOfRangeError, VaultAdapter, Version, VersionNotFoundError, WebhookDeliveryError, assert, assertDefined, clearAdapterCache, createFieldDecorator, detectDatabaseAdapter, fromDrizzleError, fromMongooseError, getAdapterToken, getDocumentId, getExtendUserOptions, getFieldMetadata, getFieldMetadataForProperty, getModelToken, getPermissionMetadata, getRegisteredModel, getSchemaOptions, getSchemaToken, getSettingFields, getSettingToken, getSettingsOptions, hasMethod, hasPermissionDecorator, hasProperties, hasProperty, hasSetLocale, hasToString, isArray, isBoolean, isCastError, isDocument, isDuplicateKeyError, isFieldMetadata, isFunction, isMagnetError, isNumber, isObject, isPostgresUniqueError, isSettingFieldMetadata, isString, isStringArray, isStringRecord, isUserExtension, isValidFieldType, isValidationError, isVersionDocument, mapFieldTypeToProp, mapFieldTypeToUI, registerModel, setDatabaseAdapter, wrapError };