@payloadcms/transformer-sharp 4.0.0-canary.38
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/LICENSE.md +22 -0
- package/README.md +105 -0
- package/dist/canResizeImage.d.ts +2 -0
- package/dist/canResizeImage.d.ts.map +1 -0
- package/dist/canResizeImage.js +12 -0
- package/dist/canResizeImage.js.map +1 -0
- package/dist/createSharpFromFile.d.ts +8 -0
- package/dist/createSharpFromFile.d.ts.map +1 -0
- package/dist/createSharpFromFile.js +31 -0
- package/dist/createSharpFromFile.js.map +1 -0
- package/dist/createSharpFromFile.spec.js +120 -0
- package/dist/createSharpFromFile.spec.js.map +1 -0
- package/dist/getImageResizeAction.d.ts +24 -0
- package/dist/getImageResizeAction.d.ts.map +1 -0
- package/dist/getImageResizeAction.js +56 -0
- package/dist/getImageResizeAction.js.map +1 -0
- package/dist/handleRequest.d.ts +14 -0
- package/dist/handleRequest.d.ts.map +1 -0
- package/dist/handleRequest.js +143 -0
- package/dist/handleRequest.js.map +1 -0
- package/dist/handleRequest.spec.js +188 -0
- package/dist/handleRequest.spec.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/initSharpCollections.d.ts +14 -0
- package/dist/initSharpCollections.d.ts.map +1 -0
- package/dist/initSharpCollections.js +84 -0
- package/dist/initSharpCollections.js.map +1 -0
- package/dist/initSharpCollections.spec.js +185 -0
- package/dist/initSharpCollections.spec.js.map +1 -0
- package/dist/mapWithBoundedConcurrency.d.ts +7 -0
- package/dist/mapWithBoundedConcurrency.d.ts.map +1 -0
- package/dist/mapWithBoundedConcurrency.js +26 -0
- package/dist/mapWithBoundedConcurrency.js.map +1 -0
- package/dist/mapWithBoundedConcurrency.spec.js +35 -0
- package/dist/mapWithBoundedConcurrency.spec.js.map +1 -0
- package/dist/optionallyAppendMetadata.d.ts +9 -0
- package/dist/optionallyAppendMetadata.d.ts.map +1 -0
- package/dist/optionallyAppendMetadata.js +17 -0
- package/dist/optionallyAppendMetadata.js.map +1 -0
- package/dist/parseDynamicResize.d.ts +17 -0
- package/dist/parseDynamicResize.d.ts.map +1 -0
- package/dist/parseDynamicResize.js +117 -0
- package/dist/parseDynamicResize.js.map +1 -0
- package/dist/parseDynamicResize.spec.js +123 -0
- package/dist/parseDynamicResize.spec.js.map +1 -0
- package/dist/prepareLegacyUpload.d.ts +14 -0
- package/dist/prepareLegacyUpload.d.ts.map +1 -0
- package/dist/prepareLegacyUpload.js +147 -0
- package/dist/prepareLegacyUpload.js.map +1 -0
- package/dist/prepareLegacyUpload.spec.js +95 -0
- package/dist/prepareLegacyUpload.spec.js.map +1 -0
- package/dist/sanitizeResizeConfig.d.ts +11 -0
- package/dist/sanitizeResizeConfig.d.ts.map +1 -0
- package/dist/sanitizeResizeConfig.js +20 -0
- package/dist/sanitizeResizeConfig.js.map +1 -0
- package/dist/sharpTransformer.d.ts +10 -0
- package/dist/sharpTransformer.d.ts.map +1 -0
- package/dist/sharpTransformer.js +122 -0
- package/dist/sharpTransformer.js.map +1 -0
- package/dist/sharpTransformer.spec.js +117 -0
- package/dist/sharpTransformer.spec.js.map +1 -0
- package/dist/transformFile.d.ts +12 -0
- package/dist/transformFile.d.ts.map +1 -0
- package/dist/transformFile.js +264 -0
- package/dist/transformFile.js.map +1 -0
- package/dist/transformFile.spec.js +259 -0
- package/dist/transformFile.spec.js.map +1 -0
- package/dist/types.d.ts +150 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export async function optionallyAppendMetadata({ req, sharpFile, withMetadata }) {
|
|
2
|
+
const metadata = await sharpFile.metadata();
|
|
3
|
+
if (withMetadata === true) {
|
|
4
|
+
return sharpFile.withMetadata();
|
|
5
|
+
} else if (typeof withMetadata === 'function') {
|
|
6
|
+
const useMetadata = await withMetadata({
|
|
7
|
+
metadata,
|
|
8
|
+
req
|
|
9
|
+
});
|
|
10
|
+
if (useMetadata) {
|
|
11
|
+
return sharpFile.withMetadata();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return sharpFile;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=optionallyAppendMetadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/optionallyAppendMetadata.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\nimport type { Sharp } from 'sharp'\n\nimport type { WithMetadata } from './types.js'\n\nexport async function optionallyAppendMetadata({\n req,\n sharpFile,\n withMetadata,\n}: {\n req: PayloadRequest\n sharpFile: Sharp\n withMetadata: undefined | WithMetadata\n}): Promise<Sharp> {\n const metadata = await sharpFile.metadata()\n\n if (withMetadata === true) {\n return sharpFile.withMetadata()\n } else if (typeof withMetadata === 'function') {\n const useMetadata = await withMetadata({ metadata, req })\n\n if (useMetadata) {\n return sharpFile.withMetadata()\n }\n }\n\n return sharpFile\n}\n"],"names":["optionallyAppendMetadata","req","sharpFile","withMetadata","metadata","useMetadata"],"mappings":"AAKA,OAAO,eAAeA,yBAAyB,EAC7CC,GAAG,EACHC,SAAS,EACTC,YAAY,EAKb;IACC,MAAMC,WAAW,MAAMF,UAAUE,QAAQ;IAEzC,IAAID,iBAAiB,MAAM;QACzB,OAAOD,UAAUC,YAAY;IAC/B,OAAO,IAAI,OAAOA,iBAAiB,YAAY;QAC7C,MAAME,cAAc,MAAMF,aAAa;YAAEC;YAAUH;QAAI;QAEvD,IAAII,aAAa;YACf,OAAOH,UAAUC,YAAY;QAC/B;IACF;IAEA,OAAOD;AACT"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { DynamicResizeParseResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Strictly parses the v1 dynamic resize query parameters (`width`, `height`,
|
|
4
|
+
* `withoutEnlargement`). The presence of any of them routes the request —
|
|
5
|
+
* a malformed combination is `valid: false` (mapped to `400`), not treated as
|
|
6
|
+
* an ordinary read. Every other query key (`draft`, `depth`, `where`, `prefix`,
|
|
7
|
+
* …) is ignored.
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseDynamicResize({ limits, searchParams, }: {
|
|
10
|
+
limits: {
|
|
11
|
+
maxHeight: number;
|
|
12
|
+
maxPixels: number;
|
|
13
|
+
maxWidth: number;
|
|
14
|
+
};
|
|
15
|
+
searchParams: URLSearchParams;
|
|
16
|
+
}): DynamicResizeParseResult;
|
|
17
|
+
//# sourceMappingURL=parseDynamicResize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseDynamicResize.d.ts","sourceRoot":"","sources":["../src/parseDynamicResize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AAc1D;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,YAAY,GACb,EAAE;IACD,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;IAClE,YAAY,EAAE,eAAe,CAAA;CAC9B,GAAG,wBAAwB,CAiG3B"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
const POSITIVE_INTEGER_PATTERN = /^[1-9]\d*$/;
|
|
2
|
+
function parsePositiveInteger(value) {
|
|
3
|
+
if (!POSITIVE_INTEGER_PATTERN.test(value)) {
|
|
4
|
+
return undefined;
|
|
5
|
+
}
|
|
6
|
+
const parsed = Number(value);
|
|
7
|
+
return Number.isSafeInteger(parsed) ? parsed : undefined;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Strictly parses the v1 dynamic resize query parameters (`width`, `height`,
|
|
11
|
+
* `withoutEnlargement`). The presence of any of them routes the request —
|
|
12
|
+
* a malformed combination is `valid: false` (mapped to `400`), not treated as
|
|
13
|
+
* an ordinary read. Every other query key (`draft`, `depth`, `where`, `prefix`,
|
|
14
|
+
* …) is ignored.
|
|
15
|
+
*/ export function parseDynamicResize({ limits, searchParams }) {
|
|
16
|
+
const widthValues = searchParams.getAll('width');
|
|
17
|
+
const heightValues = searchParams.getAll('height');
|
|
18
|
+
const withoutEnlargementValues = searchParams.getAll('withoutEnlargement');
|
|
19
|
+
const isRouted = widthValues.length > 0 || heightValues.length > 0 || withoutEnlargementValues.length > 0;
|
|
20
|
+
if (!isRouted) {
|
|
21
|
+
return {
|
|
22
|
+
isRouted: false
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
if (widthValues.length > 1) {
|
|
26
|
+
return {
|
|
27
|
+
error: '`width` may only be specified once.',
|
|
28
|
+
isRouted: true,
|
|
29
|
+
valid: false
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (heightValues.length > 1) {
|
|
33
|
+
return {
|
|
34
|
+
error: '`height` may only be specified once.',
|
|
35
|
+
isRouted: true,
|
|
36
|
+
valid: false
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
if (withoutEnlargementValues.length > 1) {
|
|
40
|
+
return {
|
|
41
|
+
error: '`withoutEnlargement` may only be specified once.',
|
|
42
|
+
isRouted: true,
|
|
43
|
+
valid: false
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (widthValues.length === 0 && heightValues.length === 0) {
|
|
47
|
+
return {
|
|
48
|
+
error: 'At least one of `width` or `height` is required to resize.',
|
|
49
|
+
isRouted: true,
|
|
50
|
+
valid: false
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
let width;
|
|
54
|
+
if (widthValues.length === 1) {
|
|
55
|
+
width = parsePositiveInteger(widthValues[0]);
|
|
56
|
+
if (width === undefined) {
|
|
57
|
+
return {
|
|
58
|
+
error: '`width` must be a positive integer.',
|
|
59
|
+
isRouted: true,
|
|
60
|
+
valid: false
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (width > limits.maxWidth) {
|
|
64
|
+
return {
|
|
65
|
+
error: `\`width\` exceeds the configured maximum of ${limits.maxWidth}.`,
|
|
66
|
+
isRouted: true,
|
|
67
|
+
valid: false
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
let height;
|
|
72
|
+
if (heightValues.length === 1) {
|
|
73
|
+
height = parsePositiveInteger(heightValues[0]);
|
|
74
|
+
if (height === undefined) {
|
|
75
|
+
return {
|
|
76
|
+
error: '`height` must be a positive integer.',
|
|
77
|
+
isRouted: true,
|
|
78
|
+
valid: false
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (height > limits.maxHeight) {
|
|
82
|
+
return {
|
|
83
|
+
error: `\`height\` exceeds the configured maximum of ${limits.maxHeight}.`,
|
|
84
|
+
isRouted: true,
|
|
85
|
+
valid: false
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (width !== undefined && height !== undefined && width * height > limits.maxPixels) {
|
|
90
|
+
return {
|
|
91
|
+
error: `Requested dimensions exceed the configured maximum of ${limits.maxPixels} pixels.`,
|
|
92
|
+
isRouted: true,
|
|
93
|
+
valid: false
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
let withoutEnlargement;
|
|
97
|
+
if (withoutEnlargementValues.length === 1) {
|
|
98
|
+
const raw = withoutEnlargementValues[0];
|
|
99
|
+
if (raw !== 'true' && raw !== 'false') {
|
|
100
|
+
return {
|
|
101
|
+
error: '`withoutEnlargement` must be "true" or "false".',
|
|
102
|
+
isRouted: true,
|
|
103
|
+
valid: false
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
withoutEnlargement = raw === 'true';
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
height,
|
|
110
|
+
isRouted: true,
|
|
111
|
+
valid: true,
|
|
112
|
+
width,
|
|
113
|
+
withoutEnlargement
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
//# sourceMappingURL=parseDynamicResize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/parseDynamicResize.ts"],"sourcesContent":["import type { DynamicResizeParseResult } from './types.js'\n\nconst POSITIVE_INTEGER_PATTERN = /^[1-9]\\d*$/\n\nfunction parsePositiveInteger(value: string): number | undefined {\n if (!POSITIVE_INTEGER_PATTERN.test(value)) {\n return undefined\n }\n\n const parsed = Number(value)\n\n return Number.isSafeInteger(parsed) ? parsed : undefined\n}\n\n/**\n * Strictly parses the v1 dynamic resize query parameters (`width`, `height`,\n * `withoutEnlargement`). The presence of any of them routes the request —\n * a malformed combination is `valid: false` (mapped to `400`), not treated as\n * an ordinary read. Every other query key (`draft`, `depth`, `where`, `prefix`,\n * …) is ignored.\n */\nexport function parseDynamicResize({\n limits,\n searchParams,\n}: {\n limits: { maxHeight: number; maxPixels: number; maxWidth: number }\n searchParams: URLSearchParams\n}): DynamicResizeParseResult {\n const widthValues = searchParams.getAll('width')\n const heightValues = searchParams.getAll('height')\n const withoutEnlargementValues = searchParams.getAll('withoutEnlargement')\n\n const isRouted =\n widthValues.length > 0 || heightValues.length > 0 || withoutEnlargementValues.length > 0\n\n if (!isRouted) {\n return { isRouted: false }\n }\n\n if (widthValues.length > 1) {\n return { error: '`width` may only be specified once.', isRouted: true, valid: false }\n }\n\n if (heightValues.length > 1) {\n return { error: '`height` may only be specified once.', isRouted: true, valid: false }\n }\n\n if (withoutEnlargementValues.length > 1) {\n return {\n error: '`withoutEnlargement` may only be specified once.',\n isRouted: true,\n valid: false,\n }\n }\n\n if (widthValues.length === 0 && heightValues.length === 0) {\n return {\n error: 'At least one of `width` or `height` is required to resize.',\n isRouted: true,\n valid: false,\n }\n }\n\n let width: number | undefined\n\n if (widthValues.length === 1) {\n width = parsePositiveInteger(widthValues[0]!)\n\n if (width === undefined) {\n return { error: '`width` must be a positive integer.', isRouted: true, valid: false }\n }\n\n if (width > limits.maxWidth) {\n return {\n error: `\\`width\\` exceeds the configured maximum of ${limits.maxWidth}.`,\n isRouted: true,\n valid: false,\n }\n }\n }\n\n let height: number | undefined\n\n if (heightValues.length === 1) {\n height = parsePositiveInteger(heightValues[0]!)\n\n if (height === undefined) {\n return { error: '`height` must be a positive integer.', isRouted: true, valid: false }\n }\n\n if (height > limits.maxHeight) {\n return {\n error: `\\`height\\` exceeds the configured maximum of ${limits.maxHeight}.`,\n isRouted: true,\n valid: false,\n }\n }\n }\n\n if (width !== undefined && height !== undefined && width * height > limits.maxPixels) {\n return {\n error: `Requested dimensions exceed the configured maximum of ${limits.maxPixels} pixels.`,\n isRouted: true,\n valid: false,\n }\n }\n\n let withoutEnlargement: boolean | undefined\n\n if (withoutEnlargementValues.length === 1) {\n const raw = withoutEnlargementValues[0]\n\n if (raw !== 'true' && raw !== 'false') {\n return {\n error: '`withoutEnlargement` must be \"true\" or \"false\".',\n isRouted: true,\n valid: false,\n }\n }\n\n withoutEnlargement = raw === 'true'\n }\n\n return { height, isRouted: true, valid: true, width, withoutEnlargement }\n}\n"],"names":["POSITIVE_INTEGER_PATTERN","parsePositiveInteger","value","test","undefined","parsed","Number","isSafeInteger","parseDynamicResize","limits","searchParams","widthValues","getAll","heightValues","withoutEnlargementValues","isRouted","length","error","valid","width","maxWidth","height","maxHeight","maxPixels","withoutEnlargement","raw"],"mappings":"AAEA,MAAMA,2BAA2B;AAEjC,SAASC,qBAAqBC,KAAa;IACzC,IAAI,CAACF,yBAAyBG,IAAI,CAACD,QAAQ;QACzC,OAAOE;IACT;IAEA,MAAMC,SAASC,OAAOJ;IAEtB,OAAOI,OAAOC,aAAa,CAACF,UAAUA,SAASD;AACjD;AAEA;;;;;;CAMC,GACD,OAAO,SAASI,mBAAmB,EACjCC,MAAM,EACNC,YAAY,EAIb;IACC,MAAMC,cAAcD,aAAaE,MAAM,CAAC;IACxC,MAAMC,eAAeH,aAAaE,MAAM,CAAC;IACzC,MAAME,2BAA2BJ,aAAaE,MAAM,CAAC;IAErD,MAAMG,WACJJ,YAAYK,MAAM,GAAG,KAAKH,aAAaG,MAAM,GAAG,KAAKF,yBAAyBE,MAAM,GAAG;IAEzF,IAAI,CAACD,UAAU;QACb,OAAO;YAAEA,UAAU;QAAM;IAC3B;IAEA,IAAIJ,YAAYK,MAAM,GAAG,GAAG;QAC1B,OAAO;YAAEC,OAAO;YAAuCF,UAAU;YAAMG,OAAO;QAAM;IACtF;IAEA,IAAIL,aAAaG,MAAM,GAAG,GAAG;QAC3B,OAAO;YAAEC,OAAO;YAAwCF,UAAU;YAAMG,OAAO;QAAM;IACvF;IAEA,IAAIJ,yBAAyBE,MAAM,GAAG,GAAG;QACvC,OAAO;YACLC,OAAO;YACPF,UAAU;YACVG,OAAO;QACT;IACF;IAEA,IAAIP,YAAYK,MAAM,KAAK,KAAKH,aAAaG,MAAM,KAAK,GAAG;QACzD,OAAO;YACLC,OAAO;YACPF,UAAU;YACVG,OAAO;QACT;IACF;IAEA,IAAIC;IAEJ,IAAIR,YAAYK,MAAM,KAAK,GAAG;QAC5BG,QAAQlB,qBAAqBU,WAAW,CAAC,EAAE;QAE3C,IAAIQ,UAAUf,WAAW;YACvB,OAAO;gBAAEa,OAAO;gBAAuCF,UAAU;gBAAMG,OAAO;YAAM;QACtF;QAEA,IAAIC,QAAQV,OAAOW,QAAQ,EAAE;YAC3B,OAAO;gBACLH,OAAO,CAAC,4CAA4C,EAAER,OAAOW,QAAQ,CAAC,CAAC,CAAC;gBACxEL,UAAU;gBACVG,OAAO;YACT;QACF;IACF;IAEA,IAAIG;IAEJ,IAAIR,aAAaG,MAAM,KAAK,GAAG;QAC7BK,SAASpB,qBAAqBY,YAAY,CAAC,EAAE;QAE7C,IAAIQ,WAAWjB,WAAW;YACxB,OAAO;gBAAEa,OAAO;gBAAwCF,UAAU;gBAAMG,OAAO;YAAM;QACvF;QAEA,IAAIG,SAASZ,OAAOa,SAAS,EAAE;YAC7B,OAAO;gBACLL,OAAO,CAAC,6CAA6C,EAAER,OAAOa,SAAS,CAAC,CAAC,CAAC;gBAC1EP,UAAU;gBACVG,OAAO;YACT;QACF;IACF;IAEA,IAAIC,UAAUf,aAAaiB,WAAWjB,aAAae,QAAQE,SAASZ,OAAOc,SAAS,EAAE;QACpF,OAAO;YACLN,OAAO,CAAC,sDAAsD,EAAER,OAAOc,SAAS,CAAC,QAAQ,CAAC;YAC1FR,UAAU;YACVG,OAAO;QACT;IACF;IAEA,IAAIM;IAEJ,IAAIV,yBAAyBE,MAAM,KAAK,GAAG;QACzC,MAAMS,MAAMX,wBAAwB,CAAC,EAAE;QAEvC,IAAIW,QAAQ,UAAUA,QAAQ,SAAS;YACrC,OAAO;gBACLR,OAAO;gBACPF,UAAU;gBACVG,OAAO;YACT;QACF;QAEAM,qBAAqBC,QAAQ;IAC/B;IAEA,OAAO;QAAEJ;QAAQN,UAAU;QAAMG,OAAO;QAAMC;QAAOK;IAAmB;AAC1E"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { parseDynamicResize } from './parseDynamicResize.js';
|
|
3
|
+
const DEFAULT_LIMITS = {
|
|
4
|
+
maxHeight: 4096,
|
|
5
|
+
maxPixels: 16_777_216,
|
|
6
|
+
maxWidth: 4096
|
|
7
|
+
};
|
|
8
|
+
const parse = (query)=>parseDynamicResize({
|
|
9
|
+
limits: DEFAULT_LIMITS,
|
|
10
|
+
searchParams: new URLSearchParams(query)
|
|
11
|
+
});
|
|
12
|
+
describe('parseDynamicResize', ()=>{
|
|
13
|
+
it('should route a request containing only withoutEnlargement, but reject it as invalid', ()=>{
|
|
14
|
+
const result = parse('withoutEnlargement=true');
|
|
15
|
+
expect(result.isRouted).toBe(true);
|
|
16
|
+
expect(result).toMatchObject({
|
|
17
|
+
valid: false
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
it.each([
|
|
21
|
+
true,
|
|
22
|
+
false
|
|
23
|
+
])('should parse a valid withoutEnlargement=%s alongside width', (withoutEnlargement)=>{
|
|
24
|
+
expect(parse(`width=500&withoutEnlargement=${withoutEnlargement}`)).toEqual({
|
|
25
|
+
height: undefined,
|
|
26
|
+
isRouted: true,
|
|
27
|
+
valid: true,
|
|
28
|
+
width: 500,
|
|
29
|
+
withoutEnlargement
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
it('should reject an invalid withoutEnlargement value', ()=>{
|
|
33
|
+
const result = parse('width=500&withoutEnlargement=yes');
|
|
34
|
+
expect(result).toMatchObject({
|
|
35
|
+
isRouted: true,
|
|
36
|
+
valid: false
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
it.each([
|
|
40
|
+
'width=500&width=600',
|
|
41
|
+
'height=500&height=600',
|
|
42
|
+
'width=500&withoutEnlargement=true&withoutEnlargement=false'
|
|
43
|
+
])('should reject a repeated parameter: %s', (query)=>{
|
|
44
|
+
expect(parse(query)).toMatchObject({
|
|
45
|
+
isRouted: true,
|
|
46
|
+
valid: false
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
it.each([
|
|
50
|
+
'abc',
|
|
51
|
+
'12.5',
|
|
52
|
+
'-5',
|
|
53
|
+
'0',
|
|
54
|
+
'',
|
|
55
|
+
'5px',
|
|
56
|
+
' 5'
|
|
57
|
+
])('should reject a non-positive-integer width: %s', (value)=>{
|
|
58
|
+
const result = parse(`width=${encodeURIComponent(value)}`);
|
|
59
|
+
expect(result).toMatchObject({
|
|
60
|
+
isRouted: true,
|
|
61
|
+
valid: false
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
it('should reject an unsafe-integer width without throwing', ()=>{
|
|
65
|
+
const result = parse('width=99999999999999999999999999999999');
|
|
66
|
+
expect(result).toMatchObject({
|
|
67
|
+
isRouted: true,
|
|
68
|
+
valid: false
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
it('should reject a width exceeding the configured maxWidth', ()=>{
|
|
72
|
+
const result = parse('width=5000');
|
|
73
|
+
expect(result).toMatchObject({
|
|
74
|
+
isRouted: true,
|
|
75
|
+
valid: false
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
it('should reject a height exceeding the configured maxHeight', ()=>{
|
|
79
|
+
const result = parse('height=5000');
|
|
80
|
+
expect(result).toMatchObject({
|
|
81
|
+
isRouted: true,
|
|
82
|
+
valid: false
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
it('should accept a width exactly at the configured maxWidth', ()=>{
|
|
86
|
+
expect(parse('width=4096')).toMatchObject({
|
|
87
|
+
isRouted: true,
|
|
88
|
+
valid: true
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
it('should reject a width/height combination whose product exceeds maxPixels even when each dimension is individually within its own limit', ()=>{
|
|
92
|
+
const result = parseDynamicResize({
|
|
93
|
+
limits: {
|
|
94
|
+
maxHeight: 4096,
|
|
95
|
+
maxPixels: 1000,
|
|
96
|
+
maxWidth: 4096
|
|
97
|
+
},
|
|
98
|
+
searchParams: new URLSearchParams('width=100&height=100')
|
|
99
|
+
});
|
|
100
|
+
expect(result).toMatchObject({
|
|
101
|
+
isRouted: true,
|
|
102
|
+
valid: false
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
it('should accept a width/height combination within the configured maxPixels', ()=>{
|
|
106
|
+
const result = parseDynamicResize({
|
|
107
|
+
limits: {
|
|
108
|
+
maxHeight: 4096,
|
|
109
|
+
maxPixels: 1000,
|
|
110
|
+
maxWidth: 4096
|
|
111
|
+
},
|
|
112
|
+
searchParams: new URLSearchParams('width=10&height=10')
|
|
113
|
+
});
|
|
114
|
+
expect(result).toMatchObject({
|
|
115
|
+
height: 10,
|
|
116
|
+
isRouted: true,
|
|
117
|
+
valid: true,
|
|
118
|
+
width: 10
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
//# sourceMappingURL=parseDynamicResize.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/parseDynamicResize.spec.ts"],"sourcesContent":["import { describe, expect, it } from 'vitest'\n\nimport { parseDynamicResize } from './parseDynamicResize.js'\n\nconst DEFAULT_LIMITS = { maxHeight: 4096, maxPixels: 16_777_216, maxWidth: 4096 }\n\nconst parse = (query: string) =>\n parseDynamicResize({ limits: DEFAULT_LIMITS, searchParams: new URLSearchParams(query) })\n\ndescribe('parseDynamicResize', () => {\n it('should route a request containing only withoutEnlargement, but reject it as invalid', () => {\n const result = parse('withoutEnlargement=true')\n expect(result.isRouted).toBe(true)\n expect(result).toMatchObject({ valid: false })\n })\n\n it.each([true, false])(\n 'should parse a valid withoutEnlargement=%s alongside width',\n (withoutEnlargement) => {\n expect(parse(`width=500&withoutEnlargement=${withoutEnlargement}`)).toEqual({\n height: undefined,\n isRouted: true,\n valid: true,\n width: 500,\n withoutEnlargement,\n })\n },\n )\n\n it('should reject an invalid withoutEnlargement value', () => {\n const result = parse('width=500&withoutEnlargement=yes')\n expect(result).toMatchObject({ isRouted: true, valid: false })\n })\n\n it.each([\n 'width=500&width=600',\n 'height=500&height=600',\n 'width=500&withoutEnlargement=true&withoutEnlargement=false',\n ])('should reject a repeated parameter: %s', (query) => {\n expect(parse(query)).toMatchObject({ isRouted: true, valid: false })\n })\n\n it.each(['abc', '12.5', '-5', '0', '', '5px', ' 5'])(\n 'should reject a non-positive-integer width: %s',\n (value) => {\n const result = parse(`width=${encodeURIComponent(value)}`)\n expect(result).toMatchObject({ isRouted: true, valid: false })\n },\n )\n\n it('should reject an unsafe-integer width without throwing', () => {\n const result = parse('width=99999999999999999999999999999999')\n expect(result).toMatchObject({ isRouted: true, valid: false })\n })\n\n it('should reject a width exceeding the configured maxWidth', () => {\n const result = parse('width=5000')\n expect(result).toMatchObject({ isRouted: true, valid: false })\n })\n\n it('should reject a height exceeding the configured maxHeight', () => {\n const result = parse('height=5000')\n expect(result).toMatchObject({ isRouted: true, valid: false })\n })\n\n it('should accept a width exactly at the configured maxWidth', () => {\n expect(parse('width=4096')).toMatchObject({ isRouted: true, valid: true })\n })\n\n it('should reject a width/height combination whose product exceeds maxPixels even when each dimension is individually within its own limit', () => {\n const result = parseDynamicResize({\n limits: { maxHeight: 4096, maxPixels: 1000, maxWidth: 4096 },\n searchParams: new URLSearchParams('width=100&height=100'),\n })\n expect(result).toMatchObject({ isRouted: true, valid: false })\n })\n\n it('should accept a width/height combination within the configured maxPixels', () => {\n const result = parseDynamicResize({\n limits: { maxHeight: 4096, maxPixels: 1000, maxWidth: 4096 },\n searchParams: new URLSearchParams('width=10&height=10'),\n })\n expect(result).toMatchObject({ height: 10, isRouted: true, valid: true, width: 10 })\n })\n})\n"],"names":["describe","expect","it","parseDynamicResize","DEFAULT_LIMITS","maxHeight","maxPixels","maxWidth","parse","query","limits","searchParams","URLSearchParams","result","isRouted","toBe","toMatchObject","valid","each","withoutEnlargement","toEqual","height","undefined","width","value","encodeURIComponent"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAE7C,SAASC,kBAAkB,QAAQ,0BAAyB;AAE5D,MAAMC,iBAAiB;IAAEC,WAAW;IAAMC,WAAW;IAAYC,UAAU;AAAK;AAEhF,MAAMC,QAAQ,CAACC,QACbN,mBAAmB;QAAEO,QAAQN;QAAgBO,cAAc,IAAIC,gBAAgBH;IAAO;AAExFT,SAAS,sBAAsB;IAC7BE,GAAG,uFAAuF;QACxF,MAAMW,SAASL,MAAM;QACrBP,OAAOY,OAAOC,QAAQ,EAAEC,IAAI,CAAC;QAC7Bd,OAAOY,QAAQG,aAAa,CAAC;YAAEC,OAAO;QAAM;IAC9C;IAEAf,GAAGgB,IAAI,CAAC;QAAC;QAAM;KAAM,EACnB,8DACA,CAACC;QACClB,OAAOO,MAAM,CAAC,6BAA6B,EAAEW,oBAAoB,GAAGC,OAAO,CAAC;YAC1EC,QAAQC;YACRR,UAAU;YACVG,OAAO;YACPM,OAAO;YACPJ;QACF;IACF;IAGFjB,GAAG,qDAAqD;QACtD,MAAMW,SAASL,MAAM;QACrBP,OAAOY,QAAQG,aAAa,CAAC;YAAEF,UAAU;YAAMG,OAAO;QAAM;IAC9D;IAEAf,GAAGgB,IAAI,CAAC;QACN;QACA;QACA;KACD,EAAE,0CAA0C,CAACT;QAC5CR,OAAOO,MAAMC,QAAQO,aAAa,CAAC;YAAEF,UAAU;YAAMG,OAAO;QAAM;IACpE;IAEAf,GAAGgB,IAAI,CAAC;QAAC;QAAO;QAAQ;QAAM;QAAK;QAAI;QAAO;KAAK,EACjD,kDACA,CAACM;QACC,MAAMX,SAASL,MAAM,CAAC,MAAM,EAAEiB,mBAAmBD,QAAQ;QACzDvB,OAAOY,QAAQG,aAAa,CAAC;YAAEF,UAAU;YAAMG,OAAO;QAAM;IAC9D;IAGFf,GAAG,0DAA0D;QAC3D,MAAMW,SAASL,MAAM;QACrBP,OAAOY,QAAQG,aAAa,CAAC;YAAEF,UAAU;YAAMG,OAAO;QAAM;IAC9D;IAEAf,GAAG,2DAA2D;QAC5D,MAAMW,SAASL,MAAM;QACrBP,OAAOY,QAAQG,aAAa,CAAC;YAAEF,UAAU;YAAMG,OAAO;QAAM;IAC9D;IAEAf,GAAG,6DAA6D;QAC9D,MAAMW,SAASL,MAAM;QACrBP,OAAOY,QAAQG,aAAa,CAAC;YAAEF,UAAU;YAAMG,OAAO;QAAM;IAC9D;IAEAf,GAAG,4DAA4D;QAC7DD,OAAOO,MAAM,eAAeQ,aAAa,CAAC;YAAEF,UAAU;YAAMG,OAAO;QAAK;IAC1E;IAEAf,GAAG,0IAA0I;QAC3I,MAAMW,SAASV,mBAAmB;YAChCO,QAAQ;gBAAEL,WAAW;gBAAMC,WAAW;gBAAMC,UAAU;YAAK;YAC3DI,cAAc,IAAIC,gBAAgB;QACpC;QACAX,OAAOY,QAAQG,aAAa,CAAC;YAAEF,UAAU;YAAMG,OAAO;QAAM;IAC9D;IAEAf,GAAG,4EAA4E;QAC7E,MAAMW,SAASV,mBAAmB;YAChCO,QAAQ;gBAAEL,WAAW;gBAAMC,WAAW;gBAAMC,UAAU;YAAK;YAC3DI,cAAc,IAAIC,gBAAgB;QACpC;QACAX,OAAOY,QAAQG,aAAa,CAAC;YAAEK,QAAQ;YAAIP,UAAU;YAAMG,OAAO;YAAMM,OAAO;QAAG;IACpF;AACF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { UploadTransformerInternal } from 'payload/internal';
|
|
2
|
+
import type { SharpCollectionConfig, SharpDependency } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Computes the legacy upload tasks (the main file, optionally cropped, and every
|
|
5
|
+
* configured legacy image size) and hands each to the injected `transform` callback
|
|
6
|
+
* exactly once. Reads the Sharp-owned config from `sharpTransformer({ collections })`
|
|
7
|
+
* at factory-construction time — not from the sanitized collection, which only gets
|
|
8
|
+
* the narrowed projection `init()` writes back.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createPrepareLegacyUpload({ collections, sharpDependency, }: {
|
|
11
|
+
collections: Partial<Record<string, SharpCollectionConfig>>;
|
|
12
|
+
sharpDependency: SharpDependency;
|
|
13
|
+
}): NonNullable<UploadTransformerInternal['prepareUpload']>;
|
|
14
|
+
//# sourceMappingURL=prepareLegacyUpload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepareLegacyUpload.d.ts","sourceRoot":"","sources":["../src/prepareLegacyUpload.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAgC,yBAAyB,EAAE,MAAM,kBAAkB,CAAA;AAI/F,OAAO,KAAK,EAAE,qBAAqB,EAAE,eAAe,EAA0B,MAAM,YAAY,CAAA;AAsBhG;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,EACxC,WAAW,EACX,eAAe,GAChB,EAAE;IACD,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAA;IAC3D,eAAe,EAAE,eAAe,CAAA;CACjC,GAAG,WAAW,CAAC,yBAAyB,CAAC,eAAe,CAAC,CAAC,CA6G1D"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { isNumber } from 'payload/shared';
|
|
2
|
+
import { canResizeImage } from './canResizeImage.js';
|
|
3
|
+
import { createSharpFromFile } from './createSharpFromFile.js';
|
|
4
|
+
import { getImageResizeAction } from './getImageResizeAction.js';
|
|
5
|
+
import { mapWithBoundedConcurrency } from './mapWithBoundedConcurrency.js';
|
|
6
|
+
import { sanitizeResizeConfig } from './sanitizeResizeConfig.js';
|
|
7
|
+
/**
|
|
8
|
+
* Sharp throws on truncated/header-only files. Returns `undefined` instead —
|
|
9
|
+
* matching core's dependency-free probe — since unreadable dimensions shouldn't fail the upload.
|
|
10
|
+
*/ async function tryProbe(file, sharpDependency) {
|
|
11
|
+
try {
|
|
12
|
+
const sharpFile = await createSharpFromFile({
|
|
13
|
+
file,
|
|
14
|
+
sharpDependency
|
|
15
|
+
});
|
|
16
|
+
const metadata = await sharpFile.metadata();
|
|
17
|
+
return metadata.width && metadata.height ? metadata : undefined;
|
|
18
|
+
} catch {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Computes the legacy upload tasks (the main file, optionally cropped, and every
|
|
24
|
+
* configured legacy image size) and hands each to the injected `transform` callback
|
|
25
|
+
* exactly once. Reads the Sharp-owned config from `sharpTransformer({ collections })`
|
|
26
|
+
* at factory-construction time — not from the sanitized collection, which only gets
|
|
27
|
+
* the narrowed projection `init()` writes back.
|
|
28
|
+
*/ export function createPrepareLegacyUpload({ collections, sharpDependency }) {
|
|
29
|
+
return async ({ collectionSlug, file, req, transform, uploadEdits })=>{
|
|
30
|
+
const collectionUpload = collections[collectionSlug] ?? {};
|
|
31
|
+
const fileSupportsResize = canResizeImage(file.type);
|
|
32
|
+
const cropData = uploadEdits && typeof uploadEdits === 'object' && 'crop' in uploadEdits ? uploadEdits.crop : undefined;
|
|
33
|
+
let originalDimensions;
|
|
34
|
+
if (fileSupportsResize) {
|
|
35
|
+
const originalMeta = await tryProbe(file, sharpDependency);
|
|
36
|
+
if (originalMeta) {
|
|
37
|
+
originalDimensions = {
|
|
38
|
+
height: originalMeta.height,
|
|
39
|
+
width: originalMeta.width
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Unreadable dimensions can't be cropped/resized — treat as non-resizable rather than failing the upload.
|
|
44
|
+
const canProcessAsImage = fileSupportsResize && originalDimensions !== undefined;
|
|
45
|
+
const crop = cropData && originalDimensions ? {
|
|
46
|
+
cropData,
|
|
47
|
+
heightInPixels: uploadEdits.heightInPixels,
|
|
48
|
+
originalDimensions,
|
|
49
|
+
widthInPixels: uploadEdits.widthInPixels
|
|
50
|
+
} : undefined;
|
|
51
|
+
const mainResultFile = await transform({
|
|
52
|
+
fieldPath: 'filename',
|
|
53
|
+
options: {
|
|
54
|
+
collectionUpload,
|
|
55
|
+
crop,
|
|
56
|
+
kind: 'main'
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
const mainResult = await describeResult({
|
|
60
|
+
fieldPath: 'filename',
|
|
61
|
+
fileSupportsResize: canProcessAsImage,
|
|
62
|
+
resultFile: mainResultFile,
|
|
63
|
+
sharpDependency
|
|
64
|
+
});
|
|
65
|
+
const results = [
|
|
66
|
+
mainResult
|
|
67
|
+
];
|
|
68
|
+
// A cropped upload derives its sizes from the crop output, not the original.
|
|
69
|
+
const isCropped = Boolean(crop && mainResult.width && mainResult.height);
|
|
70
|
+
const sizeSourceFile = isCropped ? mainResultFile : undefined;
|
|
71
|
+
const sizeSourceDimensions = isCropped ? {
|
|
72
|
+
height: mainResult.height,
|
|
73
|
+
width: mainResult.width
|
|
74
|
+
} : originalDimensions;
|
|
75
|
+
// Same precedence `init()` applies: Sharp's setting, else the collection's own `focalPoint`.
|
|
76
|
+
const effectiveFocalPoint = collectionUpload.focalPoint ?? req.payload.collections[collectionSlug]?.config.upload?.focalPoint;
|
|
77
|
+
const focalPointEnabled = effectiveFocalPoint !== false;
|
|
78
|
+
const variants = collectionUpload.variants;
|
|
79
|
+
if (canProcessAsImage && Array.isArray(variants) && sizeSourceDimensions) {
|
|
80
|
+
const focalPoint = focalPointEnabled && uploadEdits?.focalPoint ? {
|
|
81
|
+
x: isNumber(uploadEdits.focalPoint.x) ? Math.round(uploadEdits.focalPoint.x) : 50,
|
|
82
|
+
y: isNumber(uploadEdits.focalPoint.y) ? Math.round(uploadEdits.focalPoint.y) : 50
|
|
83
|
+
} : undefined;
|
|
84
|
+
const sizeResults = await mapWithBoundedConcurrency(variants, async (rawConfig)=>{
|
|
85
|
+
const imageResizeConfig = sanitizeResizeConfig(rawConfig);
|
|
86
|
+
const fieldPath = `variants.${imageResizeConfig.name}`;
|
|
87
|
+
const resizeAction = getImageResizeAction({
|
|
88
|
+
dimensions: sizeSourceDimensions,
|
|
89
|
+
hasFocalPoint: Boolean(focalPoint),
|
|
90
|
+
imageResizeConfig
|
|
91
|
+
});
|
|
92
|
+
if (resizeAction === 'omit') {
|
|
93
|
+
return {
|
|
94
|
+
fieldPath
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const sizeResultFile = await transform({
|
|
98
|
+
fieldPath,
|
|
99
|
+
file: sizeSourceFile,
|
|
100
|
+
options: {
|
|
101
|
+
collectionUpload,
|
|
102
|
+
focalPoint: resizeAction === 'resizeWithFocalPoint' ? focalPoint : undefined,
|
|
103
|
+
imageResizeConfig,
|
|
104
|
+
kind: 'size',
|
|
105
|
+
originalDimensions: sizeSourceDimensions
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
return describeResult({
|
|
109
|
+
fieldPath,
|
|
110
|
+
fileSupportsResize: true,
|
|
111
|
+
resultFile: sizeResultFile,
|
|
112
|
+
sharpDependency
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
results.push(...sizeResults);
|
|
116
|
+
}
|
|
117
|
+
return results;
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
async function describeResult({ fieldPath, fileSupportsResize, resultFile, sharpDependency }) {
|
|
121
|
+
if (!fileSupportsResize) {
|
|
122
|
+
return {
|
|
123
|
+
fieldPath,
|
|
124
|
+
file: resultFile,
|
|
125
|
+
mimeType: resultFile.type
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const meta = await tryProbe(resultFile, sharpDependency);
|
|
129
|
+
if (!meta) {
|
|
130
|
+
return {
|
|
131
|
+
fieldPath,
|
|
132
|
+
file: resultFile,
|
|
133
|
+
mimeType: resultFile.type
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
// `tryProbe` never sets `animated: true`, so `meta.height` is already the
|
|
137
|
+
// single-frame height — do not divide by page count here.
|
|
138
|
+
return {
|
|
139
|
+
fieldPath,
|
|
140
|
+
file: resultFile,
|
|
141
|
+
height: meta.height,
|
|
142
|
+
mimeType: resultFile.type,
|
|
143
|
+
width: meta.width
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
//# sourceMappingURL=prepareLegacyUpload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/prepareLegacyUpload.ts"],"sourcesContent":["import type { FocalPoint, ProbedImageSize } from 'payload'\nimport type { PreparedUploadTransformation, UploadTransformerInternal } from 'payload/internal'\n\nimport { isNumber } from 'payload/shared'\n\nimport type { SharpCollectionConfig, SharpDependency, SharpUploadTaskOptions } from './types.js'\n\nimport { canResizeImage } from './canResizeImage.js'\nimport { createSharpFromFile } from './createSharpFromFile.js'\nimport { getImageResizeAction } from './getImageResizeAction.js'\nimport { mapWithBoundedConcurrency } from './mapWithBoundedConcurrency.js'\nimport { sanitizeResizeConfig } from './sanitizeResizeConfig.js'\n\n/**\n * Sharp throws on truncated/header-only files. Returns `undefined` instead —\n * matching core's dependency-free probe — since unreadable dimensions shouldn't fail the upload.\n */\nasync function tryProbe(file: File, sharpDependency: SharpDependency) {\n try {\n const sharpFile = await createSharpFromFile({ file, sharpDependency })\n const metadata = await sharpFile.metadata()\n return metadata.width && metadata.height ? metadata : undefined\n } catch {\n return undefined\n }\n}\n\n/**\n * Computes the legacy upload tasks (the main file, optionally cropped, and every\n * configured legacy image size) and hands each to the injected `transform` callback\n * exactly once. Reads the Sharp-owned config from `sharpTransformer({ collections })`\n * at factory-construction time — not from the sanitized collection, which only gets\n * the narrowed projection `init()` writes back.\n */\nexport function createPrepareLegacyUpload({\n collections,\n sharpDependency,\n}: {\n collections: Partial<Record<string, SharpCollectionConfig>>\n sharpDependency: SharpDependency\n}): NonNullable<UploadTransformerInternal['prepareUpload']> {\n return async ({ collectionSlug, file, req, transform, uploadEdits }) => {\n const collectionUpload = collections[collectionSlug] ?? {}\n\n const fileSupportsResize = canResizeImage(file.type)\n\n const cropData =\n uploadEdits && typeof uploadEdits === 'object' && 'crop' in uploadEdits\n ? uploadEdits.crop\n : undefined\n\n let originalDimensions: ProbedImageSize | undefined\n\n if (fileSupportsResize) {\n const originalMeta = await tryProbe(file, sharpDependency)\n if (originalMeta) {\n originalDimensions = { height: originalMeta.height, width: originalMeta.width }\n }\n }\n\n // Unreadable dimensions can't be cropped/resized — treat as non-resizable rather than failing the upload.\n const canProcessAsImage = fileSupportsResize && originalDimensions !== undefined\n\n const crop =\n cropData && originalDimensions\n ? {\n cropData,\n heightInPixels: uploadEdits.heightInPixels!,\n originalDimensions,\n widthInPixels: uploadEdits.widthInPixels!,\n }\n : undefined\n\n const mainResultFile = await transform({\n fieldPath: 'filename',\n options: { collectionUpload, crop, kind: 'main' } satisfies SharpUploadTaskOptions,\n })\n\n const mainResult = await describeResult({\n fieldPath: 'filename',\n fileSupportsResize: canProcessAsImage,\n resultFile: mainResultFile,\n sharpDependency,\n })\n\n const results: PreparedUploadTransformation[] = [mainResult]\n\n // A cropped upload derives its sizes from the crop output, not the original.\n const isCropped = Boolean(crop && mainResult.width && mainResult.height)\n const sizeSourceFile = isCropped ? mainResultFile : undefined\n const sizeSourceDimensions: ProbedImageSize | undefined = isCropped\n ? { height: mainResult.height!, width: mainResult.width! }\n : originalDimensions\n\n // Same precedence `init()` applies: Sharp's setting, else the collection's own `focalPoint`.\n const effectiveFocalPoint =\n collectionUpload.focalPoint ??\n req.payload.collections[collectionSlug]?.config.upload?.focalPoint\n const focalPointEnabled = effectiveFocalPoint !== false\n const variants = collectionUpload.variants\n\n if (canProcessAsImage && Array.isArray(variants) && sizeSourceDimensions) {\n const focalPoint: FocalPoint | undefined =\n focalPointEnabled && uploadEdits?.focalPoint\n ? {\n x: isNumber(uploadEdits.focalPoint.x) ? Math.round(uploadEdits.focalPoint.x) : 50,\n y: isNumber(uploadEdits.focalPoint.y) ? Math.round(uploadEdits.focalPoint.y) : 50,\n }\n : undefined\n\n const sizeResults = await mapWithBoundedConcurrency(variants, async (rawConfig) => {\n const imageResizeConfig = sanitizeResizeConfig(rawConfig)\n const fieldPath = `variants.${imageResizeConfig.name}` as const\n\n const resizeAction = getImageResizeAction({\n dimensions: sizeSourceDimensions,\n hasFocalPoint: Boolean(focalPoint),\n imageResizeConfig,\n })\n\n if (resizeAction === 'omit') {\n return { fieldPath } satisfies PreparedUploadTransformation\n }\n\n const sizeResultFile = await transform({\n fieldPath,\n file: sizeSourceFile,\n options: {\n collectionUpload,\n focalPoint: resizeAction === 'resizeWithFocalPoint' ? focalPoint : undefined,\n imageResizeConfig,\n kind: 'size',\n originalDimensions: sizeSourceDimensions,\n } satisfies SharpUploadTaskOptions,\n })\n\n return describeResult({\n fieldPath,\n fileSupportsResize: true,\n resultFile: sizeResultFile,\n sharpDependency,\n })\n })\n\n results.push(...sizeResults)\n }\n\n return results\n }\n}\n\nasync function describeResult({\n fieldPath,\n fileSupportsResize,\n resultFile,\n sharpDependency,\n}: {\n fieldPath: PreparedUploadTransformation['fieldPath']\n fileSupportsResize: boolean\n resultFile: File\n sharpDependency: SharpDependency\n}): Promise<PreparedUploadTransformation> {\n if (!fileSupportsResize) {\n return { fieldPath, file: resultFile, mimeType: resultFile.type }\n }\n\n const meta = await tryProbe(resultFile, sharpDependency)\n\n if (!meta) {\n return { fieldPath, file: resultFile, mimeType: resultFile.type }\n }\n\n // `tryProbe` never sets `animated: true`, so `meta.height` is already the\n // single-frame height — do not divide by page count here.\n return {\n fieldPath,\n file: resultFile,\n height: meta.height,\n mimeType: resultFile.type,\n width: meta.width,\n }\n}\n"],"names":["isNumber","canResizeImage","createSharpFromFile","getImageResizeAction","mapWithBoundedConcurrency","sanitizeResizeConfig","tryProbe","file","sharpDependency","sharpFile","metadata","width","height","undefined","createPrepareLegacyUpload","collections","collectionSlug","req","transform","uploadEdits","collectionUpload","fileSupportsResize","type","cropData","crop","originalDimensions","originalMeta","canProcessAsImage","heightInPixels","widthInPixels","mainResultFile","fieldPath","options","kind","mainResult","describeResult","resultFile","results","isCropped","Boolean","sizeSourceFile","sizeSourceDimensions","effectiveFocalPoint","focalPoint","payload","config","upload","focalPointEnabled","variants","Array","isArray","x","Math","round","y","sizeResults","rawConfig","imageResizeConfig","name","resizeAction","dimensions","hasFocalPoint","sizeResultFile","push","mimeType","meta"],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { createPrepareLegacyUpload } from './prepareLegacyUpload.js';
|
|
3
|
+
const sharpDependency = ()=>({
|
|
4
|
+
metadata: async ()=>({
|
|
5
|
+
height: 1000,
|
|
6
|
+
width: 1000
|
|
7
|
+
})
|
|
8
|
+
});
|
|
9
|
+
const makeReq = ({ focalPoint })=>({
|
|
10
|
+
payload: {
|
|
11
|
+
collections: {
|
|
12
|
+
media: {
|
|
13
|
+
config: {
|
|
14
|
+
upload: {
|
|
15
|
+
focalPoint
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
const runPrepareUpload = async ({ collectionFocalPoint, sharpConfig })=>{
|
|
23
|
+
const transform = vi.fn(async (_task)=>new File([
|
|
24
|
+
'x'
|
|
25
|
+
], 'image.png', {
|
|
26
|
+
type: 'image/png'
|
|
27
|
+
}));
|
|
28
|
+
await createPrepareLegacyUpload({
|
|
29
|
+
collections: {
|
|
30
|
+
media: sharpConfig
|
|
31
|
+
},
|
|
32
|
+
sharpDependency
|
|
33
|
+
})({
|
|
34
|
+
collectionSlug: 'media',
|
|
35
|
+
file: new File([
|
|
36
|
+
'x'
|
|
37
|
+
], 'image.png', {
|
|
38
|
+
type: 'image/png'
|
|
39
|
+
}),
|
|
40
|
+
req: makeReq({
|
|
41
|
+
focalPoint: collectionFocalPoint
|
|
42
|
+
}),
|
|
43
|
+
transform,
|
|
44
|
+
uploadEdits: {
|
|
45
|
+
focalPoint: {
|
|
46
|
+
x: 10,
|
|
47
|
+
y: 90
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
const sizeTask = transform.mock.calls.map(([task])=>task.options).find((options)=>options.kind === 'size');
|
|
52
|
+
return sizeTask?.kind === 'size' ? sizeTask.focalPoint : undefined;
|
|
53
|
+
};
|
|
54
|
+
const variants = [
|
|
55
|
+
{
|
|
56
|
+
name: 'card',
|
|
57
|
+
height: 200,
|
|
58
|
+
width: 400
|
|
59
|
+
}
|
|
60
|
+
];
|
|
61
|
+
describe('createPrepareLegacyUpload', ()=>{
|
|
62
|
+
it.each([
|
|
63
|
+
{
|
|
64
|
+
collectionFocalPoint: false,
|
|
65
|
+
expected: undefined,
|
|
66
|
+
sharpFocalPoint: undefined
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
collectionFocalPoint: false,
|
|
70
|
+
expected: {
|
|
71
|
+
x: 10,
|
|
72
|
+
y: 90
|
|
73
|
+
},
|
|
74
|
+
sharpFocalPoint: true
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
collectionFocalPoint: undefined,
|
|
78
|
+
expected: {
|
|
79
|
+
x: 10,
|
|
80
|
+
y: 90
|
|
81
|
+
},
|
|
82
|
+
sharpFocalPoint: undefined
|
|
83
|
+
}
|
|
84
|
+
])('should resolve the size focal point from Sharp ($sharpFocalPoint) over the collection ($collectionFocalPoint)', async ({ collectionFocalPoint, expected, sharpFocalPoint })=>{
|
|
85
|
+
expect(await runPrepareUpload({
|
|
86
|
+
collectionFocalPoint,
|
|
87
|
+
sharpConfig: {
|
|
88
|
+
focalPoint: sharpFocalPoint,
|
|
89
|
+
variants
|
|
90
|
+
}
|
|
91
|
+
})).toEqual(expected);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
//# sourceMappingURL=prepareLegacyUpload.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/prepareLegacyUpload.spec.ts"],"sourcesContent":["import type { PayloadRequest, UploadEdits } from 'payload'\nimport type { UploadTransformTask } from 'payload/internal'\n\nimport { describe, expect, it, vi } from 'vitest'\n\nimport type { SharpCollectionConfig, SharpDependency, SharpUploadTaskOptions } from './types.js'\n\nimport { createPrepareLegacyUpload } from './prepareLegacyUpload.js'\n\nconst sharpDependency = (() => ({\n metadata: async () => ({ height: 1000, width: 1000 }),\n})) as unknown as SharpDependency\n\nconst makeReq = ({ focalPoint }: { focalPoint?: boolean }): PayloadRequest =>\n ({\n payload: { collections: { media: { config: { upload: { focalPoint } } } } },\n }) as unknown as PayloadRequest\n\nconst runPrepareUpload = async ({\n collectionFocalPoint,\n sharpConfig,\n}: {\n collectionFocalPoint?: boolean\n sharpConfig: SharpCollectionConfig\n}) => {\n const transform = vi.fn(\n async (_task: UploadTransformTask) => new File(['x'], 'image.png', { type: 'image/png' }),\n )\n\n await createPrepareLegacyUpload({ collections: { media: sharpConfig }, sharpDependency })({\n collectionSlug: 'media',\n file: new File(['x'], 'image.png', { type: 'image/png' }),\n req: makeReq({ focalPoint: collectionFocalPoint }),\n transform,\n uploadEdits: { focalPoint: { x: 10, y: 90 } } as UploadEdits,\n })\n\n const sizeTask = transform.mock.calls\n .map(([task]) => task.options as SharpUploadTaskOptions)\n .find((options) => options.kind === 'size')\n\n return sizeTask?.kind === 'size' ? sizeTask.focalPoint : undefined\n}\n\nconst variants = [{ name: 'card', height: 200, width: 400 }]\n\ndescribe('createPrepareLegacyUpload', () => {\n it.each([\n { collectionFocalPoint: false, expected: undefined, sharpFocalPoint: undefined },\n { collectionFocalPoint: false, expected: { x: 10, y: 90 }, sharpFocalPoint: true },\n { collectionFocalPoint: undefined, expected: { x: 10, y: 90 }, sharpFocalPoint: undefined },\n ])(\n 'should resolve the size focal point from Sharp ($sharpFocalPoint) over the collection ($collectionFocalPoint)',\n async ({ collectionFocalPoint, expected, sharpFocalPoint }) => {\n expect(\n await runPrepareUpload({\n collectionFocalPoint,\n sharpConfig: { focalPoint: sharpFocalPoint, variants },\n }),\n ).toEqual(expected)\n },\n )\n})\n"],"names":["describe","expect","it","vi","createPrepareLegacyUpload","sharpDependency","metadata","height","width","makeReq","focalPoint","payload","collections","media","config","upload","runPrepareUpload","collectionFocalPoint","sharpConfig","transform","fn","_task","File","type","collectionSlug","file","req","uploadEdits","x","y","sizeTask","mock","calls","map","task","options","find","kind","undefined","variants","name","each","expected","sharpFocalPoint","toEqual"],"mappings":"AAGA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,EAAEC,EAAE,QAAQ,SAAQ;AAIjD,SAASC,yBAAyB,QAAQ,2BAA0B;AAEpE,MAAMC,kBAAmB,IAAO,CAAA;QAC9BC,UAAU,UAAa,CAAA;gBAAEC,QAAQ;gBAAMC,OAAO;YAAK,CAAA;IACrD,CAAA;AAEA,MAAMC,UAAU,CAAC,EAAEC,UAAU,EAA4B,GACtD,CAAA;QACCC,SAAS;YAAEC,aAAa;gBAAEC,OAAO;oBAAEC,QAAQ;wBAAEC,QAAQ;4BAAEL;wBAAW;oBAAE;gBAAE;YAAE;QAAE;IAC5E,CAAA;AAEF,MAAMM,mBAAmB,OAAO,EAC9BC,oBAAoB,EACpBC,WAAW,EAIZ;IACC,MAAMC,YAAYhB,GAAGiB,EAAE,CACrB,OAAOC,QAA+B,IAAIC,KAAK;YAAC;SAAI,EAAE,aAAa;YAAEC,MAAM;QAAY;IAGzF,MAAMnB,0BAA0B;QAAEQ,aAAa;YAAEC,OAAOK;QAAY;QAAGb;IAAgB,GAAG;QACxFmB,gBAAgB;QAChBC,MAAM,IAAIH,KAAK;YAAC;SAAI,EAAE,aAAa;YAAEC,MAAM;QAAY;QACvDG,KAAKjB,QAAQ;YAAEC,YAAYO;QAAqB;QAChDE;QACAQ,aAAa;YAAEjB,YAAY;gBAAEkB,GAAG;gBAAIC,GAAG;YAAG;QAAE;IAC9C;IAEA,MAAMC,WAAWX,UAAUY,IAAI,CAACC,KAAK,CAClCC,GAAG,CAAC,CAAC,CAACC,KAAK,GAAKA,KAAKC,OAAO,EAC5BC,IAAI,CAAC,CAACD,UAAYA,QAAQE,IAAI,KAAK;IAEtC,OAAOP,UAAUO,SAAS,SAASP,SAASpB,UAAU,GAAG4B;AAC3D;AAEA,MAAMC,WAAW;IAAC;QAAEC,MAAM;QAAQjC,QAAQ;QAAKC,OAAO;IAAI;CAAE;AAE5DR,SAAS,6BAA6B;IACpCE,GAAGuC,IAAI,CAAC;QACN;YAAExB,sBAAsB;YAAOyB,UAAUJ;YAAWK,iBAAiBL;QAAU;QAC/E;YAAErB,sBAAsB;YAAOyB,UAAU;gBAAEd,GAAG;gBAAIC,GAAG;YAAG;YAAGc,iBAAiB;QAAK;QACjF;YAAE1B,sBAAsBqB;YAAWI,UAAU;gBAAEd,GAAG;gBAAIC,GAAG;YAAG;YAAGc,iBAAiBL;QAAU;KAC3F,EACC,iHACA,OAAO,EAAErB,oBAAoB,EAAEyB,QAAQ,EAAEC,eAAe,EAAE;QACxD1C,OACE,MAAMe,iBAAiB;YACrBC;YACAC,aAAa;gBAAER,YAAYiC;gBAAiBJ;YAAS;QACvD,IACAK,OAAO,CAACF;IACZ;AAEJ"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ImageSize } from 'payload';
|
|
2
|
+
/**
|
|
3
|
+
* Sanitize the resize config. If the resize config has the `withoutReduction`
|
|
4
|
+
* property set to true, the `fit` and `position` properties will be set to `contain`
|
|
5
|
+
* and `top left` respectively.
|
|
6
|
+
*
|
|
7
|
+
* @param resizeConfig - the resize config
|
|
8
|
+
* @returns a sanitized resize config
|
|
9
|
+
*/
|
|
10
|
+
export declare const sanitizeResizeConfig: (resizeConfig: ImageSize) => ImageSize;
|
|
11
|
+
//# sourceMappingURL=sanitizeResizeConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitizeResizeConfig.d.ts","sourceRoot":"","sources":["../src/sanitizeResizeConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAExC;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,iBAAkB,SAAS,KAAG,SAU9D,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitize the resize config. If the resize config has the `withoutReduction`
|
|
3
|
+
* property set to true, the `fit` and `position` properties will be set to `contain`
|
|
4
|
+
* and `top left` respectively.
|
|
5
|
+
*
|
|
6
|
+
* @param resizeConfig - the resize config
|
|
7
|
+
* @returns a sanitized resize config
|
|
8
|
+
*/ export const sanitizeResizeConfig = (resizeConfig)=>{
|
|
9
|
+
if (resizeConfig.withoutReduction) {
|
|
10
|
+
return {
|
|
11
|
+
...resizeConfig,
|
|
12
|
+
// Why fit `contain` should also be set to https://github.com/lovell/sharp/issues/3595
|
|
13
|
+
fit: resizeConfig?.fit || 'contain',
|
|
14
|
+
position: resizeConfig?.position || 'left top'
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
return resizeConfig;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=sanitizeResizeConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sanitizeResizeConfig.ts"],"sourcesContent":["import type { ImageSize } from 'payload'\n\n/**\n * Sanitize the resize config. If the resize config has the `withoutReduction`\n * property set to true, the `fit` and `position` properties will be set to `contain`\n * and `top left` respectively.\n *\n * @param resizeConfig - the resize config\n * @returns a sanitized resize config\n */\nexport const sanitizeResizeConfig = (resizeConfig: ImageSize): ImageSize => {\n if (resizeConfig.withoutReduction) {\n return {\n ...resizeConfig,\n // Why fit `contain` should also be set to https://github.com/lovell/sharp/issues/3595\n fit: resizeConfig?.fit || 'contain',\n position: resizeConfig?.position || 'left top',\n }\n }\n return resizeConfig\n}\n"],"names":["sanitizeResizeConfig","resizeConfig","withoutReduction","fit","position"],"mappings":"AAEA;;;;;;;CAOC,GACD,OAAO,MAAMA,uBAAuB,CAACC;IACnC,IAAIA,aAAaC,gBAAgB,EAAE;QACjC,OAAO;YACL,GAAGD,YAAY;YACf,sFAAsF;YACtFE,KAAKF,cAAcE,OAAO;YAC1BC,UAAUH,cAAcG,YAAY;QACtC;IACF;IACA,OAAOH;AACT,EAAC"}
|