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.
- package/dist/admin/RichText.d.ts +1 -1
- package/dist/admin/RichText.d.ts.map +1 -1
- package/dist/admin/RichText.js.map +1 -1
- package/dist/admin/functions/index.d.ts +10 -8
- package/dist/admin/functions/index.d.ts.map +1 -1
- package/dist/admin/functions/index.js.map +1 -1
- package/dist/admin/types.d.ts +2 -2
- package/dist/admin/types.d.ts.map +1 -1
- package/dist/admin/types.js.map +1 -1
- package/dist/auth/endpoints/login.d.ts.map +1 -1
- package/dist/auth/endpoints/login.js +2 -11
- package/dist/auth/endpoints/login.js.map +1 -1
- package/dist/auth/loginWithCookie.d.ts +33 -0
- package/dist/auth/loginWithCookie.d.ts.map +1 -0
- package/dist/auth/loginWithCookie.js +34 -0
- package/dist/auth/loginWithCookie.js.map +1 -0
- package/dist/auth/serverFunctions/cookies.d.ts +47 -0
- package/dist/auth/serverFunctions/cookies.d.ts.map +1 -0
- package/dist/auth/serverFunctions/cookies.js +52 -0
- package/dist/auth/serverFunctions/cookies.js.map +1 -0
- package/dist/auth/serverFunctions/login.d.ts +29 -0
- package/dist/auth/serverFunctions/login.d.ts.map +1 -0
- package/dist/auth/serverFunctions/login.js +63 -0
- package/dist/auth/serverFunctions/login.js.map +1 -0
- package/dist/auth/serverFunctions/logout.d.ts +17 -0
- package/dist/auth/serverFunctions/logout.d.ts.map +1 -0
- package/dist/auth/serverFunctions/logout.js +58 -0
- package/dist/auth/serverFunctions/logout.js.map +1 -0
- package/dist/auth/serverFunctions/refresh.d.ts +17 -0
- package/dist/auth/serverFunctions/refresh.d.ts.map +1 -0
- package/dist/auth/serverFunctions/refresh.js +61 -0
- package/dist/auth/serverFunctions/refresh.js.map +1 -0
- package/dist/collections/config/client.d.ts +2 -3
- package/dist/collections/config/client.d.ts.map +1 -1
- package/dist/collections/config/client.js +5 -7
- package/dist/collections/config/client.js.map +1 -1
- package/dist/collections/config/defaults.d.ts.map +1 -1
- package/dist/collections/config/defaults.js +1 -0
- package/dist/collections/config/defaults.js.map +1 -1
- package/dist/collections/config/sanitize.d.ts +3 -8
- package/dist/collections/config/sanitize.d.ts.map +1 -1
- package/dist/collections/config/sanitize.js +2 -6
- package/dist/collections/config/sanitize.js.map +1 -1
- package/dist/collections/config/types.d.ts +1 -1
- package/dist/collections/config/types.d.ts.map +1 -1
- package/dist/collections/config/types.js.map +1 -1
- package/dist/collections/config/useAsTitle.spec.js +27 -27
- package/dist/collections/config/useAsTitle.spec.js.map +1 -1
- package/dist/collections/operations/create.d.ts.map +1 -1
- package/dist/collections/operations/create.js +10 -0
- package/dist/collections/operations/create.js.map +1 -1
- package/dist/collections/operations/restoreVersion.d.ts.map +1 -1
- package/dist/collections/operations/restoreVersion.js +7 -4
- package/dist/collections/operations/restoreVersion.js.map +1 -1
- package/dist/collections/operations/updateByID.js +1 -0
- package/dist/collections/operations/updateByID.js.map +1 -1
- package/dist/config/build.js +1 -1
- package/dist/config/build.js.map +1 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +5 -2
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/orderable/index.d.ts +1 -1
- package/dist/config/orderable/index.d.ts.map +1 -1
- package/dist/config/orderable/index.js +2 -2
- package/dist/config/orderable/index.js.map +1 -1
- package/dist/config/sanitize.d.ts +1 -1
- package/dist/config/sanitize.d.ts.map +1 -1
- package/dist/config/sanitize.js +33 -40
- package/dist/config/sanitize.js.map +1 -1
- package/dist/config/types.d.ts +1 -1
- package/dist/config/types.js.map +1 -1
- package/dist/database/createDatabaseAdapter.d.ts +1 -1
- package/dist/database/createDatabaseAdapter.d.ts.map +1 -1
- package/dist/database/createDatabaseAdapter.js +0 -2
- package/dist/database/createDatabaseAdapter.js.map +1 -1
- package/dist/database/types.d.ts +6 -0
- package/dist/database/types.d.ts.map +1 -1
- package/dist/database/types.js.map +1 -1
- package/dist/exports/auth.d.ts +5 -0
- package/dist/exports/auth.d.ts.map +1 -0
- package/dist/exports/auth.js +6 -0
- package/dist/exports/auth.js.map +1 -0
- package/dist/exports/internal.d.ts +2 -0
- package/dist/exports/internal.d.ts.map +1 -1
- package/dist/exports/internal.js +3 -1
- package/dist/exports/internal.js.map +1 -1
- package/dist/fields/baseFields/slug/duplicateContext.d.ts +11 -0
- package/dist/fields/baseFields/slug/duplicateContext.d.ts.map +1 -0
- package/dist/fields/baseFields/slug/duplicateContext.js +21 -0
- package/dist/fields/baseFields/slug/duplicateContext.js.map +1 -0
- package/dist/fields/baseFields/slug/fillEmptyLocalizedSlugs.d.ts +22 -0
- package/dist/fields/baseFields/slug/fillEmptyLocalizedSlugs.d.ts.map +1 -0
- package/dist/fields/baseFields/slug/fillEmptyLocalizedSlugs.js +63 -0
- package/dist/fields/baseFields/slug/fillEmptyLocalizedSlugs.js.map +1 -0
- package/dist/fields/baseFields/slug/generateSlug.d.ts +13 -8
- package/dist/fields/baseFields/slug/generateSlug.d.ts.map +1 -1
- package/dist/fields/baseFields/slug/generateSlug.js +98 -45
- package/dist/fields/baseFields/slug/generateSlug.js.map +1 -1
- package/dist/fields/baseFields/slug/generateSlugBeforeDuplicate.d.ts +18 -0
- package/dist/fields/baseFields/slug/generateSlugBeforeDuplicate.d.ts.map +1 -0
- package/dist/fields/baseFields/slug/generateSlugBeforeDuplicate.js +20 -0
- package/dist/fields/baseFields/slug/generateSlugBeforeDuplicate.js.map +1 -0
- package/dist/fields/baseFields/slug/getSlugFallbackValue.d.ts +22 -0
- package/dist/fields/baseFields/slug/getSlugFallbackValue.d.ts.map +1 -0
- package/dist/fields/baseFields/slug/getSlugFallbackValue.js +23 -0
- package/dist/fields/baseFields/slug/getSlugFallbackValue.js.map +1 -0
- package/dist/fields/baseFields/slug/hasValue.d.ts +3 -0
- package/dist/fields/baseFields/slug/hasValue.d.ts.map +1 -0
- package/dist/fields/baseFields/slug/hasValue.js +3 -0
- package/dist/fields/baseFields/slug/hasValue.js.map +1 -0
- package/dist/fields/config/reservedFieldNames.spec.js +18 -18
- package/dist/fields/config/reservedFieldNames.spec.js.map +1 -1
- package/dist/fields/config/sanitize.d.ts +3 -9
- package/dist/fields/config/sanitize.d.ts.map +1 -1
- package/dist/fields/config/sanitize.js +33 -34
- package/dist/fields/config/sanitize.js.map +1 -1
- package/dist/fields/config/sanitize.spec.js +128 -105
- package/dist/fields/config/sanitize.spec.js.map +1 -1
- package/dist/fields/config/types.d.ts +4 -3
- package/dist/fields/config/types.d.ts.map +1 -1
- package/dist/fields/config/types.js.map +1 -1
- package/dist/fields/hooks/beforeValidate/promise.d.ts.map +1 -1
- package/dist/fields/hooks/beforeValidate/promise.js +5 -3
- package/dist/fields/hooks/beforeValidate/promise.js.map +1 -1
- package/dist/fields/hooks/beforeValidate/stripNullRows.d.ts +10 -0
- package/dist/fields/hooks/beforeValidate/stripNullRows.d.ts.map +1 -0
- package/dist/fields/hooks/beforeValidate/stripNullRows.js +18 -0
- package/dist/fields/hooks/beforeValidate/stripNullRows.js.map +1 -0
- package/dist/fields/validations.d.ts.map +1 -1
- package/dist/fields/validations.js +7 -8
- package/dist/fields/validations.js.map +1 -1
- package/dist/fields/validations.spec.js +61 -37
- package/dist/fields/validations.spec.js.map +1 -1
- package/dist/globals/config/sanitize.d.ts +2 -7
- package/dist/globals/config/sanitize.d.ts.map +1 -1
- package/dist/globals/config/sanitize.js +2 -6
- package/dist/globals/config/sanitize.js.map +1 -1
- package/dist/globals/config/sanitize.spec.js +6 -6
- package/dist/globals/config/sanitize.spec.js.map +1 -1
- package/dist/globals/operations/countGlobalVersions.d.ts.map +1 -1
- package/dist/globals/operations/countGlobalVersions.js +1 -0
- package/dist/globals/operations/countGlobalVersions.js.map +1 -1
- package/dist/index.bundled.d.ts +247 -178
- package/dist/index.d.ts +49 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/query-presets/constraints.js +1 -1
- package/dist/query-presets/constraints.js.map +1 -1
- package/dist/queues/config/collection.d.ts.map +1 -1
- package/dist/queues/config/collection.js +37 -43
- package/dist/queues/config/collection.js.map +1 -1
- package/dist/queues/config/global.d.ts +5 -6
- package/dist/queues/config/global.d.ts.map +1 -1
- package/dist/queues/config/global.js +1 -1
- package/dist/queues/config/global.js.map +1 -1
- package/dist/queues/config/types/index.d.ts +29 -24
- package/dist/queues/config/types/index.d.ts.map +1 -1
- package/dist/queues/config/types/index.js.map +1 -1
- package/dist/queues/config/types/taskTypes.d.ts +4 -7
- package/dist/queues/config/types/taskTypes.d.ts.map +1 -1
- package/dist/queues/config/types/taskTypes.js.map +1 -1
- package/dist/queues/config/types/workflowJSONTypes.d.ts +10 -9
- package/dist/queues/config/types/workflowJSONTypes.d.ts.map +1 -1
- package/dist/queues/config/types/workflowJSONTypes.js.map +1 -1
- package/dist/queues/config/types/workflowTypes.d.ts +11 -58
- package/dist/queues/config/types/workflowTypes.d.ts.map +1 -1
- package/dist/queues/config/types/workflowTypes.js.map +1 -1
- package/dist/queues/endpoints/handleSchedules.js +1 -1
- package/dist/queues/endpoints/handleSchedules.js.map +1 -1
- package/dist/queues/errors/handleTaskError.js +4 -4
- package/dist/queues/errors/handleTaskError.js.map +1 -1
- package/dist/queues/errors/handleWorkflowError.js +1 -1
- package/dist/queues/errors/handleWorkflowError.js.map +1 -1
- package/dist/queues/errors/index.d.ts +6 -0
- package/dist/queues/errors/index.d.ts.map +1 -1
- package/dist/queues/errors/index.js +5 -0
- package/dist/queues/errors/index.js.map +1 -1
- package/dist/queues/localAPI.d.ts +4 -4
- package/dist/queues/localAPI.d.ts.map +1 -1
- package/dist/queues/localAPI.js +63 -66
- package/dist/queues/localAPI.js.map +1 -1
- package/dist/queues/operations/handleSchedules/countRunnableOrActiveJobsForQueue.d.ts +4 -4
- package/dist/queues/operations/handleSchedules/countRunnableOrActiveJobsForQueue.d.ts.map +1 -1
- package/dist/queues/operations/handleSchedules/countRunnableOrActiveJobsForQueue.js.map +1 -1
- package/dist/queues/operations/handleSchedules/index.d.ts +1 -1
- package/dist/queues/operations/handleSchedules/index.d.ts.map +1 -1
- package/dist/queues/operations/handleSchedules/index.js +1 -1
- package/dist/queues/operations/handleSchedules/index.js.map +1 -1
- package/dist/queues/operations/runJobs/heartbeat.d.ts +13 -0
- package/dist/queues/operations/runJobs/heartbeat.d.ts.map +1 -0
- package/dist/queues/operations/runJobs/heartbeat.js +66 -0
- package/dist/queues/operations/runJobs/heartbeat.js.map +1 -0
- package/dist/queues/operations/runJobs/index.d.ts.map +1 -1
- package/dist/queues/operations/runJobs/index.js +133 -84
- package/dist/queues/operations/runJobs/index.js.map +1 -1
- package/dist/queues/operations/runJobs/runJSONJob/index.d.ts.map +1 -1
- package/dist/queues/operations/runJobs/runJSONJob/index.js +6 -3
- package/dist/queues/operations/runJobs/runJSONJob/index.js.map +1 -1
- package/dist/queues/operations/runJobs/runJob/getRunTaskFunction.js +5 -5
- package/dist/queues/operations/runJobs/runJob/getRunTaskFunction.js.map +1 -1
- package/dist/queues/operations/runJobs/runJob/getUpdateJobFunction.d.ts +2 -1
- package/dist/queues/operations/runJobs/runJob/getUpdateJobFunction.d.ts.map +1 -1
- package/dist/queues/operations/runJobs/runJob/getUpdateJobFunction.js +39 -8
- package/dist/queues/operations/runJobs/runJob/getUpdateJobFunction.js.map +1 -1
- package/dist/queues/operations/runJobs/runJob/importHandlerPath.js.map +1 -1
- package/dist/queues/operations/runJobs/runJob/index.d.ts.map +1 -1
- package/dist/queues/operations/runJobs/runJob/index.js +4 -4
- package/dist/queues/operations/runJobs/runJob/index.js.map +1 -1
- package/dist/queues/utilities/updateJob.d.ts.map +1 -1
- package/dist/queues/utilities/updateJob.js +3 -0
- package/dist/queues/utilities/updateJob.js.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/uploads/checkFileRestrictions.d.ts +1 -1
- package/dist/uploads/checkFileRestrictions.d.ts.map +1 -1
- package/dist/uploads/checkFileRestrictions.js +15 -1
- package/dist/uploads/checkFileRestrictions.js.map +1 -1
- package/dist/uploads/endpoints/uploadInstructions.d.ts +12 -0
- package/dist/uploads/endpoints/uploadInstructions.d.ts.map +1 -1
- package/dist/uploads/endpoints/uploadInstructions.js +66 -20
- package/dist/uploads/endpoints/uploadInstructions.js.map +1 -1
- package/dist/uploads/generateFileData.js +4 -1
- package/dist/uploads/generateFileData.js.map +1 -1
- package/dist/uploads/getFileFromUploadInstructions.d.ts +8 -0
- package/dist/uploads/getFileFromUploadInstructions.d.ts.map +1 -0
- package/dist/uploads/getFileFromUploadInstructions.js +62 -0
- package/dist/uploads/getFileFromUploadInstructions.js.map +1 -0
- package/dist/uploads/getImageSize.d.ts +12 -1
- package/dist/uploads/getImageSize.d.ts.map +1 -1
- package/dist/uploads/getImageSize.js +20 -18
- package/dist/uploads/getImageSize.js.map +1 -1
- package/dist/uploads/getImageSize.spec.js +298 -0
- package/dist/uploads/getImageSize.spec.js.map +1 -0
- package/dist/uploads/probeImageSize.d.ts +39 -0
- package/dist/uploads/probeImageSize.d.ts.map +1 -0
- package/dist/uploads/probeImageSize.js +374 -0
- package/dist/uploads/probeImageSize.js.map +1 -0
- package/dist/uploads/probeImageSize.spec.js +366 -0
- package/dist/uploads/probeImageSize.spec.js.map +1 -0
- package/dist/uploads/stagedUpload.d.ts +27 -0
- package/dist/uploads/stagedUpload.d.ts.map +1 -0
- package/dist/uploads/stagedUpload.js +197 -0
- package/dist/uploads/stagedUpload.js.map +1 -0
- package/dist/uploads/types.d.ts +41 -13
- package/dist/uploads/types.d.ts.map +1 -1
- package/dist/uploads/types.js.map +1 -1
- package/dist/utilities/addDataAndFileToRequest.d.ts.map +1 -1
- package/dist/utilities/addDataAndFileToRequest.js +12 -46
- package/dist/utilities/addDataAndFileToRequest.js.map +1 -1
- package/dist/utilities/configToJSONSchema.spec.js +33 -33
- package/dist/utilities/configToJSONSchema.spec.js.map +1 -1
- package/dist/utilities/fieldValueExists.d.ts +29 -0
- package/dist/utilities/fieldValueExists.d.ts.map +1 -0
- package/dist/utilities/fieldValueExists.js +27 -0
- package/dist/utilities/fieldValueExists.js.map +1 -0
- package/dist/utilities/getUniqueFieldValue.d.ts +27 -0
- package/dist/utilities/getUniqueFieldValue.d.ts.map +1 -0
- package/dist/utilities/getUniqueFieldValue.js +26 -0
- package/dist/utilities/getUniqueFieldValue.js.map +1 -0
- package/dist/versions/deleteScheduledPublishJobs.js +2 -2
- package/dist/versions/deleteScheduledPublishJobs.js.map +1 -1
- package/dist/versions/payloadPackageList.d.ts.map +1 -1
- package/dist/versions/payloadPackageList.js +0 -1
- package/dist/versions/payloadPackageList.js.map +1 -1
- package/package.json +8 -3
- package/dist/database/defaultUpdateJobs.d.ts +0 -3
- package/dist/database/defaultUpdateJobs.d.ts.map +0 -1
- package/dist/database/defaultUpdateJobs.js +0 -41
- package/dist/database/defaultUpdateJobs.js.map +0 -1
- package/dist/fields/baseFields/slug/countVersions.d.ts +0 -13
- package/dist/fields/baseFields/slug/countVersions.d.ts.map +0 -1
- package/dist/fields/baseFields/slug/countVersions.js +0 -27
- package/dist/fields/baseFields/slug/countVersions.js.map +0 -1
- package/dist/uploads/tempFile.d.ts +0 -7
- package/dist/uploads/tempFile.d.ts.map +0 -1
- package/dist/uploads/tempFile.js +0 -39
- package/dist/uploads/tempFile.js.map +0 -1
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import { createReadStream } from 'fs';
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
import { imageDimensionsFromData, imageDimensionsFromStream } from 'image-dimensions';
|
|
4
|
+
/**
|
|
5
|
+
* Image dimension probe used as a fallback when `sharp` is not configured.
|
|
6
|
+
* Reads only the header bytes needed to determine width and height.
|
|
7
|
+
*
|
|
8
|
+
* PNG, JPEG, GIF, WebP, AVIF and HEIF/HEIC are delegated to `image-dimensions`
|
|
9
|
+
* (actively maintained, zero dependencies). BMP, ICO/CUR, SVG, TIFF and JPEG
|
|
10
|
+
* XL have no such maintained equivalent, so they're read here directly; each
|
|
11
|
+
* of those parsers advances by a fixed amount or is bounded by an explicit
|
|
12
|
+
* guard, so malformed input can never block the event loop.
|
|
13
|
+
*
|
|
14
|
+
* Replaces the archived `image-size` package, whose ICNS/HEIF parsers shipped
|
|
15
|
+
* unpatched denial-of-service vulnerabilities (CVE-2025-71330, CVE-2025-71319).
|
|
16
|
+
*
|
|
17
|
+
* Two edge cases changed behavior compared to the previous hand-rolled parser:
|
|
18
|
+
* - JPEG files using arithmetic coding or hierarchical encoding (SOF markers
|
|
19
|
+
* 5-7, 9-11, 13-15) are no longer read; `image-dimensions` only recognizes
|
|
20
|
+
* baseline and progressive JPEG (SOF0-3). These encodings are not produced
|
|
21
|
+
* by browsers or cameras, so this is not expected to affect real uploads.
|
|
22
|
+
* - AVIF/HEIF detection now checks the container's brand list instead of
|
|
23
|
+
* accepting any ISO base media file with a `ftyp` box, so non-image formats
|
|
24
|
+
* that share the same container (for example MP4/MOV) are correctly no
|
|
25
|
+
* longer misidentified as images.
|
|
26
|
+
*
|
|
27
|
+
* @throws if the buffer is not a recognized/parseable image format
|
|
28
|
+
*/ export function probeImageSize(data) {
|
|
29
|
+
const modernDimensions = imageDimensionsFromData(data);
|
|
30
|
+
const dimensions = modernDimensions ? {
|
|
31
|
+
height: modernDimensions.height,
|
|
32
|
+
width: modernDimensions.width
|
|
33
|
+
} : probeLegacyFormat(data);
|
|
34
|
+
if (!dimensions || !dimensions.width || !dimensions.height) {
|
|
35
|
+
throw new Error('Unsupported image type: unable to determine dimensions');
|
|
36
|
+
}
|
|
37
|
+
return dimensions;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Bytes read from the start of the file to detect a legacy/JXL format from
|
|
41
|
+
* its header; comfortably covers every signature `detectLegacyType` checks.
|
|
42
|
+
*/ const HEADER_SNIFF_LENGTH = 4096;
|
|
43
|
+
/**
|
|
44
|
+
* Probe used when the file lives on disk via `tempFilePath`. PNG, JPEG, GIF,
|
|
45
|
+
* WebP, AVIF and HEIF/HEIC are read through `imageDimensionsFromStream`,
|
|
46
|
+
* which reads only as many bytes as are needed to find the header, so a
|
|
47
|
+
* large file's data is never pulled into memory. BMP, ICO/CUR, SVG, TIFF and
|
|
48
|
+
* JPEG XL are detected from a small header sniff and, only then, read in
|
|
49
|
+
* full for `probeImageSize` to parse.
|
|
50
|
+
*
|
|
51
|
+
* @throws if the file is not a recognized/parseable image format
|
|
52
|
+
*/ export async function probeImageSizeFromPath(tempFilePath) {
|
|
53
|
+
const headerSniff = await readHeaderSniff(tempFilePath);
|
|
54
|
+
if (detectLegacyType(headerSniff)) {
|
|
55
|
+
return probeImageSize(await fs.readFile(tempFilePath));
|
|
56
|
+
}
|
|
57
|
+
const modernDimensions = await imageDimensionsFromStream(ReadableStream.from(createReadStream(tempFilePath)));
|
|
58
|
+
if (modernDimensions) {
|
|
59
|
+
return {
|
|
60
|
+
height: modernDimensions.height,
|
|
61
|
+
width: modernDimensions.width
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return probeImageSize(await fs.readFile(tempFilePath));
|
|
65
|
+
}
|
|
66
|
+
async function readHeaderSniff(tempFilePath) {
|
|
67
|
+
const handle = await fs.open(tempFilePath, 'r');
|
|
68
|
+
try {
|
|
69
|
+
const buffer = Buffer.alloc(HEADER_SNIFF_LENGTH);
|
|
70
|
+
const { bytesRead } = await handle.read(buffer, 0, HEADER_SNIFF_LENGTH, 0);
|
|
71
|
+
return buffer.subarray(0, bytesRead);
|
|
72
|
+
} finally{
|
|
73
|
+
await handle.close();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function probeLegacyFormat(data) {
|
|
77
|
+
const type = detectLegacyType(data);
|
|
78
|
+
return type ? legacyParsers[type](data) : null;
|
|
79
|
+
}
|
|
80
|
+
function detectLegacyType(data) {
|
|
81
|
+
if (data.length < 2) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
if (data[0] === 0x42 && data[1] === 0x4d) {
|
|
85
|
+
return 'bmp';
|
|
86
|
+
}
|
|
87
|
+
if (data.length >= 8 && (data[0] === 0x49 && data[1] === 0x49 && data[2] === 0x2a || data[0] === 0x4d && data[1] === 0x4d && data[3] === 0x2a)) {
|
|
88
|
+
return 'tiff';
|
|
89
|
+
}
|
|
90
|
+
if (data.length >= 6 && data[0] === 0 && data[1] === 0 && (data[2] === 1 || data[2] === 2) && data[3] === 0) {
|
|
91
|
+
return 'ico';
|
|
92
|
+
}
|
|
93
|
+
if (data[0] === 0xff && data[1] === 0x0a || isJXLContainerSignature(data)) {
|
|
94
|
+
return 'jxl';
|
|
95
|
+
}
|
|
96
|
+
const head = data.toString('utf8', 0, Math.min(data.length, 1000));
|
|
97
|
+
if (/<svg[\s>]/i.test(head) || head.trimStart().startsWith('<?xml') && /<svg/i.test(head)) {
|
|
98
|
+
return 'svg';
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
const legacyParsers = {
|
|
103
|
+
bmp: (data)=>({
|
|
104
|
+
height: Math.abs(data.readInt32LE(22)),
|
|
105
|
+
width: data.readInt32LE(18)
|
|
106
|
+
}),
|
|
107
|
+
ico: (data)=>{
|
|
108
|
+
const count = data.readUInt16LE(4);
|
|
109
|
+
let best = {
|
|
110
|
+
height: 0,
|
|
111
|
+
width: 0
|
|
112
|
+
};
|
|
113
|
+
for(let i = 0; i < count && i < 1000; i++){
|
|
114
|
+
const entry = 6 + i * 16;
|
|
115
|
+
if (entry + 2 > data.length) {
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
// A zero byte means 256 px in the ICO format
|
|
119
|
+
const width = data[entry] === 0 ? 256 : data[entry];
|
|
120
|
+
const height = data[entry + 1] === 0 ? 256 : data[entry + 1];
|
|
121
|
+
if (width * height > best.width * best.height) {
|
|
122
|
+
best = {
|
|
123
|
+
height,
|
|
124
|
+
width
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return best.width ? best : null;
|
|
129
|
+
},
|
|
130
|
+
jxl: (data)=>parseJXL(data),
|
|
131
|
+
svg: (data)=>parseSVG(data),
|
|
132
|
+
tiff: (data)=>{
|
|
133
|
+
const isLittleEndian = data[0] === 0x49;
|
|
134
|
+
const readU16 = (offset)=>isLittleEndian ? data.readUInt16LE(offset) : data.readUInt16BE(offset);
|
|
135
|
+
const readU32 = (offset)=>isLittleEndian ? data.readUInt32LE(offset) : data.readUInt32BE(offset);
|
|
136
|
+
const ifdOffset = readU32(4);
|
|
137
|
+
if (ifdOffset + 2 > data.length) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
const entryCount = readU16(ifdOffset);
|
|
141
|
+
let width;
|
|
142
|
+
let height;
|
|
143
|
+
for(let i = 0; i < entryCount && i < 1000; i++){
|
|
144
|
+
const entry = ifdOffset + 2 + i * 12;
|
|
145
|
+
if (entry + 12 > data.length) {
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
const tag = readU16(entry);
|
|
149
|
+
const fieldType = readU16(entry + 2);
|
|
150
|
+
// SHORT (type 3) values are 16-bit, otherwise read as 32-bit LONG
|
|
151
|
+
const value = fieldType === 3 ? readU16(entry + 8) : readU32(entry + 8);
|
|
152
|
+
if (tag === 256) {
|
|
153
|
+
width = value;
|
|
154
|
+
} else if (tag === 257) {
|
|
155
|
+
height = value;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return width && height ? {
|
|
159
|
+
height,
|
|
160
|
+
width
|
|
161
|
+
} : null;
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
function parseSVG(data) {
|
|
165
|
+
const text = data.toString('utf8', 0, Math.min(data.length, 65536));
|
|
166
|
+
const tagMatch = text.match(/<svg[^>]*>/i);
|
|
167
|
+
if (!tagMatch) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
const tag = tagMatch[0];
|
|
171
|
+
const readLength = (name)=>{
|
|
172
|
+
const match = tag.match(new RegExp(`${name}\\s*=\\s*["']?\\s*([^"'\\s>]+)`, 'i'));
|
|
173
|
+
if (!match) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
// Percentage units are relative and yield no concrete pixel size
|
|
177
|
+
if (/%\s*$/.test(match[1])) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
const value = parseFloat(match[1]);
|
|
181
|
+
return Number.isFinite(value) ? value : null;
|
|
182
|
+
};
|
|
183
|
+
const width = readLength('width');
|
|
184
|
+
const height = readLength('height');
|
|
185
|
+
if (width != null && height != null) {
|
|
186
|
+
return {
|
|
187
|
+
height: Math.round(height),
|
|
188
|
+
width: Math.round(width)
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
const viewBoxMatch = tag.match(/viewbox\s*=\s*["']?\s*([\d.\s,+-]+)/i);
|
|
192
|
+
if (viewBoxMatch) {
|
|
193
|
+
const parts = viewBoxMatch[1].trim().split(/[\s,]+/).map(Number);
|
|
194
|
+
if (parts.length === 4 && parts.every((n)=>Number.isFinite(n))) {
|
|
195
|
+
const [, , viewWidth, viewHeight] = parts;
|
|
196
|
+
if (width != null) {
|
|
197
|
+
return {
|
|
198
|
+
height: Math.round(width / viewWidth * viewHeight),
|
|
199
|
+
width: Math.round(width)
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
if (height != null) {
|
|
203
|
+
return {
|
|
204
|
+
height: Math.round(height),
|
|
205
|
+
width: Math.round(height / viewHeight * viewWidth)
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
height: Math.round(viewHeight),
|
|
210
|
+
width: Math.round(viewWidth)
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* JPEG XL isn't supported by `image-dimensions`, so its size header is read
|
|
218
|
+
* directly. A JXL file is either a bare codestream starting `FF 0A`, or an
|
|
219
|
+
* ISOBMFF container carrying the codestream in a single `jxlc` box or split
|
|
220
|
+
* across several `jxlp` boxes; either way the dimensions live in the first
|
|
221
|
+
* bits of the codestream (the `SizeHeader`). See https://www.w3.org/TR/jpeg-xl/
|
|
222
|
+
* for the bitstream layout.
|
|
223
|
+
*/ function parseJXL(data) {
|
|
224
|
+
if (data[0] === 0xff && data[1] === 0x0a) {
|
|
225
|
+
return parseJXLSizeHeader(data, 2);
|
|
226
|
+
}
|
|
227
|
+
// A boxed codestream still starts with the `FF 0A` signature, so it's
|
|
228
|
+
// skipped here too, same as the bare-codestream case above
|
|
229
|
+
const jxlcBox = findBox(data, 'jxlc', 0);
|
|
230
|
+
if (jxlcBox) {
|
|
231
|
+
return parseJXLSizeHeader(data, jxlcBox.bodyOffset + 2);
|
|
232
|
+
}
|
|
233
|
+
const jxlpBoxes = findAllBoxes(data, 'jxlp');
|
|
234
|
+
if (!jxlpBoxes.length) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
// Each `jxlp` payload is prefixed with a 4-byte partial-codestream index
|
|
238
|
+
const codestream = Buffer.concat(jxlpBoxes.map((box)=>data.subarray(box.bodyOffset + 4, box.offset + box.size)));
|
|
239
|
+
return parseJXLSizeHeader(codestream, 2);
|
|
240
|
+
}
|
|
241
|
+
function isJXLContainerSignature(data) {
|
|
242
|
+
return data.length >= 12 && data.readUInt32BE(0) === 0x0000000c && data.toString('ascii', 4, 8) === 'JXL ' && data[8] === 0x0d && data[9] === 0x0a && data[10] === 0x87 && data[11] === 0x0a;
|
|
243
|
+
}
|
|
244
|
+
function readBoxHeader(data, offset) {
|
|
245
|
+
if (offset + 8 > data.length) {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
const name = data.toString('ascii', offset + 4, offset + 8);
|
|
249
|
+
let size = data.readUInt32BE(offset);
|
|
250
|
+
let bodyOffset = offset + 8;
|
|
251
|
+
if (size === 1) {
|
|
252
|
+
// A size of 1 means a 64-bit size follows the 8-byte header
|
|
253
|
+
if (offset + 16 > data.length) {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
const largeSize = data.readBigUInt64BE(offset + 8);
|
|
257
|
+
if (largeSize > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
size = Number(largeSize);
|
|
261
|
+
bodyOffset = offset + 16;
|
|
262
|
+
} else if (size === 0) {
|
|
263
|
+
// A size of 0 means the box extends to the end of the buffer
|
|
264
|
+
size = data.length - offset;
|
|
265
|
+
}
|
|
266
|
+
if (size < bodyOffset - offset || offset + size > data.length) {
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
name,
|
|
271
|
+
bodyOffset,
|
|
272
|
+
offset,
|
|
273
|
+
size
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
// Bounded to the same 1000-entry cap used elsewhere in this file so a
|
|
277
|
+
// malformed chain of boxes can never block the event loop
|
|
278
|
+
function findBox(data, name, startOffset) {
|
|
279
|
+
let offset = startOffset;
|
|
280
|
+
for(let i = 0; i < 1000 && offset < data.length; i++){
|
|
281
|
+
const box = readBoxHeader(data, offset);
|
|
282
|
+
if (!box) {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
if (box.name === name) {
|
|
286
|
+
return box;
|
|
287
|
+
}
|
|
288
|
+
offset += box.size;
|
|
289
|
+
}
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
function findAllBoxes(data, name) {
|
|
293
|
+
const boxes = [];
|
|
294
|
+
let offset = 0;
|
|
295
|
+
for(let i = 0; i < 1000 && offset < data.length; i++){
|
|
296
|
+
const box = readBoxHeader(data, offset);
|
|
297
|
+
if (!box) {
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
if (box.name === name) {
|
|
301
|
+
boxes.push(box);
|
|
302
|
+
}
|
|
303
|
+
offset += box.size;
|
|
304
|
+
}
|
|
305
|
+
return boxes;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Reads the JXL `SizeHeader` bit-packed structure (little-endian, LSB
|
|
309
|
+
* first) starting at `startOffset` in the codestream.
|
|
310
|
+
*/ function parseJXLSizeHeader(data, startOffset) {
|
|
311
|
+
let byteOffset = startOffset;
|
|
312
|
+
let bitOffset = 0;
|
|
313
|
+
const readBits = (length)=>{
|
|
314
|
+
let result = 0;
|
|
315
|
+
let bitsRead = 0;
|
|
316
|
+
while(bitsRead < length){
|
|
317
|
+
if (byteOffset >= data.length) {
|
|
318
|
+
throw new RangeError('Unexpected end of JXL codestream');
|
|
319
|
+
}
|
|
320
|
+
const currentByte = data[byteOffset];
|
|
321
|
+
const bitsLeft = 8 - bitOffset;
|
|
322
|
+
const bitsToRead = Math.min(length - bitsRead, bitsLeft);
|
|
323
|
+
const mask = (1 << bitsToRead) - 1;
|
|
324
|
+
result |= (currentByte >> bitOffset & mask) << bitsRead;
|
|
325
|
+
bitsRead += bitsToRead;
|
|
326
|
+
bitOffset += bitsToRead;
|
|
327
|
+
if (bitOffset === 8) {
|
|
328
|
+
byteOffset++;
|
|
329
|
+
bitOffset = 0;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return result;
|
|
333
|
+
};
|
|
334
|
+
const readExplicitDimension = ()=>{
|
|
335
|
+
const sizeClass = readBits(2);
|
|
336
|
+
const extraBits = [
|
|
337
|
+
9,
|
|
338
|
+
13,
|
|
339
|
+
18,
|
|
340
|
+
30
|
|
341
|
+
][sizeClass];
|
|
342
|
+
return 1 + readBits(extraBits);
|
|
343
|
+
};
|
|
344
|
+
try {
|
|
345
|
+
const isSmallImage = readBits(1) === 1;
|
|
346
|
+
const height = isSmallImage ? 8 * (1 + readBits(5)) : readExplicitDimension();
|
|
347
|
+
const widthMode = readBits(3);
|
|
348
|
+
let width;
|
|
349
|
+
if (isSmallImage && widthMode === 0) {
|
|
350
|
+
width = 8 * (1 + readBits(5));
|
|
351
|
+
} else if (widthMode === 0) {
|
|
352
|
+
width = readExplicitDimension();
|
|
353
|
+
} else {
|
|
354
|
+
const aspectRatios = [
|
|
355
|
+
1,
|
|
356
|
+
1.2,
|
|
357
|
+
4 / 3,
|
|
358
|
+
1.5,
|
|
359
|
+
16 / 9,
|
|
360
|
+
5 / 4,
|
|
361
|
+
2
|
|
362
|
+
];
|
|
363
|
+
width = Math.floor(height * aspectRatios[widthMode - 1]);
|
|
364
|
+
}
|
|
365
|
+
return {
|
|
366
|
+
height,
|
|
367
|
+
width
|
|
368
|
+
};
|
|
369
|
+
} catch {
|
|
370
|
+
return null;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
//# sourceMappingURL=probeImageSize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/uploads/probeImageSize.ts"],"sourcesContent":["import { createReadStream } from 'fs'\nimport fs from 'fs/promises'\nimport { imageDimensionsFromData, imageDimensionsFromStream } from 'image-dimensions'\n\nimport type { ProbedImageSize } from './types.js'\n\n/**\n * Image dimension probe used as a fallback when `sharp` is not configured.\n * Reads only the header bytes needed to determine width and height.\n *\n * PNG, JPEG, GIF, WebP, AVIF and HEIF/HEIC are delegated to `image-dimensions`\n * (actively maintained, zero dependencies). BMP, ICO/CUR, SVG, TIFF and JPEG\n * XL have no such maintained equivalent, so they're read here directly; each\n * of those parsers advances by a fixed amount or is bounded by an explicit\n * guard, so malformed input can never block the event loop.\n *\n * Replaces the archived `image-size` package, whose ICNS/HEIF parsers shipped\n * unpatched denial-of-service vulnerabilities (CVE-2025-71330, CVE-2025-71319).\n *\n * Two edge cases changed behavior compared to the previous hand-rolled parser:\n * - JPEG files using arithmetic coding or hierarchical encoding (SOF markers\n * 5-7, 9-11, 13-15) are no longer read; `image-dimensions` only recognizes\n * baseline and progressive JPEG (SOF0-3). These encodings are not produced\n * by browsers or cameras, so this is not expected to affect real uploads.\n * - AVIF/HEIF detection now checks the container's brand list instead of\n * accepting any ISO base media file with a `ftyp` box, so non-image formats\n * that share the same container (for example MP4/MOV) are correctly no\n * longer misidentified as images.\n *\n * @throws if the buffer is not a recognized/parseable image format\n */\nexport function probeImageSize(data: Buffer): ProbedImageSize {\n const modernDimensions = imageDimensionsFromData(data)\n const dimensions = modernDimensions\n ? { height: modernDimensions.height, width: modernDimensions.width }\n : probeLegacyFormat(data)\n\n if (!dimensions || !dimensions.width || !dimensions.height) {\n throw new Error('Unsupported image type: unable to determine dimensions')\n }\n\n return dimensions\n}\n\n/**\n * Bytes read from the start of the file to detect a legacy/JXL format from\n * its header; comfortably covers every signature `detectLegacyType` checks.\n */\nconst HEADER_SNIFF_LENGTH = 4096\n\n/**\n * Probe used when the file lives on disk via `tempFilePath`. PNG, JPEG, GIF,\n * WebP, AVIF and HEIF/HEIC are read through `imageDimensionsFromStream`,\n * which reads only as many bytes as are needed to find the header, so a\n * large file's data is never pulled into memory. BMP, ICO/CUR, SVG, TIFF and\n * JPEG XL are detected from a small header sniff and, only then, read in\n * full for `probeImageSize` to parse.\n *\n * @throws if the file is not a recognized/parseable image format\n */\nexport async function probeImageSizeFromPath(tempFilePath: string): Promise<ProbedImageSize> {\n const headerSniff = await readHeaderSniff(tempFilePath)\n\n if (detectLegacyType(headerSniff)) {\n return probeImageSize(await fs.readFile(tempFilePath))\n }\n\n const modernDimensions = await imageDimensionsFromStream(\n ReadableStream.from(createReadStream(tempFilePath)),\n )\n\n if (modernDimensions) {\n return { height: modernDimensions.height, width: modernDimensions.width }\n }\n\n return probeImageSize(await fs.readFile(tempFilePath))\n}\n\nasync function readHeaderSniff(tempFilePath: string): Promise<Buffer> {\n const handle = await fs.open(tempFilePath, 'r')\n\n try {\n const buffer = Buffer.alloc(HEADER_SNIFF_LENGTH)\n const { bytesRead } = await handle.read(buffer, 0, HEADER_SNIFF_LENGTH, 0)\n return buffer.subarray(0, bytesRead)\n } finally {\n await handle.close()\n }\n}\n\ntype Dimensions = null | ProbedImageSize\n\ntype LegacyImageType = 'bmp' | 'ico' | 'jxl' | 'svg' | 'tiff'\n\nfunction probeLegacyFormat(data: Buffer): Dimensions {\n const type = detectLegacyType(data)\n return type ? legacyParsers[type](data) : null\n}\n\nfunction detectLegacyType(data: Buffer): LegacyImageType | null {\n if (data.length < 2) {\n return null\n }\n\n if (data[0] === 0x42 && data[1] === 0x4d) {\n return 'bmp'\n }\n if (\n data.length >= 8 &&\n ((data[0] === 0x49 && data[1] === 0x49 && data[2] === 0x2a) ||\n (data[0] === 0x4d && data[1] === 0x4d && data[3] === 0x2a))\n ) {\n return 'tiff'\n }\n if (\n data.length >= 6 &&\n data[0] === 0 &&\n data[1] === 0 &&\n (data[2] === 1 || data[2] === 2) &&\n data[3] === 0\n ) {\n return 'ico'\n }\n if ((data[0] === 0xff && data[1] === 0x0a) || isJXLContainerSignature(data)) {\n return 'jxl'\n }\n\n const head = data.toString('utf8', 0, Math.min(data.length, 1000))\n if (/<svg[\\s>]/i.test(head) || (head.trimStart().startsWith('<?xml') && /<svg/i.test(head))) {\n return 'svg'\n }\n\n return null\n}\n\nconst legacyParsers: Record<LegacyImageType, (data: Buffer) => Dimensions> = {\n bmp: (data) => ({ height: Math.abs(data.readInt32LE(22)), width: data.readInt32LE(18) }),\n ico: (data) => {\n const count = data.readUInt16LE(4)\n let best: ProbedImageSize = { height: 0, width: 0 }\n\n for (let i = 0; i < count && i < 1000; i++) {\n const entry = 6 + i * 16\n if (entry + 2 > data.length) {\n break\n }\n // A zero byte means 256 px in the ICO format\n const width = data[entry] === 0 ? 256 : data[entry]!\n const height = data[entry + 1] === 0 ? 256 : data[entry + 1]!\n if (width * height > best.width * best.height) {\n best = { height, width }\n }\n }\n\n return best.width ? best : null\n },\n jxl: (data) => parseJXL(data),\n svg: (data) => parseSVG(data),\n tiff: (data) => {\n const isLittleEndian = data[0] === 0x49\n const readU16 = (offset: number) =>\n isLittleEndian ? data.readUInt16LE(offset) : data.readUInt16BE(offset)\n const readU32 = (offset: number) =>\n isLittleEndian ? data.readUInt32LE(offset) : data.readUInt32BE(offset)\n\n const ifdOffset = readU32(4)\n if (ifdOffset + 2 > data.length) {\n return null\n }\n\n const entryCount = readU16(ifdOffset)\n let width: number | undefined\n let height: number | undefined\n\n for (let i = 0; i < entryCount && i < 1000; i++) {\n const entry = ifdOffset + 2 + i * 12\n if (entry + 12 > data.length) {\n break\n }\n const tag = readU16(entry)\n const fieldType = readU16(entry + 2)\n // SHORT (type 3) values are 16-bit, otherwise read as 32-bit LONG\n const value = fieldType === 3 ? readU16(entry + 8) : readU32(entry + 8)\n if (tag === 256) {\n width = value\n } else if (tag === 257) {\n height = value\n }\n }\n\n return width && height ? { height, width } : null\n },\n}\n\nfunction parseSVG(data: Buffer): Dimensions {\n const text = data.toString('utf8', 0, Math.min(data.length, 65536))\n const tagMatch = text.match(/<svg[^>]*>/i)\n if (!tagMatch) {\n return null\n }\n\n const tag = tagMatch[0]\n const readLength = (name: string): null | number => {\n const match = tag.match(new RegExp(`${name}\\\\s*=\\\\s*[\"']?\\\\s*([^\"'\\\\s>]+)`, 'i'))\n if (!match) {\n return null\n }\n // Percentage units are relative and yield no concrete pixel size\n if (/%\\s*$/.test(match[1]!)) {\n return null\n }\n const value = parseFloat(match[1]!)\n return Number.isFinite(value) ? value : null\n }\n\n const width = readLength('width')\n const height = readLength('height')\n if (width != null && height != null) {\n return { height: Math.round(height), width: Math.round(width) }\n }\n\n const viewBoxMatch = tag.match(/viewbox\\s*=\\s*[\"']?\\s*([\\d.\\s,+-]+)/i)\n if (viewBoxMatch) {\n const parts = viewBoxMatch[1]!\n .trim()\n .split(/[\\s,]+/)\n .map(Number)\n if (parts.length === 4 && parts.every((n) => Number.isFinite(n))) {\n const [, , viewWidth, viewHeight] = parts as [number, number, number, number]\n if (width != null) {\n return { height: Math.round((width / viewWidth) * viewHeight), width: Math.round(width) }\n }\n if (height != null) {\n return { height: Math.round(height), width: Math.round((height / viewHeight) * viewWidth) }\n }\n return { height: Math.round(viewHeight), width: Math.round(viewWidth) }\n }\n }\n\n return null\n}\n\n/**\n * JPEG XL isn't supported by `image-dimensions`, so its size header is read\n * directly. A JXL file is either a bare codestream starting `FF 0A`, or an\n * ISOBMFF container carrying the codestream in a single `jxlc` box or split\n * across several `jxlp` boxes; either way the dimensions live in the first\n * bits of the codestream (the `SizeHeader`). See https://www.w3.org/TR/jpeg-xl/\n * for the bitstream layout.\n */\nfunction parseJXL(data: Buffer): Dimensions {\n if (data[0] === 0xff && data[1] === 0x0a) {\n return parseJXLSizeHeader(data, 2)\n }\n\n // A boxed codestream still starts with the `FF 0A` signature, so it's\n // skipped here too, same as the bare-codestream case above\n const jxlcBox = findBox(data, 'jxlc', 0)\n if (jxlcBox) {\n return parseJXLSizeHeader(data, jxlcBox.bodyOffset + 2)\n }\n\n const jxlpBoxes = findAllBoxes(data, 'jxlp')\n if (!jxlpBoxes.length) {\n return null\n }\n\n // Each `jxlp` payload is prefixed with a 4-byte partial-codestream index\n const codestream = Buffer.concat(\n jxlpBoxes.map((box) => data.subarray(box.bodyOffset + 4, box.offset + box.size)),\n )\n return parseJXLSizeHeader(codestream, 2)\n}\n\nfunction isJXLContainerSignature(data: Buffer): boolean {\n return (\n data.length >= 12 &&\n data.readUInt32BE(0) === 0x0000000c &&\n data.toString('ascii', 4, 8) === 'JXL ' &&\n data[8] === 0x0d &&\n data[9] === 0x0a &&\n data[10] === 0x87 &&\n data[11] === 0x0a\n )\n}\n\ntype Box = { bodyOffset: number; name: string; offset: number; size: number }\n\nfunction readBoxHeader(data: Buffer, offset: number): Box | null {\n if (offset + 8 > data.length) {\n return null\n }\n\n const name = data.toString('ascii', offset + 4, offset + 8)\n let size = data.readUInt32BE(offset)\n let bodyOffset = offset + 8\n\n if (size === 1) {\n // A size of 1 means a 64-bit size follows the 8-byte header\n if (offset + 16 > data.length) {\n return null\n }\n const largeSize = data.readBigUInt64BE(offset + 8)\n if (largeSize > BigInt(Number.MAX_SAFE_INTEGER)) {\n return null\n }\n size = Number(largeSize)\n bodyOffset = offset + 16\n } else if (size === 0) {\n // A size of 0 means the box extends to the end of the buffer\n size = data.length - offset\n }\n\n if (size < bodyOffset - offset || offset + size > data.length) {\n return null\n }\n\n return { name, bodyOffset, offset, size }\n}\n\n// Bounded to the same 1000-entry cap used elsewhere in this file so a\n// malformed chain of boxes can never block the event loop\nfunction findBox(data: Buffer, name: string, startOffset: number): Box | null {\n let offset = startOffset\n\n for (let i = 0; i < 1000 && offset < data.length; i++) {\n const box = readBoxHeader(data, offset)\n if (!box) {\n return null\n }\n if (box.name === name) {\n return box\n }\n offset += box.size\n }\n\n return null\n}\n\nfunction findAllBoxes(data: Buffer, name: string): Box[] {\n const boxes: Box[] = []\n let offset = 0\n\n for (let i = 0; i < 1000 && offset < data.length; i++) {\n const box = readBoxHeader(data, offset)\n if (!box) {\n break\n }\n if (box.name === name) {\n boxes.push(box)\n }\n offset += box.size\n }\n\n return boxes\n}\n\n/**\n * Reads the JXL `SizeHeader` bit-packed structure (little-endian, LSB\n * first) starting at `startOffset` in the codestream.\n */\nfunction parseJXLSizeHeader(data: Buffer, startOffset: number): Dimensions {\n let byteOffset = startOffset\n let bitOffset = 0\n\n const readBits = (length: number): number => {\n let result = 0\n let bitsRead = 0\n\n while (bitsRead < length) {\n if (byteOffset >= data.length) {\n throw new RangeError('Unexpected end of JXL codestream')\n }\n const currentByte = data[byteOffset]!\n const bitsLeft = 8 - bitOffset\n const bitsToRead = Math.min(length - bitsRead, bitsLeft)\n const mask = (1 << bitsToRead) - 1\n result |= ((currentByte >> bitOffset) & mask) << bitsRead\n\n bitsRead += bitsToRead\n bitOffset += bitsToRead\n if (bitOffset === 8) {\n byteOffset++\n bitOffset = 0\n }\n }\n\n return result\n }\n\n const readExplicitDimension = (): number => {\n const sizeClass = readBits(2)\n const extraBits = [9, 13, 18, 30][sizeClass]!\n return 1 + readBits(extraBits)\n }\n\n try {\n const isSmallImage = readBits(1) === 1\n const height = isSmallImage ? 8 * (1 + readBits(5)) : readExplicitDimension()\n const widthMode = readBits(3)\n\n let width: number\n if (isSmallImage && widthMode === 0) {\n width = 8 * (1 + readBits(5))\n } else if (widthMode === 0) {\n width = readExplicitDimension()\n } else {\n const aspectRatios = [1, 1.2, 4 / 3, 1.5, 16 / 9, 5 / 4, 2]\n width = Math.floor(height * aspectRatios[widthMode - 1]!)\n }\n\n return { height, width }\n } catch {\n return null\n }\n}\n"],"names":["createReadStream","fs","imageDimensionsFromData","imageDimensionsFromStream","probeImageSize","data","modernDimensions","dimensions","height","width","probeLegacyFormat","Error","HEADER_SNIFF_LENGTH","probeImageSizeFromPath","tempFilePath","headerSniff","readHeaderSniff","detectLegacyType","readFile","ReadableStream","from","handle","open","buffer","Buffer","alloc","bytesRead","read","subarray","close","type","legacyParsers","length","isJXLContainerSignature","head","toString","Math","min","test","trimStart","startsWith","bmp","abs","readInt32LE","ico","count","readUInt16LE","best","i","entry","jxl","parseJXL","svg","parseSVG","tiff","isLittleEndian","readU16","offset","readUInt16BE","readU32","readUInt32LE","readUInt32BE","ifdOffset","entryCount","tag","fieldType","value","text","tagMatch","match","readLength","name","RegExp","parseFloat","Number","isFinite","round","viewBoxMatch","parts","trim","split","map","every","n","viewWidth","viewHeight","parseJXLSizeHeader","jxlcBox","findBox","bodyOffset","jxlpBoxes","findAllBoxes","codestream","concat","box","size","readBoxHeader","largeSize","readBigUInt64BE","BigInt","MAX_SAFE_INTEGER","startOffset","boxes","push","byteOffset","bitOffset","readBits","result","bitsRead","RangeError","currentByte","bitsLeft","bitsToRead","mask","readExplicitDimension","sizeClass","extraBits","isSmallImage","widthMode","aspectRatios","floor"],"mappings":"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"}
|