@strapi/upload 5.60.0 → 5.61.0
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/components/AssetPickerDialog/MediaLibraryPickerDialog.js +29 -0
- package/dist/admin/components/AssetPickerDialog/MediaLibraryPickerDialog.js.map +1 -0
- package/dist/admin/components/AssetPickerDialog/MediaLibraryPickerDialog.mjs +27 -0
- package/dist/admin/components/AssetPickerDialog/MediaLibraryPickerDialog.mjs.map +1 -0
- package/dist/admin/components/Drawer.js +12 -7
- package/dist/admin/components/Drawer.js.map +1 -1
- package/dist/admin/components/Drawer.mjs +12 -7
- package/dist/admin/components/Drawer.mjs.map +1 -1
- package/dist/admin/components/EditorFileDropZone/EditorFileDropZone.js +188 -0
- package/dist/admin/components/EditorFileDropZone/EditorFileDropZone.js.map +1 -0
- package/dist/admin/components/EditorFileDropZone/EditorFileDropZone.mjs +186 -0
- package/dist/admin/components/EditorFileDropZone/EditorFileDropZone.mjs.map +1 -0
- package/dist/admin/components/MediaLibraryInput/AddAssetMenu.js +5 -1
- package/dist/admin/components/MediaLibraryInput/AddAssetMenu.js.map +1 -1
- package/dist/admin/components/MediaLibraryInput/AddAssetMenu.mjs +5 -1
- package/dist/admin/components/MediaLibraryInput/AddAssetMenu.mjs.map +1 -1
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js +37 -27
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js.map +1 -1
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.mjs +37 -27
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.mjs.map +1 -1
- package/dist/admin/components/MediaLibraryInput/openAssetDetails.js +46 -0
- package/dist/admin/components/MediaLibraryInput/openAssetDetails.js.map +1 -0
- package/dist/admin/components/MediaLibraryInput/openAssetDetails.mjs +43 -0
- package/dist/admin/components/MediaLibraryInput/openAssetDetails.mjs.map +1 -0
- package/dist/admin/index.js +10 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +10 -1
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/pages/Assets/AssetsPage.js +1 -1
- package/dist/admin/pages/Assets/AssetsPage.js.map +1 -1
- package/dist/admin/pages/Assets/AssetsPage.mjs +2 -2
- package/dist/admin/pages/Assets/AssetsPage.mjs.map +1 -1
- package/dist/admin/pages/Assets/components/AssetDetails/AssetCropEditor.mjs +2 -2
- package/dist/admin/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +181 -65
- package/dist/admin/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
- package/dist/admin/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +184 -69
- package/dist/admin/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
- package/dist/admin/pages/Assets/components/AssetDetails/AssetPreview.mjs +1 -1
- package/dist/admin/pages/Assets/hooks/useIsAssetDetailsOpen.js +2 -6
- package/dist/admin/pages/Assets/hooks/useIsAssetDetailsOpen.js.map +1 -1
- package/dist/admin/pages/Assets/hooks/useIsAssetDetailsOpen.mjs +2 -6
- package/dist/admin/pages/Assets/hooks/useIsAssetDetailsOpen.mjs.map +1 -1
- package/dist/admin/src/components/AssetPickerDialog/MediaLibraryPickerDialog.d.ts +19 -0
- package/dist/admin/src/components/Drawer.d.ts +8 -0
- package/dist/admin/src/components/EditorFileDropZone/EditorFileDropZone.d.ts +21 -0
- package/dist/admin/src/components/MediaLibraryInput/AddAssetMenu.d.ts +7 -1
- package/dist/admin/src/components/MediaLibraryInput/openAssetDetails.d.ts +10 -0
- package/dist/admin/src/pages/Assets/components/AssetDetails/AssetDetailsDrawer.d.ts +41 -5
- package/dist/admin/src/pages/Assets/hooks/useIsAssetDetailsOpen.d.ts +2 -6
- package/dist/admin/translations/en.json.js +4 -0
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +4 -0
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/server/audit-logs.js +264 -0
- package/dist/server/audit-logs.js.map +1 -0
- package/dist/server/audit-logs.mjs +255 -0
- package/dist/server/audit-logs.mjs.map +1 -0
- package/dist/server/bootstrap.js +4 -0
- package/dist/server/bootstrap.js.map +1 -1
- package/dist/server/bootstrap.mjs +4 -0
- package/dist/server/bootstrap.mjs.map +1 -1
- package/dist/server/controllers/admin-folder-file.js +23 -1
- package/dist/server/controllers/admin-folder-file.js.map +1 -1
- package/dist/server/controllers/admin-folder-file.mjs +23 -1
- package/dist/server/controllers/admin-folder-file.mjs.map +1 -1
- package/dist/server/services/folder.js +48 -1
- package/dist/server/services/folder.js.map +1 -1
- package/dist/server/services/folder.mjs +48 -1
- package/dist/server/services/folder.mjs.map +1 -1
- package/dist/server/services/image-manipulation.js +12 -5
- package/dist/server/services/image-manipulation.js.map +1 -1
- package/dist/server/services/image-manipulation.mjs +12 -5
- package/dist/server/services/image-manipulation.mjs.map +1 -1
- package/dist/server/services/upload.js +100 -16
- package/dist/server/services/upload.js.map +1 -1
- package/dist/server/services/upload.mjs +102 -18
- package/dist/server/services/upload.mjs.map +1 -1
- package/dist/server/src/audit-logs.d.ts +142 -0
- package/dist/server/src/audit-logs.d.ts.map +1 -0
- package/dist/server/src/bootstrap.d.ts.map +1 -1
- package/dist/server/src/controllers/admin-folder-file.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +3 -3
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/mcp/ambient-instance.d.ts.map +1 -1
- package/dist/server/src/services/folder.d.ts.map +1 -1
- package/dist/server/src/services/image-manipulation.d.ts +3 -3
- package/dist/server/src/services/image-manipulation.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +3 -3
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/upload.d.ts.map +1 -1
- package/package.json +9 -16
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-manipulation.js","sources":["../../../server/src/services/image-manipulation.ts"],"sourcesContent":["import fs from 'fs';\nimport { join } from 'path';\nimport sharp, { type Metadata, type ResizeOptions, type SharpOptions } from 'sharp';\nimport crypto from 'crypto';\nimport { strings, file as fileUtils } from '@strapi/utils';\n\nimport { getService } from '../utils';\n\nimport type { Config, UploadableFile } from '../types';\n\ntype Dimensions = {\n width: number | null;\n height: number | null;\n};\n\nconst { bytesToKbytes } = fileUtils;\n\n/**\n * Instance-level sharp options from the plugin config (e.g. `limitInputPixels`).\n * Global settings (`cache`, `concurrency`) are applied once in the plugin register phase.\n * Returns `undefined` when nothing is configured so bare stream pipelines can use `sharp()`.\n */\nconst getSharpOptions = (): SharpOptions | undefined => {\n const { limitInputPixels } = strapi.config.get<Config['sharp']>('plugin::upload.sharp', {}) ?? {};\n\n if (limitInputPixels == null) {\n return undefined;\n }\n\n return { limitInputPixels };\n};\n\nconst FORMATS_TO_RESIZE = new Set(['jpeg', 'png', 'webp', 'tiff', 'gif']);\nconst FORMATS_TO_PROCESS = new Set(['jpeg', 'png', 'webp', 'tiff', 'svg', 'gif', 'avif']);\nconst FORMATS_TO_OPTIMIZE = new Set(['jpeg', 'png', 'webp', 'tiff', 'avif']);\n\nconst isOptimizableFormat = (\n format: string | undefined\n): format is 'jpeg' | 'png' | 'webp' | 'tiff' | 'avif' =>\n format !== undefined && FORMATS_TO_OPTIMIZE.has(format);\n\nconst writeStreamToFile = (stream: NodeJS.ReadWriteStream, path: string) =>\n new Promise<void>((resolve, reject) => {\n const writeStream = fs.createWriteStream(path);\n // Reject promise if there is an error with the provided stream\n stream.on('error', reject);\n stream.pipe(writeStream);\n writeStream.on('close', () => resolve());\n writeStream.on('error', reject);\n });\n\nconst getMetadata = (file: UploadableFile): Promise<Metadata> => {\n const options = getSharpOptions();\n\n if (!file.filepath) {\n return new Promise((resolve, reject) => {\n const pipeline = options ? sharp(options) : sharp();\n pipeline.metadata().then(resolve).catch(reject);\n file.getStream().pipe(pipeline);\n });\n }\n\n return sharp(file.filepath, options).metadata();\n};\n\nconst getDimensions = async (file: UploadableFile): Promise<Dimensions> => {\n const { width = null, height = null } = await getMetadata(file);\n\n return { width, height };\n};\n\nconst THUMBNAIL_RESIZE_OPTIONS = {\n width: 245,\n height: 156,\n fit: 'inside',\n} satisfies ResizeOptions;\n\nconst resizeFileTo = async (\n file: UploadableFile,\n options: ResizeOptions,\n {\n name,\n hash,\n }: {\n name: string;\n hash: string;\n }\n) => {\n const filePath = file.tmpWorkingDirectory ? join(file.tmpWorkingDirectory, hash) : hash;\n\n let newInfo;\n if (!file.filepath) {\n const transform = sharp({ ...getSharpOptions(), animated: true })\n .resize(options)\n .on('info', (info) => {\n newInfo = info;\n });\n\n await writeStreamToFile(file.getStream().pipe(transform), filePath);\n } else {\n newInfo = await sharp(file.filepath, { ...getSharpOptions(), animated: true })\n .resize(options)\n .toFile(filePath);\n }\n\n const { width, height, size, pageHeight } = newInfo ?? {};\n\n const newFile: UploadableFile = {\n name,\n hash,\n ext: file.ext,\n mime: file.mime,\n filepath: filePath,\n path: file.path || null,\n getStream: () => fs.createReadStream(filePath),\n };\n\n Object.assign(newFile, {\n width,\n height: pageHeight ?? height,\n size: size ? bytesToKbytes(size) : 0,\n sizeInBytes: size,\n });\n return newFile;\n};\n\nconst generateThumbnail = async (file: UploadableFile) => {\n if (\n file.width &&\n file.height &&\n (file.width > THUMBNAIL_RESIZE_OPTIONS.width || file.height > THUMBNAIL_RESIZE_OPTIONS.height)\n ) {\n return resizeFileTo(file, THUMBNAIL_RESIZE_OPTIONS, {\n name: `thumbnail_${file.name}`,\n hash: `thumbnail_${file.hash}`,\n });\n }\n\n return null;\n};\n\n/**\n * Optimize image by:\n * - auto orienting image based on EXIF data\n * - reduce image quality\n *\n */\nconst optimize = async (file: UploadableFile) => {\n const { sizeOptimization = false, autoOrientation = false } =\n (await getService('upload').getSettings()) ?? {};\n\n const { format, size } = await getMetadata(file);\n\n if ((sizeOptimization || autoOrientation) && isOptimizableFormat(format)) {\n let transformer;\n if (!file.filepath) {\n transformer = sharp({ ...getSharpOptions(), animated: true });\n } else {\n transformer = sharp(file.filepath, { ...getSharpOptions(), animated: true });\n }\n // reduce image quality\n transformer[format]({ quality: sizeOptimization ? 80 : 100 });\n // rotate image based on EXIF data\n if (autoOrientation) {\n transformer.rotate();\n }\n const filePath = file.tmpWorkingDirectory\n ? join(file.tmpWorkingDirectory, `optimized-${file.hash}`)\n : `optimized-${file.hash}`;\n\n let newInfo;\n if (!file.filepath) {\n transformer.on('info', (info) => {\n newInfo = info;\n });\n\n await writeStreamToFile(file.getStream().pipe(transformer), filePath);\n } else {\n newInfo = await transformer.toFile(filePath);\n }\n\n const {\n width: newWidth,\n height: newHeight,\n size: newSize,\n pageHeight: newPageHeight,\n } = newInfo ?? {};\n\n const newFile = { ...file };\n\n newFile.getStream = () => fs.createReadStream(filePath);\n newFile.filepath = filePath;\n\n if (newSize && size && newSize > size) {\n // Ignore optimization if output is bigger than original\n return file;\n }\n\n return Object.assign(newFile, {\n width: newWidth,\n height: newPageHeight ?? newHeight,\n size: newSize ? bytesToKbytes(newSize) : 0,\n sizeInBytes: newSize,\n });\n }\n\n return file;\n};\n\nconst DEFAULT_BREAKPOINTS = {\n large: 1000,\n medium: 750,\n small: 500,\n};\n\nconst getBreakpoints = () =>\n strapi.config.get<Record<string, number>>('plugin::upload.breakpoints', DEFAULT_BREAKPOINTS);\n\nconst generateResponsiveFormats = async (file: UploadableFile) => {\n const { responsiveDimensions = false } = (await getService('upload').getSettings()) ?? {};\n\n if (!responsiveDimensions) return [];\n\n const originalDimensions = await getDimensions(file);\n\n const breakpoints = getBreakpoints();\n const results = [];\n\n for (const key of Object.keys(breakpoints)) {\n const breakpoint = breakpoints[key];\n\n if (breakpointSmallerThan(breakpoint, originalDimensions)) {\n results.push(await generateBreakpoint(key, { file, breakpoint }));\n }\n }\n\n return results;\n};\n\nconst generateBreakpoint = async (\n key: string,\n { file, breakpoint }: { file: UploadableFile; breakpoint: number }\n) => {\n const newFile = await resizeFileTo(\n file,\n {\n width: breakpoint,\n height: breakpoint,\n fit: 'inside',\n },\n {\n name: `${key}_${file.name}`,\n hash: `${key}_${file.hash}`,\n }\n );\n return {\n key,\n file: newFile,\n };\n};\n\nconst breakpointSmallerThan = (breakpoint: number, { width, height }: Dimensions) => {\n return breakpoint < (width ?? 0) || breakpoint < (height ?? 0);\n};\n\n/**\n * Applies a simple image transformation to see if the image is faulty/corrupted.\n */\nconst isFaultyImage = async (file: UploadableFile) => {\n const options = getSharpOptions();\n\n if (!file.filepath) {\n return new Promise<boolean>((resolve) => {\n const pipeline = options ? sharp(options) : sharp();\n pipeline\n .stats()\n .then(() => resolve(false))\n .catch(() => resolve(true));\n file.getStream().pipe(pipeline);\n });\n }\n\n try {\n await sharp(file.filepath, options).stats();\n return false;\n } catch {\n return true;\n }\n};\n\nconst isOptimizableImage = async (file: UploadableFile) => {\n let format;\n try {\n const metadata = await getMetadata(file);\n format = metadata.format;\n } catch {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_OPTIMIZE.has(format);\n};\n\nconst isResizableImage = async (file: UploadableFile) => {\n let format;\n try {\n const metadata = await getMetadata(file);\n format = metadata.format;\n } catch {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_RESIZE.has(format);\n};\n\nconst isImage = async (file: UploadableFile) => {\n let format;\n try {\n const metadata = await getMetadata(file);\n format = metadata.format;\n } catch {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_PROCESS.has(format);\n};\n\nconst generateFileName = (name: string) => {\n const randomSuffix = () => crypto.randomBytes(5).toString('hex');\n const baseName = strings.nameToSlug(name, { separator: '_', lowercase: false });\n\n return `${baseName}_${randomSuffix()}`;\n};\n\nexport default {\n isFaultyImage,\n isOptimizableImage,\n isResizableImage,\n isImage,\n getDimensions,\n generateResponsiveFormats,\n generateThumbnail,\n optimize,\n generateFileName,\n};\n"],"names":["bytesToKbytes","fileUtils","getSharpOptions","limitInputPixels","strapi","config","get","undefined","FORMATS_TO_RESIZE","Set","FORMATS_TO_PROCESS","FORMATS_TO_OPTIMIZE","isOptimizableFormat","format","has","writeStreamToFile","stream","path","Promise","resolve","reject","writeStream","fs","createWriteStream","on","pipe","getMetadata","file","options","filepath","pipeline","sharp","metadata","then","catch","getStream","getDimensions","width","height","THUMBNAIL_RESIZE_OPTIONS","fit","resizeFileTo","name","hash","filePath","tmpWorkingDirectory","join","newInfo","transform","animated","resize","info","toFile","size","pageHeight","newFile","ext","mime","createReadStream","Object","assign","sizeInBytes","generateThumbnail","optimize","sizeOptimization","autoOrientation","getService","getSettings","transformer","quality","rotate","newWidth","newHeight","newSize","newPageHeight","DEFAULT_BREAKPOINTS","large","medium","small","getBreakpoints","generateResponsiveFormats","responsiveDimensions","originalDimensions","breakpoints","results","key","keys","breakpoint","breakpointSmallerThan","push","generateBreakpoint","isFaultyImage","stats","isOptimizableImage","isResizableImage","isImage","generateFileName","randomSuffix","crypto","randomBytes","toString","baseName","strings","nameToSlug","separator","lowercase"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"image-manipulation.js","sources":["../../../server/src/services/image-manipulation.ts"],"sourcesContent":["import fs from 'fs';\nimport { join } from 'path';\nimport sharp, { type Metadata, type ResizeOptions, type SharpOptions } from 'sharp';\nimport crypto from 'crypto';\nimport { strings, file as fileUtils } from '@strapi/utils';\n\nimport { getService } from '../utils';\n\nimport type { Config, UploadableFile } from '../types';\n\ntype Dimensions = {\n width: number | null;\n height: number | null;\n};\n\nconst { bytesToKbytes } = fileUtils;\n\n/**\n * Instance-level sharp options from the plugin config (e.g. `limitInputPixels`).\n * Global settings (`cache`, `concurrency`) are applied once in the plugin register phase.\n * Returns `undefined` when nothing is configured so bare stream pipelines can use `sharp()`.\n */\nconst getSharpOptions = (): SharpOptions | undefined => {\n const { limitInputPixels } = strapi.config.get<Config['sharp']>('plugin::upload.sharp', {}) ?? {};\n\n if (limitInputPixels == null) {\n return undefined;\n }\n\n return { limitInputPixels };\n};\n\nconst FORMATS_TO_RESIZE = new Set(['jpeg', 'png', 'webp', 'tiff', 'gif', 'avif']);\nconst FORMATS_TO_PROCESS = new Set(['jpeg', 'png', 'webp', 'tiff', 'svg', 'gif', 'avif']);\nconst FORMATS_TO_OPTIMIZE = new Set(['jpeg', 'png', 'webp', 'tiff', 'avif']);\n\nconst isOptimizableFormat = (\n format: string | undefined\n): format is 'jpeg' | 'png' | 'webp' | 'tiff' | 'avif' =>\n format !== undefined && FORMATS_TO_OPTIMIZE.has(format);\n\n/**\n * sharp reports AVIF files as `heif` with `av1` compression. Normalize them to `avif`;\n * other HEIF files (e.g. HEIC, `hevc` compression) keep the `heif` format and stay unprocessed.\n */\nconst getFormat = ({ format, compression }: Metadata) =>\n format === 'heif' && compression === 'av1' ? 'avif' : format;\n\nconst writeStreamToFile = (stream: NodeJS.ReadWriteStream, path: string) =>\n new Promise<void>((resolve, reject) => {\n const writeStream = fs.createWriteStream(path);\n // Reject promise if there is an error with the provided stream\n stream.on('error', reject);\n stream.pipe(writeStream);\n writeStream.on('close', () => resolve());\n writeStream.on('error', reject);\n });\n\nconst getMetadata = (file: UploadableFile): Promise<Metadata> => {\n const options = getSharpOptions();\n\n if (!file.filepath) {\n return new Promise((resolve, reject) => {\n const pipeline = options ? sharp(options) : sharp();\n pipeline.metadata().then(resolve).catch(reject);\n file.getStream().pipe(pipeline);\n });\n }\n\n return sharp(file.filepath, options).metadata();\n};\n\nconst getDimensions = async (file: UploadableFile): Promise<Dimensions> => {\n const { width = null, height = null } = await getMetadata(file);\n\n return { width, height };\n};\n\nconst THUMBNAIL_RESIZE_OPTIONS = {\n width: 245,\n height: 156,\n fit: 'inside',\n} satisfies ResizeOptions;\n\nconst resizeFileTo = async (\n file: UploadableFile,\n options: ResizeOptions,\n {\n name,\n hash,\n }: {\n name: string;\n hash: string;\n }\n) => {\n const filePath = file.tmpWorkingDirectory ? join(file.tmpWorkingDirectory, hash) : hash;\n\n let newInfo;\n if (!file.filepath) {\n const transform = sharp({ ...getSharpOptions(), animated: true })\n .resize(options)\n .on('info', (info) => {\n newInfo = info;\n });\n\n await writeStreamToFile(file.getStream().pipe(transform), filePath);\n } else {\n newInfo = await sharp(file.filepath, { ...getSharpOptions(), animated: true })\n .resize(options)\n .toFile(filePath);\n }\n\n const { width, height, size, pageHeight } = newInfo ?? {};\n\n const newFile: UploadableFile = {\n name,\n hash,\n ext: file.ext,\n mime: file.mime,\n filepath: filePath,\n path: file.path || null,\n getStream: () => fs.createReadStream(filePath),\n };\n\n Object.assign(newFile, {\n width,\n height: pageHeight ?? height,\n size: size ? bytesToKbytes(size) : 0,\n sizeInBytes: size,\n });\n return newFile;\n};\n\nconst generateThumbnail = async (file: UploadableFile) => {\n if (\n file.width &&\n file.height &&\n (file.width > THUMBNAIL_RESIZE_OPTIONS.width || file.height > THUMBNAIL_RESIZE_OPTIONS.height)\n ) {\n return resizeFileTo(file, THUMBNAIL_RESIZE_OPTIONS, {\n name: `thumbnail_${file.name}`,\n hash: `thumbnail_${file.hash}`,\n });\n }\n\n return null;\n};\n\n/**\n * Optimize image by:\n * - auto orienting image based on EXIF data\n * - reduce image quality\n *\n */\nconst optimize = async (file: UploadableFile) => {\n const { sizeOptimization = false, autoOrientation = false } =\n (await getService('upload').getSettings()) ?? {};\n\n const metadata = await getMetadata(file);\n const format = getFormat(metadata);\n const { size } = metadata;\n\n if ((sizeOptimization || autoOrientation) && isOptimizableFormat(format)) {\n let transformer;\n if (!file.filepath) {\n transformer = sharp({ ...getSharpOptions(), animated: true });\n } else {\n transformer = sharp(file.filepath, { ...getSharpOptions(), animated: true });\n }\n // reduce image quality\n transformer[format]({ quality: sizeOptimization ? 80 : 100 });\n // rotate image based on EXIF data\n if (autoOrientation) {\n transformer.rotate();\n }\n const filePath = file.tmpWorkingDirectory\n ? join(file.tmpWorkingDirectory, `optimized-${file.hash}`)\n : `optimized-${file.hash}`;\n\n let newInfo;\n if (!file.filepath) {\n transformer.on('info', (info) => {\n newInfo = info;\n });\n\n await writeStreamToFile(file.getStream().pipe(transformer), filePath);\n } else {\n newInfo = await transformer.toFile(filePath);\n }\n\n const {\n width: newWidth,\n height: newHeight,\n size: newSize,\n pageHeight: newPageHeight,\n } = newInfo ?? {};\n\n const newFile = { ...file };\n\n newFile.getStream = () => fs.createReadStream(filePath);\n newFile.filepath = filePath;\n\n if (newSize && size && newSize > size) {\n // Ignore optimization if output is bigger than original\n return file;\n }\n\n return Object.assign(newFile, {\n width: newWidth,\n height: newPageHeight ?? newHeight,\n size: newSize ? bytesToKbytes(newSize) : 0,\n sizeInBytes: newSize,\n });\n }\n\n return file;\n};\n\nconst DEFAULT_BREAKPOINTS = {\n large: 1000,\n medium: 750,\n small: 500,\n};\n\nconst getBreakpoints = () =>\n strapi.config.get<Record<string, number>>('plugin::upload.breakpoints', DEFAULT_BREAKPOINTS);\n\nconst generateResponsiveFormats = async (file: UploadableFile) => {\n const { responsiveDimensions = false } = (await getService('upload').getSettings()) ?? {};\n\n if (!responsiveDimensions) return [];\n\n const originalDimensions = await getDimensions(file);\n\n const breakpoints = getBreakpoints();\n const results = [];\n\n for (const key of Object.keys(breakpoints)) {\n const breakpoint = breakpoints[key];\n\n if (breakpointSmallerThan(breakpoint, originalDimensions)) {\n results.push(await generateBreakpoint(key, { file, breakpoint }));\n }\n }\n\n return results;\n};\n\nconst generateBreakpoint = async (\n key: string,\n { file, breakpoint }: { file: UploadableFile; breakpoint: number }\n) => {\n const newFile = await resizeFileTo(\n file,\n {\n width: breakpoint,\n height: breakpoint,\n fit: 'inside',\n },\n {\n name: `${key}_${file.name}`,\n hash: `${key}_${file.hash}`,\n }\n );\n return {\n key,\n file: newFile,\n };\n};\n\nconst breakpointSmallerThan = (breakpoint: number, { width, height }: Dimensions) => {\n return breakpoint < (width ?? 0) || breakpoint < (height ?? 0);\n};\n\n/**\n * Applies a simple image transformation to see if the image is faulty/corrupted.\n */\nconst isFaultyImage = async (file: UploadableFile) => {\n const options = getSharpOptions();\n\n if (!file.filepath) {\n return new Promise<boolean>((resolve) => {\n const pipeline = options ? sharp(options) : sharp();\n pipeline\n .stats()\n .then(() => resolve(false))\n .catch(() => resolve(true));\n file.getStream().pipe(pipeline);\n });\n }\n\n try {\n await sharp(file.filepath, options).stats();\n return false;\n } catch {\n return true;\n }\n};\n\nconst isOptimizableImage = async (file: UploadableFile) => {\n let format;\n try {\n const metadata = await getMetadata(file);\n format = getFormat(metadata);\n } catch {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_OPTIMIZE.has(format);\n};\n\nconst isResizableImage = async (file: UploadableFile) => {\n let format;\n try {\n const metadata = await getMetadata(file);\n format = getFormat(metadata);\n } catch {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_RESIZE.has(format);\n};\n\nconst isImage = async (file: UploadableFile) => {\n let format;\n try {\n const metadata = await getMetadata(file);\n format = getFormat(metadata);\n } catch {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_PROCESS.has(format);\n};\n\nconst generateFileName = (name: string) => {\n const randomSuffix = () => crypto.randomBytes(5).toString('hex');\n const baseName = strings.nameToSlug(name, { separator: '_', lowercase: false });\n\n return `${baseName}_${randomSuffix()}`;\n};\n\nexport default {\n isFaultyImage,\n isOptimizableImage,\n isResizableImage,\n isImage,\n getDimensions,\n generateResponsiveFormats,\n generateThumbnail,\n optimize,\n generateFileName,\n};\n"],"names":["bytesToKbytes","fileUtils","getSharpOptions","limitInputPixels","strapi","config","get","undefined","FORMATS_TO_RESIZE","Set","FORMATS_TO_PROCESS","FORMATS_TO_OPTIMIZE","isOptimizableFormat","format","has","getFormat","compression","writeStreamToFile","stream","path","Promise","resolve","reject","writeStream","fs","createWriteStream","on","pipe","getMetadata","file","options","filepath","pipeline","sharp","metadata","then","catch","getStream","getDimensions","width","height","THUMBNAIL_RESIZE_OPTIONS","fit","resizeFileTo","name","hash","filePath","tmpWorkingDirectory","join","newInfo","transform","animated","resize","info","toFile","size","pageHeight","newFile","ext","mime","createReadStream","Object","assign","sizeInBytes","generateThumbnail","optimize","sizeOptimization","autoOrientation","getService","getSettings","transformer","quality","rotate","newWidth","newHeight","newSize","newPageHeight","DEFAULT_BREAKPOINTS","large","medium","small","getBreakpoints","generateResponsiveFormats","responsiveDimensions","originalDimensions","breakpoints","results","key","keys","breakpoint","breakpointSmallerThan","push","generateBreakpoint","isFaultyImage","stats","isOptimizableImage","isResizableImage","isImage","generateFileName","randomSuffix","crypto","randomBytes","toString","baseName","strings","nameToSlug","separator","lowercase"],"mappings":"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"}
|
|
@@ -24,7 +24,8 @@ const FORMATS_TO_RESIZE = new Set([
|
|
|
24
24
|
'png',
|
|
25
25
|
'webp',
|
|
26
26
|
'tiff',
|
|
27
|
-
'gif'
|
|
27
|
+
'gif',
|
|
28
|
+
'avif'
|
|
28
29
|
]);
|
|
29
30
|
const FORMATS_TO_PROCESS = new Set([
|
|
30
31
|
'jpeg',
|
|
@@ -43,6 +44,10 @@ const FORMATS_TO_OPTIMIZE = new Set([
|
|
|
43
44
|
'avif'
|
|
44
45
|
]);
|
|
45
46
|
const isOptimizableFormat = (format)=>format !== undefined && FORMATS_TO_OPTIMIZE.has(format);
|
|
47
|
+
/**
|
|
48
|
+
* sharp reports AVIF files as `heif` with `av1` compression. Normalize them to `avif`;
|
|
49
|
+
* other HEIF files (e.g. HEIC, `hevc` compression) keep the `heif` format and stay unprocessed.
|
|
50
|
+
*/ const getFormat = ({ format, compression })=>format === 'heif' && compression === 'av1' ? 'avif' : format;
|
|
46
51
|
const writeStreamToFile = (stream, path)=>new Promise((resolve, reject)=>{
|
|
47
52
|
const writeStream = fs.createWriteStream(path);
|
|
48
53
|
// Reject promise if there is an error with the provided stream
|
|
@@ -125,7 +130,9 @@ const generateThumbnail = async (file)=>{
|
|
|
125
130
|
*
|
|
126
131
|
*/ const optimize = async (file)=>{
|
|
127
132
|
const { sizeOptimization = false, autoOrientation = false } = await getService('upload').getSettings() ?? {};
|
|
128
|
-
const
|
|
133
|
+
const metadata = await getMetadata(file);
|
|
134
|
+
const format = getFormat(metadata);
|
|
135
|
+
const { size } = metadata;
|
|
129
136
|
if ((sizeOptimization || autoOrientation) && isOptimizableFormat(format)) {
|
|
130
137
|
let transformer;
|
|
131
138
|
if (!file.filepath) {
|
|
@@ -238,7 +245,7 @@ const isOptimizableImage = async (file)=>{
|
|
|
238
245
|
let format;
|
|
239
246
|
try {
|
|
240
247
|
const metadata = await getMetadata(file);
|
|
241
|
-
format = metadata
|
|
248
|
+
format = getFormat(metadata);
|
|
242
249
|
} catch {
|
|
243
250
|
// throw when the file is not a supported image
|
|
244
251
|
return false;
|
|
@@ -249,7 +256,7 @@ const isResizableImage = async (file)=>{
|
|
|
249
256
|
let format;
|
|
250
257
|
try {
|
|
251
258
|
const metadata = await getMetadata(file);
|
|
252
|
-
format = metadata
|
|
259
|
+
format = getFormat(metadata);
|
|
253
260
|
} catch {
|
|
254
261
|
// throw when the file is not a supported image
|
|
255
262
|
return false;
|
|
@@ -260,7 +267,7 @@ const isImage = async (file)=>{
|
|
|
260
267
|
let format;
|
|
261
268
|
try {
|
|
262
269
|
const metadata = await getMetadata(file);
|
|
263
|
-
format = metadata
|
|
270
|
+
format = getFormat(metadata);
|
|
264
271
|
} catch {
|
|
265
272
|
// throw when the file is not a supported image
|
|
266
273
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-manipulation.mjs","sources":["../../../server/src/services/image-manipulation.ts"],"sourcesContent":["import fs from 'fs';\nimport { join } from 'path';\nimport sharp, { type Metadata, type ResizeOptions, type SharpOptions } from 'sharp';\nimport crypto from 'crypto';\nimport { strings, file as fileUtils } from '@strapi/utils';\n\nimport { getService } from '../utils';\n\nimport type { Config, UploadableFile } from '../types';\n\ntype Dimensions = {\n width: number | null;\n height: number | null;\n};\n\nconst { bytesToKbytes } = fileUtils;\n\n/**\n * Instance-level sharp options from the plugin config (e.g. `limitInputPixels`).\n * Global settings (`cache`, `concurrency`) are applied once in the plugin register phase.\n * Returns `undefined` when nothing is configured so bare stream pipelines can use `sharp()`.\n */\nconst getSharpOptions = (): SharpOptions | undefined => {\n const { limitInputPixels } = strapi.config.get<Config['sharp']>('plugin::upload.sharp', {}) ?? {};\n\n if (limitInputPixels == null) {\n return undefined;\n }\n\n return { limitInputPixels };\n};\n\nconst FORMATS_TO_RESIZE = new Set(['jpeg', 'png', 'webp', 'tiff', 'gif']);\nconst FORMATS_TO_PROCESS = new Set(['jpeg', 'png', 'webp', 'tiff', 'svg', 'gif', 'avif']);\nconst FORMATS_TO_OPTIMIZE = new Set(['jpeg', 'png', 'webp', 'tiff', 'avif']);\n\nconst isOptimizableFormat = (\n format: string | undefined\n): format is 'jpeg' | 'png' | 'webp' | 'tiff' | 'avif' =>\n format !== undefined && FORMATS_TO_OPTIMIZE.has(format);\n\nconst writeStreamToFile = (stream: NodeJS.ReadWriteStream, path: string) =>\n new Promise<void>((resolve, reject) => {\n const writeStream = fs.createWriteStream(path);\n // Reject promise if there is an error with the provided stream\n stream.on('error', reject);\n stream.pipe(writeStream);\n writeStream.on('close', () => resolve());\n writeStream.on('error', reject);\n });\n\nconst getMetadata = (file: UploadableFile): Promise<Metadata> => {\n const options = getSharpOptions();\n\n if (!file.filepath) {\n return new Promise((resolve, reject) => {\n const pipeline = options ? sharp(options) : sharp();\n pipeline.metadata().then(resolve).catch(reject);\n file.getStream().pipe(pipeline);\n });\n }\n\n return sharp(file.filepath, options).metadata();\n};\n\nconst getDimensions = async (file: UploadableFile): Promise<Dimensions> => {\n const { width = null, height = null } = await getMetadata(file);\n\n return { width, height };\n};\n\nconst THUMBNAIL_RESIZE_OPTIONS = {\n width: 245,\n height: 156,\n fit: 'inside',\n} satisfies ResizeOptions;\n\nconst resizeFileTo = async (\n file: UploadableFile,\n options: ResizeOptions,\n {\n name,\n hash,\n }: {\n name: string;\n hash: string;\n }\n) => {\n const filePath = file.tmpWorkingDirectory ? join(file.tmpWorkingDirectory, hash) : hash;\n\n let newInfo;\n if (!file.filepath) {\n const transform = sharp({ ...getSharpOptions(), animated: true })\n .resize(options)\n .on('info', (info) => {\n newInfo = info;\n });\n\n await writeStreamToFile(file.getStream().pipe(transform), filePath);\n } else {\n newInfo = await sharp(file.filepath, { ...getSharpOptions(), animated: true })\n .resize(options)\n .toFile(filePath);\n }\n\n const { width, height, size, pageHeight } = newInfo ?? {};\n\n const newFile: UploadableFile = {\n name,\n hash,\n ext: file.ext,\n mime: file.mime,\n filepath: filePath,\n path: file.path || null,\n getStream: () => fs.createReadStream(filePath),\n };\n\n Object.assign(newFile, {\n width,\n height: pageHeight ?? height,\n size: size ? bytesToKbytes(size) : 0,\n sizeInBytes: size,\n });\n return newFile;\n};\n\nconst generateThumbnail = async (file: UploadableFile) => {\n if (\n file.width &&\n file.height &&\n (file.width > THUMBNAIL_RESIZE_OPTIONS.width || file.height > THUMBNAIL_RESIZE_OPTIONS.height)\n ) {\n return resizeFileTo(file, THUMBNAIL_RESIZE_OPTIONS, {\n name: `thumbnail_${file.name}`,\n hash: `thumbnail_${file.hash}`,\n });\n }\n\n return null;\n};\n\n/**\n * Optimize image by:\n * - auto orienting image based on EXIF data\n * - reduce image quality\n *\n */\nconst optimize = async (file: UploadableFile) => {\n const { sizeOptimization = false, autoOrientation = false } =\n (await getService('upload').getSettings()) ?? {};\n\n const { format, size } = await getMetadata(file);\n\n if ((sizeOptimization || autoOrientation) && isOptimizableFormat(format)) {\n let transformer;\n if (!file.filepath) {\n transformer = sharp({ ...getSharpOptions(), animated: true });\n } else {\n transformer = sharp(file.filepath, { ...getSharpOptions(), animated: true });\n }\n // reduce image quality\n transformer[format]({ quality: sizeOptimization ? 80 : 100 });\n // rotate image based on EXIF data\n if (autoOrientation) {\n transformer.rotate();\n }\n const filePath = file.tmpWorkingDirectory\n ? join(file.tmpWorkingDirectory, `optimized-${file.hash}`)\n : `optimized-${file.hash}`;\n\n let newInfo;\n if (!file.filepath) {\n transformer.on('info', (info) => {\n newInfo = info;\n });\n\n await writeStreamToFile(file.getStream().pipe(transformer), filePath);\n } else {\n newInfo = await transformer.toFile(filePath);\n }\n\n const {\n width: newWidth,\n height: newHeight,\n size: newSize,\n pageHeight: newPageHeight,\n } = newInfo ?? {};\n\n const newFile = { ...file };\n\n newFile.getStream = () => fs.createReadStream(filePath);\n newFile.filepath = filePath;\n\n if (newSize && size && newSize > size) {\n // Ignore optimization if output is bigger than original\n return file;\n }\n\n return Object.assign(newFile, {\n width: newWidth,\n height: newPageHeight ?? newHeight,\n size: newSize ? bytesToKbytes(newSize) : 0,\n sizeInBytes: newSize,\n });\n }\n\n return file;\n};\n\nconst DEFAULT_BREAKPOINTS = {\n large: 1000,\n medium: 750,\n small: 500,\n};\n\nconst getBreakpoints = () =>\n strapi.config.get<Record<string, number>>('plugin::upload.breakpoints', DEFAULT_BREAKPOINTS);\n\nconst generateResponsiveFormats = async (file: UploadableFile) => {\n const { responsiveDimensions = false } = (await getService('upload').getSettings()) ?? {};\n\n if (!responsiveDimensions) return [];\n\n const originalDimensions = await getDimensions(file);\n\n const breakpoints = getBreakpoints();\n const results = [];\n\n for (const key of Object.keys(breakpoints)) {\n const breakpoint = breakpoints[key];\n\n if (breakpointSmallerThan(breakpoint, originalDimensions)) {\n results.push(await generateBreakpoint(key, { file, breakpoint }));\n }\n }\n\n return results;\n};\n\nconst generateBreakpoint = async (\n key: string,\n { file, breakpoint }: { file: UploadableFile; breakpoint: number }\n) => {\n const newFile = await resizeFileTo(\n file,\n {\n width: breakpoint,\n height: breakpoint,\n fit: 'inside',\n },\n {\n name: `${key}_${file.name}`,\n hash: `${key}_${file.hash}`,\n }\n );\n return {\n key,\n file: newFile,\n };\n};\n\nconst breakpointSmallerThan = (breakpoint: number, { width, height }: Dimensions) => {\n return breakpoint < (width ?? 0) || breakpoint < (height ?? 0);\n};\n\n/**\n * Applies a simple image transformation to see if the image is faulty/corrupted.\n */\nconst isFaultyImage = async (file: UploadableFile) => {\n const options = getSharpOptions();\n\n if (!file.filepath) {\n return new Promise<boolean>((resolve) => {\n const pipeline = options ? sharp(options) : sharp();\n pipeline\n .stats()\n .then(() => resolve(false))\n .catch(() => resolve(true));\n file.getStream().pipe(pipeline);\n });\n }\n\n try {\n await sharp(file.filepath, options).stats();\n return false;\n } catch {\n return true;\n }\n};\n\nconst isOptimizableImage = async (file: UploadableFile) => {\n let format;\n try {\n const metadata = await getMetadata(file);\n format = metadata.format;\n } catch {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_OPTIMIZE.has(format);\n};\n\nconst isResizableImage = async (file: UploadableFile) => {\n let format;\n try {\n const metadata = await getMetadata(file);\n format = metadata.format;\n } catch {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_RESIZE.has(format);\n};\n\nconst isImage = async (file: UploadableFile) => {\n let format;\n try {\n const metadata = await getMetadata(file);\n format = metadata.format;\n } catch {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_PROCESS.has(format);\n};\n\nconst generateFileName = (name: string) => {\n const randomSuffix = () => crypto.randomBytes(5).toString('hex');\n const baseName = strings.nameToSlug(name, { separator: '_', lowercase: false });\n\n return `${baseName}_${randomSuffix()}`;\n};\n\nexport default {\n isFaultyImage,\n isOptimizableImage,\n isResizableImage,\n isImage,\n getDimensions,\n generateResponsiveFormats,\n generateThumbnail,\n optimize,\n generateFileName,\n};\n"],"names":["bytesToKbytes","fileUtils","getSharpOptions","limitInputPixels","strapi","config","get","undefined","FORMATS_TO_RESIZE","Set","FORMATS_TO_PROCESS","FORMATS_TO_OPTIMIZE","isOptimizableFormat","format","has","writeStreamToFile","stream","path","Promise","resolve","reject","writeStream","fs","createWriteStream","on","pipe","getMetadata","file","options","filepath","pipeline","sharp","metadata","then","catch","getStream","getDimensions","width","height","THUMBNAIL_RESIZE_OPTIONS","fit","resizeFileTo","name","hash","filePath","tmpWorkingDirectory","join","newInfo","transform","animated","resize","info","toFile","size","pageHeight","newFile","ext","mime","createReadStream","Object","assign","sizeInBytes","generateThumbnail","optimize","sizeOptimization","autoOrientation","getService","getSettings","transformer","quality","rotate","newWidth","newHeight","newSize","newPageHeight","DEFAULT_BREAKPOINTS","large","medium","small","getBreakpoints","generateResponsiveFormats","responsiveDimensions","originalDimensions","breakpoints","results","key","keys","breakpoint","breakpointSmallerThan","push","generateBreakpoint","isFaultyImage","stats","isOptimizableImage","isResizableImage","isImage","generateFileName","randomSuffix","crypto","randomBytes","toString","baseName","strings","nameToSlug","separator","lowercase"],"mappings":";;;;;;;AAeA,MAAM,EAAEA,aAAa,EAAE,GAAGC,IAAAA;AAE1B;;;;AAIC,IACD,MAAMC,eAAAA,GAAkB,IAAA;AACtB,IAAA,MAAM,EAAEC,gBAAgB,EAAE,GAAGC,MAAAA,CAAOC,MAAM,CAACC,GAAG,CAAkB,sBAAA,EAAwB,EAAC,CAAA,IAAM,EAAC;AAEhG,IAAA,IAAIH,oBAAoB,IAAA,EAAM;QAC5B,OAAOI,SAAAA;AACT,IAAA;IAEA,OAAO;AAAEJ,QAAAA;AAAiB,KAAA;AAC5B,CAAA;AAEA,MAAMK,iBAAAA,GAAoB,IAAIC,GAAAA,CAAI;AAAC,IAAA,MAAA;AAAQ,IAAA,KAAA;AAAO,IAAA,MAAA;AAAQ,IAAA,MAAA;AAAQ,IAAA;AAAM,CAAA,CAAA;AACxE,MAAMC,kBAAAA,GAAqB,IAAID,GAAAA,CAAI;AAAC,IAAA,MAAA;AAAQ,IAAA,KAAA;AAAO,IAAA,MAAA;AAAQ,IAAA,MAAA;AAAQ,IAAA,KAAA;AAAO,IAAA,KAAA;AAAO,IAAA;AAAO,CAAA,CAAA;AACxF,MAAME,mBAAAA,GAAsB,IAAIF,GAAAA,CAAI;AAAC,IAAA,MAAA;AAAQ,IAAA,KAAA;AAAO,IAAA,MAAA;AAAQ,IAAA,MAAA;AAAQ,IAAA;AAAO,CAAA,CAAA;AAE3E,MAAMG,sBAAsB,CAC1BC,MAAAA,GAEAA,WAAWN,SAAAA,IAAaI,mBAAAA,CAAoBG,GAAG,CAACD,MAAAA,CAAAA;AAElD,MAAME,oBAAoB,CAACC,MAAAA,EAAgCC,OACzD,IAAIC,OAAAA,CAAc,CAACC,OAAAA,EAASC,MAAAA,GAAAA;QAC1B,MAAMC,WAAAA,GAAcC,EAAAA,CAAGC,iBAAiB,CAACN,IAAAA,CAAAA;;QAEzCD,MAAAA,CAAOQ,EAAE,CAAC,OAAA,EAASJ,MAAAA,CAAAA;AACnBJ,QAAAA,MAAAA,CAAOS,IAAI,CAACJ,WAAAA,CAAAA;QACZA,WAAAA,CAAYG,EAAE,CAAC,OAAA,EAAS,IAAML,OAAAA,EAAAA,CAAAA;QAC9BE,WAAAA,CAAYG,EAAE,CAAC,OAAA,EAASJ,MAAAA,CAAAA;AAC1B,IAAA,CAAA,CAAA;AAEF,MAAMM,cAAc,CAACC,IAAAA,GAAAA;AACnB,IAAA,MAAMC,OAAAA,GAAU1B,eAAAA,EAAAA;IAEhB,IAAI,CAACyB,IAAAA,CAAKE,QAAQ,EAAE;QAClB,OAAO,IAAIX,OAAAA,CAAQ,CAACC,OAAAA,EAASC,MAAAA,GAAAA;YAC3B,MAAMU,QAAAA,GAAWF,OAAAA,GAAUG,KAAAA,CAAMH,OAAAA,CAAAA,GAAWG,KAAAA,EAAAA;AAC5CD,YAAAA,QAAAA,CAASE,QAAQ,EAAA,CAAGC,IAAI,CAACd,OAAAA,CAAAA,CAASe,KAAK,CAACd,MAAAA,CAAAA;YACxCO,IAAAA,CAAKQ,SAAS,EAAA,CAAGV,IAAI,CAACK,QAAAA,CAAAA;AACxB,QAAA,CAAA,CAAA;AACF,IAAA;AAEA,IAAA,OAAOC,KAAAA,CAAMJ,IAAAA,CAAKE,QAAQ,EAAED,SAASI,QAAQ,EAAA;AAC/C,CAAA;AAEA,MAAMI,gBAAgB,OAAOT,IAAAA,GAAAA;IAC3B,MAAM,EAAEU,QAAQ,IAAI,EAAEC,SAAS,IAAI,EAAE,GAAG,MAAMZ,WAAAA,CAAYC,IAAAA,CAAAA;IAE1D,OAAO;AAAEU,QAAAA,KAAAA;AAAOC,QAAAA;AAAO,KAAA;AACzB,CAAA;AAEA,MAAMC,wBAAAA,GAA2B;IAC/BF,KAAAA,EAAO,GAAA;IACPC,MAAAA,EAAQ,GAAA;IACRE,GAAAA,EAAK;AACP,CAAA;AAEA,MAAMC,YAAAA,GAAe,OACnBd,IAAAA,EACAC,OAAAA,EACA,EACEc,IAAI,EACJC,IAAI,EAIL,GAAA;IAED,MAAMC,QAAAA,GAAWjB,KAAKkB,mBAAmB,GAAGC,KAAKnB,IAAAA,CAAKkB,mBAAmB,EAAEF,IAAAA,CAAAA,GAAQA,IAAAA;IAEnF,IAAII,OAAAA;IACJ,IAAI,CAACpB,IAAAA,CAAKE,QAAQ,EAAE;AAClB,QAAA,MAAMmB,YAAYjB,KAAAA,CAAM;AAAE,YAAA,GAAG7B,eAAAA,EAAiB;YAAE+C,QAAAA,EAAU;AAAK,SAAA,CAAA,CAC5DC,MAAM,CAACtB,OAAAA,CAAAA,CACPJ,EAAE,CAAC,QAAQ,CAAC2B,IAAAA,GAAAA;YACXJ,OAAAA,GAAUI,IAAAA;AACZ,QAAA,CAAA,CAAA;AAEF,QAAA,MAAMpC,kBAAkBY,IAAAA,CAAKQ,SAAS,EAAA,CAAGV,IAAI,CAACuB,SAAAA,CAAAA,EAAYJ,QAAAA,CAAAA;IAC5D,CAAA,MAAO;AACLG,QAAAA,OAAAA,GAAU,MAAMhB,KAAAA,CAAMJ,IAAAA,CAAKE,QAAQ,EAAE;AAAE,YAAA,GAAG3B,eAAAA,EAAiB;YAAE+C,QAAAA,EAAU;AAAK,SAAA,CAAA,CACzEC,MAAM,CAACtB,OAAAA,CAAAA,CACPwB,MAAM,CAACR,QAAAA,CAAAA;AACZ,IAAA;IAEA,MAAM,EAAEP,KAAK,EAAEC,MAAM,EAAEe,IAAI,EAAEC,UAAU,EAAE,GAAGP,OAAAA,IAAW,EAAC;AAExD,IAAA,MAAMQ,OAAAA,GAA0B;AAC9Bb,QAAAA,IAAAA;AACAC,QAAAA,IAAAA;AACAa,QAAAA,GAAAA,EAAK7B,KAAK6B,GAAG;AACbC,QAAAA,IAAAA,EAAM9B,KAAK8B,IAAI;QACf5B,QAAAA,EAAUe,QAAAA;QACV3B,IAAAA,EAAMU,IAAAA,CAAKV,IAAI,IAAI,IAAA;QACnBkB,SAAAA,EAAW,IAAMb,EAAAA,CAAGoC,gBAAgB,CAACd,QAAAA;AACvC,KAAA;IAEAe,MAAAA,CAAOC,MAAM,CAACL,OAAAA,EAAS;AACrBlB,QAAAA,KAAAA;AACAC,QAAAA,MAAAA,EAAQgB,UAAAA,IAAchB,MAAAA;QACtBe,IAAAA,EAAMA,IAAAA,GAAOrD,cAAcqD,IAAAA,CAAAA,GAAQ,CAAA;QACnCQ,WAAAA,EAAaR;AACf,KAAA,CAAA;IACA,OAAOE,OAAAA;AACT,CAAA;AAEA,MAAMO,oBAAoB,OAAOnC,IAAAA,GAAAA;AAC/B,IAAA,IACEA,KAAKU,KAAK,IACVV,KAAKW,MAAM,KACVX,IAAAA,CAAKU,KAAK,GAAGE,wBAAAA,CAAyBF,KAAK,IAAIV,IAAAA,CAAKW,MAAM,GAAGC,wBAAAA,CAAyBD,MAAM,CAAD,EAC5F;QACA,OAAOG,YAAAA,CAAad,MAAMY,wBAAAA,EAA0B;AAClDG,YAAAA,IAAAA,EAAM,CAAC,UAAU,EAAEf,IAAAA,CAAKe,IAAI,CAAA,CAAE;AAC9BC,YAAAA,IAAAA,EAAM,CAAC,UAAU,EAAEhB,IAAAA,CAAKgB,IAAI,CAAA;AAC9B,SAAA,CAAA;AACF,IAAA;IAEA,OAAO,IAAA;AACT,CAAA;AAEA;;;;;IAMA,MAAMoB,WAAW,OAAOpC,IAAAA,GAAAA;AACtB,IAAA,MAAM,EAAEqC,gBAAAA,GAAmB,KAAK,EAAEC,kBAAkB,KAAK,EAAE,GACxD,MAAMC,UAAAA,CAAW,QAAA,CAAA,CAAUC,WAAW,MAAO,EAAC;AAEjD,IAAA,MAAM,EAAEtD,MAAM,EAAEwC,IAAI,EAAE,GAAG,MAAM3B,WAAAA,CAAYC,IAAAA,CAAAA;AAE3C,IAAA,IAAI,CAACqC,gBAAAA,IAAoBC,eAAc,KAAMrD,oBAAoBC,MAAAA,CAAAA,EAAS;QACxE,IAAIuD,WAAAA;QACJ,IAAI,CAACzC,IAAAA,CAAKE,QAAQ,EAAE;AAClBuC,YAAAA,WAAAA,GAAcrC,KAAAA,CAAM;AAAE,gBAAA,GAAG7B,eAAAA,EAAiB;gBAAE+C,QAAAA,EAAU;AAAK,aAAA,CAAA;QAC7D,CAAA,MAAO;YACLmB,WAAAA,GAAcrC,KAAAA,CAAMJ,IAAAA,CAAKE,QAAQ,EAAE;AAAE,gBAAA,GAAG3B,eAAAA,EAAiB;gBAAE+C,QAAAA,EAAU;AAAK,aAAA,CAAA;AAC5E,QAAA;;QAEAmB,WAAW,CAACvD,OAAO,CAAC;AAAEwD,YAAAA,OAAAA,EAASL,mBAAmB,EAAA,GAAK;AAAI,SAAA,CAAA;;AAE3D,QAAA,IAAIC,eAAAA,EAAiB;AACnBG,YAAAA,WAAAA,CAAYE,MAAM,EAAA;AACpB,QAAA;QACA,MAAM1B,QAAAA,GAAWjB,KAAKkB,mBAAmB,GACrCC,KAAKnB,IAAAA,CAAKkB,mBAAmB,EAAE,CAAC,UAAU,EAAElB,IAAAA,CAAKgB,IAAI,EAAE,CAAA,GACvD,CAAC,UAAU,EAAEhB,IAAAA,CAAKgB,IAAI,CAAA,CAAE;QAE5B,IAAII,OAAAA;QACJ,IAAI,CAACpB,IAAAA,CAAKE,QAAQ,EAAE;YAClBuC,WAAAA,CAAY5C,EAAE,CAAC,MAAA,EAAQ,CAAC2B,IAAAA,GAAAA;gBACtBJ,OAAAA,GAAUI,IAAAA;AACZ,YAAA,CAAA,CAAA;AAEA,YAAA,MAAMpC,kBAAkBY,IAAAA,CAAKQ,SAAS,EAAA,CAAGV,IAAI,CAAC2C,WAAAA,CAAAA,EAAcxB,QAAAA,CAAAA;QAC9D,CAAA,MAAO;YACLG,OAAAA,GAAU,MAAMqB,WAAAA,CAAYhB,MAAM,CAACR,QAAAA,CAAAA;AACrC,QAAA;AAEA,QAAA,MAAM,EACJP,KAAAA,EAAOkC,QAAQ,EACfjC,QAAQkC,SAAS,EACjBnB,IAAAA,EAAMoB,OAAO,EACbnB,UAAAA,EAAYoB,aAAa,EAC1B,GAAG3B,WAAW,EAAC;AAEhB,QAAA,MAAMQ,OAAAA,GAAU;AAAE,YAAA,GAAG5B;AAAK,SAAA;AAE1B4B,QAAAA,OAAAA,CAAQpB,SAAS,GAAG,IAAMb,EAAAA,CAAGoC,gBAAgB,CAACd,QAAAA,CAAAA;AAC9CW,QAAAA,OAAAA,CAAQ1B,QAAQ,GAAGe,QAAAA;QAEnB,IAAI6B,OAAAA,IAAWpB,IAAAA,IAAQoB,OAAAA,GAAUpB,IAAAA,EAAM;;YAErC,OAAO1B,IAAAA;AACT,QAAA;QAEA,OAAOgC,MAAAA,CAAOC,MAAM,CAACL,OAAAA,EAAS;YAC5BlB,KAAAA,EAAOkC,QAAAA;AACPjC,YAAAA,MAAAA,EAAQoC,aAAAA,IAAiBF,SAAAA;YACzBnB,IAAAA,EAAMoB,OAAAA,GAAUzE,cAAcyE,OAAAA,CAAAA,GAAW,CAAA;YACzCZ,WAAAA,EAAaY;AACf,SAAA,CAAA;AACF,IAAA;IAEA,OAAO9C,IAAAA;AACT,CAAA;AAEA,MAAMgD,mBAAAA,GAAsB;IAC1BC,KAAAA,EAAO,IAAA;IACPC,MAAAA,EAAQ,GAAA;IACRC,KAAAA,EAAO;AACT,CAAA;AAEA,MAAMC,iBAAiB,IACrB3E,MAAAA,CAAOC,MAAM,CAACC,GAAG,CAAyB,4BAAA,EAA8BqE,mBAAAA,CAAAA;AAE1E,MAAMK,4BAA4B,OAAOrD,IAAAA,GAAAA;IACvC,MAAM,EAAEsD,oBAAAA,GAAuB,KAAK,EAAE,GAAG,MAAOf,UAAAA,CAAW,QAAA,CAAA,CAAUC,WAAW,EAAA,IAAO,EAAC;IAExF,IAAI,CAACc,oBAAAA,EAAsB,OAAO,EAAE;IAEpC,MAAMC,kBAAAA,GAAqB,MAAM9C,aAAAA,CAAcT,IAAAA,CAAAA;AAE/C,IAAA,MAAMwD,WAAAA,GAAcJ,cAAAA,EAAAA;AACpB,IAAA,MAAMK,UAAU,EAAE;AAElB,IAAA,KAAK,MAAMC,GAAAA,IAAO1B,MAAAA,CAAO2B,IAAI,CAACH,WAAAA,CAAAA,CAAc;QAC1C,MAAMI,UAAAA,GAAaJ,WAAW,CAACE,GAAAA,CAAI;QAEnC,IAAIG,qBAAAA,CAAsBD,YAAYL,kBAAAA,CAAAA,EAAqB;AACzDE,YAAAA,OAAAA,CAAQK,IAAI,CAAC,MAAMC,kBAAAA,CAAmBL,GAAAA,EAAK;AAAE1D,gBAAAA,IAAAA;AAAM4D,gBAAAA;AAAW,aAAA,CAAA,CAAA;AAChE,QAAA;AACF,IAAA;IAEA,OAAOH,OAAAA;AACT,CAAA;AAEA,MAAMM,qBAAqB,OACzBL,GAAAA,EACA,EAAE1D,IAAI,EAAE4D,UAAU,EAAgD,GAAA;IAElE,MAAMhC,OAAAA,GAAU,MAAMd,YAAAA,CACpBd,IAAAA,EACA;QACEU,KAAAA,EAAOkD,UAAAA;QACPjD,MAAAA,EAAQiD,UAAAA;QACR/C,GAAAA,EAAK;KACP,EACA;AACEE,QAAAA,IAAAA,EAAM,GAAG2C,GAAAA,CAAI,CAAC,EAAE1D,IAAAA,CAAKe,IAAI,CAAA,CAAE;AAC3BC,QAAAA,IAAAA,EAAM,GAAG0C,GAAAA,CAAI,CAAC,EAAE1D,IAAAA,CAAKgB,IAAI,CAAA;AAC3B,KAAA,CAAA;IAEF,OAAO;AACL0C,QAAAA,GAAAA;QACA1D,IAAAA,EAAM4B;AACR,KAAA;AACF,CAAA;AAEA,MAAMiC,wBAAwB,CAACD,UAAAA,EAAoB,EAAElD,KAAK,EAAEC,MAAM,EAAc,GAAA;IAC9E,OAAOiD,UAAAA,IAAclD,KAAAA,IAAS,CAAA,KAAMkD,UAAAA,IAAcjD,UAAU,CAAA,CAAA;AAC9D,CAAA;AAEA;;IAGA,MAAMqD,gBAAgB,OAAOhE,IAAAA,GAAAA;AAC3B,IAAA,MAAMC,OAAAA,GAAU1B,eAAAA,EAAAA;IAEhB,IAAI,CAACyB,IAAAA,CAAKE,QAAQ,EAAE;QAClB,OAAO,IAAIX,QAAiB,CAACC,OAAAA,GAAAA;YAC3B,MAAMW,QAAAA,GAAWF,OAAAA,GAAUG,KAAAA,CAAMH,OAAAA,CAAAA,GAAWG,KAAAA,EAAAA;YAC5CD,QAAAA,CACG8D,KAAK,EAAA,CACL3D,IAAI,CAAC,IAAMd,QAAQ,KAAA,CAAA,CAAA,CACnBe,KAAK,CAAC,IAAMf,OAAAA,CAAQ,IAAA,CAAA,CAAA;YACvBQ,IAAAA,CAAKQ,SAAS,EAAA,CAAGV,IAAI,CAACK,QAAAA,CAAAA;AACxB,QAAA,CAAA,CAAA;AACF,IAAA;IAEA,IAAI;AACF,QAAA,MAAMC,KAAAA,CAAMJ,IAAAA,CAAKE,QAAQ,EAAED,SAASgE,KAAK,EAAA;QACzC,OAAO,KAAA;AACT,IAAA,CAAA,CAAE,OAAM;QACN,OAAO,IAAA;AACT,IAAA;AACF,CAAA;AAEA,MAAMC,qBAAqB,OAAOlE,IAAAA,GAAAA;IAChC,IAAId,MAAAA;IACJ,IAAI;QACF,MAAMmB,QAAAA,GAAW,MAAMN,WAAAA,CAAYC,IAAAA,CAAAA;AACnCd,QAAAA,MAAAA,GAASmB,SAASnB,MAAM;AAC1B,IAAA,CAAA,CAAE,OAAM;;QAEN,OAAO,KAAA;AACT,IAAA;IACA,OAAOA,MAAAA,IAAUF,mBAAAA,CAAoBG,GAAG,CAACD,MAAAA,CAAAA;AAC3C,CAAA;AAEA,MAAMiF,mBAAmB,OAAOnE,IAAAA,GAAAA;IAC9B,IAAId,MAAAA;IACJ,IAAI;QACF,MAAMmB,QAAAA,GAAW,MAAMN,WAAAA,CAAYC,IAAAA,CAAAA;AACnCd,QAAAA,MAAAA,GAASmB,SAASnB,MAAM;AAC1B,IAAA,CAAA,CAAE,OAAM;;QAEN,OAAO,KAAA;AACT,IAAA;IACA,OAAOA,MAAAA,IAAUL,iBAAAA,CAAkBM,GAAG,CAACD,MAAAA,CAAAA;AACzC,CAAA;AAEA,MAAMkF,UAAU,OAAOpE,IAAAA,GAAAA;IACrB,IAAId,MAAAA;IACJ,IAAI;QACF,MAAMmB,QAAAA,GAAW,MAAMN,WAAAA,CAAYC,IAAAA,CAAAA;AACnCd,QAAAA,MAAAA,GAASmB,SAASnB,MAAM;AAC1B,IAAA,CAAA,CAAE,OAAM;;QAEN,OAAO,KAAA;AACT,IAAA;IACA,OAAOA,MAAAA,IAAUH,kBAAAA,CAAmBI,GAAG,CAACD,MAAAA,CAAAA;AAC1C,CAAA;AAEA,MAAMmF,mBAAmB,CAACtD,IAAAA,GAAAA;AACxB,IAAA,MAAMuD,eAAe,IAAMC,MAAAA,CAAOC,WAAW,CAAC,CAAA,CAAA,CAAGC,QAAQ,CAAC,KAAA,CAAA;AAC1D,IAAA,MAAMC,QAAAA,GAAWC,OAAAA,CAAQC,UAAU,CAAC7D,IAAAA,EAAM;QAAE8D,SAAAA,EAAW,GAAA;QAAKC,SAAAA,EAAW;AAAM,KAAA,CAAA;AAE7E,IAAA,OAAO,CAAA,EAAGJ,QAAAA,CAAS,CAAC,EAAEJ,YAAAA,EAAAA,CAAAA,CAAgB;AACxC,CAAA;AAEA,wBAAe;AACbN,IAAAA,aAAAA;AACAE,IAAAA,kBAAAA;AACAC,IAAAA,gBAAAA;AACAC,IAAAA,OAAAA;AACA3D,IAAAA,aAAAA;AACA4C,IAAAA,yBAAAA;AACAlB,IAAAA,iBAAAA;AACAC,IAAAA,QAAAA;AACAiC,IAAAA;AACF,CAAA;;;;"}
|
|
1
|
+
{"version":3,"file":"image-manipulation.mjs","sources":["../../../server/src/services/image-manipulation.ts"],"sourcesContent":["import fs from 'fs';\nimport { join } from 'path';\nimport sharp, { type Metadata, type ResizeOptions, type SharpOptions } from 'sharp';\nimport crypto from 'crypto';\nimport { strings, file as fileUtils } from '@strapi/utils';\n\nimport { getService } from '../utils';\n\nimport type { Config, UploadableFile } from '../types';\n\ntype Dimensions = {\n width: number | null;\n height: number | null;\n};\n\nconst { bytesToKbytes } = fileUtils;\n\n/**\n * Instance-level sharp options from the plugin config (e.g. `limitInputPixels`).\n * Global settings (`cache`, `concurrency`) are applied once in the plugin register phase.\n * Returns `undefined` when nothing is configured so bare stream pipelines can use `sharp()`.\n */\nconst getSharpOptions = (): SharpOptions | undefined => {\n const { limitInputPixels } = strapi.config.get<Config['sharp']>('plugin::upload.sharp', {}) ?? {};\n\n if (limitInputPixels == null) {\n return undefined;\n }\n\n return { limitInputPixels };\n};\n\nconst FORMATS_TO_RESIZE = new Set(['jpeg', 'png', 'webp', 'tiff', 'gif', 'avif']);\nconst FORMATS_TO_PROCESS = new Set(['jpeg', 'png', 'webp', 'tiff', 'svg', 'gif', 'avif']);\nconst FORMATS_TO_OPTIMIZE = new Set(['jpeg', 'png', 'webp', 'tiff', 'avif']);\n\nconst isOptimizableFormat = (\n format: string | undefined\n): format is 'jpeg' | 'png' | 'webp' | 'tiff' | 'avif' =>\n format !== undefined && FORMATS_TO_OPTIMIZE.has(format);\n\n/**\n * sharp reports AVIF files as `heif` with `av1` compression. Normalize them to `avif`;\n * other HEIF files (e.g. HEIC, `hevc` compression) keep the `heif` format and stay unprocessed.\n */\nconst getFormat = ({ format, compression }: Metadata) =>\n format === 'heif' && compression === 'av1' ? 'avif' : format;\n\nconst writeStreamToFile = (stream: NodeJS.ReadWriteStream, path: string) =>\n new Promise<void>((resolve, reject) => {\n const writeStream = fs.createWriteStream(path);\n // Reject promise if there is an error with the provided stream\n stream.on('error', reject);\n stream.pipe(writeStream);\n writeStream.on('close', () => resolve());\n writeStream.on('error', reject);\n });\n\nconst getMetadata = (file: UploadableFile): Promise<Metadata> => {\n const options = getSharpOptions();\n\n if (!file.filepath) {\n return new Promise((resolve, reject) => {\n const pipeline = options ? sharp(options) : sharp();\n pipeline.metadata().then(resolve).catch(reject);\n file.getStream().pipe(pipeline);\n });\n }\n\n return sharp(file.filepath, options).metadata();\n};\n\nconst getDimensions = async (file: UploadableFile): Promise<Dimensions> => {\n const { width = null, height = null } = await getMetadata(file);\n\n return { width, height };\n};\n\nconst THUMBNAIL_RESIZE_OPTIONS = {\n width: 245,\n height: 156,\n fit: 'inside',\n} satisfies ResizeOptions;\n\nconst resizeFileTo = async (\n file: UploadableFile,\n options: ResizeOptions,\n {\n name,\n hash,\n }: {\n name: string;\n hash: string;\n }\n) => {\n const filePath = file.tmpWorkingDirectory ? join(file.tmpWorkingDirectory, hash) : hash;\n\n let newInfo;\n if (!file.filepath) {\n const transform = sharp({ ...getSharpOptions(), animated: true })\n .resize(options)\n .on('info', (info) => {\n newInfo = info;\n });\n\n await writeStreamToFile(file.getStream().pipe(transform), filePath);\n } else {\n newInfo = await sharp(file.filepath, { ...getSharpOptions(), animated: true })\n .resize(options)\n .toFile(filePath);\n }\n\n const { width, height, size, pageHeight } = newInfo ?? {};\n\n const newFile: UploadableFile = {\n name,\n hash,\n ext: file.ext,\n mime: file.mime,\n filepath: filePath,\n path: file.path || null,\n getStream: () => fs.createReadStream(filePath),\n };\n\n Object.assign(newFile, {\n width,\n height: pageHeight ?? height,\n size: size ? bytesToKbytes(size) : 0,\n sizeInBytes: size,\n });\n return newFile;\n};\n\nconst generateThumbnail = async (file: UploadableFile) => {\n if (\n file.width &&\n file.height &&\n (file.width > THUMBNAIL_RESIZE_OPTIONS.width || file.height > THUMBNAIL_RESIZE_OPTIONS.height)\n ) {\n return resizeFileTo(file, THUMBNAIL_RESIZE_OPTIONS, {\n name: `thumbnail_${file.name}`,\n hash: `thumbnail_${file.hash}`,\n });\n }\n\n return null;\n};\n\n/**\n * Optimize image by:\n * - auto orienting image based on EXIF data\n * - reduce image quality\n *\n */\nconst optimize = async (file: UploadableFile) => {\n const { sizeOptimization = false, autoOrientation = false } =\n (await getService('upload').getSettings()) ?? {};\n\n const metadata = await getMetadata(file);\n const format = getFormat(metadata);\n const { size } = metadata;\n\n if ((sizeOptimization || autoOrientation) && isOptimizableFormat(format)) {\n let transformer;\n if (!file.filepath) {\n transformer = sharp({ ...getSharpOptions(), animated: true });\n } else {\n transformer = sharp(file.filepath, { ...getSharpOptions(), animated: true });\n }\n // reduce image quality\n transformer[format]({ quality: sizeOptimization ? 80 : 100 });\n // rotate image based on EXIF data\n if (autoOrientation) {\n transformer.rotate();\n }\n const filePath = file.tmpWorkingDirectory\n ? join(file.tmpWorkingDirectory, `optimized-${file.hash}`)\n : `optimized-${file.hash}`;\n\n let newInfo;\n if (!file.filepath) {\n transformer.on('info', (info) => {\n newInfo = info;\n });\n\n await writeStreamToFile(file.getStream().pipe(transformer), filePath);\n } else {\n newInfo = await transformer.toFile(filePath);\n }\n\n const {\n width: newWidth,\n height: newHeight,\n size: newSize,\n pageHeight: newPageHeight,\n } = newInfo ?? {};\n\n const newFile = { ...file };\n\n newFile.getStream = () => fs.createReadStream(filePath);\n newFile.filepath = filePath;\n\n if (newSize && size && newSize > size) {\n // Ignore optimization if output is bigger than original\n return file;\n }\n\n return Object.assign(newFile, {\n width: newWidth,\n height: newPageHeight ?? newHeight,\n size: newSize ? bytesToKbytes(newSize) : 0,\n sizeInBytes: newSize,\n });\n }\n\n return file;\n};\n\nconst DEFAULT_BREAKPOINTS = {\n large: 1000,\n medium: 750,\n small: 500,\n};\n\nconst getBreakpoints = () =>\n strapi.config.get<Record<string, number>>('plugin::upload.breakpoints', DEFAULT_BREAKPOINTS);\n\nconst generateResponsiveFormats = async (file: UploadableFile) => {\n const { responsiveDimensions = false } = (await getService('upload').getSettings()) ?? {};\n\n if (!responsiveDimensions) return [];\n\n const originalDimensions = await getDimensions(file);\n\n const breakpoints = getBreakpoints();\n const results = [];\n\n for (const key of Object.keys(breakpoints)) {\n const breakpoint = breakpoints[key];\n\n if (breakpointSmallerThan(breakpoint, originalDimensions)) {\n results.push(await generateBreakpoint(key, { file, breakpoint }));\n }\n }\n\n return results;\n};\n\nconst generateBreakpoint = async (\n key: string,\n { file, breakpoint }: { file: UploadableFile; breakpoint: number }\n) => {\n const newFile = await resizeFileTo(\n file,\n {\n width: breakpoint,\n height: breakpoint,\n fit: 'inside',\n },\n {\n name: `${key}_${file.name}`,\n hash: `${key}_${file.hash}`,\n }\n );\n return {\n key,\n file: newFile,\n };\n};\n\nconst breakpointSmallerThan = (breakpoint: number, { width, height }: Dimensions) => {\n return breakpoint < (width ?? 0) || breakpoint < (height ?? 0);\n};\n\n/**\n * Applies a simple image transformation to see if the image is faulty/corrupted.\n */\nconst isFaultyImage = async (file: UploadableFile) => {\n const options = getSharpOptions();\n\n if (!file.filepath) {\n return new Promise<boolean>((resolve) => {\n const pipeline = options ? sharp(options) : sharp();\n pipeline\n .stats()\n .then(() => resolve(false))\n .catch(() => resolve(true));\n file.getStream().pipe(pipeline);\n });\n }\n\n try {\n await sharp(file.filepath, options).stats();\n return false;\n } catch {\n return true;\n }\n};\n\nconst isOptimizableImage = async (file: UploadableFile) => {\n let format;\n try {\n const metadata = await getMetadata(file);\n format = getFormat(metadata);\n } catch {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_OPTIMIZE.has(format);\n};\n\nconst isResizableImage = async (file: UploadableFile) => {\n let format;\n try {\n const metadata = await getMetadata(file);\n format = getFormat(metadata);\n } catch {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_RESIZE.has(format);\n};\n\nconst isImage = async (file: UploadableFile) => {\n let format;\n try {\n const metadata = await getMetadata(file);\n format = getFormat(metadata);\n } catch {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_PROCESS.has(format);\n};\n\nconst generateFileName = (name: string) => {\n const randomSuffix = () => crypto.randomBytes(5).toString('hex');\n const baseName = strings.nameToSlug(name, { separator: '_', lowercase: false });\n\n return `${baseName}_${randomSuffix()}`;\n};\n\nexport default {\n isFaultyImage,\n isOptimizableImage,\n isResizableImage,\n isImage,\n getDimensions,\n generateResponsiveFormats,\n generateThumbnail,\n optimize,\n generateFileName,\n};\n"],"names":["bytesToKbytes","fileUtils","getSharpOptions","limitInputPixels","strapi","config","get","undefined","FORMATS_TO_RESIZE","Set","FORMATS_TO_PROCESS","FORMATS_TO_OPTIMIZE","isOptimizableFormat","format","has","getFormat","compression","writeStreamToFile","stream","path","Promise","resolve","reject","writeStream","fs","createWriteStream","on","pipe","getMetadata","file","options","filepath","pipeline","sharp","metadata","then","catch","getStream","getDimensions","width","height","THUMBNAIL_RESIZE_OPTIONS","fit","resizeFileTo","name","hash","filePath","tmpWorkingDirectory","join","newInfo","transform","animated","resize","info","toFile","size","pageHeight","newFile","ext","mime","createReadStream","Object","assign","sizeInBytes","generateThumbnail","optimize","sizeOptimization","autoOrientation","getService","getSettings","transformer","quality","rotate","newWidth","newHeight","newSize","newPageHeight","DEFAULT_BREAKPOINTS","large","medium","small","getBreakpoints","generateResponsiveFormats","responsiveDimensions","originalDimensions","breakpoints","results","key","keys","breakpoint","breakpointSmallerThan","push","generateBreakpoint","isFaultyImage","stats","isOptimizableImage","isResizableImage","isImage","generateFileName","randomSuffix","crypto","randomBytes","toString","baseName","strings","nameToSlug","separator","lowercase"],"mappings":"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"}
|
|
@@ -9,6 +9,7 @@ var mimeTypes = require('mime-types');
|
|
|
9
9
|
var utils = require('@strapi/utils');
|
|
10
10
|
var constants = require('../constants.js');
|
|
11
11
|
var index = require('../utils/index.js');
|
|
12
|
+
var auditLogs = require('../audit-logs.js');
|
|
12
13
|
|
|
13
14
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
15
|
|
|
@@ -20,6 +21,15 @@ var ___default = /*#__PURE__*/_interopDefault(_);
|
|
|
20
21
|
|
|
21
22
|
const { UPDATED_BY_ATTRIBUTE, CREATED_BY_ATTRIBUTE } = utils.contentTypes.constants;
|
|
22
23
|
const { MEDIA_CREATE, MEDIA_UPDATE, MEDIA_DELETE } = constants.ALLOWED_WEBHOOK_EVENTS;
|
|
24
|
+
// The audit log records the folder of an updated file
|
|
25
|
+
const FOLDER_REF_POPULATE = {
|
|
26
|
+
folder: {
|
|
27
|
+
fields: [
|
|
28
|
+
'id',
|
|
29
|
+
'name'
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
};
|
|
23
33
|
const { ApplicationError, NotFoundError } = utils.errors;
|
|
24
34
|
const { bytesToKbytes } = utils.file;
|
|
25
35
|
/**
|
|
@@ -196,6 +206,15 @@ var upload = (({ strapi })=>{
|
|
|
196
206
|
}
|
|
197
207
|
return uploadedFiles;
|
|
198
208
|
}
|
|
209
|
+
// `_.set(fileData, ['formats', key], ...)` reads an all-digit key (a `breakpoints`
|
|
210
|
+
// entry like `{ 100: 100 }`) as an array index and builds an array when formats is
|
|
211
|
+
// unset, so build the object explicitly.
|
|
212
|
+
function setFormat(fileData, key, format) {
|
|
213
|
+
fileData.formats = {
|
|
214
|
+
...fileData.formats,
|
|
215
|
+
[key]: format
|
|
216
|
+
};
|
|
217
|
+
}
|
|
199
218
|
/**
|
|
200
219
|
* When uploading an image, an additional thumbnail is generated.
|
|
201
220
|
* Also, if there are responsive formats defined, another set of images will be generated too.
|
|
@@ -214,16 +233,13 @@ var upload = (({ strapi })=>{
|
|
|
214
233
|
// For performance reasons, all uploads are wrapped in a single Promise.all
|
|
215
234
|
const uploadThumbnail = async (thumbnailFile)=>{
|
|
216
235
|
await index.getService('provider').upload(thumbnailFile);
|
|
217
|
-
|
|
236
|
+
setFormat(fileData, 'thumbnail', thumbnailFile);
|
|
218
237
|
};
|
|
219
238
|
// Generate thumbnail and responsive formats
|
|
220
239
|
const uploadResponsiveFormat = async (format)=>{
|
|
221
240
|
const { key, file } = format;
|
|
222
241
|
await index.getService('provider').upload(file);
|
|
223
|
-
|
|
224
|
-
'formats',
|
|
225
|
-
key
|
|
226
|
-
], file);
|
|
242
|
+
setFormat(fileData, key, file);
|
|
227
243
|
};
|
|
228
244
|
const uploadPromises = [];
|
|
229
245
|
// Upload image
|
|
@@ -265,10 +281,7 @@ var upload = (({ strapi })=>{
|
|
|
265
281
|
} else {
|
|
266
282
|
await index.getService('provider').upload(newFormat);
|
|
267
283
|
}
|
|
268
|
-
|
|
269
|
-
'formats',
|
|
270
|
-
key
|
|
271
|
-
], newFormat);
|
|
284
|
+
setFormat(fileData, key, newFormat);
|
|
272
285
|
};
|
|
273
286
|
const promises = [];
|
|
274
287
|
// Replace the main file
|
|
@@ -322,7 +335,7 @@ var upload = (({ strapi })=>{
|
|
|
322
335
|
}
|
|
323
336
|
async function updateFileInfo(id, { name, alternativeText, caption, focalPoint, folder }, opts) {
|
|
324
337
|
const { user } = opts ?? {};
|
|
325
|
-
const dbFile = await findOne(id);
|
|
338
|
+
const dbFile = await findOne(id, FOLDER_REF_POPULATE);
|
|
326
339
|
if (!dbFile) {
|
|
327
340
|
throw new NotFoundError();
|
|
328
341
|
}
|
|
@@ -333,18 +346,22 @@ var upload = (({ strapi })=>{
|
|
|
333
346
|
alternativeText: ___default.default.isNil(alternativeText) ? dbFile.alternativeText : alternativeText,
|
|
334
347
|
caption: ___default.default.isNil(caption) ? dbFile.caption : caption,
|
|
335
348
|
focalPoint: ___default.default.isNil(focalPoint) ? dbFile.focalPoint : focalPoint,
|
|
336
|
-
|
|
349
|
+
...___default.default.isUndefined(folder) ? {} : {
|
|
350
|
+
folder
|
|
351
|
+
},
|
|
337
352
|
folderPath: ___default.default.isUndefined(folder) ? dbFile.folderPath : await fileService.getFolderPath(folder)
|
|
338
353
|
};
|
|
339
354
|
return update(id, newInfos, {
|
|
340
355
|
user
|
|
356
|
+
}, {
|
|
357
|
+
previous: dbFile
|
|
341
358
|
});
|
|
342
359
|
}
|
|
343
360
|
async function replace(id, { data, file }, opts) {
|
|
344
361
|
const { user } = opts ?? {};
|
|
345
362
|
const config = strapi.config.get('plugin::upload');
|
|
346
363
|
const { isImage } = index.getService('image-manipulation');
|
|
347
|
-
const dbFile = await findOne(id);
|
|
364
|
+
const dbFile = await findOne(id, FOLDER_REF_POPULATE);
|
|
348
365
|
if (!dbFile) {
|
|
349
366
|
throw new NotFoundError();
|
|
350
367
|
}
|
|
@@ -375,8 +392,14 @@ var upload = (({ strapi })=>{
|
|
|
375
392
|
folderPath: dbFile.folderPath
|
|
376
393
|
});
|
|
377
394
|
}
|
|
378
|
-
//
|
|
379
|
-
|
|
395
|
+
// `update` only writes the keys it gets, so clear the old image values. A new
|
|
396
|
+
// image gets its own from replaceImage / uploadImage; a non-image keeps null,
|
|
397
|
+
// like a fresh upload of the same file.
|
|
398
|
+
___default.default.assign(fileData, {
|
|
399
|
+
width: null,
|
|
400
|
+
height: null,
|
|
401
|
+
formats: null
|
|
402
|
+
});
|
|
380
403
|
if (dbFile.provider === config.provider) {
|
|
381
404
|
if (await isImage(fileData)) {
|
|
382
405
|
await replaceImage(fileData, dbFile);
|
|
@@ -402,9 +425,35 @@ var upload = (({ strapi })=>{
|
|
|
402
425
|
}
|
|
403
426
|
return update(id, fileData, {
|
|
404
427
|
user
|
|
428
|
+
}, {
|
|
429
|
+
replaced: true,
|
|
430
|
+
previous: dbFile
|
|
405
431
|
});
|
|
406
432
|
}
|
|
407
|
-
async function
|
|
433
|
+
async function getFolderAfterUpdate(values, previous) {
|
|
434
|
+
const previousFolder = previous?.folder ?? null;
|
|
435
|
+
if (values.folder === undefined) {
|
|
436
|
+
return previousFolder;
|
|
437
|
+
}
|
|
438
|
+
const value = values.folder;
|
|
439
|
+
const folderId = value !== null && typeof value === 'object' ? value.id : value;
|
|
440
|
+
if (folderId == null) {
|
|
441
|
+
return null;
|
|
442
|
+
}
|
|
443
|
+
if (previousFolder && Number(previousFolder.id) === Number(folderId)) {
|
|
444
|
+
return previousFolder;
|
|
445
|
+
}
|
|
446
|
+
return strapi.db.query(constants.FOLDER_MODEL_UID).findOne({
|
|
447
|
+
where: {
|
|
448
|
+
id: folderId
|
|
449
|
+
},
|
|
450
|
+
select: [
|
|
451
|
+
'id',
|
|
452
|
+
'name'
|
|
453
|
+
]
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
async function update(id, values, opts, { replaced = false, previous: knownPrevious } = {}) {
|
|
408
457
|
const { user } = opts ?? {};
|
|
409
458
|
const fileValues = {
|
|
410
459
|
...values
|
|
@@ -415,6 +464,20 @@ var upload = (({ strapi })=>{
|
|
|
415
464
|
});
|
|
416
465
|
}
|
|
417
466
|
await sendMediaMetrics(fileValues);
|
|
467
|
+
// Callers that already read the file pass it, with its folder
|
|
468
|
+
const previous = knownPrevious ?? await strapi.db.query(constants.FILE_MODEL_UID).findOne({
|
|
469
|
+
where: {
|
|
470
|
+
id
|
|
471
|
+
},
|
|
472
|
+
populate: {
|
|
473
|
+
folder: {
|
|
474
|
+
select: [
|
|
475
|
+
'id',
|
|
476
|
+
'name'
|
|
477
|
+
]
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
});
|
|
418
481
|
const res = await strapi.db.query(constants.FILE_MODEL_UID).update({
|
|
419
482
|
where: {
|
|
420
483
|
id
|
|
@@ -422,6 +485,18 @@ var upload = (({ strapi })=>{
|
|
|
422
485
|
data: fileValues
|
|
423
486
|
});
|
|
424
487
|
await emitEvent(MEDIA_UPDATE, res);
|
|
488
|
+
// The webhook event above carries no folder (a private field) and not the file as it was
|
|
489
|
+
if (res && previous) {
|
|
490
|
+
const folder = await getFolderAfterUpdate(values, previous);
|
|
491
|
+
strapi.eventHub.emit(auditLogs.AUDITED_EVENTS.MEDIA_UPDATE_AUDIT, {
|
|
492
|
+
file: auditLogs.toAuditedFile({
|
|
493
|
+
...res,
|
|
494
|
+
folder
|
|
495
|
+
}),
|
|
496
|
+
previous: auditLogs.toAuditedFile(previous),
|
|
497
|
+
replaced
|
|
498
|
+
});
|
|
499
|
+
}
|
|
425
500
|
return res;
|
|
426
501
|
}
|
|
427
502
|
async function add(values, opts) {
|
|
@@ -595,13 +670,22 @@ var upload = (({ strapi })=>{
|
|
|
595
670
|
} else {
|
|
596
671
|
await index.getService('metrics').trackUsage('didDisableResponsiveDimensions');
|
|
597
672
|
}
|
|
598
|
-
|
|
673
|
+
const previous = await getSettings();
|
|
674
|
+
await strapi.store({
|
|
599
675
|
type: 'plugin',
|
|
600
676
|
name: 'upload',
|
|
601
677
|
key: 'settings'
|
|
602
678
|
}).set({
|
|
603
679
|
value
|
|
604
680
|
});
|
|
681
|
+
const changes = auditLogs.getUploadSettingsChanges(previous, value);
|
|
682
|
+
if (Object.keys(changes).length > 0) {
|
|
683
|
+
await utils.emitAudit({
|
|
684
|
+
strapi
|
|
685
|
+
}, auditLogs.AUDITED_EVENTS.UPLOAD_SETTINGS_UPDATE, {
|
|
686
|
+
changes
|
|
687
|
+
});
|
|
688
|
+
}
|
|
605
689
|
}
|
|
606
690
|
async function getConfiguration() {
|
|
607
691
|
const res = await strapi.store({
|