nextjs-cms 0.6.5 → 0.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/api/lib/serverActions.js +8 -8
  2. package/dist/api/routers/accountSettings.js +4 -4
  3. package/dist/api/trpc.js +1 -1
  4. package/dist/auth/lib/actions.d.ts.map +1 -1
  5. package/dist/auth/lib/actions.js +6 -5
  6. package/dist/core/config/config-loader.d.ts +12 -0
  7. package/dist/core/config/config-loader.d.ts.map +1 -1
  8. package/dist/core/config/config-loader.js +17 -1
  9. package/dist/core/factories/FieldFactory.d.ts.map +1 -1
  10. package/dist/core/factories/FieldFactory.js +2 -1
  11. package/dist/core/fields/color.d.ts.map +1 -1
  12. package/dist/core/fields/color.js +3 -2
  13. package/dist/core/fields/date.d.ts.map +1 -1
  14. package/dist/core/fields/date.js +3 -2
  15. package/dist/core/fields/document.d.ts.map +1 -1
  16. package/dist/core/fields/document.js +14 -13
  17. package/dist/core/fields/field-group.d.ts +3 -2
  18. package/dist/core/fields/field-group.d.ts.map +1 -1
  19. package/dist/core/fields/map.d.ts.map +1 -1
  20. package/dist/core/fields/map.js +3 -2
  21. package/dist/core/fields/number.d.ts.map +1 -1
  22. package/dist/core/fields/number.js +8 -7
  23. package/dist/core/fields/password.d.ts.map +1 -1
  24. package/dist/core/fields/password.js +5 -4
  25. package/dist/core/fields/photo.d.ts +78 -0
  26. package/dist/core/fields/photo.d.ts.map +1 -1
  27. package/dist/core/fields/photo.js +70 -28
  28. package/dist/core/fields/select.js +3 -3
  29. package/dist/core/fields/slug.d.ts +5 -1
  30. package/dist/core/fields/slug.d.ts.map +1 -1
  31. package/dist/core/fields/slug.js +9 -4
  32. package/dist/core/fields/text.d.ts.map +1 -1
  33. package/dist/core/fields/text.js +4 -3
  34. package/dist/core/fields/video.d.ts.map +1 -1
  35. package/dist/core/fields/video.js +13 -12
  36. package/dist/core/sections/category.d.ts +2 -2
  37. package/dist/core/sections/category.js +3 -3
  38. package/dist/core/sections/hasItems.d.ts +74 -2
  39. package/dist/core/sections/hasItems.d.ts.map +1 -1
  40. package/dist/core/sections/section.d.ts +1 -1
  41. package/dist/core/sections/simple.d.ts +2 -2
  42. package/dist/core/submit/ItemEditSubmit.d.ts +6 -0
  43. package/dist/core/submit/ItemEditSubmit.d.ts.map +1 -1
  44. package/dist/core/submit/ItemEditSubmit.js +8 -0
  45. package/dist/core/submit/submit.d.ts +27 -0
  46. package/dist/core/submit/submit.d.ts.map +1 -1
  47. package/dist/core/submit/submit.js +107 -3
  48. package/dist/translations/dictionaries/ar.d.ts +68 -0
  49. package/dist/translations/dictionaries/ar.d.ts.map +1 -1
  50. package/dist/translations/dictionaries/ar.js +81 -0
  51. package/dist/translations/dictionaries/en.d.ts +68 -0
  52. package/dist/translations/dictionaries/en.d.ts.map +1 -1
  53. package/dist/translations/dictionaries/en.js +81 -0
  54. package/dist/translations/index.d.ts +3 -2
  55. package/dist/translations/index.d.ts.map +1 -1
  56. package/dist/translations/index.js +11 -3
  57. package/dist/validators/checkbox.d.ts +1 -1
  58. package/dist/validators/checkbox.d.ts.map +1 -1
  59. package/dist/validators/checkbox.js +7 -3
  60. package/dist/validators/color.d.ts +1 -1
  61. package/dist/validators/color.d.ts.map +1 -1
  62. package/dist/validators/color.js +6 -4
  63. package/dist/validators/date.d.ts +1 -1
  64. package/dist/validators/date.d.ts.map +1 -1
  65. package/dist/validators/date.js +5 -3
  66. package/dist/validators/document.d.ts +1 -1
  67. package/dist/validators/document.d.ts.map +1 -1
  68. package/dist/validators/document.js +10 -8
  69. package/dist/validators/index.d.ts +7 -6
  70. package/dist/validators/index.d.ts.map +1 -1
  71. package/dist/validators/index.js +7 -6
  72. package/dist/validators/map.d.ts +1 -1
  73. package/dist/validators/map.d.ts.map +1 -1
  74. package/dist/validators/map.js +7 -3
  75. package/dist/validators/number.d.ts +1 -1
  76. package/dist/validators/number.d.ts.map +1 -1
  77. package/dist/validators/number.js +19 -10
  78. package/dist/validators/password.d.ts +1 -1
  79. package/dist/validators/password.d.ts.map +1 -1
  80. package/dist/validators/password.js +13 -5
  81. package/dist/validators/photo.d.ts +1 -1
  82. package/dist/validators/photo.d.ts.map +1 -1
  83. package/dist/validators/photo.js +15 -13
  84. package/dist/validators/richText.d.ts +1 -1
  85. package/dist/validators/richText.d.ts.map +1 -1
  86. package/dist/validators/richText.js +14 -6
  87. package/dist/validators/select-multiple.d.ts +1 -1
  88. package/dist/validators/select-multiple.d.ts.map +1 -1
  89. package/dist/validators/select-multiple.js +8 -6
  90. package/dist/validators/select.d.ts +1 -1
  91. package/dist/validators/select.d.ts.map +1 -1
  92. package/dist/validators/select.js +8 -3
  93. package/dist/validators/slug.d.ts +4 -0
  94. package/dist/validators/slug.d.ts.map +1 -0
  95. package/dist/validators/slug.js +26 -0
  96. package/dist/validators/text.d.ts +1 -1
  97. package/dist/validators/text.d.ts.map +1 -1
  98. package/dist/validators/text.js +13 -3
  99. package/dist/validators/textarea.d.ts +1 -1
  100. package/dist/validators/textarea.d.ts.map +1 -1
  101. package/dist/validators/textarea.js +13 -3
  102. package/dist/validators/types.d.ts +7 -0
  103. package/dist/validators/types.d.ts.map +1 -0
  104. package/dist/validators/types.js +0 -0
  105. package/dist/validators/video.d.ts +1 -1
  106. package/dist/validators/video.d.ts.map +1 -1
  107. package/dist/validators/video.js +10 -8
  108. package/package.json +3 -3
@@ -2,6 +2,7 @@ import { Field, baseFieldConfigSchema } from './field.js';
2
2
  import { entityKind } from '../helpers/index.js';
3
3
  import bcrypt from 'bcrypt';
4
4
  import * as z from 'zod';
5
+ import getString from '../../translations/index.js';
5
6
  const passwordValidationTypeSchema = z.strictObject({
6
7
  regex: z.custom().describe('The regex pattern for validation'),
7
8
  message: z.string().describe('The error message if validation fails'),
@@ -55,7 +56,7 @@ export class PasswordField extends Field {
55
56
  */
56
57
  if (this.adminGenerated && this.required) {
57
58
  if (!this.value || this.value.trim().length === 0) {
58
- throw new Error(`Field ${this.label} is required`);
59
+ throw new Error(getString('fieldIsRequired', 'en', { field: String(this.label) }));
59
60
  }
60
61
  }
61
62
  }
@@ -74,7 +75,7 @@ export class PasswordField extends Field {
74
75
  /**
75
76
  * Display the provided message
76
77
  */
77
- throw new Error(`Field ${this.label}: ${this.validation.message}`);
78
+ throw new Error(`${String(this.label)}: ${this.validation.message}`);
78
79
  }
79
80
  }
80
81
  /**
@@ -82,7 +83,7 @@ export class PasswordField extends Field {
82
83
  */
83
84
  if (this.minLength) {
84
85
  if (this.minLength > this.value.length) {
85
- throw new Error(`Field ${this.label} must be at least ${this.minLength} characters long`);
86
+ throw new Error(getString('minLength', 'en', { min: this.minLength }));
86
87
  }
87
88
  }
88
89
  /**
@@ -90,7 +91,7 @@ export class PasswordField extends Field {
90
91
  */
91
92
  if (this.maxLength) {
92
93
  if (this.maxLength < this.value.length) {
93
- throw new Error(`Field ${this.label} must be at most ${this.maxLength} characters long`);
94
+ throw new Error(getString('maxLength', 'en', { max: this.maxLength }));
94
95
  }
95
96
  }
96
97
  /**
@@ -23,12 +23,32 @@ declare const configSchema: z.ZodObject<{
23
23
  * }
24
24
  */
25
25
  crop: z.ZodBoolean;
26
+ /**
27
+ * Background color for padding when crop is false.
28
+ * Falls back to CMS config media.images.background if not provided.
29
+ */
30
+ background: z.ZodOptional<z.ZodObject<{
31
+ r: z.ZodNumber;
32
+ g: z.ZodNumber;
33
+ b: z.ZodNumber;
34
+ alpha: z.ZodNumber;
35
+ }, z.core.$strict>>;
26
36
  }, z.core.$strict>>;
27
37
  thumbnail: z.ZodOptional<z.ZodObject<{
28
38
  width: z.ZodNumber;
29
39
  height: z.ZodNumber;
30
40
  crop: z.ZodBoolean;
31
41
  quality: z.ZodOptional<z.ZodNumber>;
42
+ /**
43
+ * Background color for padding when crop is false.
44
+ * Falls back to CMS config media.images.background if not provided.
45
+ */
46
+ background: z.ZodOptional<z.ZodObject<{
47
+ r: z.ZodNumber;
48
+ g: z.ZodNumber;
49
+ b: z.ZodNumber;
50
+ alpha: z.ZodNumber;
51
+ }, z.core.$strict>>;
32
52
  }, z.core.$strict>>;
33
53
  /**
34
54
  * Maximum file size
@@ -74,6 +94,12 @@ export declare class PhotoField extends FileField<'photo', Config> {
74
94
  width: number;
75
95
  height: number;
76
96
  crop: boolean;
97
+ background?: {
98
+ r: number;
99
+ g: number;
100
+ b: number;
101
+ alpha: number;
102
+ };
77
103
  } | undefined;
78
104
  readonly maxFileSize: {
79
105
  size: number;
@@ -107,11 +133,23 @@ export declare class PhotoField extends FileField<'photo', Config> {
107
133
  height: number;
108
134
  crop: boolean;
109
135
  quality?: number;
136
+ background?: {
137
+ r: number;
138
+ g: number;
139
+ b: number;
140
+ alpha: number;
141
+ };
110
142
  };
111
143
  size: {
112
144
  width: number;
113
145
  height: number;
114
146
  crop: boolean;
147
+ background?: {
148
+ r: number;
149
+ g: number;
150
+ b: number;
151
+ alpha: number;
152
+ };
115
153
  } | undefined;
116
154
  maxFileSize: {
117
155
  size: number;
@@ -170,12 +208,32 @@ declare const optionsSchema: z.ZodObject<{
170
208
  * }
171
209
  */
172
210
  crop: z.ZodBoolean;
211
+ /**
212
+ * Background color for padding when crop is false.
213
+ * Falls back to CMS config media.images.background if not provided.
214
+ */
215
+ background: z.ZodOptional<z.ZodObject<{
216
+ r: z.ZodNumber;
217
+ g: z.ZodNumber;
218
+ b: z.ZodNumber;
219
+ alpha: z.ZodNumber;
220
+ }, z.core.$strict>>;
173
221
  }, z.core.$strict>>;
174
222
  thumbnail: z.ZodOptional<z.ZodObject<{
175
223
  width: z.ZodNumber;
176
224
  height: z.ZodNumber;
177
225
  crop: z.ZodBoolean;
178
226
  quality: z.ZodOptional<z.ZodNumber>;
227
+ /**
228
+ * Background color for padding when crop is false.
229
+ * Falls back to CMS config media.images.background if not provided.
230
+ */
231
+ background: z.ZodOptional<z.ZodObject<{
232
+ r: z.ZodNumber;
233
+ g: z.ZodNumber;
234
+ b: z.ZodNumber;
235
+ alpha: z.ZodNumber;
236
+ }, z.core.$strict>>;
179
237
  }, z.core.$strict>>;
180
238
  /**
181
239
  * Maximum file size
@@ -242,12 +300,32 @@ declare const photoFieldConfigSchema: z.ZodObject<{
242
300
  * }
243
301
  */
244
302
  crop: z.ZodBoolean;
303
+ /**
304
+ * Background color for padding when crop is false.
305
+ * Falls back to CMS config media.images.background if not provided.
306
+ */
307
+ background: z.ZodOptional<z.ZodObject<{
308
+ r: z.ZodNumber;
309
+ g: z.ZodNumber;
310
+ b: z.ZodNumber;
311
+ alpha: z.ZodNumber;
312
+ }, z.core.$strict>>;
245
313
  }, z.core.$strict>>;
246
314
  thumbnail: z.ZodOptional<z.ZodObject<{
247
315
  width: z.ZodNumber;
248
316
  height: z.ZodNumber;
249
317
  crop: z.ZodBoolean;
250
318
  quality: z.ZodOptional<z.ZodNumber>;
319
+ /**
320
+ * Background color for padding when crop is false.
321
+ * Falls back to CMS config media.images.background if not provided.
322
+ */
323
+ background: z.ZodOptional<z.ZodObject<{
324
+ r: z.ZodNumber;
325
+ g: z.ZodNumber;
326
+ b: z.ZodNumber;
327
+ alpha: z.ZodNumber;
328
+ }, z.core.$strict>>;
251
329
  }, z.core.$strict>>;
252
330
  /**
253
331
  * Maximum file size
@@ -1 +1 @@
1
- {"version":3,"file":"photo.d.ts","sourceRoot":"","sources":["../../../src/core/fields/photo.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"photo.d.ts","sourceRoot":"","sources":["../../../src/core/fields/photo.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,15 @@ import { customAlphabet } from 'nanoid';
8
8
  import { FileField } from './fileField.js';
9
9
  import { humanReadableFileSize } from '../../utils/index.js';
10
10
  import { getCMSConfig } from '../config/index.js';
11
+ import getString from '../../translations/index.js';
12
+ const backgroundSchema = z
13
+ .strictObject({
14
+ r: z.number().min(0).max(255).describe('Red channel (0-255)'),
15
+ g: z.number().min(0).max(255).describe('Green channel (0-255)'),
16
+ b: z.number().min(0).max(255).describe('Blue channel (0-255)'),
17
+ alpha: z.number().min(0).max(1).describe('Alpha channel (0-1)'),
18
+ })
19
+ .describe('Background color for image padding (used when crop is false)');
11
20
  const sizeSchema = z.strictObject({
12
21
  width: z.number().describe('Image width in pixels'),
13
22
  height: z.number().describe('Image height in pixels'),
@@ -25,12 +34,22 @@ const sizeSchema = z.strictObject({
25
34
  * }
26
35
  */
27
36
  crop: z.boolean().describe('Whether to crop the image to fit dimensions'),
37
+ /**
38
+ * Background color for padding when crop is false.
39
+ * Falls back to CMS config media.images.background if not provided.
40
+ */
41
+ background: backgroundSchema.optional().describe('Background color for padding when not cropping'),
28
42
  });
29
43
  const thumbnailSchema = z.strictObject({
30
44
  width: z.number().describe('Thumbnail width in pixels'),
31
45
  height: z.number().describe('Thumbnail height in pixels'),
32
46
  crop: z.boolean().describe('Whether to crop the thumbnail'),
33
47
  quality: z.number().optional().describe('Thumbnail quality (0-100)'),
48
+ /**
49
+ * Background color for padding when crop is false.
50
+ * Falls back to CMS config media.images.background if not provided.
51
+ */
52
+ background: backgroundSchema.optional().describe('Background color for padding when not cropping'),
34
53
  });
35
54
  const maxFileSizeSchema = z.strictObject({
36
55
  size: z.number().describe('Maximum file size'),
@@ -112,7 +131,7 @@ export class PhotoField extends FileField {
112
131
  return 'image/png';
113
132
  if (e === 'webp')
114
133
  return 'image/webp';
115
- throw new Error(`Invalid image extension provided: ${e}`);
134
+ throw new Error(getString('invalidImageExtension', 'en', { extensions: e }));
116
135
  });
117
136
  /**
118
137
  * Set the allowed extensions, add jpg if jpeg is present
@@ -147,7 +166,7 @@ export class PhotoField extends FileField {
147
166
  }
148
167
  exportForClient() {
149
168
  if (this._thumbnail === undefined) {
150
- throw new Error('PhotoField.build() must be called before exportForClient()');
169
+ throw new Error(getString('photoFieldBuildRequired', 'en'));
151
170
  }
152
171
  return {
153
172
  ...super.exportForClient(),
@@ -165,17 +184,19 @@ export class PhotoField extends FileField {
165
184
  */
166
185
  async writeToFile() {
167
186
  if (!this._folder) {
168
- throw new Error(`${this.label}: Folder is not set. Make sure to set the folder by calling postSubmit() before writing the file to disk`);
187
+ throw new Error(getString('folderNotSet', 'en', { field: String(this.label) }));
169
188
  }
170
189
  if (!this._sharpImage) {
171
- throw new Error(`${this.label}: Image is not set. Make sure to call prepareForSubmission() before writing the file to disk`);
190
+ throw new Error(getString('imageNotSet', 'en', { field: String(this.label) }));
172
191
  }
173
192
  try {
174
193
  /**
175
194
  * If .photos, and 'sectionName' folders don't exist, create them
176
195
  */
177
196
  const thumbnail = await this.getThumbnail();
178
- const uploadsFolder = (await getCMSConfig()).media.upload.path;
197
+ const cmsConfig = await getCMSConfig();
198
+ const uploadsFolder = cmsConfig.media.upload.path;
199
+ const cmsBackground = cmsConfig.media.images.background;
179
200
  const photosFolder = path.join(uploadsFolder, '.photos', this._folder);
180
201
  const thumbsFolder = path.join(uploadsFolder, '.thumbs', this._folder);
181
202
  if (!fs.existsSync(photosFolder)) {
@@ -186,23 +207,43 @@ export class PhotoField extends FileField {
186
207
  }
187
208
  /**
188
209
  * Check if the image needs to be resized and write the file to disk
210
+ * - crop: true -> fit: 'cover' (crops to fill dimensions)
211
+ * - crop: false -> fit: 'contain' with background (preserves all content, adds padding)
189
212
  */
190
- if (this.size && this.size.crop) {
191
- await this._sharpImage
192
- .clone()
193
- .resize({
194
- width: this.size.width,
195
- height: this.size.height,
196
- fit: 'cover',
197
- })
198
- .webp()
199
- .toFile(path.join(uploadsFolder, '.photos', this._folder, this.value));
213
+ if (this.size) {
214
+ if (this.size.crop) {
215
+ // Crop mode: use 'cover' to fill dimensions by cropping excess
216
+ await this._sharpImage
217
+ .clone()
218
+ .resize({
219
+ width: this.size.width,
220
+ height: this.size.height,
221
+ fit: 'cover',
222
+ })
223
+ .webp()
224
+ .toFile(path.join(uploadsFolder, '.photos', this._folder, this.value));
225
+ }
226
+ else {
227
+ // Contain mode: preserve all content with background padding
228
+ // Use field-level background, fall back to CMS config background
229
+ await this._sharpImage
230
+ .clone()
231
+ .resize({
232
+ width: this.size.width,
233
+ height: this.size.height,
234
+ fit: 'contain',
235
+ background: this.size.background ?? cmsBackground,
236
+ })
237
+ .webp()
238
+ .toFile(path.join(uploadsFolder, '.photos', this._folder, this.value));
239
+ }
200
240
  }
201
241
  else {
202
242
  await this._sharpImage.clone().toFile(path.join(uploadsFolder, '.photos', this._folder, this.value));
203
243
  }
204
244
  /**
205
245
  * Also, write a thumbnail
246
+ * Use CMS config background for padding when crop is false
206
247
  */
207
248
  await this._sharpImage
208
249
  .clone()
@@ -210,6 +251,7 @@ export class PhotoField extends FileField {
210
251
  width: thumbnail.width,
211
252
  height: thumbnail.height,
212
253
  fit: thumbnail.crop ? 'cover' : 'contain',
254
+ background: thumbnail.background ?? cmsBackground,
213
255
  })
214
256
  .webp({
215
257
  quality: thumbnail.quality ?? 80,
@@ -217,7 +259,7 @@ export class PhotoField extends FileField {
217
259
  .toFile(path.join(uploadsFolder, '.thumbs', this._folder, this.value));
218
260
  }
219
261
  catch (error) {
220
- throw new Error(`${this.label}: Error writing file to disk ${error.message}`);
262
+ throw new Error(getString('fileWriteError', 'en', { field: String(this.label) }) + ` ${error.message}`);
221
263
  }
222
264
  }
223
265
  async postSubmit(folder) {
@@ -230,7 +272,7 @@ export class PhotoField extends FileField {
230
272
  if (!this._file)
231
273
  return;
232
274
  if (!this._folder) {
233
- throw new Error(`${this.label}: Folder is not set. Make sure to set the folder before writing the file to disk`);
275
+ throw new Error(getString('folderNotSet', 'en', { field: String(this.label) }));
234
276
  }
235
277
  try {
236
278
  const uploadsFolder = (await getCMSConfig()).media.upload.path;
@@ -238,7 +280,7 @@ export class PhotoField extends FileField {
238
280
  await fs.promises.unlink(pathToFile);
239
281
  }
240
282
  catch (error) {
241
- throw new Error(`${this.label}: Error deleting file from disk`);
283
+ throw new Error(getString('fileDeleteError', 'en', { field: String(this.label) }));
242
284
  }
243
285
  }
244
286
  async cleanupReplacedFile(previousValue, sectionName) {
@@ -277,7 +319,7 @@ export class PhotoField extends FileField {
277
319
  */
278
320
  if (this.required) {
279
321
  if (!this._file?.type || !this._file?.name || !this._file?.size) {
280
- throw new Error(`Field ${this.label} is required`);
322
+ throw new Error(getString('fieldIsRequired', 'en', { field: String(this.label) }));
281
323
  }
282
324
  }
283
325
  }
@@ -298,7 +340,7 @@ export class PhotoField extends FileField {
298
340
  if (ext === 'jpg')
299
341
  ext = 'jpeg';
300
342
  if (!ext || !this.extensions.includes(ext)) {
301
- throw new Error(`${this.label}: Invalid file type or extension. Allowed extensions: ${this.extensions.join(', ')}`);
343
+ throw new Error(getString('invalidFileTypeOrExtension', 'en', { field: String(this.label), extensions: this.extensions.join(', ') }));
302
344
  }
303
345
  /**
304
346
  * Construct the image
@@ -309,7 +351,7 @@ export class PhotoField extends FileField {
309
351
  * Check mime type
310
352
  */
311
353
  if (!this.mimeType.includes(this._file.type)) {
312
- throw new Error(`${this.label}: Invalid file type or extension. Allowed extensions: ${this.extensions.join(', ')}`);
354
+ throw new Error(getString('invalidFileTypeOrExtension', 'en', { field: String(this.label), extensions: this.extensions.join(', ') }));
313
355
  }
314
356
  /**
315
357
  * Check actual mime type
@@ -319,7 +361,7 @@ export class PhotoField extends FileField {
319
361
  if (!actualMimeType ||
320
362
  !this.extensions.includes(actualMimeType.ext) ||
321
363
  !this.mimeType.includes(actualMimeType.mime)) {
322
- throw new Error(`${this.label}: Invalid file type or extension. Allowed extensions: ${this.extensions.join(', ')}`);
364
+ throw new Error(getString('invalidFileTypeOrExtension', 'en', { field: String(this.label), extensions: this.extensions.join(', ') }));
323
365
  }
324
366
  /**
325
367
  * Disable caching for the image to avoid unlink issues
@@ -340,20 +382,20 @@ export class PhotoField extends FileField {
340
382
  */
341
383
  const fileSize = buffer.length;
342
384
  if (!fileSize || !metadata.size) {
343
- throw new Error(`Field ${this.label} is required`);
385
+ throw new Error(getString('fieldIsRequired', 'en', { field: String(this.label) }));
344
386
  }
345
387
  /**
346
388
  * Check the file size
347
389
  */
348
390
  if (fileSize > this.maxFileSize.size * (this.maxFileSize.unit === 'kb' ? 1024 : 1024 * 1024)) {
349
- throw new Error(`${this.label}: File size (${humanReadableFileSize(fileSize)}) exceeds the maximum allowed size of ${this.maxFileSize.size} ${this.maxFileSize.unit}`);
391
+ throw new Error(getString('fileSizeExceedsMax', 'en', { field: String(this.label), actual: humanReadableFileSize(fileSize), max: `${this.maxFileSize.size} ${this.maxFileSize.unit}` }));
350
392
  }
351
393
  /**
352
394
  * Don't just trust the file extension
353
395
  * Check the format
354
396
  */
355
397
  if (!metadata.format || !this.extensions.includes(metadata.format)) {
356
- throw new Error(`${this.label}: Invalid file type or extension. Allowed extensions: ${this.extensions.join(', ')}`);
398
+ throw new Error(getString('invalidFileTypeOrExtension', 'en', { field: String(this.label), extensions: this.extensions.join(', ') }));
357
399
  }
358
400
  /**
359
401
  * Check stat
@@ -362,7 +404,7 @@ export class PhotoField extends FileField {
362
404
  await image.stats();
363
405
  }
364
406
  catch (error) {
365
- throw new Error(`File is corrupted`);
407
+ throw new Error(getString('fileCorrupted', 'en'));
366
408
  }
367
409
  /**
368
410
  * Convert the image to webp
@@ -371,7 +413,7 @@ export class PhotoField extends FileField {
371
413
  image.toFormat('webp').withExif({});
372
414
  }
373
415
  catch (error) {
374
- throw new Error(`File is corrupted`);
416
+ throw new Error(getString('fileCorrupted', 'en'));
375
417
  }
376
418
  /**
377
419
  * Check the size
@@ -388,7 +430,7 @@ export class PhotoField extends FileField {
388
430
  * Check if the size matches the required size
389
431
  */
390
432
  if (metadata.width !== this.size.width || metadata.height !== this.size.height) {
391
- throw new Error(`${this.label}: Uploaded image size (${metadata.width}x${metadata.height} pixels) does not match the required size: ${this.size.width}x${this.size.height} pixels`);
433
+ throw new Error(getString('imageDimensionMismatchDetailed', 'en', { field: String(this.label), actual: `${metadata.width}x${metadata.height}`, required: `${this.size.width}x${this.size.height}` }));
392
434
  }
393
435
  }
394
436
  }
@@ -119,7 +119,7 @@ export class SelectField extends Field {
119
119
  };
120
120
  }
121
121
  else {
122
- throw new Error('Select field requires either db, section or an options array.');
122
+ throw new Error(`[SelectField: ${this.label}]: Select field requires either db, section or an options array.`);
123
123
  }
124
124
  }
125
125
  /**
@@ -402,7 +402,7 @@ export class SelectField extends Field {
402
402
  if (this.db.table.trim().length === 0 ||
403
403
  this.db.identifier.trim().length === 0 ||
404
404
  this.db.label.trim().length === 0) {
405
- throw new Error('Table, identifier and label are required');
405
+ throw new Error(`Field ${String(this.label)}: Table, identifier and label are required`);
406
406
  }
407
407
  }
408
408
  checkRequired() {
@@ -411,7 +411,7 @@ export class SelectField extends Field {
411
411
  */
412
412
  if (this.required) {
413
413
  if (!this.value || this.value.toString().trim().length === 0) {
414
- throw new Error(`Field ${this.label} is required`);
414
+ throw new Error(`Field ${String(this.label)} is required`);
415
415
  }
416
416
  }
417
417
  }
@@ -2,6 +2,7 @@ import type { BaseFieldConfig } from './field.js';
2
2
  import { Field } from './field.js';
3
3
  import { entityKind } from '../helpers/index.js';
4
4
  import * as z from 'zod';
5
+ import type { TextFieldConfig } from './text.js';
5
6
  declare const slugFieldConfigSchema: z.ZodObject<{
6
7
  placeholder: z.ZodOptional<z.ZodString>;
7
8
  minLength: z.ZodOptional<z.ZodNumber>;
@@ -53,6 +54,7 @@ export declare class SlugField extends Field<'slug', Config> {
53
54
  readonly minLength: number | undefined;
54
55
  readonly placeholder: string | undefined;
55
56
  readonly forFieldName: string;
57
+ readonly forFieldConfig: TextFieldConfig;
56
58
  private readonly _defaultValue;
57
59
  value: string | undefined;
58
60
  constructor(config: BaseFieldConfig<Config>);
@@ -86,7 +88,9 @@ export declare class SlugField extends Field<'slug', Config> {
86
88
  checkRequired(): void;
87
89
  hasSqlNameAndValue(): boolean;
88
90
  /**
89
- * Prepare the field for submission
91
+ * Prepare the field for submission.
92
+ * Normalizes the slug and validates length constraints.
93
+ * Uniqueness checking is handled centrally by the Submit class.
90
94
  */
91
95
  prepareForSubmission(): Promise<void>;
92
96
  }
@@ -1 +1 @@
1
- {"version":3,"file":"slug.d.ts","sourceRoot":"","sources":["../../../src/core/fields/slug.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,EAAE,KAAK,EAAyB,MAAM,YAAY,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAGxB,QAAA,MAAM,qBAAqB;;;;IAIvB;;;OAGG;;IAEH;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAEL,CAAA;AAEF,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAA;AAEnD,qBAAa,SAAU,SAAQ,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC;IAChD,gBAAyB,CAAC,UAAU,CAAC,EAAE,MAAM,CAAc;IAC3D,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IACzC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;gBAEtB,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC;IAU3C;;;;;;;OAOG;IACH,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAUpB,eAAe;;;;;;;;;;;;;;IAU/B;;OAEG;IACH,QAAQ,IAAI,MAAM,GAAG,SAAS;IAI9B,aAAa;IAQJ,kBAAkB,IAAI,OAAO;IAOtC;;OAEG;IACG,oBAAoB;CAwB7B;AAED,MAAM,MAAM,qBAAqB,GAAG,UAAU,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAE5E,QAAA,MAAM,aAAa;;;;IAnHf;;;OAGG;;IAEH;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA6GL,CAAA;AAEF,QAAA,MAAM,YAAY;;;;;;IAxHd;;;OAGG;;IAEH;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAmHL,CAAA;AAEF;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAE1D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,GAAG,eAAe,CAkB/E"}
1
+ {"version":3,"file":"slug.d.ts","sourceRoot":"","sources":["../../../src/core/fields/slug.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,EAAE,KAAK,EAAyB,MAAM,YAAY,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AACxB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAGhD,QAAA,MAAM,qBAAqB;;;;IAIvB;;;OAGG;;IAEH;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAEL,CAAA;AAEF,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAA;AAEnD,qBAAa,SAAU,SAAQ,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC;IAChD,gBAAyB,CAAC,UAAU,CAAC,EAAE,MAAM,CAAc;IAC3D,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,cAAc,EAAE,eAAe,CAAA;IACxC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IACzC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;gBAEtB,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC;IAW3C;;;;;;;OAOG;IACH,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAUpB,eAAe;;;;;;;;;;;;;;IAU/B;;OAEG;IACH,QAAQ,IAAI,MAAM,GAAG,SAAS;IAI9B,aAAa;IAQJ,kBAAkB,IAAI,OAAO;IAOtC;;;;OAIG;IACG,oBAAoB;CAwB7B;AAED,MAAM,MAAM,qBAAqB,GAAG,UAAU,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAE5E,QAAA,MAAM,aAAa;;;;IAvHf;;;OAGG;;IAEH;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAiHL,CAAA;AAEF,QAAA,MAAM,YAAY;;;;;;IA5Hd;;;OAGG;;IAEH;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAuHL,CAAA;AAEF;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAE1D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,GAAG,eAAe,CAkB/E"}
@@ -1,6 +1,7 @@
1
1
  import { Field, baseFieldConfigSchema } from './field.js';
2
2
  import { entityKind } from '../helpers/index.js';
3
3
  import * as z from 'zod';
4
+ import getString from '../../translations/index.js';
4
5
  const slugFieldConfigSchema = z.strictObject({
5
6
  placeholder: z.string().optional().describe('The placeholder text for the field'),
6
7
  minLength: z.number().optional().describe('The minimum length of the slug'),
@@ -23,6 +24,7 @@ export class SlugField extends Field {
23
24
  minLength;
24
25
  placeholder;
25
26
  forFieldName;
27
+ forFieldConfig;
26
28
  _defaultValue;
27
29
  value;
28
30
  constructor(config) {
@@ -33,6 +35,7 @@ export class SlugField extends Field {
33
35
  this.value = config.defaultValue;
34
36
  this._defaultValue = config.defaultValue;
35
37
  this.forFieldName = config.for.name;
38
+ this.forFieldConfig = config.for;
36
39
  }
37
40
  /**
38
41
  * Convert a string to a URL-friendly slug.
@@ -69,7 +72,7 @@ export class SlugField extends Field {
69
72
  checkRequired() {
70
73
  if (this.required) {
71
74
  if (!this.value || this.value.trim().length === 0) {
72
- throw new Error(`Field ${this.label} is required`);
75
+ throw new Error(getString('fieldIsRequired', 'en', { field: String(this.label) }));
73
76
  }
74
77
  }
75
78
  }
@@ -80,7 +83,9 @@ export class SlugField extends Field {
80
83
  return this.adminGenerated === true || this._defaultValue !== undefined;
81
84
  }
82
85
  /**
83
- * Prepare the field for submission
86
+ * Prepare the field for submission.
87
+ * Normalizes the slug and validates length constraints.
88
+ * Uniqueness checking is handled centrally by the Submit class.
84
89
  */
85
90
  async prepareForSubmission() {
86
91
  if (this.value) {
@@ -91,7 +96,7 @@ export class SlugField extends Field {
91
96
  */
92
97
  if (this.minLength) {
93
98
  if (this.minLength > this.value.length) {
94
- throw new Error(`Field ${this.label} must be at least ${this.minLength} characters long`);
99
+ throw new Error(getString('minLength', 'en', { min: this.minLength }));
95
100
  }
96
101
  }
97
102
  /**
@@ -99,7 +104,7 @@ export class SlugField extends Field {
99
104
  */
100
105
  if (this.maxLength) {
101
106
  if (this.maxLength < this.value.length) {
102
- throw new Error(`Field ${this.label} must be at most ${this.maxLength} characters long`);
107
+ throw new Error(getString('maxLength', 'en', { max: this.maxLength }));
103
108
  }
104
109
  }
105
110
  }
@@ -1 +1 @@
1
- {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/core/fields/text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,EAAE,KAAK,EAAyB,MAAM,YAAY,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAGxB,QAAA,MAAM,YAAY;;;;IAId;;;;OAIG;;IAEH;;;;;OAKG;;kBAEL,CAAA;AAEF,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAE1C,qBAAa,SAAU,SAAQ,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC;IAChD,gBAAyB,CAAC,UAAU,CAAC,EAAE,MAAM,CAAc;IAC3D,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IACzC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;gBAEd,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC;IAU3C;;OAEG;IACH,OAAO,CAAC,aAAa;IAgBL,eAAe;;;;;;;;;;;;;;IAU/B;;OAEG;IACH,QAAQ,IAAI,MAAM,GAAG,SAAS;IAI9B,aAAa;IAWJ,kBAAkB,IAAI,OAAO;IAOtC;;OAEG;IACG,oBAAoB;CAyB7B;AAED,MAAM,MAAM,qBAAqB,GAAG,UAAU,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAE5E,QAAA,MAAM,aAAa;;;;IA1Hf;;;;OAIG;;IAEH;;;;;OAKG;;;;;;;;kBAkHL,CAAA;AAEF,QAAA,MAAM,qBAAqB;;;;;;IA/HvB;;;;OAIG;;IAEH;;;;;OAKG;;;;;;;;kBAwHL,CAAA;AAEF;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAA;AAEnE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,GAAG,eAAe,CAmB/E"}
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/core/fields/text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,EAAE,KAAK,EAAyB,MAAM,YAAY,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAIxB,QAAA,MAAM,YAAY;;;;IAId;;;;OAIG;;IAEH;;;;;OAKG;;kBAEL,CAAA;AAEF,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAE1C,qBAAa,SAAU,SAAQ,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC;IAChD,gBAAyB,CAAC,UAAU,CAAC,EAAE,MAAM,CAAc;IAC3D,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;IACxC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IACzC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;gBAEd,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC;IAU3C;;OAEG;IACH,OAAO,CAAC,aAAa;IAgBL,eAAe;;;;;;;;;;;;;;IAU/B;;OAEG;IACH,QAAQ,IAAI,MAAM,GAAG,SAAS;IAI9B,aAAa;IAWJ,kBAAkB,IAAI,OAAO;IAOtC;;OAEG;IACG,oBAAoB;CAyB7B;AAED,MAAM,MAAM,qBAAqB,GAAG,UAAU,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAE5E,QAAA,MAAM,aAAa;;;;IA1Hf;;;;OAIG;;IAEH;;;;;OAKG;;;;;;;;kBAkHL,CAAA;AAEF,QAAA,MAAM,qBAAqB;;;;;;IA/HvB;;;;OAIG;;IAEH;;;;;OAKG;;;;;;;;kBAwHL,CAAA;AAEF;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAA;AAEnE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,GAAG,eAAe,CAmB/E"}
@@ -2,6 +2,7 @@ import { Field, baseFieldConfigSchema } from './field.js';
2
2
  import { entityKind } from '../helpers/index.js';
3
3
  import * as z from 'zod';
4
4
  import { escapeHTML } from '../security/dom.js';
5
+ import getString from '../../translations/index.js';
5
6
  const configSchema = z.strictObject({
6
7
  placeholder: z.string().optional().describe('The placeholder text for the field'),
7
8
  minLength: z.number().optional().describe('The minimum length of the field value'),
@@ -75,7 +76,7 @@ export class TextField extends Field {
75
76
  */
76
77
  if (this.required) {
77
78
  if (!this.value || this.value.trim().length === 0) {
78
- throw new Error(`Field ${this.label} is required`);
79
+ throw new Error(getString('fieldIsRequired', 'en', { field: String(this.label) }));
79
80
  }
80
81
  }
81
82
  }
@@ -99,7 +100,7 @@ export class TextField extends Field {
99
100
  */
100
101
  if (this.minLength) {
101
102
  if (this.minLength > this.value.length) {
102
- throw new Error(`Field ${this.label} must be at least ${this.minLength} characters long`);
103
+ throw new Error(getString('minLength', 'en', { min: this.minLength }));
103
104
  }
104
105
  }
105
106
  /**
@@ -107,7 +108,7 @@ export class TextField extends Field {
107
108
  */
108
109
  if (this.maxLength) {
109
110
  if (this.maxLength < this.value.length) {
110
- throw new Error(`Field ${this.label} must be at most ${this.maxLength} characters long`);
111
+ throw new Error(getString('maxLength', 'en', { max: this.maxLength }));
111
112
  }
112
113
  }
113
114
  }
@@ -1 +1 @@
1
- {"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../../src/core/fields/video.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAIhD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE1C,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAExB,QAAA,MAAM,YAAY;IACd;;OAEG;;;;;;;;IAQH;;;OAGG;;;;;;kBAKL,CAAA;AAEF,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAE1C,qBAAa,UAAW,SAAQ,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IACtD,gBAAyB,CAAC,UAAU,CAAC,EAAE,MAAM,CAAe;IAC5D,QAAQ,CAAC,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;KAAE,CAAA;IACzD,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,CAAA;IAE7B;;;OAGG;IACH,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,kBAAkB,CAAU;gBACxB,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI;IA6BxC,eAAe;;kBAzCD,MAAM;kBAAQ,IAAI,GAAG,IAAI;;;;;;;;;;;;;IAkDjD,iBAAiB,CAAC,EACpB,WAAW,EACX,MAAM,EACN,aAAiB,GACpB,EAAE;QACC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;QACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;QACvB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAClC,GAAG,OAAO,CAAC,UAAU,CAAC;IAgBvB;;OAEG;IACG,WAAW;IA+BK,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKzC,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAenC,mBAAmB,CAAC,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMpG;;OAEG;IACH,QAAQ,IAAI,MAAM;IAIX,WAAW,CAAC,KAAK,EAAE,MAAM;IAIvB,QAAQ,CAAC,KAAK,EAAE,GAAG;IAQnB,OAAO,CAAC,IAAI,EAAE,IAAI;IAK3B,aAAa;IAYb;;OAEG;IACG,oBAAoB;CAoD7B;AAED,MAAM,MAAM,sBAAsB,GAAG,UAAU,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAE9E,QAAA,MAAM,aAAa;IA7Pf;;OAEG;;;;;;;;IAQH;;;OAGG;;;;;;;;;;;;;kBAmPL,CAAA;AAEF,QAAA,MAAM,sBAAsB;;;IAlQxB;;OAEG;;;;;;;;IAQH;;;OAGG;;;;;;;;;;;;;kBAyPL,CAAA;AAEF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAErE;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,GAAG,gBAAgB,CAmBjF"}
1
+ {"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../../src/core/fields/video.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAIhD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE1C,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAGxB,QAAA,MAAM,YAAY;IACd;;OAEG;;;;;;;;IAQH;;;OAGG;;;;;;kBAKL,CAAA;AAEF,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAA;AAE1C,qBAAa,UAAW,SAAQ,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IACtD,gBAAyB,CAAC,UAAU,CAAC,EAAE,MAAM,CAAe;IAC5D,QAAQ,CAAC,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;KAAE,CAAA;IACzD,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,CAAA;IAE7B;;;OAGG;IACH,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,kBAAkB,CAAU;gBACxB,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI;IA6BxC,eAAe;;kBAzCD,MAAM;kBAAQ,IAAI,GAAG,IAAI;;;;;;;;;;;;;IAkDjD,iBAAiB,CAAC,EACpB,WAAW,EACX,MAAM,EACN,aAAiB,GACpB,EAAE;QACC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;QACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;QACvB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAClC,GAAG,OAAO,CAAC,UAAU,CAAC;IAgBvB;;OAEG;IACG,WAAW;IA2BK,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKzC,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAanC,mBAAmB,CAAC,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMpG;;OAEG;IACH,QAAQ,IAAI,MAAM;IAIX,WAAW,CAAC,KAAK,EAAE,MAAM;IAIvB,QAAQ,CAAC,KAAK,EAAE,GAAG;IAQnB,OAAO,CAAC,IAAI,EAAE,IAAI;IAK3B,aAAa;IAYb;;OAEG;IACG,oBAAoB;CAoD7B;AAED,MAAM,MAAM,sBAAsB,GAAG,UAAU,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAE9E,QAAA,MAAM,aAAa;IAvPf;;OAEG;;;;;;;;IAQH;;;OAGG;;;;;;;;;;;;;kBA6OL,CAAA;AAEF,QAAA,MAAM,sBAAsB;;;IA5PxB;;OAEG;;;;;;;;IAQH;;;OAGG;;;;;;;;;;;;;kBAmPL,CAAA;AAEF;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAErE;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,GAAG,gBAAgB,CAmBjF"}