payload 4.0.0-internal.cd69eef → 4.0.0-internal.d1cc1d3

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 (279) hide show
  1. package/dist/admin/RichText.d.ts +1 -1
  2. package/dist/admin/RichText.d.ts.map +1 -1
  3. package/dist/admin/RichText.js.map +1 -1
  4. package/dist/admin/functions/index.d.ts +10 -8
  5. package/dist/admin/functions/index.d.ts.map +1 -1
  6. package/dist/admin/functions/index.js.map +1 -1
  7. package/dist/admin/types.d.ts +2 -2
  8. package/dist/admin/types.d.ts.map +1 -1
  9. package/dist/admin/types.js.map +1 -1
  10. package/dist/auth/endpoints/login.d.ts.map +1 -1
  11. package/dist/auth/endpoints/login.js +2 -11
  12. package/dist/auth/endpoints/login.js.map +1 -1
  13. package/dist/auth/loginWithCookie.d.ts +33 -0
  14. package/dist/auth/loginWithCookie.d.ts.map +1 -0
  15. package/dist/auth/loginWithCookie.js +34 -0
  16. package/dist/auth/loginWithCookie.js.map +1 -0
  17. package/dist/auth/serverFunctions/cookies.d.ts +47 -0
  18. package/dist/auth/serverFunctions/cookies.d.ts.map +1 -0
  19. package/dist/auth/serverFunctions/cookies.js +52 -0
  20. package/dist/auth/serverFunctions/cookies.js.map +1 -0
  21. package/dist/auth/serverFunctions/login.d.ts +29 -0
  22. package/dist/auth/serverFunctions/login.d.ts.map +1 -0
  23. package/dist/auth/serverFunctions/login.js +63 -0
  24. package/dist/auth/serverFunctions/login.js.map +1 -0
  25. package/dist/auth/serverFunctions/logout.d.ts +17 -0
  26. package/dist/auth/serverFunctions/logout.d.ts.map +1 -0
  27. package/dist/auth/serverFunctions/logout.js +58 -0
  28. package/dist/auth/serverFunctions/logout.js.map +1 -0
  29. package/dist/auth/serverFunctions/refresh.d.ts +17 -0
  30. package/dist/auth/serverFunctions/refresh.d.ts.map +1 -0
  31. package/dist/auth/serverFunctions/refresh.js +61 -0
  32. package/dist/auth/serverFunctions/refresh.js.map +1 -0
  33. package/dist/collections/config/client.d.ts +2 -3
  34. package/dist/collections/config/client.d.ts.map +1 -1
  35. package/dist/collections/config/client.js +5 -7
  36. package/dist/collections/config/client.js.map +1 -1
  37. package/dist/collections/config/defaults.d.ts.map +1 -1
  38. package/dist/collections/config/defaults.js +1 -0
  39. package/dist/collections/config/defaults.js.map +1 -1
  40. package/dist/collections/config/sanitize.d.ts +3 -8
  41. package/dist/collections/config/sanitize.d.ts.map +1 -1
  42. package/dist/collections/config/sanitize.js +2 -6
  43. package/dist/collections/config/sanitize.js.map +1 -1
  44. package/dist/collections/config/types.d.ts +1 -1
  45. package/dist/collections/config/types.d.ts.map +1 -1
  46. package/dist/collections/config/types.js.map +1 -1
  47. package/dist/collections/config/useAsTitle.spec.js +27 -27
  48. package/dist/collections/config/useAsTitle.spec.js.map +1 -1
  49. package/dist/collections/operations/create.d.ts.map +1 -1
  50. package/dist/collections/operations/create.js +10 -0
  51. package/dist/collections/operations/create.js.map +1 -1
  52. package/dist/collections/operations/restoreVersion.d.ts.map +1 -1
  53. package/dist/collections/operations/restoreVersion.js +7 -4
  54. package/dist/collections/operations/restoreVersion.js.map +1 -1
  55. package/dist/collections/operations/updateByID.js +1 -0
  56. package/dist/collections/operations/updateByID.js.map +1 -1
  57. package/dist/config/build.js +1 -1
  58. package/dist/config/build.js.map +1 -1
  59. package/dist/config/defaults.d.ts.map +1 -1
  60. package/dist/config/defaults.js +5 -2
  61. package/dist/config/defaults.js.map +1 -1
  62. package/dist/config/orderable/index.d.ts +1 -1
  63. package/dist/config/orderable/index.d.ts.map +1 -1
  64. package/dist/config/orderable/index.js +2 -2
  65. package/dist/config/orderable/index.js.map +1 -1
  66. package/dist/config/sanitize.d.ts +1 -1
  67. package/dist/config/sanitize.d.ts.map +1 -1
  68. package/dist/config/sanitize.js +33 -40
  69. package/dist/config/sanitize.js.map +1 -1
  70. package/dist/config/types.d.ts +1 -1
  71. package/dist/config/types.js.map +1 -1
  72. package/dist/database/createDatabaseAdapter.d.ts +1 -1
  73. package/dist/database/createDatabaseAdapter.d.ts.map +1 -1
  74. package/dist/database/createDatabaseAdapter.js +0 -2
  75. package/dist/database/createDatabaseAdapter.js.map +1 -1
  76. package/dist/database/types.d.ts +6 -0
  77. package/dist/database/types.d.ts.map +1 -1
  78. package/dist/database/types.js.map +1 -1
  79. package/dist/exports/auth.d.ts +5 -0
  80. package/dist/exports/auth.d.ts.map +1 -0
  81. package/dist/exports/auth.js +6 -0
  82. package/dist/exports/auth.js.map +1 -0
  83. package/dist/exports/internal.d.ts +2 -0
  84. package/dist/exports/internal.d.ts.map +1 -1
  85. package/dist/exports/internal.js +3 -1
  86. package/dist/exports/internal.js.map +1 -1
  87. package/dist/fields/baseFields/slug/duplicateContext.d.ts +11 -0
  88. package/dist/fields/baseFields/slug/duplicateContext.d.ts.map +1 -0
  89. package/dist/fields/baseFields/slug/duplicateContext.js +21 -0
  90. package/dist/fields/baseFields/slug/duplicateContext.js.map +1 -0
  91. package/dist/fields/baseFields/slug/fillEmptyLocalizedSlugs.d.ts +22 -0
  92. package/dist/fields/baseFields/slug/fillEmptyLocalizedSlugs.d.ts.map +1 -0
  93. package/dist/fields/baseFields/slug/fillEmptyLocalizedSlugs.js +63 -0
  94. package/dist/fields/baseFields/slug/fillEmptyLocalizedSlugs.js.map +1 -0
  95. package/dist/fields/baseFields/slug/generateSlug.d.ts +13 -8
  96. package/dist/fields/baseFields/slug/generateSlug.d.ts.map +1 -1
  97. package/dist/fields/baseFields/slug/generateSlug.js +98 -45
  98. package/dist/fields/baseFields/slug/generateSlug.js.map +1 -1
  99. package/dist/fields/baseFields/slug/generateSlugBeforeDuplicate.d.ts +18 -0
  100. package/dist/fields/baseFields/slug/generateSlugBeforeDuplicate.d.ts.map +1 -0
  101. package/dist/fields/baseFields/slug/generateSlugBeforeDuplicate.js +20 -0
  102. package/dist/fields/baseFields/slug/generateSlugBeforeDuplicate.js.map +1 -0
  103. package/dist/fields/baseFields/slug/getSlugFallbackValue.d.ts +22 -0
  104. package/dist/fields/baseFields/slug/getSlugFallbackValue.d.ts.map +1 -0
  105. package/dist/fields/baseFields/slug/getSlugFallbackValue.js +23 -0
  106. package/dist/fields/baseFields/slug/getSlugFallbackValue.js.map +1 -0
  107. package/dist/fields/baseFields/slug/hasValue.d.ts +3 -0
  108. package/dist/fields/baseFields/slug/hasValue.d.ts.map +1 -0
  109. package/dist/fields/baseFields/slug/hasValue.js +3 -0
  110. package/dist/fields/baseFields/slug/hasValue.js.map +1 -0
  111. package/dist/fields/config/reservedFieldNames.spec.js +18 -18
  112. package/dist/fields/config/reservedFieldNames.spec.js.map +1 -1
  113. package/dist/fields/config/sanitize.d.ts +3 -9
  114. package/dist/fields/config/sanitize.d.ts.map +1 -1
  115. package/dist/fields/config/sanitize.js +33 -34
  116. package/dist/fields/config/sanitize.js.map +1 -1
  117. package/dist/fields/config/sanitize.spec.js +128 -105
  118. package/dist/fields/config/sanitize.spec.js.map +1 -1
  119. package/dist/fields/config/types.d.ts +4 -3
  120. package/dist/fields/config/types.d.ts.map +1 -1
  121. package/dist/fields/config/types.js.map +1 -1
  122. package/dist/fields/hooks/beforeValidate/promise.d.ts.map +1 -1
  123. package/dist/fields/hooks/beforeValidate/promise.js +5 -3
  124. package/dist/fields/hooks/beforeValidate/promise.js.map +1 -1
  125. package/dist/fields/hooks/beforeValidate/stripNullRows.d.ts +10 -0
  126. package/dist/fields/hooks/beforeValidate/stripNullRows.d.ts.map +1 -0
  127. package/dist/fields/hooks/beforeValidate/stripNullRows.js +18 -0
  128. package/dist/fields/hooks/beforeValidate/stripNullRows.js.map +1 -0
  129. package/dist/fields/validations.d.ts.map +1 -1
  130. package/dist/fields/validations.js +7 -8
  131. package/dist/fields/validations.js.map +1 -1
  132. package/dist/fields/validations.spec.js +61 -37
  133. package/dist/fields/validations.spec.js.map +1 -1
  134. package/dist/globals/config/sanitize.d.ts +2 -7
  135. package/dist/globals/config/sanitize.d.ts.map +1 -1
  136. package/dist/globals/config/sanitize.js +2 -6
  137. package/dist/globals/config/sanitize.js.map +1 -1
  138. package/dist/globals/config/sanitize.spec.js +6 -6
  139. package/dist/globals/config/sanitize.spec.js.map +1 -1
  140. package/dist/globals/operations/countGlobalVersions.d.ts.map +1 -1
  141. package/dist/globals/operations/countGlobalVersions.js +1 -0
  142. package/dist/globals/operations/countGlobalVersions.js.map +1 -1
  143. package/dist/index.bundled.d.ts +247 -178
  144. package/dist/index.d.ts +49 -17
  145. package/dist/index.d.ts.map +1 -1
  146. package/dist/index.js +3 -0
  147. package/dist/index.js.map +1 -1
  148. package/dist/query-presets/constraints.js +1 -1
  149. package/dist/query-presets/constraints.js.map +1 -1
  150. package/dist/queues/config/collection.d.ts.map +1 -1
  151. package/dist/queues/config/collection.js +37 -43
  152. package/dist/queues/config/collection.js.map +1 -1
  153. package/dist/queues/config/global.d.ts +5 -6
  154. package/dist/queues/config/global.d.ts.map +1 -1
  155. package/dist/queues/config/global.js +1 -1
  156. package/dist/queues/config/global.js.map +1 -1
  157. package/dist/queues/config/types/index.d.ts +29 -24
  158. package/dist/queues/config/types/index.d.ts.map +1 -1
  159. package/dist/queues/config/types/index.js.map +1 -1
  160. package/dist/queues/config/types/taskTypes.d.ts +4 -7
  161. package/dist/queues/config/types/taskTypes.d.ts.map +1 -1
  162. package/dist/queues/config/types/taskTypes.js.map +1 -1
  163. package/dist/queues/config/types/workflowJSONTypes.d.ts +10 -9
  164. package/dist/queues/config/types/workflowJSONTypes.d.ts.map +1 -1
  165. package/dist/queues/config/types/workflowJSONTypes.js.map +1 -1
  166. package/dist/queues/config/types/workflowTypes.d.ts +11 -58
  167. package/dist/queues/config/types/workflowTypes.d.ts.map +1 -1
  168. package/dist/queues/config/types/workflowTypes.js.map +1 -1
  169. package/dist/queues/endpoints/handleSchedules.js +1 -1
  170. package/dist/queues/endpoints/handleSchedules.js.map +1 -1
  171. package/dist/queues/errors/handleTaskError.js +4 -4
  172. package/dist/queues/errors/handleTaskError.js.map +1 -1
  173. package/dist/queues/errors/handleWorkflowError.js +1 -1
  174. package/dist/queues/errors/handleWorkflowError.js.map +1 -1
  175. package/dist/queues/errors/index.d.ts +6 -0
  176. package/dist/queues/errors/index.d.ts.map +1 -1
  177. package/dist/queues/errors/index.js +5 -0
  178. package/dist/queues/errors/index.js.map +1 -1
  179. package/dist/queues/localAPI.d.ts +4 -4
  180. package/dist/queues/localAPI.d.ts.map +1 -1
  181. package/dist/queues/localAPI.js +63 -66
  182. package/dist/queues/localAPI.js.map +1 -1
  183. package/dist/queues/operations/handleSchedules/countRunnableOrActiveJobsForQueue.d.ts +4 -4
  184. package/dist/queues/operations/handleSchedules/countRunnableOrActiveJobsForQueue.d.ts.map +1 -1
  185. package/dist/queues/operations/handleSchedules/countRunnableOrActiveJobsForQueue.js.map +1 -1
  186. package/dist/queues/operations/handleSchedules/index.d.ts +1 -1
  187. package/dist/queues/operations/handleSchedules/index.d.ts.map +1 -1
  188. package/dist/queues/operations/handleSchedules/index.js +1 -1
  189. package/dist/queues/operations/handleSchedules/index.js.map +1 -1
  190. package/dist/queues/operations/runJobs/heartbeat.d.ts +13 -0
  191. package/dist/queues/operations/runJobs/heartbeat.d.ts.map +1 -0
  192. package/dist/queues/operations/runJobs/heartbeat.js +66 -0
  193. package/dist/queues/operations/runJobs/heartbeat.js.map +1 -0
  194. package/dist/queues/operations/runJobs/index.d.ts.map +1 -1
  195. package/dist/queues/operations/runJobs/index.js +133 -84
  196. package/dist/queues/operations/runJobs/index.js.map +1 -1
  197. package/dist/queues/operations/runJobs/runJSONJob/index.d.ts.map +1 -1
  198. package/dist/queues/operations/runJobs/runJSONJob/index.js +6 -3
  199. package/dist/queues/operations/runJobs/runJSONJob/index.js.map +1 -1
  200. package/dist/queues/operations/runJobs/runJob/getRunTaskFunction.js +5 -5
  201. package/dist/queues/operations/runJobs/runJob/getRunTaskFunction.js.map +1 -1
  202. package/dist/queues/operations/runJobs/runJob/getUpdateJobFunction.d.ts +2 -1
  203. package/dist/queues/operations/runJobs/runJob/getUpdateJobFunction.d.ts.map +1 -1
  204. package/dist/queues/operations/runJobs/runJob/getUpdateJobFunction.js +39 -8
  205. package/dist/queues/operations/runJobs/runJob/getUpdateJobFunction.js.map +1 -1
  206. package/dist/queues/operations/runJobs/runJob/importHandlerPath.js.map +1 -1
  207. package/dist/queues/operations/runJobs/runJob/index.d.ts.map +1 -1
  208. package/dist/queues/operations/runJobs/runJob/index.js +4 -4
  209. package/dist/queues/operations/runJobs/runJob/index.js.map +1 -1
  210. package/dist/queues/utilities/updateJob.d.ts.map +1 -1
  211. package/dist/queues/utilities/updateJob.js +3 -0
  212. package/dist/queues/utilities/updateJob.js.map +1 -1
  213. package/dist/types/index.d.ts +2 -2
  214. package/dist/types/index.d.ts.map +1 -1
  215. package/dist/types/index.js.map +1 -1
  216. package/dist/uploads/checkFileRestrictions.d.ts +1 -1
  217. package/dist/uploads/checkFileRestrictions.d.ts.map +1 -1
  218. package/dist/uploads/checkFileRestrictions.js +15 -1
  219. package/dist/uploads/checkFileRestrictions.js.map +1 -1
  220. package/dist/uploads/endpoints/uploadInstructions.d.ts +12 -0
  221. package/dist/uploads/endpoints/uploadInstructions.d.ts.map +1 -1
  222. package/dist/uploads/endpoints/uploadInstructions.js +66 -20
  223. package/dist/uploads/endpoints/uploadInstructions.js.map +1 -1
  224. package/dist/uploads/generateFileData.js +4 -1
  225. package/dist/uploads/generateFileData.js.map +1 -1
  226. package/dist/uploads/getFileFromUploadInstructions.d.ts +8 -0
  227. package/dist/uploads/getFileFromUploadInstructions.d.ts.map +1 -0
  228. package/dist/uploads/getFileFromUploadInstructions.js +62 -0
  229. package/dist/uploads/getFileFromUploadInstructions.js.map +1 -0
  230. package/dist/uploads/getImageSize.d.ts +12 -1
  231. package/dist/uploads/getImageSize.d.ts.map +1 -1
  232. package/dist/uploads/getImageSize.js +20 -18
  233. package/dist/uploads/getImageSize.js.map +1 -1
  234. package/dist/uploads/getImageSize.spec.js +298 -0
  235. package/dist/uploads/getImageSize.spec.js.map +1 -0
  236. package/dist/uploads/probeImageSize.d.ts +39 -0
  237. package/dist/uploads/probeImageSize.d.ts.map +1 -0
  238. package/dist/uploads/probeImageSize.js +374 -0
  239. package/dist/uploads/probeImageSize.js.map +1 -0
  240. package/dist/uploads/probeImageSize.spec.js +366 -0
  241. package/dist/uploads/probeImageSize.spec.js.map +1 -0
  242. package/dist/uploads/stagedUpload.d.ts +27 -0
  243. package/dist/uploads/stagedUpload.d.ts.map +1 -0
  244. package/dist/uploads/stagedUpload.js +197 -0
  245. package/dist/uploads/stagedUpload.js.map +1 -0
  246. package/dist/uploads/types.d.ts +41 -13
  247. package/dist/uploads/types.d.ts.map +1 -1
  248. package/dist/uploads/types.js.map +1 -1
  249. package/dist/utilities/addDataAndFileToRequest.d.ts.map +1 -1
  250. package/dist/utilities/addDataAndFileToRequest.js +12 -46
  251. package/dist/utilities/addDataAndFileToRequest.js.map +1 -1
  252. package/dist/utilities/configToJSONSchema.spec.js +33 -33
  253. package/dist/utilities/configToJSONSchema.spec.js.map +1 -1
  254. package/dist/utilities/fieldValueExists.d.ts +29 -0
  255. package/dist/utilities/fieldValueExists.d.ts.map +1 -0
  256. package/dist/utilities/fieldValueExists.js +27 -0
  257. package/dist/utilities/fieldValueExists.js.map +1 -0
  258. package/dist/utilities/getUniqueFieldValue.d.ts +27 -0
  259. package/dist/utilities/getUniqueFieldValue.d.ts.map +1 -0
  260. package/dist/utilities/getUniqueFieldValue.js +26 -0
  261. package/dist/utilities/getUniqueFieldValue.js.map +1 -0
  262. package/dist/versions/deleteScheduledPublishJobs.js +2 -2
  263. package/dist/versions/deleteScheduledPublishJobs.js.map +1 -1
  264. package/dist/versions/payloadPackageList.d.ts.map +1 -1
  265. package/dist/versions/payloadPackageList.js +0 -1
  266. package/dist/versions/payloadPackageList.js.map +1 -1
  267. package/package.json +8 -3
  268. package/dist/database/defaultUpdateJobs.d.ts +0 -3
  269. package/dist/database/defaultUpdateJobs.d.ts.map +0 -1
  270. package/dist/database/defaultUpdateJobs.js +0 -41
  271. package/dist/database/defaultUpdateJobs.js.map +0 -1
  272. package/dist/fields/baseFields/slug/countVersions.d.ts +0 -13
  273. package/dist/fields/baseFields/slug/countVersions.d.ts.map +0 -1
  274. package/dist/fields/baseFields/slug/countVersions.js +0 -27
  275. package/dist/fields/baseFields/slug/countVersions.js.map +0 -1
  276. package/dist/uploads/tempFile.d.ts +0 -7
  277. package/dist/uploads/tempFile.d.ts.map +0 -1
  278. package/dist/uploads/tempFile.js +0 -39
  279. package/dist/uploads/tempFile.js.map +0 -1
@@ -0,0 +1,298 @@
1
+ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'fs';
2
+ import os from 'os';
3
+ import path from 'path';
4
+ import sharp from 'sharp';
5
+ import { fileURLToPath } from 'url';
6
+ import { afterAll, afterEach, describe, expect, it, vi } from 'vitest';
7
+ import { getImageSize } from './getImageSize.js';
8
+ // Tracks bytes actually read off disk so the streaming test below can assert
9
+ // that a large file's tail is never pulled into memory
10
+ const counters = vi.hoisted(()=>({
11
+ bytesReadFromDisk: 0
12
+ }));
13
+ vi.mock('fs', async (importOriginal)=>{
14
+ const actual = await importOriginal();
15
+ return {
16
+ ...actual,
17
+ createReadStream: (...args)=>{
18
+ const stream = actual.createReadStream(...args);
19
+ stream.on('data', (chunk)=>{
20
+ counters.bytesReadFromDisk += chunk.length;
21
+ });
22
+ return stream;
23
+ }
24
+ };
25
+ });
26
+ const dirname = path.dirname(fileURLToPath(import.meta.url));
27
+ const fixturesDir = path.resolve(dirname, '../../../../test/uploads');
28
+ // Minimal JPEG XL bare-codestream encoder (bit-packed, little-endian, LSB
29
+ // first). See probeImageSize.spec.ts for the full JXL parsing test suite;
30
+ // this only needs to produce a valid header for the sharp-fallback tests below
31
+ const encodeJXLCodestream = (width, height)=>{
32
+ const bits = [];
33
+ const pushBits = (value, length)=>{
34
+ for(let i = 0; i < length; i++){
35
+ bits.push(value >> i & 1);
36
+ }
37
+ };
38
+ const pushDimension = (value)=>{
39
+ const n = value - 1;
40
+ const sizeClasses = [
41
+ 9,
42
+ 13,
43
+ 18,
44
+ 30
45
+ ];
46
+ const classIndex = sizeClasses.findIndex((extraBits)=>n < 2 ** extraBits);
47
+ pushBits(classIndex, 2);
48
+ pushBits(n, sizeClasses[classIndex]);
49
+ };
50
+ pushBits(0, 1); // isSmallImage = false
51
+ pushDimension(height);
52
+ pushBits(0, 3); // widthMode = 0 (explicit dimension)
53
+ pushDimension(width);
54
+ const body = Buffer.alloc(Math.ceil(bits.length / 8));
55
+ bits.forEach((bit, i)=>{
56
+ if (bit) {
57
+ body[Math.floor(i / 8)] |= 1 << i % 8;
58
+ }
59
+ });
60
+ return Buffer.concat([
61
+ Buffer.from([
62
+ 0xff,
63
+ 0x0a
64
+ ]),
65
+ body
66
+ ]);
67
+ };
68
+ const fileFor = (name)=>{
69
+ const data = readFileSync(path.join(fixturesDir, name));
70
+ // In-memory uploads carry an empty `tempFilePath`, which must fall back to `data`
71
+ return {
72
+ data,
73
+ mimetype: 'image/test',
74
+ name,
75
+ size: data.length,
76
+ tempFilePath: ''
77
+ };
78
+ };
79
+ describe('getImageSize', ()=>{
80
+ const cases = [
81
+ {
82
+ file: 'test-image.png',
83
+ height: 800,
84
+ width: 800
85
+ },
86
+ {
87
+ file: 'test-image.jpg',
88
+ height: 800,
89
+ width: 800
90
+ },
91
+ {
92
+ file: 'non-animated.webp',
93
+ height: 420,
94
+ width: 900
95
+ },
96
+ {
97
+ file: 'test-image-avif.avif',
98
+ height: 800,
99
+ width: 800
100
+ },
101
+ {
102
+ file: 'image.svg',
103
+ height: 260,
104
+ width: 260
105
+ }
106
+ ];
107
+ it.each(cases)('should read $file dimensions via sharp', async ({ file, height, width })=>{
108
+ expect(await getImageSize({
109
+ file: fileFor(file),
110
+ sharp
111
+ })).toEqual({
112
+ height,
113
+ width
114
+ });
115
+ });
116
+ it.each(cases)('should read $file dimensions via the probe fallback', async ({ file, height, width })=>{
117
+ expect(await getImageSize({
118
+ file: fileFor(file)
119
+ })).toEqual({
120
+ height,
121
+ width
122
+ });
123
+ });
124
+ it('should fall back to the probe when sharp cannot decode a header-only image', async ()=>{
125
+ // A 1x1 PNG truncated after IHDR: the header is readable but there is no
126
+ // pixel data, so sharp throws while the probe still measures it.
127
+ const data = Buffer.from('89504e470d0a1a0a0000000d49484452000000010000000108060000001f15c489', 'hex');
128
+ const file = {
129
+ data,
130
+ mimetype: 'image/png',
131
+ name: 'truncated.png',
132
+ size: data.length,
133
+ tempFilePath: ''
134
+ };
135
+ expect(await getImageSize({
136
+ file,
137
+ sharp
138
+ })).toEqual({
139
+ height: 1,
140
+ width: 1
141
+ });
142
+ expect(await getImageSize({
143
+ file
144
+ })).toEqual({
145
+ height: 1,
146
+ width: 1
147
+ });
148
+ });
149
+ it('should read TIFF dimensions from a tempFilePath without a temp-file workaround', async ()=>{
150
+ const tempFilePath = path.join(fixturesDir, 'test-image.tiff');
151
+ const file = {
152
+ mimetype: 'image/tiff',
153
+ name: 'test-image.tiff',
154
+ tempFilePath
155
+ };
156
+ expect(await getImageSize({
157
+ file,
158
+ sharp
159
+ })).toEqual({
160
+ height: 100,
161
+ width: 200
162
+ });
163
+ expect(await getImageSize({
164
+ file
165
+ })).toEqual({
166
+ height: 100,
167
+ width: 200
168
+ });
169
+ });
170
+ describe('sharp cannot decode JPEG XL', ()=>{
171
+ const tempDir = mkdtempSync(path.join(os.tmpdir(), 'payload-get-image-size-jxl-'));
172
+ afterAll(()=>{
173
+ rmSync(tempDir, {
174
+ recursive: true,
175
+ force: true
176
+ });
177
+ });
178
+ it('should fall back to the probe for an in-memory JPEG XL buffer', async ()=>{
179
+ // `isImage('image/jxl')` is true, so `generateFileData` always calls
180
+ // `getImageSize` with `sharp` for JXL uploads; sharp rejects the format
181
+ // (libvips has no JXL codec) and the probe must take over
182
+ const data = encodeJXLCodestream(1920, 1080);
183
+ const file = {
184
+ data,
185
+ mimetype: 'image/jxl',
186
+ name: 'test.jxl',
187
+ size: data.length,
188
+ tempFilePath: ''
189
+ };
190
+ expect(await getImageSize({
191
+ file,
192
+ sharp
193
+ })).toEqual({
194
+ height: 1080,
195
+ width: 1920
196
+ });
197
+ });
198
+ it('should fall back to the probe for a JPEG XL tempFilePath', async ()=>{
199
+ const tempFilePath = path.join(tempDir, 'test.jxl');
200
+ writeFileSync(tempFilePath, encodeJXLCodestream(640, 480));
201
+ const file = {
202
+ mimetype: 'image/jxl',
203
+ name: 'test.jxl',
204
+ tempFilePath
205
+ };
206
+ expect(await getImageSize({
207
+ file,
208
+ sharp
209
+ })).toEqual({
210
+ height: 480,
211
+ width: 640
212
+ });
213
+ });
214
+ });
215
+ describe('streaming from tempFilePath', ()=>{
216
+ const tempDir = mkdtempSync(path.join(os.tmpdir(), 'payload-get-image-size-'));
217
+ afterEach(()=>{
218
+ counters.bytesReadFromDisk = 0;
219
+ });
220
+ afterAll(()=>{
221
+ rmSync(tempDir, {
222
+ recursive: true,
223
+ force: true
224
+ });
225
+ });
226
+ it('should not read a whole large PNG into memory when probing via tempFilePath', async ()=>{
227
+ // image-dimensions only reads the PNG signature (bytes 0-7) and the
228
+ // width/height fields (bytes 16-23); everything else here is filler
229
+ const header = Buffer.alloc(24);
230
+ header.write('\x89PNG\r\n\x1a\n', 0, 'binary');
231
+ header.writeUInt32BE(1920, 16);
232
+ header.writeUInt32BE(1080, 20);
233
+ const largeFileSize = 3 * 1024 * 1024;
234
+ const largeFile = Buffer.concat([
235
+ header,
236
+ Buffer.alloc(largeFileSize)
237
+ ]);
238
+ const tempFilePath = path.join(tempDir, 'large.png');
239
+ writeFileSync(tempFilePath, largeFile);
240
+ const file = {
241
+ mimetype: 'image/png',
242
+ name: 'large.png',
243
+ tempFilePath
244
+ };
245
+ expect(await getImageSize({
246
+ file
247
+ })).toEqual({
248
+ height: 1080,
249
+ width: 1920
250
+ });
251
+ // Confirms the read actually went through `createReadStream` rather
252
+ // than skipping it entirely (which would trivially satisfy "< 500KB")
253
+ expect(counters.bytesReadFromDisk).toBeGreaterThan(0);
254
+ expect(counters.bytesReadFromDisk).toBeLessThan(500 * 1024);
255
+ expect(counters.bytesReadFromDisk).toBeLessThan(largeFile.length);
256
+ });
257
+ it.each(cases.filter(({ file })=>file !== 'image.svg'))('should read $file dimensions via imageDimensionsFromStream when streamed from a tempFilePath', async ({ file, height, width })=>{
258
+ const tempFilePath = path.join(tempDir, file);
259
+ writeFileSync(tempFilePath, readFileSync(path.join(fixturesDir, file)));
260
+ const streamedFile = {
261
+ mimetype: 'image/test',
262
+ name: file,
263
+ tempFilePath
264
+ };
265
+ expect(await getImageSize({
266
+ file: streamedFile
267
+ })).toEqual({
268
+ height,
269
+ width
270
+ });
271
+ });
272
+ it('should read GIF dimensions when streamed from a tempFilePath', async ()=>{
273
+ // No GIF fixture lives in this directory; `image-dimensions` only needs
274
+ // the 6-byte signature plus the 4-byte width/height fields that follow it
275
+ const header = Buffer.concat([
276
+ Buffer.from('GIF89a', 'ascii'),
277
+ Buffer.alloc(4)
278
+ ]);
279
+ header.writeUInt16LE(64, 6);
280
+ header.writeUInt16LE(48, 8);
281
+ const tempFilePath = path.join(tempDir, 'test.gif');
282
+ writeFileSync(tempFilePath, header);
283
+ const file = {
284
+ mimetype: 'image/gif',
285
+ name: 'test.gif',
286
+ tempFilePath
287
+ };
288
+ expect(await getImageSize({
289
+ file
290
+ })).toEqual({
291
+ height: 48,
292
+ width: 64
293
+ });
294
+ });
295
+ });
296
+ });
297
+
298
+ //# sourceMappingURL=getImageSize.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/uploads/getImageSize.spec.ts"],"sourcesContent":["import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'fs'\nimport os from 'os'\nimport path from 'path'\nimport sharp from 'sharp'\nimport { fileURLToPath } from 'url'\nimport { afterAll, afterEach, describe, expect, it, vi } from 'vitest'\n\nimport type { PayloadRequest } from '../types/index.js'\n\nimport { getImageSize } from './getImageSize.js'\n\n// Tracks bytes actually read off disk so the streaming test below can assert\n// that a large file's tail is never pulled into memory\nconst counters = vi.hoisted(() => ({ bytesReadFromDisk: 0 }))\n\nvi.mock('fs', async (importOriginal) => {\n const actual = await importOriginal<typeof import('fs')>()\n return {\n ...actual,\n createReadStream: (...args: Parameters<typeof actual.createReadStream>) => {\n const stream = actual.createReadStream(...args)\n stream.on('data', (chunk: Buffer) => {\n counters.bytesReadFromDisk += chunk.length\n })\n return stream\n },\n }\n})\n\nconst dirname = path.dirname(fileURLToPath(import.meta.url))\nconst fixturesDir = path.resolve(dirname, '../../../../test/uploads')\n\n// Minimal JPEG XL bare-codestream encoder (bit-packed, little-endian, LSB\n// first). See probeImageSize.spec.ts for the full JXL parsing test suite;\n// this only needs to produce a valid header for the sharp-fallback tests below\nconst encodeJXLCodestream = (width: number, height: number): Buffer => {\n const bits: number[] = []\n const pushBits = (value: number, length: number) => {\n for (let i = 0; i < length; i++) {\n bits.push((value >> i) & 1)\n }\n }\n const pushDimension = (value: number) => {\n const n = value - 1\n const sizeClasses = [9, 13, 18, 30]\n const classIndex = sizeClasses.findIndex((extraBits) => n < 2 ** extraBits)\n pushBits(classIndex, 2)\n pushBits(n, sizeClasses[classIndex]!)\n }\n\n pushBits(0, 1) // isSmallImage = false\n pushDimension(height)\n pushBits(0, 3) // widthMode = 0 (explicit dimension)\n pushDimension(width)\n\n const body = Buffer.alloc(Math.ceil(bits.length / 8))\n bits.forEach((bit, i) => {\n if (bit) {\n body[Math.floor(i / 8)]! |= 1 << i % 8\n }\n })\n\n return Buffer.concat([Buffer.from([0xff, 0x0a]), body])\n}\n\nconst fileFor = (name: string): PayloadRequest['file'] => {\n const data = readFileSync(path.join(fixturesDir, name))\n // In-memory uploads carry an empty `tempFilePath`, which must fall back to `data`\n return {\n data,\n mimetype: 'image/test',\n name,\n size: data.length,\n tempFilePath: '',\n } as PayloadRequest['file']\n}\n\ndescribe('getImageSize', () => {\n const cases: Array<{ file: string; height: number; width: number }> = [\n { file: 'test-image.png', height: 800, width: 800 },\n { file: 'test-image.jpg', height: 800, width: 800 },\n { file: 'non-animated.webp', height: 420, width: 900 },\n { file: 'test-image-avif.avif', height: 800, width: 800 },\n { file: 'image.svg', height: 260, width: 260 },\n ]\n\n it.each(cases)('should read $file dimensions via sharp', async ({ file, height, width }) => {\n expect(await getImageSize({ file: fileFor(file), sharp })).toEqual({ height, width })\n })\n\n it.each(cases)(\n 'should read $file dimensions via the probe fallback',\n async ({ file, height, width }) => {\n expect(await getImageSize({ file: fileFor(file) })).toEqual({ height, width })\n },\n )\n\n it('should fall back to the probe when sharp cannot decode a header-only image', async () => {\n // A 1x1 PNG truncated after IHDR: the header is readable but there is no\n // pixel data, so sharp throws while the probe still measures it.\n const data = Buffer.from(\n '89504e470d0a1a0a0000000d49484452000000010000000108060000001f15c489',\n 'hex',\n )\n const file = {\n data,\n mimetype: 'image/png',\n name: 'truncated.png',\n size: data.length,\n tempFilePath: '',\n } as PayloadRequest['file']\n\n expect(await getImageSize({ file, sharp })).toEqual({ height: 1, width: 1 })\n expect(await getImageSize({ file })).toEqual({ height: 1, width: 1 })\n })\n\n it('should read TIFF dimensions from a tempFilePath without a temp-file workaround', async () => {\n const tempFilePath = path.join(fixturesDir, 'test-image.tiff')\n const file = {\n mimetype: 'image/tiff',\n name: 'test-image.tiff',\n tempFilePath,\n } as PayloadRequest['file']\n\n expect(await getImageSize({ file, sharp })).toEqual({ height: 100, width: 200 })\n expect(await getImageSize({ file })).toEqual({ height: 100, width: 200 })\n })\n\n describe('sharp cannot decode JPEG XL', () => {\n const tempDir = mkdtempSync(path.join(os.tmpdir(), 'payload-get-image-size-jxl-'))\n\n afterAll(() => {\n rmSync(tempDir, { recursive: true, force: true })\n })\n\n it('should fall back to the probe for an in-memory JPEG XL buffer', async () => {\n // `isImage('image/jxl')` is true, so `generateFileData` always calls\n // `getImageSize` with `sharp` for JXL uploads; sharp rejects the format\n // (libvips has no JXL codec) and the probe must take over\n const data = encodeJXLCodestream(1920, 1080)\n const file = {\n data,\n mimetype: 'image/jxl',\n name: 'test.jxl',\n size: data.length,\n tempFilePath: '',\n } as PayloadRequest['file']\n\n expect(await getImageSize({ file, sharp })).toEqual({ height: 1080, width: 1920 })\n })\n\n it('should fall back to the probe for a JPEG XL tempFilePath', async () => {\n const tempFilePath = path.join(tempDir, 'test.jxl')\n writeFileSync(tempFilePath, encodeJXLCodestream(640, 480))\n\n const file = {\n mimetype: 'image/jxl',\n name: 'test.jxl',\n tempFilePath,\n } as PayloadRequest['file']\n\n expect(await getImageSize({ file, sharp })).toEqual({ height: 480, width: 640 })\n })\n })\n\n describe('streaming from tempFilePath', () => {\n const tempDir = mkdtempSync(path.join(os.tmpdir(), 'payload-get-image-size-'))\n\n afterEach(() => {\n counters.bytesReadFromDisk = 0\n })\n\n afterAll(() => {\n rmSync(tempDir, { recursive: true, force: true })\n })\n\n it('should not read a whole large PNG into memory when probing via tempFilePath', async () => {\n // image-dimensions only reads the PNG signature (bytes 0-7) and the\n // width/height fields (bytes 16-23); everything else here is filler\n const header = Buffer.alloc(24)\n header.write('\\x89PNG\\r\\n\\x1a\\n', 0, 'binary')\n header.writeUInt32BE(1920, 16)\n header.writeUInt32BE(1080, 20)\n const largeFileSize = 3 * 1024 * 1024\n const largeFile = Buffer.concat([header, Buffer.alloc(largeFileSize)])\n\n const tempFilePath = path.join(tempDir, 'large.png')\n writeFileSync(tempFilePath, largeFile)\n\n const file = {\n mimetype: 'image/png',\n name: 'large.png',\n tempFilePath,\n } as PayloadRequest['file']\n\n expect(await getImageSize({ file })).toEqual({ height: 1080, width: 1920 })\n // Confirms the read actually went through `createReadStream` rather\n // than skipping it entirely (which would trivially satisfy \"< 500KB\")\n expect(counters.bytesReadFromDisk).toBeGreaterThan(0)\n expect(counters.bytesReadFromDisk).toBeLessThan(500 * 1024)\n expect(counters.bytesReadFromDisk).toBeLessThan(largeFile.length)\n })\n\n it.each(cases.filter(({ file }) => file !== 'image.svg'))(\n 'should read $file dimensions via imageDimensionsFromStream when streamed from a tempFilePath',\n async ({ file, height, width }) => {\n const tempFilePath = path.join(tempDir, file)\n writeFileSync(tempFilePath, readFileSync(path.join(fixturesDir, file)))\n\n const streamedFile = {\n mimetype: 'image/test',\n name: file,\n tempFilePath,\n } as PayloadRequest['file']\n\n expect(await getImageSize({ file: streamedFile })).toEqual({ height, width })\n },\n )\n\n it('should read GIF dimensions when streamed from a tempFilePath', async () => {\n // No GIF fixture lives in this directory; `image-dimensions` only needs\n // the 6-byte signature plus the 4-byte width/height fields that follow it\n const header = Buffer.concat([Buffer.from('GIF89a', 'ascii'), Buffer.alloc(4)])\n header.writeUInt16LE(64, 6)\n header.writeUInt16LE(48, 8)\n\n const tempFilePath = path.join(tempDir, 'test.gif')\n writeFileSync(tempFilePath, header)\n\n const file = {\n mimetype: 'image/gif',\n name: 'test.gif',\n tempFilePath,\n } as PayloadRequest['file']\n\n expect(await getImageSize({ file })).toEqual({ height: 48, width: 64 })\n })\n })\n})\n"],"names":["mkdtempSync","readFileSync","rmSync","writeFileSync","os","path","sharp","fileURLToPath","afterAll","afterEach","describe","expect","it","vi","getImageSize","counters","hoisted","bytesReadFromDisk","mock","importOriginal","actual","createReadStream","args","stream","on","chunk","length","dirname","url","fixturesDir","resolve","encodeJXLCodestream","width","height","bits","pushBits","value","i","push","pushDimension","n","sizeClasses","classIndex","findIndex","extraBits","body","Buffer","alloc","Math","ceil","forEach","bit","floor","concat","from","fileFor","name","data","join","mimetype","size","tempFilePath","cases","file","each","toEqual","tempDir","tmpdir","recursive","force","header","write","writeUInt32BE","largeFileSize","largeFile","toBeGreaterThan","toBeLessThan","filter","streamedFile","writeUInt16LE"],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { ProbedImageSize } from './types.js';
2
+ /**
3
+ * Image dimension probe used as a fallback when `sharp` is not configured.
4
+ * Reads only the header bytes needed to determine width and height.
5
+ *
6
+ * PNG, JPEG, GIF, WebP, AVIF and HEIF/HEIC are delegated to `image-dimensions`
7
+ * (actively maintained, zero dependencies). BMP, ICO/CUR, SVG, TIFF and JPEG
8
+ * XL have no such maintained equivalent, so they're read here directly; each
9
+ * of those parsers advances by a fixed amount or is bounded by an explicit
10
+ * guard, so malformed input can never block the event loop.
11
+ *
12
+ * Replaces the archived `image-size` package, whose ICNS/HEIF parsers shipped
13
+ * unpatched denial-of-service vulnerabilities (CVE-2025-71330, CVE-2025-71319).
14
+ *
15
+ * Two edge cases changed behavior compared to the previous hand-rolled parser:
16
+ * - JPEG files using arithmetic coding or hierarchical encoding (SOF markers
17
+ * 5-7, 9-11, 13-15) are no longer read; `image-dimensions` only recognizes
18
+ * baseline and progressive JPEG (SOF0-3). These encodings are not produced
19
+ * by browsers or cameras, so this is not expected to affect real uploads.
20
+ * - AVIF/HEIF detection now checks the container's brand list instead of
21
+ * accepting any ISO base media file with a `ftyp` box, so non-image formats
22
+ * that share the same container (for example MP4/MOV) are correctly no
23
+ * longer misidentified as images.
24
+ *
25
+ * @throws if the buffer is not a recognized/parseable image format
26
+ */
27
+ export declare function probeImageSize(data: Buffer): ProbedImageSize;
28
+ /**
29
+ * Probe used when the file lives on disk via `tempFilePath`. PNG, JPEG, GIF,
30
+ * WebP, AVIF and HEIF/HEIC are read through `imageDimensionsFromStream`,
31
+ * which reads only as many bytes as are needed to find the header, so a
32
+ * large file's data is never pulled into memory. BMP, ICO/CUR, SVG, TIFF and
33
+ * JPEG XL are detected from a small header sniff and, only then, read in
34
+ * full for `probeImageSize` to parse.
35
+ *
36
+ * @throws if the file is not a recognized/parseable image format
37
+ */
38
+ export declare function probeImageSizeFromPath(tempFilePath: string): Promise<ProbedImageSize>;
39
+ //# sourceMappingURL=probeImageSize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probeImageSize.d.ts","sourceRoot":"","sources":["../../src/uploads/probeImageSize.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAW5D;AAQD;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAgB3F"}