nextjs-cms 0.10.0 → 0.10.2

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 (36) hide show
  1. package/dist/api/actions/pages.d.ts +3 -3
  2. package/dist/api/trpc/root.d.ts +3 -3
  3. package/dist/api/trpc/routers/navigation.d.ts +3 -3
  4. package/dist/api/trpc/server.d.ts +9 -9
  5. package/dist/core/config/config-loader.d.ts +2 -2
  6. package/dist/core/fields/date-range.d.ts +4 -4
  7. package/dist/core/fields/inline-image.d.ts +45 -0
  8. package/dist/core/fields/inline-image.d.ts.map +1 -0
  9. package/dist/core/fields/inline-image.js +30 -0
  10. package/dist/core/fields/photo.d.ts +6 -6
  11. package/dist/core/fields/richText.d.ts +8 -8
  12. package/dist/core/fields/richText.d.ts.map +1 -1
  13. package/dist/core/fields/richText.js +4 -35
  14. package/dist/core/fields/select.d.ts +1 -1
  15. package/dist/core/helpers/index.d.ts +2 -0
  16. package/dist/core/helpers/index.d.ts.map +1 -1
  17. package/dist/core/helpers/index.js +1 -0
  18. package/dist/core/helpers/inline-image.d.ts +46 -0
  19. package/dist/core/helpers/inline-image.d.ts.map +1 -0
  20. package/dist/core/helpers/inline-image.js +30 -0
  21. package/dist/core/sections/category.d.ts +4 -4
  22. package/dist/core/sections/hasItems.d.ts +10 -10
  23. package/dist/core/sections/section.d.ts +3 -3
  24. package/dist/core/sections/simple.d.ts +4 -4
  25. package/dist/core/security/dom.d.ts +4 -0
  26. package/dist/core/security/dom.d.ts.map +1 -1
  27. package/dist/core/security/dom.js +5 -1
  28. package/dist/utils/index.d.ts +1 -1
  29. package/dist/utils/index.d.ts.map +1 -1
  30. package/dist/utils/index.js +1 -1
  31. package/dist/utils/utils.d.ts +13 -0
  32. package/dist/utils/utils.d.ts.map +1 -1
  33. package/dist/utils/utils.js +15 -0
  34. package/dist/validators/richText.d.ts.map +1 -1
  35. package/dist/validators/richText.js +35 -1
  36. package/package.json +2 -2
@@ -70,13 +70,13 @@ declare const optionsSchema: z.ZodObject<{
70
70
  maxDate: z.ZodOptional<z.ZodUnion<readonly [z.ZodDate, z.ZodLiteral<"now">]>>;
71
71
  defaultStartValue: z.ZodOptional<z.ZodDate>;
72
72
  defaultEndValue: z.ZodOptional<z.ZodDate>;
73
+ order: z.ZodOptional<z.ZodNumber>;
74
+ localized: z.ZodOptional<z.ZodBoolean>;
73
75
  label: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
74
76
  required: z.ZodOptional<z.ZodBoolean>;
75
77
  defaultValue: z.ZodOptional<z.ZodAny>;
76
- order: z.ZodOptional<z.ZodNumber>;
77
78
  conditionalRules: z.ZodOptional<z.ZodUnion<readonly [z.ZodTuple<[z.ZodCustom<import("../types/index.js").ConditionalRule, import("../types/index.js").ConditionalRule>], null>, z.ZodCustom<import("../types/index.js").ConditionalRuleGroup, import("../types/index.js").ConditionalRuleGroup>]>>;
78
79
  adminGenerated: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodLiteral<false>, z.ZodLiteral<"readonly">]>>;
79
- localized: z.ZodOptional<z.ZodBoolean>;
80
80
  }, z.core.$strict>;
81
81
  declare const dateRangeFieldConfigSchema: z.ZodObject<{
82
82
  /**
@@ -97,13 +97,13 @@ declare const dateRangeFieldConfigSchema: z.ZodObject<{
97
97
  maxDate: z.ZodOptional<z.ZodUnion<readonly [z.ZodDate, z.ZodLiteral<"now">]>>;
98
98
  defaultStartValue: z.ZodOptional<z.ZodDate>;
99
99
  defaultEndValue: z.ZodOptional<z.ZodDate>;
100
+ order: z.ZodOptional<z.ZodNumber>;
101
+ localized: z.ZodOptional<z.ZodBoolean>;
100
102
  label: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>;
101
103
  required: z.ZodOptional<z.ZodBoolean>;
102
104
  defaultValue: z.ZodOptional<z.ZodAny>;
103
- order: z.ZodOptional<z.ZodNumber>;
104
105
  conditionalRules: z.ZodOptional<z.ZodUnion<readonly [z.ZodTuple<[z.ZodCustom<import("../types/index.js").ConditionalRule, import("../types/index.js").ConditionalRule>], null>, z.ZodCustom<import("../types/index.js").ConditionalRuleGroup, import("../types/index.js").ConditionalRuleGroup>]>>;
105
106
  adminGenerated: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodLiteral<false>, z.ZodLiteral<"readonly">]>>;
106
- localized: z.ZodOptional<z.ZodBoolean>;
107
107
  }, z.core.$strict>;
108
108
  export type DateRangeFieldConfig = z.infer<typeof dateRangeFieldConfigSchema>;
109
109
  /**
@@ -0,0 +1,45 @@
1
+ import type sharp from 'sharp';
2
+ import type { Background } from '../helpers/background.js';
3
+ /**
4
+ * Inline-image sizing shared by the rich-text field, the editor upload route, and the client-side
5
+ * validator.
6
+ *
7
+ * Deliberately a leaf module with type-only imports: the validator runs in the browser, and
8
+ * reaching these through `core/fields/index.js` would pull the whole field barrel — and with it
9
+ * the database client, sharp, and fs — into the client bundle.
10
+ */
11
+ export type InlineImageSize = {
12
+ width: number;
13
+ height: number;
14
+ fit: 'inside';
15
+ } | {
16
+ width: number;
17
+ height: number;
18
+ fit: 'cover';
19
+ } | {
20
+ width: number;
21
+ height: number;
22
+ fit: 'contain';
23
+ background?: Background;
24
+ };
25
+ export type InlineImageMaxFileSize = {
26
+ size: number;
27
+ unit: 'kb' | 'mb';
28
+ };
29
+ /**
30
+ * Bounds every inline image is fitted into unless the field overrides `size`.
31
+ * 1200x675 is 16:9 at a width that covers typical article body content, scaled down to fit so a
32
+ * body image is never cropped or padded unless the field asks for it.
33
+ */
34
+ export declare const DEFAULT_INLINE_IMAGE_SIZE: InlineImageSize;
35
+ /** Largest accepted inline image unless the field overrides `maxFileSize`. */
36
+ export declare const DEFAULT_MAX_FILE_SIZE: InlineImageMaxFileSize;
37
+ /** Same shape `extractInlineImages` looks for, so every side agrees on what an inline image is. */
38
+ export declare const INLINE_IMAGE_REGEX: RegExp;
39
+ /**
40
+ * Sharp resize options for an inline image, so every place that writes one — the field on save and
41
+ * the editor upload route — sizes it identically. `background` is the CMS-config fallback, used
42
+ * only when the field asks for `contain` without naming its own.
43
+ */
44
+ export declare function inlineImageResizeOptions(size: InlineImageSize, background: Background): sharp.ResizeOptions;
45
+ //# sourceMappingURL=inline-image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inline-image.d.ts","sourceRoot":"","sources":["../../../src/core/fields/inline-image.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAE1D;;;;;;;GAOG;AAEH,MAAM,MAAM,eAAe,GACrB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,QAAQ,CAAA;CAAE,GAChD;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,GAC/C;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,SAAS,CAAC;IAAC,UAAU,CAAC,EAAE,UAAU,CAAA;CAAE,CAAA;AAEhF,MAAM,MAAM,sBAAsB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;CAAE,CAAA;AAExE;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,EAAE,eAIvC,CAAA;AAED,8EAA8E;AAC9E,eAAO,MAAM,qBAAqB,EAAE,sBAAgD,CAAA;AAEpF,mGAAmG;AACnG,eAAO,MAAM,kBAAkB,QAAmD,CAAA;AAElF;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,GAAG,KAAK,CAAC,aAAa,CAU3G"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Bounds every inline image is fitted into unless the field overrides `size`.
3
+ * 1200x675 is 16:9 at a width that covers typical article body content, scaled down to fit so a
4
+ * body image is never cropped or padded unless the field asks for it.
5
+ */
6
+ export const DEFAULT_INLINE_IMAGE_SIZE = {
7
+ width: 1200,
8
+ height: 675,
9
+ fit: 'inside',
10
+ };
11
+ /** Largest accepted inline image unless the field overrides `maxFileSize`. */
12
+ export const DEFAULT_MAX_FILE_SIZE = { size: 1, unit: 'mb' };
13
+ /** Same shape `extractInlineImages` looks for, so every side agrees on what an inline image is. */
14
+ export const INLINE_IMAGE_REGEX = /<img.*?src="(data:image\/.*?;base64,.*?)".*?>/g;
15
+ /**
16
+ * Sharp resize options for an inline image, so every place that writes one — the field on save and
17
+ * the editor upload route — sizes it identically. `background` is the CMS-config fallback, used
18
+ * only when the field asks for `contain` without naming its own.
19
+ */
20
+ export function inlineImageResizeOptions(size, background) {
21
+ return {
22
+ width: size.width,
23
+ height: size.height,
24
+ fit: size.fit,
25
+ // `inside` only ever scales down — enlarging a smaller image to fill the box would cost
26
+ // quality for nothing. `cover` and `contain` produce the exact box, so they may enlarge.
27
+ withoutEnlargement: size.fit === 'inside',
28
+ ...(size.fit === 'contain' ? { background: size.background ?? background } : {}),
29
+ };
30
+ }
@@ -140,10 +140,10 @@ declare const configSchema: z.ZodObject<{
140
140
  * @hint 'jpg' is an alias for 'jpeg'
141
141
  */
142
142
  fileType: z.ZodOptional<z.ZodArray<z.ZodEnum<{
143
- webp: "webp";
144
- jpg: "jpg";
145
143
  jpeg: "jpeg";
144
+ jpg: "jpg";
146
145
  png: "png";
146
+ webp: "webp";
147
147
  }>>>;
148
148
  /**
149
149
  * Remove the extension from the file name
@@ -353,10 +353,10 @@ declare const optionsSchema: z.ZodObject<{
353
353
  * @hint 'jpg' is an alias for 'jpeg'
354
354
  */
355
355
  fileType: z.ZodOptional<z.ZodArray<z.ZodEnum<{
356
- webp: "webp";
357
- jpg: "jpg";
358
356
  jpeg: "jpeg";
357
+ jpg: "jpg";
359
358
  png: "png";
359
+ webp: "webp";
360
360
  }>>>;
361
361
  /**
362
362
  * Remove the extension from the file name
@@ -467,10 +467,10 @@ declare const photoFieldConfigSchema: z.ZodObject<{
467
467
  * @hint 'jpg' is an alias for 'jpeg'
468
468
  */
469
469
  fileType: z.ZodOptional<z.ZodArray<z.ZodEnum<{
470
- webp: "webp";
471
- jpg: "jpg";
472
470
  jpeg: "jpeg";
471
+ jpg: "jpg";
473
472
  png: "png";
473
+ webp: "webp";
474
474
  }>>>;
475
475
  /**
476
476
  * Remove the extension from the file name
@@ -61,10 +61,10 @@ declare const allowImageUploadsSchema: z.ZodObject<{
61
61
  */
62
62
  omitExtension: z.ZodOptional<z.ZodBoolean>;
63
63
  format: z.ZodOptional<z.ZodEnum<{
64
- webp: "webp";
65
- jpg: "jpg";
66
64
  jpeg: "jpeg";
65
+ jpg: "jpg";
67
66
  png: "png";
67
+ webp: "webp";
68
68
  }>>;
69
69
  }, z.core.$strict>;
70
70
  declare const configSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -133,10 +133,10 @@ declare const configSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
133
133
  */
134
134
  omitExtension: z.ZodOptional<z.ZodBoolean>;
135
135
  format: z.ZodOptional<z.ZodEnum<{
136
- webp: "webp";
137
- jpg: "jpg";
138
136
  jpeg: "jpeg";
137
+ jpg: "jpg";
139
138
  png: "png";
139
+ webp: "webp";
140
140
  }>>;
141
141
  }, z.core.$strict>>;
142
142
  }, z.core.$strict>, z.ZodObject<{
@@ -261,10 +261,10 @@ declare const optionsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
261
261
  */
262
262
  omitExtension: z.ZodOptional<z.ZodBoolean>;
263
263
  format: z.ZodOptional<z.ZodEnum<{
264
- webp: "webp";
265
- jpg: "jpg";
266
264
  jpeg: "jpeg";
265
+ jpg: "jpg";
267
266
  png: "png";
267
+ webp: "webp";
268
268
  }>>;
269
269
  }, z.core.$strict>>;
270
270
  name: z.ZodString;
@@ -357,10 +357,10 @@ declare const richTextFieldConfigSchema: z.ZodIntersection<z.ZodDiscriminatedUni
357
357
  */
358
358
  omitExtension: z.ZodOptional<z.ZodBoolean>;
359
359
  format: z.ZodOptional<z.ZodEnum<{
360
- webp: "webp";
361
- jpg: "jpg";
362
360
  jpeg: "jpeg";
361
+ jpg: "jpg";
363
362
  png: "png";
363
+ webp: "webp";
364
364
  }>>;
365
365
  }, z.core.$strict>>;
366
366
  name: z.ZodString;
@@ -1 +1 @@
1
- {"version":3,"file":"richText.d.ts","sourceRoot":"","sources":["../../../src/core/fields/richText.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"richText.d.ts","sourceRoot":"","sources":["../../../src/core/fields/richText.ts"],"names":[],"mappings":"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"}
@@ -7,9 +7,10 @@ import * as z from 'zod';
7
7
  import { db } from '../../db/client.js';
8
8
  import { EditorPhotosTable } from '../../db/schema.js';
9
9
  import getString from '../../translations/index.js';
10
- import { humanReadableFileSize } from '../../utils/index.js';
10
+ import { base64ByteLength, humanReadableFileSize, maxFileSizeToBytes } from '../../utils/index.js';
11
11
  import { getCMSConfig } from '../config/index.js';
12
12
  import { backgroundSchema, entityKind } from '../helpers/index.js';
13
+ import { DEFAULT_INLINE_IMAGE_SIZE, DEFAULT_MAX_FILE_SIZE, inlineImageResizeOptions } from '../helpers/inline-image.js';
13
14
  import { sanitizeRichText } from '../security/dom.js';
14
15
  import { baseFieldConfigSchema, Field } from './field.js';
15
16
  const positiveInt = z.number().int().positive();
@@ -42,27 +43,6 @@ const inlineImageSizeSchema = z.discriminatedUnion('fit', [
42
43
  background: backgroundSchema.optional().describe('Background color for padding'),
43
44
  }),
44
45
  ]);
45
- /**
46
- * Bounds every inline image is fitted into unless the field overrides `size`.
47
- * 1200x675 is 16:9 at a width that covers typical article body content, scaled down to fit so a
48
- * body image is never cropped or padded unless the field asks for it.
49
- */
50
- const DEFAULT_INLINE_IMAGE_SIZE = {
51
- width: 1200,
52
- height: 675,
53
- fit: 'inside',
54
- };
55
- /** Largest accepted inline image unless the field overrides `maxFileSize`. */
56
- const DEFAULT_MAX_FILE_SIZE = { size: 1, unit: 'mb' };
57
- const BYTES_PER_UNIT = { kb: 1024, mb: 1024 * 1024 };
58
- /**
59
- * Decoded byte length of a base64 payload, without allocating the buffer — inline images are
60
- * rejected before anything is decoded or written.
61
- */
62
- function base64ByteLength(base64) {
63
- const padding = base64.endsWith('==') ? 2 : base64.endsWith('=') ? 1 : 0;
64
- return Math.floor((base64.length * 3) / 4) - padding;
65
- }
66
46
  /**
67
47
  * Matches the `{name}` placeholder (whitespace tolerated: `{ name }`).
68
48
  *
@@ -239,7 +219,7 @@ export class RichTextField extends Field {
239
219
  const regex = /<img.*?src="(data:image\/.*?;base64,.*?)".*?>/g;
240
220
  const matches = this.value.matchAll(regex);
241
221
  const maxFileSize = this.allowImageUploads.maxFileSize ?? DEFAULT_MAX_FILE_SIZE;
242
- const maxBytes = maxFileSize.size * BYTES_PER_UNIT[maxFileSize.unit];
222
+ const maxBytes = maxFileSizeToBytes(maxFileSize);
243
223
  for (const match of matches) {
244
224
  const base64String = match[1];
245
225
  const extension = base64String.split(';')[0].split('/')[1];
@@ -294,18 +274,7 @@ export class RichTextField extends Field {
294
274
  const image = sharp(buffer);
295
275
  const size = this.allowImageUploads.size ?? DEFAULT_INLINE_IMAGE_SIZE;
296
276
  await image
297
- .resize({
298
- width: size.width,
299
- height: size.height,
300
- fit: size.fit,
301
- // `inside` only ever scales down — enlarging a smaller image to fill the box
302
- // would cost quality for nothing. `cover` and `contain` produce the exact box,
303
- // so they are allowed to enlarge.
304
- withoutEnlargement: size.fit === 'inside',
305
- ...(size.fit === 'contain'
306
- ? { background: size.background ?? cmsConfig.media.images.background }
307
- : {}),
308
- })
277
+ .resize(inlineImageResizeOptions(size, cmsConfig.media.images.background))
309
278
  .toFormat(this.allowImageUploads.format ?? 'webp')
310
279
  .toFile(path.join(uploadsFolder, '.photos', sectionName, photo.name));
311
280
  /**
@@ -379,8 +379,8 @@ declare const selectFieldConfigSchema: z.ZodIntersection<z.ZodUnion<readonly [z.
379
379
  }, z.core.$strict>]>, z.ZodObject<{
380
380
  type: z.ZodLiteral<"select">;
381
381
  optionsType: z.ZodEnum<{
382
- db: "db";
383
382
  section: "section";
383
+ db: "db";
384
384
  static: "static";
385
385
  }>;
386
386
  build: z.ZodFunction<z.core.$ZodFunctionArgs, z.ZodCustom<SelectField, SelectField>>;
@@ -4,6 +4,8 @@ export type { LZEntity } from './entity.js';
4
4
  export { hasOwnEntityKind } from './entity.js';
5
5
  export { evaluateConditionalRule, evaluateConditionalRuleGroup, normalizeConditionalRules, } from './conditional-rules.js';
6
6
  export { backgroundSchema } from './background.js';
7
+ export { inlineImageResizeOptions, DEFAULT_INLINE_IMAGE_SIZE, DEFAULT_MAX_FILE_SIZE, INLINE_IMAGE_REGEX, } from './inline-image.js';
8
+ export type { InlineImageSize, InlineImageMaxFileSize } from './inline-image.js';
7
9
  export type { Background } from './background.js';
8
10
  export { watermarkPositionEnum, watermarkObjectSchema, watermarkConfigSchema, WATERMARK_DEFAULTS, resolveWatermark, } from './watermark.js';
9
11
  export type { WatermarkPosition, WatermarkObject, WatermarkConfig, ResolvedWatermark } from './watermark.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/helpers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAI9C,OAAO,EACH,uBAAuB,EACvB,4BAA4B,EAC5B,yBAAyB,GAC5B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EACH,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,GACnB,MAAM,gBAAgB,CAAA;AACvB,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/helpers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAA;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAI9C,OAAO,EACH,uBAAuB,EACvB,4BAA4B,EAC5B,yBAAyB,GAC5B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EACH,wBAAwB,EACxB,yBAAyB,EACzB,qBAAqB,EACrB,kBAAkB,GACrB,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAChF,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EACH,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,GACnB,MAAM,gBAAgB,CAAA;AACvB,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA"}
@@ -6,4 +6,5 @@ export { hasOwnEntityKind } from './entity.js';
6
6
  // duplicate export when `core/index` merges both barrels.
7
7
  export { evaluateConditionalRule, evaluateConditionalRuleGroup, normalizeConditionalRules, } from './conditional-rules.js';
8
8
  export { backgroundSchema } from './background.js';
9
+ export { inlineImageResizeOptions, DEFAULT_INLINE_IMAGE_SIZE, DEFAULT_MAX_FILE_SIZE, INLINE_IMAGE_REGEX, } from './inline-image.js';
9
10
  export { watermarkPositionEnum, watermarkObjectSchema, watermarkConfigSchema, WATERMARK_DEFAULTS, resolveWatermark, } from './watermark.js';
@@ -0,0 +1,46 @@
1
+ import type sharp from 'sharp';
2
+ import type { Background } from './background.js';
3
+ /**
4
+ * Inline-image sizing shared by the rich-text field, the editor upload route, and the client-side
5
+ * validator.
6
+ *
7
+ * Deliberately a leaf module with type-only imports. The validators are environment-neutral —
8
+ * the admin form calls them in the browser, and a consumer may call them server-side — so reaching
9
+ * these through a barrel that pulls the database client, sharp, or fs would break the client build.
10
+ * Import this file directly rather than via `core/helpers/index.js` for the same reason.
11
+ */
12
+ export type InlineImageSize = {
13
+ width: number;
14
+ height: number;
15
+ fit: 'inside';
16
+ } | {
17
+ width: number;
18
+ height: number;
19
+ fit: 'cover';
20
+ } | {
21
+ width: number;
22
+ height: number;
23
+ fit: 'contain';
24
+ background?: Background;
25
+ };
26
+ export type InlineImageMaxFileSize = {
27
+ size: number;
28
+ unit: 'kb' | 'mb';
29
+ };
30
+ /**
31
+ * Bounds every inline image is fitted into unless the field overrides `size`.
32
+ * 1200x675 is 16:9 at a width that covers typical article body content, scaled down to fit so a
33
+ * body image is never cropped or padded unless the field asks for it.
34
+ */
35
+ export declare const DEFAULT_INLINE_IMAGE_SIZE: InlineImageSize;
36
+ /** Largest accepted inline image unless the field overrides `maxFileSize`. */
37
+ export declare const DEFAULT_MAX_FILE_SIZE: InlineImageMaxFileSize;
38
+ /** Same shape `extractInlineImages` looks for, so every side agrees on what an inline image is. */
39
+ export declare const INLINE_IMAGE_REGEX: RegExp;
40
+ /**
41
+ * Sharp resize options for an inline image, so every place that writes one — the field on save and
42
+ * the editor upload route — sizes it identically. `background` is the CMS-config fallback, used
43
+ * only when the field asks for `contain` without naming its own.
44
+ */
45
+ export declare function inlineImageResizeOptions(size: InlineImageSize, background: Background): sharp.ResizeOptions;
46
+ //# sourceMappingURL=inline-image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inline-image.d.ts","sourceRoot":"","sources":["../../../src/core/helpers/inline-image.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEjD;;;;;;;;GAQG;AAEH,MAAM,MAAM,eAAe,GACrB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,QAAQ,CAAA;CAAE,GAChD;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,GAC/C;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,SAAS,CAAC;IAAC,UAAU,CAAC,EAAE,UAAU,CAAA;CAAE,CAAA;AAEhF,MAAM,MAAM,sBAAsB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;CAAE,CAAA;AAExE;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,EAAE,eAIvC,CAAA;AAED,8EAA8E;AAC9E,eAAO,MAAM,qBAAqB,EAAE,sBAAgD,CAAA;AAEpF,mGAAmG;AACnG,eAAO,MAAM,kBAAkB,QAAmD,CAAA;AAElF;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,GAAG,KAAK,CAAC,aAAa,CAU3G"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Bounds every inline image is fitted into unless the field overrides `size`.
3
+ * 1200x675 is 16:9 at a width that covers typical article body content, scaled down to fit so a
4
+ * body image is never cropped or padded unless the field asks for it.
5
+ */
6
+ export const DEFAULT_INLINE_IMAGE_SIZE = {
7
+ width: 1200,
8
+ height: 675,
9
+ fit: 'inside',
10
+ };
11
+ /** Largest accepted inline image unless the field overrides `maxFileSize`. */
12
+ export const DEFAULT_MAX_FILE_SIZE = { size: 1, unit: 'mb' };
13
+ /** Same shape `extractInlineImages` looks for, so every side agrees on what an inline image is. */
14
+ export const INLINE_IMAGE_REGEX = /<img.*?src="(data:image\/.*?;base64,.*?)".*?>/g;
15
+ /**
16
+ * Sharp resize options for an inline image, so every place that writes one — the field on save and
17
+ * the editor upload route — sizes it identically. `background` is the CMS-config fallback, used
18
+ * only when the field asks for `contain` without naming its own.
19
+ */
20
+ export function inlineImageResizeOptions(size, background) {
21
+ return {
22
+ width: size.width,
23
+ height: size.height,
24
+ fit: size.fit,
25
+ // `inside` only ever scales down — enlarging a smaller image to fill the box would cost
26
+ // quality for nothing. `cover` and `contain` produce the exact box, so they may enlarge.
27
+ withoutEnlargement: size.fit === 'inside',
28
+ ...(size.fit === 'contain' ? { background: size.background ?? background } : {}),
29
+ };
30
+ }