@strapi/upload 5.47.1 → 5.48.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.
Files changed (101) hide show
  1. package/dist/admin/components/EditAssetDialog/EditAssetContent.js +12 -2
  2. package/dist/admin/components/EditAssetDialog/EditAssetContent.js.map +1 -1
  3. package/dist/admin/components/EditAssetDialog/EditAssetContent.mjs +12 -2
  4. package/dist/admin/components/EditAssetDialog/EditAssetContent.mjs.map +1 -1
  5. package/dist/admin/components/UploadAssetDialog/UploadAssetDialog.js +1 -0
  6. package/dist/admin/components/UploadAssetDialog/UploadAssetDialog.js.map +1 -1
  7. package/dist/admin/components/UploadAssetDialog/UploadAssetDialog.mjs +1 -0
  8. package/dist/admin/components/UploadAssetDialog/UploadAssetDialog.mjs.map +1 -1
  9. package/dist/admin/future/components/Drawer.js +7 -8
  10. package/dist/admin/future/components/Drawer.js.map +1 -1
  11. package/dist/admin/future/components/Drawer.mjs +7 -8
  12. package/dist/admin/future/components/Drawer.mjs.map +1 -1
  13. package/dist/admin/future/components/UploadProgressDialog.js +33 -29
  14. package/dist/admin/future/components/UploadProgressDialog.js.map +1 -1
  15. package/dist/admin/future/components/UploadProgressDialog.mjs +36 -32
  16. package/dist/admin/future/components/UploadProgressDialog.mjs.map +1 -1
  17. package/dist/admin/future/pages/Assets/AssetsPage.js +2 -2
  18. package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
  19. package/dist/admin/future/pages/Assets/AssetsPage.mjs +3 -3
  20. package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
  21. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +626 -169
  22. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
  23. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +630 -175
  24. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
  25. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.js +25 -5
  26. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.js.map +1 -1
  27. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.mjs +25 -5
  28. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.mjs.map +1 -1
  29. package/dist/admin/future/services/api.js +124 -200
  30. package/dist/admin/future/services/api.js.map +1 -1
  31. package/dist/admin/future/services/api.mjs +124 -200
  32. package/dist/admin/future/services/api.mjs.map +1 -1
  33. package/dist/admin/future/services/assets.js +57 -1
  34. package/dist/admin/future/services/assets.js.map +1 -1
  35. package/dist/admin/future/services/assets.mjs +56 -2
  36. package/dist/admin/future/services/assets.mjs.map +1 -1
  37. package/dist/admin/future/services/settings.js +18 -0
  38. package/dist/admin/future/services/settings.js.map +1 -0
  39. package/dist/admin/future/services/settings.mjs +16 -0
  40. package/dist/admin/future/services/settings.mjs.map +1 -0
  41. package/dist/admin/future/services/uploadFileViaXHR.js +92 -0
  42. package/dist/admin/future/services/uploadFileViaXHR.js.map +1 -0
  43. package/dist/admin/future/services/uploadFileViaXHR.mjs +88 -0
  44. package/dist/admin/future/services/uploadFileViaXHR.mjs.map +1 -0
  45. package/dist/admin/future/store/uploadProgress.js +32 -26
  46. package/dist/admin/future/store/uploadProgress.js.map +1 -1
  47. package/dist/admin/future/store/uploadProgress.mjs +32 -27
  48. package/dist/admin/future/store/uploadProgress.mjs.map +1 -1
  49. package/dist/admin/future/utils/createRafBatcher.js +42 -0
  50. package/dist/admin/future/utils/createRafBatcher.js.map +1 -0
  51. package/dist/admin/future/utils/createRafBatcher.mjs +40 -0
  52. package/dist/admin/future/utils/createRafBatcher.mjs.map +1 -0
  53. package/dist/admin/future/utils/downloadFile.js +19 -0
  54. package/dist/admin/future/utils/downloadFile.js.map +1 -0
  55. package/dist/admin/future/utils/downloadFile.mjs +17 -0
  56. package/dist/admin/future/utils/downloadFile.mjs.map +1 -0
  57. package/dist/admin/hooks/useAssets.js +5 -3
  58. package/dist/admin/hooks/useAssets.js.map +1 -1
  59. package/dist/admin/hooks/useAssets.mjs +5 -3
  60. package/dist/admin/hooks/useAssets.mjs.map +1 -1
  61. package/dist/admin/src/components/EditAssetDialog/EditAssetContent.d.ts +2 -1
  62. package/dist/admin/src/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.d.ts +15 -1
  63. package/dist/admin/src/future/pages/Assets/components/AssetDetails/AssetPreview.d.ts +4 -1
  64. package/dist/admin/src/future/services/api.d.ts +9 -8
  65. package/dist/admin/src/future/services/assets.d.ts +6 -1
  66. package/dist/admin/src/future/services/uploadFileViaXHR.d.ts +34 -0
  67. package/dist/admin/src/future/store/uploadProgress.d.ts +17 -4
  68. package/dist/admin/src/future/utils/createRafBatcher.d.ts +23 -0
  69. package/dist/admin/src/future/utils/downloadFile.d.ts +6 -0
  70. package/dist/admin/translations/en.json.js +21 -0
  71. package/dist/admin/translations/en.json.js.map +1 -1
  72. package/dist/admin/translations/en.json.mjs +21 -0
  73. package/dist/admin/translations/en.json.mjs.map +1 -1
  74. package/dist/server/controllers/admin-upload.js +69 -118
  75. package/dist/server/controllers/admin-upload.js.map +1 -1
  76. package/dist/server/controllers/admin-upload.mjs +69 -118
  77. package/dist/server/controllers/admin-upload.mjs.map +1 -1
  78. package/dist/server/routes/admin.js +2 -2
  79. package/dist/server/routes/admin.js.map +1 -1
  80. package/dist/server/routes/admin.mjs +2 -2
  81. package/dist/server/routes/admin.mjs.map +1 -1
  82. package/dist/server/services/image-manipulation.js +16 -8
  83. package/dist/server/services/image-manipulation.js.map +1 -1
  84. package/dist/server/services/image-manipulation.mjs +16 -8
  85. package/dist/server/services/image-manipulation.mjs.map +1 -1
  86. package/dist/server/services/upload.js +1 -1
  87. package/dist/server/services/upload.js.map +1 -1
  88. package/dist/server/services/upload.mjs +1 -1
  89. package/dist/server/services/upload.mjs.map +1 -1
  90. package/dist/server/src/controllers/admin-upload.d.ts +6 -8
  91. package/dist/server/src/controllers/admin-upload.d.ts.map +1 -1
  92. package/dist/server/src/controllers/index.d.ts +1 -1
  93. package/dist/server/src/index.d.ts +1 -1
  94. package/dist/server/src/services/image-manipulation.d.ts +5 -0
  95. package/dist/server/src/services/image-manipulation.d.ts.map +1 -1
  96. package/dist/server/src/services/upload.d.ts.map +1 -1
  97. package/dist/server/src/types.d.ts +2 -2
  98. package/dist/server/src/types.d.ts.map +1 -1
  99. package/dist/shared/contracts/files.d.ts +19 -2
  100. package/dist/shared/contracts/files.d.ts.map +1 -1
  101. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"admin-upload.js","sources":["../../../server/src/controllers/admin-upload.ts"],"sourcesContent":["import os from 'os';\nimport path from 'path';\nimport fse from 'fs-extra';\nimport _ from 'lodash';\nimport { errors, async } from '@strapi/utils';\n\nimport type { Context } from 'koa';\n\nimport { getService } from '../utils';\nimport { ACTIONS, FILE_MODEL_UID } from '../constants';\nimport { validateBulkUpdateBody, validateUploadBody } from './validation/admin/upload';\nimport { findEntityAndCheckPermissions } from './utils/find-entity-and-check-permissions';\nimport { Config, FileInfo } from '../types';\nimport { prepareUploadRequest, type FileUploadError } from '../utils/mime-validation';\nimport type { UploadFileInfo } from '../../../shared/contracts/files';\n\nexport default {\n async bulkUpdateFileInfo(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body },\n } = ctx;\n\n const { updates } = await validateBulkUpdateBody(body);\n const uploadService = getService('upload');\n\n const results = await async.map(\n updates,\n async ({ id, fileInfo }: { id: number; fileInfo: FileInfo }) => {\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const updated = await uploadService.updateFileInfo(id, fileInfo as any, { user });\n return pm.sanitizeOutput(updated, { action: ACTIONS.read });\n }\n );\n\n ctx.body = results;\n },\n\n async updateFileInfo(ctx: Context) {\n const {\n state: { userAbility, user },\n query: { id },\n request: { body },\n } = ctx;\n\n if (typeof id !== 'string') {\n throw new errors.ValidationError('File id is required');\n }\n\n const uploadService = getService('upload');\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const data = await validateUploadBody(body);\n\n const file = await uploadService.updateFileInfo(id, data.fileInfo as any, { user });\n\n ctx.body = await pm.sanitizeOutput(file, { action: ACTIONS.read });\n },\n\n async replaceFile(ctx: Context) {\n const {\n state: { userAbility, user },\n query: { id },\n request: { body, files: { files } = {} },\n } = ctx;\n\n if (typeof id !== 'string') {\n throw new errors.ValidationError('File id is required');\n }\n\n const uploadService = getService('upload');\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n if (Array.isArray(files)) {\n throw new errors.ApplicationError('Cannot replace a file with multiple ones');\n }\n\n const {\n validFiles,\n filteredBody,\n errors: validationErrors,\n } = await prepareUploadRequest(files, body, strapi);\n if (validFiles.length === 0) {\n throw new errors.ValidationError(validationErrors[0].message);\n }\n\n const data = (await validateUploadBody(filteredBody)) as { fileInfo: FileInfo };\n const replacedFile = await uploadService.replace(id, { data, file: validFiles[0] }, { user });\n\n // Sign file urls for private providers\n const signedFile = await getService('file').signFileUrls(replacedFile);\n\n ctx.body = await pm.sanitizeOutput(signedFile, { action: ACTIONS.read });\n },\n\n async uploadFiles(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body, files: { files } = {} },\n } = ctx;\n\n const uploadService = getService('upload');\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.create,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n const {\n validFiles,\n filteredBody,\n errors: validationErrors,\n } = await prepareUploadRequest(files, body, strapi);\n if (validFiles.length === 0) {\n throw new errors.ValidationError(validationErrors[0].message);\n }\n\n const isMultipleFiles = validFiles.length > 1;\n const data = await validateUploadBody(filteredBody, isMultipleFiles);\n\n let filesArray = validFiles;\n\n if (\n data.fileInfo &&\n Array.isArray(data.fileInfo) &&\n filesArray.length === data.fileInfo.length\n ) {\n // Reorder filesArray to match data.fileInfo order\n const alignedFilesArray = data.fileInfo\n .map((info) => {\n return filesArray.find((file) => file.originalFilename === info.name);\n })\n .filter(Boolean) as any[];\n\n filesArray = alignedFilesArray;\n }\n\n // Upload files first to get thumbnails\n const uploadedFiles = await uploadService.upload({ data, files: filesArray }, { user });\n if (uploadedFiles.some((file) => file.mime?.startsWith('image/'))) {\n await getService('metrics').trackUsage('didUploadImage');\n }\n\n const aiMetadataService = getService('aiMetadata');\n\n // AFTER upload - generate AI metadata for images\n if (await aiMetadataService.isEnabled()) {\n try {\n const metadataResults = await aiMetadataService.processFiles(uploadedFiles);\n // Update the uploaded files with AI metadata\n await aiMetadataService.updateFilesWithAIMetadata(uploadedFiles, metadataResults, user);\n } catch (error) {\n strapi.log.warn('AI metadata generation failed, proceeding without AI enhancements', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // Sign file urls for private providers\n const signedFiles = await async.map(uploadedFiles, getService('file').signFileUrls);\n\n ctx.body = await pm.sanitizeOutput(signedFiles, { action: ACTIONS.read });\n ctx.status = 201;\n },\n\n /**\n * @experimental\n * Stream upload files with SSE streaming for per-file progress\n *\n * Streams Server-Sent Events as each file is validated and uploaded:\n * - file:uploading — when processing starts for a file\n * - file:complete — when a file is successfully uploaded\n * - file:error — when a file fails validation or upload\n * - stream:complete — final summary with all results\n *\n */\n async unstable_uploadFilesStream(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body, files: { files } = {} },\n } = ctx;\n\n const uploadService = getService('upload');\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.create,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n if (_.isEmpty(files) || (!Array.isArray(files) && files.size === 0)) {\n throw new errors.ApplicationError('Files are empty');\n }\n\n // Take manual control of the response for SSE streaming\n ctx.respond = false;\n const res = ctx.res;\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n });\n\n const writeSSE = (event: string, data: Record<string, unknown>) => {\n res.write(`event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`);\n };\n\n // Normalize files to an array\n const filesArray = Array.isArray(files) ? files : [files];\n const total = filesArray.length;\n\n // Parse fileInfo from body\n // Multipart forms send fileInfo as either:\n // - An array of JSON strings (one per file)\n // - A single JSON string (one file, or a JSON-encoded array)\n let parsedFileInfo: UploadFileInfo[] = [];\n if (body?.fileInfo) {\n const raw = body.fileInfo;\n if (Array.isArray(raw)) {\n parsedFileInfo = raw.map((fi: unknown) =>\n typeof fi === 'string' ? JSON.parse(fi) : fi\n ) as UploadFileInfo[];\n } else if (typeof raw === 'string') {\n const parsed = JSON.parse(raw);\n // Handle case where a single string contains a JSON array\n parsedFileInfo = (Array.isArray(parsed) ? parsed : [parsed]) as UploadFileInfo[];\n } else {\n parsedFileInfo = [raw as UploadFileInfo];\n }\n }\n\n const uploadErrors: FileUploadError[] = [];\n const successfulFiles: any[] = [];\n\n // Process each file sequentially with inline validation\n for (let i = 0; i < filesArray.length; i += 1) {\n const file = filesArray[i];\n const fileName = file.originalFilename || 'unknown';\n const fileInfo: UploadFileInfo = parsedFileInfo[i] || {\n name: fileName,\n caption: null,\n alternativeText: null,\n folder: null,\n };\n\n writeSSE('file:uploading', { name: fileName, index: i, total, size: file.size || 0 });\n\n try {\n // Validate this single file using security checks\n const { validFiles, errors: validationErrors } = await prepareUploadRequest(\n file,\n { fileInfo: JSON.stringify(fileInfo) },\n strapi\n );\n\n if (validFiles.length === 0) {\n const errorMessage = validationErrors[0]?.message || 'Validation failed';\n uploadErrors.push({ name: fileName, message: errorMessage });\n writeSSE('file:error', { name: fileName, index: i, message: errorMessage });\n } else {\n // Validate using the already-parsed single fileInfo object directly\n const data = await validateUploadBody({ fileInfo }, false);\n const [uploadedFile] = await uploadService.upload(\n { data, files: [validFiles[0]] },\n { user }\n );\n\n // Sign file url\n const signedFile = await getService('file').signFileUrls(uploadedFile);\n successfulFiles.push(signedFile);\n\n writeSSE('file:complete', { name: fileName, index: i, file: signedFile });\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n uploadErrors.push({ name: fileName, message: errorMessage });\n writeSSE('file:error', { name: fileName, index: i, message: errorMessage });\n }\n }\n\n // Track image upload metric once if any images were uploaded\n if (successfulFiles.some((file) => file.mime?.startsWith('image/'))) {\n await getService('metrics').trackUsage('didUploadImage');\n }\n\n // Send final stream summary\n writeSSE('stream:complete', {\n data: await pm.sanitizeOutput(successfulFiles, { action: ACTIONS.read }),\n errors: uploadErrors,\n });\n\n res.end();\n },\n\n /**\n * @experimental\n * Upload files from URLs with SSE streaming for per-file progress\n *\n * Accepts JSON body with URLs and fetches them server-side.\n * Streams Server-Sent Events as each URL is fetched and uploaded:\n * - file:fetching — when starting to fetch a URL\n * - file:uploading — when upload starts for a fetched file\n * - file:complete — when a file is successfully uploaded\n * - file:error — when a URL fetch or upload fails\n * - stream:complete — final summary with all results\n */\n async unstable_uploadFromUrls(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body },\n } = ctx;\n\n const uploadService = getService('upload');\n const fileService = getService('file');\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.create,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n // Parse and validate request body\n const { urls, folderId } = body as { urls?: string[]; folderId?: number | null };\n\n if (!urls || !Array.isArray(urls) || urls.length === 0) {\n throw new errors.ApplicationError('URLs are required');\n }\n\n if (urls.length > 20) {\n throw new errors.ApplicationError('Maximum 20 URLs allowed per request');\n }\n\n // Take manual control of the response for SSE streaming\n ctx.respond = false;\n const res = ctx.res;\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n });\n\n const writeSSE = (event: string, data: Record<string, unknown>) => {\n res.write(`event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`);\n };\n\n const total = urls.length;\n const uploadErrors: FileUploadError[] = [];\n const successfulFiles: any[] = [];\n\n // Create temp directory for fetched files\n const tmpWorkingDirectory = await fse.mkdtemp(path.join(os.tmpdir(), 'strapi-url-upload-'));\n const { sizeLimit } = strapi.config.get<Config>('plugin::upload');\n\n try {\n // Process each URL sequentially\n for (let i = 0; i < urls.length; i += 1) {\n const url = urls[i];\n\n writeSSE('file:fetching', { url, index: i, total });\n\n try {\n // Fetch URL to temp file\n const { file } = await fileService.fetchUrlToInputFile(\n url,\n tmpWorkingDirectory,\n sizeLimit\n );\n const fileName = file.originalFilename;\n\n writeSSE('file:uploading', {\n name: fileName,\n index: i,\n total,\n size: file.size,\n });\n\n // Validate using security checks\n const fileInfo: UploadFileInfo = {\n name: fileName,\n caption: null,\n alternativeText: null,\n folder: folderId ?? null,\n };\n\n const { validFiles, errors: validationErrors } = await prepareUploadRequest(\n file,\n { fileInfo: JSON.stringify(fileInfo) },\n strapi\n );\n\n if (validFiles.length === 0) {\n const errorMessage = validationErrors[0]?.message || 'Validation failed';\n uploadErrors.push({ name: fileName, message: errorMessage });\n writeSSE('file:error', { name: fileName, url, index: i, message: errorMessage });\n } else {\n // Upload the file\n const data = await validateUploadBody({ fileInfo }, false);\n const [uploadedFile] = await uploadService.upload(\n { data, files: [validFiles[0]] },\n { user }\n );\n\n // Sign file url\n const signedFile = await fileService.signFileUrls(uploadedFile);\n successfulFiles.push(signedFile);\n\n writeSSE('file:complete', { name: fileName, index: i, file: signedFile });\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n uploadErrors.push({ name: url, message: errorMessage });\n writeSSE('file:error', { url, index: i, message: errorMessage });\n }\n }\n\n // Track image upload metric once if any images were uploaded\n if (successfulFiles.some((file) => file.mime?.startsWith('image/'))) {\n await getService('metrics').trackUsage('didUploadImage');\n }\n\n // Send final stream summary\n writeSSE('stream:complete', {\n data: await pm.sanitizeOutput(successfulFiles, { action: ACTIONS.read }),\n errors: uploadErrors,\n });\n } finally {\n // Clean up temp directory\n await fse.remove(tmpWorkingDirectory);\n }\n\n res.end();\n },\n\n // TODO: split into multiple endpoints\n async upload(ctx: Context) {\n const {\n query: { id },\n request: { files: { files } = {} },\n } = ctx;\n\n if (_.isEmpty(files) || (!Array.isArray(files) && files.size === 0)) {\n if (id) {\n return this.updateFileInfo(ctx);\n }\n\n throw new errors.ApplicationError('Files are empty');\n }\n\n await (id ? this.replaceFile : this.uploadFiles)(ctx);\n },\n};\n"],"names":["bulkUpdateFileInfo","ctx","state","userAbility","user","request","body","updates","validateBulkUpdateBody","uploadService","getService","results","async","map","id","fileInfo","pm","findEntityAndCheckPermissions","ACTIONS","update","FILE_MODEL_UID","updated","updateFileInfo","sanitizeOutput","action","read","query","errors","ValidationError","data","validateUploadBody","file","replaceFile","files","Array","isArray","ApplicationError","validFiles","filteredBody","validationErrors","prepareUploadRequest","strapi","length","message","replacedFile","replace","signedFile","signFileUrls","uploadFiles","service","createPermissionsManager","ability","create","model","isAllowed","forbidden","isMultipleFiles","filesArray","alignedFilesArray","info","find","originalFilename","name","filter","Boolean","uploadedFiles","upload","some","mime","startsWith","trackUsage","aiMetadataService","isEnabled","metadataResults","processFiles","updateFilesWithAIMetadata","error","log","warn","Error","String","signedFiles","status","unstable_uploadFilesStream","_","isEmpty","size","respond","res","writeHead","Connection","writeSSE","event","write","JSON","stringify","total","parsedFileInfo","raw","fi","parse","parsed","uploadErrors","successfulFiles","i","fileName","caption","alternativeText","folder","index","errorMessage","push","uploadedFile","end","unstable_uploadFromUrls","fileService","urls","folderId","tmpWorkingDirectory","fse","mkdtemp","path","join","os","tmpdir","sizeLimit","config","get","url","fetchUrlToInputFile","remove"],"mappings":"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"}
1
+ {"version":3,"file":"admin-upload.js","sources":["../../../server/src/controllers/admin-upload.ts"],"sourcesContent":["import os from 'os';\nimport path from 'path';\nimport fse from 'fs-extra';\nimport _ from 'lodash';\nimport { errors, async } from '@strapi/utils';\n\nimport type { Context } from 'koa';\n\nimport { getService } from '../utils';\nimport { ACTIONS, FILE_MODEL_UID } from '../constants';\nimport { validateBulkUpdateBody, validateUploadBody } from './validation/admin/upload';\nimport { findEntityAndCheckPermissions } from './utils/find-entity-and-check-permissions';\nimport { Config, FileInfo } from '../types';\nimport { prepareUploadRequest, type FileUploadError } from '../utils/mime-validation';\nimport type { UploadFileInfo } from '../../../shared/contracts/files';\n\nexport default {\n async bulkUpdateFileInfo(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body },\n } = ctx;\n\n const { updates } = await validateBulkUpdateBody(body);\n const uploadService = getService('upload');\n\n const results = await async.map(\n updates,\n async ({ id, fileInfo }: { id: number; fileInfo: FileInfo }) => {\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const updated = await uploadService.updateFileInfo(id, fileInfo as any, { user });\n\n // Sign file urls for private providers\n const signedFile = await getService('file').signFileUrls(updated);\n\n return pm.sanitizeOutput(signedFile, { action: ACTIONS.read });\n }\n );\n\n ctx.body = results;\n },\n\n async updateFileInfo(ctx: Context) {\n const {\n state: { userAbility, user },\n query: { id },\n request: { body },\n } = ctx;\n\n if (typeof id !== 'string') {\n throw new errors.ValidationError('File id is required');\n }\n\n const uploadService = getService('upload');\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const data = await validateUploadBody(body);\n\n const file = await uploadService.updateFileInfo(id, data.fileInfo as any, { user });\n\n // Sign file urls for private providers\n const signedFile = await getService('file').signFileUrls(file);\n\n ctx.body = await pm.sanitizeOutput(signedFile, { action: ACTIONS.read });\n },\n\n async replaceFile(ctx: Context) {\n const {\n state: { userAbility, user },\n query: { id },\n request: { body, files: { files } = {} },\n } = ctx;\n\n if (typeof id !== 'string') {\n throw new errors.ValidationError('File id is required');\n }\n\n const uploadService = getService('upload');\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n if (Array.isArray(files)) {\n throw new errors.ApplicationError('Cannot replace a file with multiple ones');\n }\n\n const {\n validFiles,\n filteredBody,\n errors: validationErrors,\n } = await prepareUploadRequest(files, body, strapi);\n if (validFiles.length === 0) {\n throw new errors.ValidationError(validationErrors[0].message);\n }\n\n const data = (await validateUploadBody(filteredBody)) as { fileInfo: FileInfo };\n const replacedFile = await uploadService.replace(id, { data, file: validFiles[0] }, { user });\n\n // Regenerate AI metadata for image replacements so the alt text / caption\n // reflect the new file content. Mirrors the post-upload hook in\n // `uploadFiles`; failure is logged and swallowed to keep the replace flow\n // resilient when the AI provider is unavailable.\n const aiMetadataService = getService('aiMetadata');\n if (replacedFile?.mime?.startsWith('image/') && (await aiMetadataService.isEnabled())) {\n try {\n const metadataResults = await aiMetadataService.processFiles([replacedFile]);\n await aiMetadataService.updateFilesWithAIMetadata([replacedFile], metadataResults, user);\n } catch (error) {\n strapi.log.warn('AI metadata generation failed on replace, proceeding without it', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // Sign file urls for private providers\n const signedFile = await getService('file').signFileUrls(replacedFile);\n\n ctx.body = await pm.sanitizeOutput(signedFile, { action: ACTIONS.read });\n },\n\n async uploadFiles(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body, files: { files } = {} },\n } = ctx;\n\n const uploadService = getService('upload');\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.create,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n const {\n validFiles,\n filteredBody,\n errors: validationErrors,\n } = await prepareUploadRequest(files, body, strapi);\n if (validFiles.length === 0) {\n throw new errors.ValidationError(validationErrors[0].message);\n }\n\n const isMultipleFiles = validFiles.length > 1;\n const data = await validateUploadBody(filteredBody, isMultipleFiles);\n\n let filesArray = validFiles;\n\n if (\n data.fileInfo &&\n Array.isArray(data.fileInfo) &&\n filesArray.length === data.fileInfo.length\n ) {\n // Reorder filesArray to match data.fileInfo order\n const alignedFilesArray = data.fileInfo\n .map((info) => {\n return filesArray.find((file) => file.originalFilename === info.name);\n })\n .filter(Boolean) as any[];\n\n filesArray = alignedFilesArray;\n }\n\n // Upload files first to get thumbnails\n const uploadedFiles = await uploadService.upload({ data, files: filesArray }, { user });\n if (uploadedFiles.some((file) => file.mime?.startsWith('image/'))) {\n await getService('metrics').trackUsage('didUploadImage');\n }\n\n const aiMetadataService = getService('aiMetadata');\n\n // AFTER upload - generate AI metadata for images\n if (await aiMetadataService.isEnabled()) {\n try {\n const metadataResults = await aiMetadataService.processFiles(uploadedFiles);\n // Update the uploaded files with AI metadata\n await aiMetadataService.updateFilesWithAIMetadata(uploadedFiles, metadataResults, user);\n } catch (error) {\n strapi.log.warn('AI metadata generation failed, proceeding without AI enhancements', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // Sign file urls for private providers\n const signedFiles = await async.map(uploadedFiles, getService('file').signFileUrls);\n\n ctx.body = await pm.sanitizeOutput(signedFiles, { action: ACTIONS.read });\n ctx.status = 201;\n },\n\n /**\n * @experimental\n * Upload a single file and return the created File.\n *\n * Accepts one file per request (multipart `files` + `fileInfo`) and returns a\n * single `File` object. Unlike `uploadFiles`, it does **not** run AI metadata\n * generation inline — that responsibility is decoupled and will be handled by a\n * background job. Auth and permission checks mirror `POST /upload`.\n */\n async unstable_uploadFile(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body, files: { files } = {} },\n } = ctx;\n\n const uploadService = getService('upload');\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.create,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n if (_.isEmpty(files) || (!Array.isArray(files) && files.size === 0)) {\n throw new errors.ApplicationError('Files are empty');\n }\n\n // Accept a single file per request; ignore any extras defensively.\n const file = Array.isArray(files) ? files[0] : files;\n const fileName = file.originalFilename || 'unknown';\n\n // Parse the single fileInfo object from the multipart body.\n let fileInfo: UploadFileInfo = {\n name: fileName,\n caption: null,\n alternativeText: null,\n folder: null,\n };\n if (body?.fileInfo) {\n const raw = body.fileInfo;\n if (typeof raw === 'string') {\n fileInfo = JSON.parse(raw);\n } else if (Array.isArray(raw)) {\n fileInfo = (typeof raw[0] === 'string' ? JSON.parse(raw[0]) : raw[0]) as UploadFileInfo;\n } else {\n fileInfo = raw as UploadFileInfo;\n }\n }\n\n // Validate this single file using security checks.\n const { validFiles, errors: validationErrors } = await prepareUploadRequest(\n file,\n { fileInfo: JSON.stringify(fileInfo) },\n strapi\n );\n\n if (validFiles.length === 0) {\n throw new errors.ValidationError(validationErrors[0]?.message || 'Validation failed');\n }\n\n const data = await validateUploadBody({ fileInfo }, false);\n const [uploadedFile] = await uploadService.upload({ data, files: [validFiles[0]] }, { user });\n\n if (uploadedFile.mime?.startsWith('image/')) {\n await getService('metrics').trackUsage('didUploadImage');\n }\n\n // No inline AI metadata generation — intentionally decoupled for the async job.\n\n // Sign file url for private providers.\n const signedFile = await getService('file').signFileUrls(uploadedFile);\n\n ctx.body = await pm.sanitizeOutput(signedFile, { action: ACTIONS.read });\n ctx.status = 201;\n },\n\n /**\n * @experimental\n * Upload files from URLs with SSE streaming for per-file progress\n *\n * Accepts JSON body with URLs and fetches them server-side.\n * Streams Server-Sent Events as each URL is fetched and uploaded:\n * - file:fetching — when starting to fetch a URL\n * - file:uploading — when upload starts for a fetched file\n * - file:complete — when a file is successfully uploaded\n * - file:error — when a URL fetch or upload fails\n * - stream:complete — final summary with all results\n */\n async unstable_uploadFromUrls(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body },\n } = ctx;\n\n const uploadService = getService('upload');\n const fileService = getService('file');\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.create,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n // Parse and validate request body\n const { urls, folderId } = body as { urls?: string[]; folderId?: number | null };\n\n if (!urls || !Array.isArray(urls) || urls.length === 0) {\n throw new errors.ApplicationError('URLs are required');\n }\n\n if (urls.length > 20) {\n throw new errors.ApplicationError('Maximum 20 URLs allowed per request');\n }\n\n // Take manual control of the response for SSE streaming\n ctx.respond = false;\n const res = ctx.res;\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n });\n\n const writeSSE = (event: string, data: Record<string, unknown>) => {\n res.write(`event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`);\n };\n\n const total = urls.length;\n const uploadErrors: FileUploadError[] = [];\n const successfulFiles: any[] = [];\n\n // Create temp directory for fetched files\n const tmpWorkingDirectory = await fse.mkdtemp(path.join(os.tmpdir(), 'strapi-url-upload-'));\n const { sizeLimit } = strapi.config.get<Config>('plugin::upload');\n\n try {\n // Process each URL sequentially\n for (let i = 0; i < urls.length; i += 1) {\n const url = urls[i];\n\n writeSSE('file:fetching', { url, index: i, total });\n\n try {\n // Fetch URL to temp file\n const { file } = await fileService.fetchUrlToInputFile(\n url,\n tmpWorkingDirectory,\n sizeLimit\n );\n const fileName = file.originalFilename;\n\n writeSSE('file:uploading', {\n name: fileName,\n index: i,\n total,\n size: file.size,\n });\n\n // Validate using security checks\n const fileInfo: UploadFileInfo = {\n name: fileName,\n caption: null,\n alternativeText: null,\n folder: folderId ?? null,\n };\n\n const { validFiles, errors: validationErrors } = await prepareUploadRequest(\n file,\n { fileInfo: JSON.stringify(fileInfo) },\n strapi\n );\n\n if (validFiles.length === 0) {\n const errorMessage = validationErrors[0]?.message || 'Validation failed';\n uploadErrors.push({ name: fileName, message: errorMessage });\n writeSSE('file:error', { name: fileName, url, index: i, message: errorMessage });\n } else {\n // Upload the file\n const data = await validateUploadBody({ fileInfo }, false);\n const [uploadedFile] = await uploadService.upload(\n { data, files: [validFiles[0]] },\n { user }\n );\n\n // Sign file url\n const signedFile = await fileService.signFileUrls(uploadedFile);\n successfulFiles.push(signedFile);\n\n writeSSE('file:complete', { name: fileName, index: i, file: signedFile });\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n uploadErrors.push({ name: url, message: errorMessage });\n writeSSE('file:error', { url, index: i, message: errorMessage });\n }\n }\n\n // Track image upload metric once if any images were uploaded\n if (successfulFiles.some((file) => file.mime?.startsWith('image/'))) {\n await getService('metrics').trackUsage('didUploadImage');\n }\n\n // Send final stream summary\n writeSSE('stream:complete', {\n data: await pm.sanitizeOutput(successfulFiles, { action: ACTIONS.read }),\n errors: uploadErrors,\n });\n } finally {\n // Clean up temp directory\n await fse.remove(tmpWorkingDirectory);\n }\n\n res.end();\n },\n\n // TODO: split into multiple endpoints\n async upload(ctx: Context) {\n const {\n query: { id },\n request: { files: { files } = {} },\n } = ctx;\n\n if (_.isEmpty(files) || (!Array.isArray(files) && files.size === 0)) {\n if (id) {\n return this.updateFileInfo(ctx);\n }\n\n throw new errors.ApplicationError('Files are empty');\n }\n\n await (id ? this.replaceFile : this.uploadFiles)(ctx);\n },\n};\n"],"names":["bulkUpdateFileInfo","ctx","state","userAbility","user","request","body","updates","validateBulkUpdateBody","uploadService","getService","results","async","map","id","fileInfo","pm","findEntityAndCheckPermissions","ACTIONS","update","FILE_MODEL_UID","updated","updateFileInfo","signedFile","signFileUrls","sanitizeOutput","action","read","query","errors","ValidationError","data","validateUploadBody","file","replaceFile","files","Array","isArray","ApplicationError","validFiles","filteredBody","validationErrors","prepareUploadRequest","strapi","length","message","replacedFile","replace","aiMetadataService","mime","startsWith","isEnabled","metadataResults","processFiles","updateFilesWithAIMetadata","error","log","warn","Error","String","uploadFiles","service","createPermissionsManager","ability","create","model","isAllowed","forbidden","isMultipleFiles","filesArray","alignedFilesArray","info","find","originalFilename","name","filter","Boolean","uploadedFiles","upload","some","trackUsage","signedFiles","status","unstable_uploadFile","_","isEmpty","size","fileName","caption","alternativeText","folder","raw","JSON","parse","stringify","uploadedFile","unstable_uploadFromUrls","fileService","urls","folderId","respond","res","writeHead","Connection","writeSSE","event","write","total","uploadErrors","successfulFiles","tmpWorkingDirectory","fse","mkdtemp","path","join","os","tmpdir","sizeLimit","config","get","i","url","index","fetchUrlToInputFile","errorMessage","push","remove","end"],"mappings":"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"}
@@ -19,7 +19,9 @@ var adminUpload = {
19
19
  const updated = await uploadService.updateFileInfo(id, fileInfo, {
20
20
  user
21
21
  });
22
- return pm.sanitizeOutput(updated, {
22
+ // Sign file urls for private providers
23
+ const signedFile = await getService('file').signFileUrls(updated);
24
+ return pm.sanitizeOutput(signedFile, {
23
25
  action: ACTIONS.read
24
26
  });
25
27
  });
@@ -36,7 +38,9 @@ var adminUpload = {
36
38
  const file = await uploadService.updateFileInfo(id, data.fileInfo, {
37
39
  user
38
40
  });
39
- ctx.body = await pm.sanitizeOutput(file, {
41
+ // Sign file urls for private providers
42
+ const signedFile = await getService('file').signFileUrls(file);
43
+ ctx.body = await pm.sanitizeOutput(signedFile, {
40
44
  action: ACTIONS.read
41
45
  });
42
46
  },
@@ -61,6 +65,25 @@ var adminUpload = {
61
65
  }, {
62
66
  user
63
67
  });
68
+ // Regenerate AI metadata for image replacements so the alt text / caption
69
+ // reflect the new file content. Mirrors the post-upload hook in
70
+ // `uploadFiles`; failure is logged and swallowed to keep the replace flow
71
+ // resilient when the AI provider is unavailable.
72
+ const aiMetadataService = getService('aiMetadata');
73
+ if (replacedFile?.mime?.startsWith('image/') && await aiMetadataService.isEnabled()) {
74
+ try {
75
+ const metadataResults = await aiMetadataService.processFiles([
76
+ replacedFile
77
+ ]);
78
+ await aiMetadataService.updateFilesWithAIMetadata([
79
+ replacedFile
80
+ ], metadataResults, user);
81
+ } catch (error) {
82
+ strapi.log.warn('AI metadata generation failed on replace, proceeding without it', {
83
+ error: error instanceof Error ? error.message : String(error)
84
+ });
85
+ }
86
+ }
64
87
  // Sign file urls for private providers
65
88
  const signedFile = await getService('file').signFileUrls(replacedFile);
66
89
  ctx.body = await pm.sanitizeOutput(signedFile, {
@@ -124,15 +147,13 @@ var adminUpload = {
124
147
  },
125
148
  /**
126
149
  * @experimental
127
- * Stream upload files with SSE streaming for per-file progress
150
+ * Upload a single file and return the created File.
128
151
  *
129
- * Streams Server-Sent Events as each file is validated and uploaded:
130
- * - file:uploading when processing starts for a file
131
- * - file:complete when a file is successfully uploaded
132
- * - file:error — when a file fails validation or upload
133
- * - stream:complete final summary with all results
134
- *
135
- */ async unstable_uploadFilesStream (ctx) {
152
+ * Accepts one file per request (multipart `files` + `fileInfo`) and returns a
153
+ * single `File` object. Unlike `uploadFiles`, it does **not** run AI metadata
154
+ * generation inline that responsibility is decoupled and will be handled by a
155
+ * background job. Auth and permission checks mirror `POST /upload`.
156
+ */ async unstable_uploadFile (ctx) {
136
157
  const { state: { userAbility, user }, request: { body, files: { files } = {} } } = ctx;
137
158
  const uploadService = getService('upload');
138
159
  const pm = strapi.service('admin::permission').createPermissionsManager({
@@ -146,124 +167,54 @@ var adminUpload = {
146
167
  if (_.isEmpty(files) || !Array.isArray(files) && files.size === 0) {
147
168
  throw new errors.ApplicationError('Files are empty');
148
169
  }
149
- // Take manual control of the response for SSE streaming
150
- ctx.respond = false;
151
- const res = ctx.res;
152
- res.writeHead(200, {
153
- 'Content-Type': 'text/event-stream',
154
- 'Cache-Control': 'no-cache',
155
- Connection: 'keep-alive'
156
- });
157
- const writeSSE = (event, data)=>{
158
- res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
170
+ // Accept a single file per request; ignore any extras defensively.
171
+ const file = Array.isArray(files) ? files[0] : files;
172
+ const fileName = file.originalFilename || 'unknown';
173
+ // Parse the single fileInfo object from the multipart body.
174
+ let fileInfo = {
175
+ name: fileName,
176
+ caption: null,
177
+ alternativeText: null,
178
+ folder: null
159
179
  };
160
- // Normalize files to an array
161
- const filesArray = Array.isArray(files) ? files : [
162
- files
163
- ];
164
- const total = filesArray.length;
165
- // Parse fileInfo from body
166
- // Multipart forms send fileInfo as either:
167
- // - An array of JSON strings (one per file)
168
- // - A single JSON string (one file, or a JSON-encoded array)
169
- let parsedFileInfo = [];
170
180
  if (body?.fileInfo) {
171
181
  const raw = body.fileInfo;
172
- if (Array.isArray(raw)) {
173
- parsedFileInfo = raw.map((fi)=>typeof fi === 'string' ? JSON.parse(fi) : fi);
174
- } else if (typeof raw === 'string') {
175
- const parsed = JSON.parse(raw);
176
- // Handle case where a single string contains a JSON array
177
- parsedFileInfo = Array.isArray(parsed) ? parsed : [
178
- parsed
179
- ];
182
+ if (typeof raw === 'string') {
183
+ fileInfo = JSON.parse(raw);
184
+ } else if (Array.isArray(raw)) {
185
+ fileInfo = typeof raw[0] === 'string' ? JSON.parse(raw[0]) : raw[0];
180
186
  } else {
181
- parsedFileInfo = [
182
- raw
183
- ];
187
+ fileInfo = raw;
184
188
  }
185
189
  }
186
- const uploadErrors = [];
187
- const successfulFiles = [];
188
- // Process each file sequentially with inline validation
189
- for(let i = 0; i < filesArray.length; i += 1){
190
- const file = filesArray[i];
191
- const fileName = file.originalFilename || 'unknown';
192
- const fileInfo = parsedFileInfo[i] || {
193
- name: fileName,
194
- caption: null,
195
- alternativeText: null,
196
- folder: null
197
- };
198
- writeSSE('file:uploading', {
199
- name: fileName,
200
- index: i,
201
- total,
202
- size: file.size || 0
203
- });
204
- try {
205
- // Validate this single file using security checks
206
- const { validFiles, errors: validationErrors } = await prepareUploadRequest(file, {
207
- fileInfo: JSON.stringify(fileInfo)
208
- }, strapi);
209
- if (validFiles.length === 0) {
210
- const errorMessage = validationErrors[0]?.message || 'Validation failed';
211
- uploadErrors.push({
212
- name: fileName,
213
- message: errorMessage
214
- });
215
- writeSSE('file:error', {
216
- name: fileName,
217
- index: i,
218
- message: errorMessage
219
- });
220
- } else {
221
- // Validate using the already-parsed single fileInfo object directly
222
- const data = await validateUploadBody({
223
- fileInfo
224
- }, false);
225
- const [uploadedFile] = await uploadService.upload({
226
- data,
227
- files: [
228
- validFiles[0]
229
- ]
230
- }, {
231
- user
232
- });
233
- // Sign file url
234
- const signedFile = await getService('file').signFileUrls(uploadedFile);
235
- successfulFiles.push(signedFile);
236
- writeSSE('file:complete', {
237
- name: fileName,
238
- index: i,
239
- file: signedFile
240
- });
241
- }
242
- } catch (error) {
243
- const errorMessage = error instanceof Error ? error.message : String(error);
244
- uploadErrors.push({
245
- name: fileName,
246
- message: errorMessage
247
- });
248
- writeSSE('file:error', {
249
- name: fileName,
250
- index: i,
251
- message: errorMessage
252
- });
253
- }
190
+ // Validate this single file using security checks.
191
+ const { validFiles, errors: validationErrors } = await prepareUploadRequest(file, {
192
+ fileInfo: JSON.stringify(fileInfo)
193
+ }, strapi);
194
+ if (validFiles.length === 0) {
195
+ throw new errors.ValidationError(validationErrors[0]?.message || 'Validation failed');
254
196
  }
255
- // Track image upload metric once if any images were uploaded
256
- if (successfulFiles.some((file)=>file.mime?.startsWith('image/'))) {
197
+ const data = await validateUploadBody({
198
+ fileInfo
199
+ }, false);
200
+ const [uploadedFile] = await uploadService.upload({
201
+ data,
202
+ files: [
203
+ validFiles[0]
204
+ ]
205
+ }, {
206
+ user
207
+ });
208
+ if (uploadedFile.mime?.startsWith('image/')) {
257
209
  await getService('metrics').trackUsage('didUploadImage');
258
210
  }
259
- // Send final stream summary
260
- writeSSE('stream:complete', {
261
- data: await pm.sanitizeOutput(successfulFiles, {
262
- action: ACTIONS.read
263
- }),
264
- errors: uploadErrors
211
+ // No inline AI metadata generation — intentionally decoupled for the async job.
212
+ // Sign file url for private providers.
213
+ const signedFile = await getService('file').signFileUrls(uploadedFile);
214
+ ctx.body = await pm.sanitizeOutput(signedFile, {
215
+ action: ACTIONS.read
265
216
  });
266
- res.end();
217
+ ctx.status = 201;
267
218
  },
268
219
  /**
269
220
  * @experimental
@@ -1 +1 @@
1
- {"version":3,"file":"admin-upload.mjs","sources":["../../../server/src/controllers/admin-upload.ts"],"sourcesContent":["import os from 'os';\nimport path from 'path';\nimport fse from 'fs-extra';\nimport _ from 'lodash';\nimport { errors, async } from '@strapi/utils';\n\nimport type { Context } from 'koa';\n\nimport { getService } from '../utils';\nimport { ACTIONS, FILE_MODEL_UID } from '../constants';\nimport { validateBulkUpdateBody, validateUploadBody } from './validation/admin/upload';\nimport { findEntityAndCheckPermissions } from './utils/find-entity-and-check-permissions';\nimport { Config, FileInfo } from '../types';\nimport { prepareUploadRequest, type FileUploadError } from '../utils/mime-validation';\nimport type { UploadFileInfo } from '../../../shared/contracts/files';\n\nexport default {\n async bulkUpdateFileInfo(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body },\n } = ctx;\n\n const { updates } = await validateBulkUpdateBody(body);\n const uploadService = getService('upload');\n\n const results = await async.map(\n updates,\n async ({ id, fileInfo }: { id: number; fileInfo: FileInfo }) => {\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const updated = await uploadService.updateFileInfo(id, fileInfo as any, { user });\n return pm.sanitizeOutput(updated, { action: ACTIONS.read });\n }\n );\n\n ctx.body = results;\n },\n\n async updateFileInfo(ctx: Context) {\n const {\n state: { userAbility, user },\n query: { id },\n request: { body },\n } = ctx;\n\n if (typeof id !== 'string') {\n throw new errors.ValidationError('File id is required');\n }\n\n const uploadService = getService('upload');\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const data = await validateUploadBody(body);\n\n const file = await uploadService.updateFileInfo(id, data.fileInfo as any, { user });\n\n ctx.body = await pm.sanitizeOutput(file, { action: ACTIONS.read });\n },\n\n async replaceFile(ctx: Context) {\n const {\n state: { userAbility, user },\n query: { id },\n request: { body, files: { files } = {} },\n } = ctx;\n\n if (typeof id !== 'string') {\n throw new errors.ValidationError('File id is required');\n }\n\n const uploadService = getService('upload');\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n if (Array.isArray(files)) {\n throw new errors.ApplicationError('Cannot replace a file with multiple ones');\n }\n\n const {\n validFiles,\n filteredBody,\n errors: validationErrors,\n } = await prepareUploadRequest(files, body, strapi);\n if (validFiles.length === 0) {\n throw new errors.ValidationError(validationErrors[0].message);\n }\n\n const data = (await validateUploadBody(filteredBody)) as { fileInfo: FileInfo };\n const replacedFile = await uploadService.replace(id, { data, file: validFiles[0] }, { user });\n\n // Sign file urls for private providers\n const signedFile = await getService('file').signFileUrls(replacedFile);\n\n ctx.body = await pm.sanitizeOutput(signedFile, { action: ACTIONS.read });\n },\n\n async uploadFiles(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body, files: { files } = {} },\n } = ctx;\n\n const uploadService = getService('upload');\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.create,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n const {\n validFiles,\n filteredBody,\n errors: validationErrors,\n } = await prepareUploadRequest(files, body, strapi);\n if (validFiles.length === 0) {\n throw new errors.ValidationError(validationErrors[0].message);\n }\n\n const isMultipleFiles = validFiles.length > 1;\n const data = await validateUploadBody(filteredBody, isMultipleFiles);\n\n let filesArray = validFiles;\n\n if (\n data.fileInfo &&\n Array.isArray(data.fileInfo) &&\n filesArray.length === data.fileInfo.length\n ) {\n // Reorder filesArray to match data.fileInfo order\n const alignedFilesArray = data.fileInfo\n .map((info) => {\n return filesArray.find((file) => file.originalFilename === info.name);\n })\n .filter(Boolean) as any[];\n\n filesArray = alignedFilesArray;\n }\n\n // Upload files first to get thumbnails\n const uploadedFiles = await uploadService.upload({ data, files: filesArray }, { user });\n if (uploadedFiles.some((file) => file.mime?.startsWith('image/'))) {\n await getService('metrics').trackUsage('didUploadImage');\n }\n\n const aiMetadataService = getService('aiMetadata');\n\n // AFTER upload - generate AI metadata for images\n if (await aiMetadataService.isEnabled()) {\n try {\n const metadataResults = await aiMetadataService.processFiles(uploadedFiles);\n // Update the uploaded files with AI metadata\n await aiMetadataService.updateFilesWithAIMetadata(uploadedFiles, metadataResults, user);\n } catch (error) {\n strapi.log.warn('AI metadata generation failed, proceeding without AI enhancements', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // Sign file urls for private providers\n const signedFiles = await async.map(uploadedFiles, getService('file').signFileUrls);\n\n ctx.body = await pm.sanitizeOutput(signedFiles, { action: ACTIONS.read });\n ctx.status = 201;\n },\n\n /**\n * @experimental\n * Stream upload files with SSE streaming for per-file progress\n *\n * Streams Server-Sent Events as each file is validated and uploaded:\n * - file:uploading — when processing starts for a file\n * - file:complete — when a file is successfully uploaded\n * - file:error — when a file fails validation or upload\n * - stream:complete — final summary with all results\n *\n */\n async unstable_uploadFilesStream(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body, files: { files } = {} },\n } = ctx;\n\n const uploadService = getService('upload');\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.create,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n if (_.isEmpty(files) || (!Array.isArray(files) && files.size === 0)) {\n throw new errors.ApplicationError('Files are empty');\n }\n\n // Take manual control of the response for SSE streaming\n ctx.respond = false;\n const res = ctx.res;\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n });\n\n const writeSSE = (event: string, data: Record<string, unknown>) => {\n res.write(`event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`);\n };\n\n // Normalize files to an array\n const filesArray = Array.isArray(files) ? files : [files];\n const total = filesArray.length;\n\n // Parse fileInfo from body\n // Multipart forms send fileInfo as either:\n // - An array of JSON strings (one per file)\n // - A single JSON string (one file, or a JSON-encoded array)\n let parsedFileInfo: UploadFileInfo[] = [];\n if (body?.fileInfo) {\n const raw = body.fileInfo;\n if (Array.isArray(raw)) {\n parsedFileInfo = raw.map((fi: unknown) =>\n typeof fi === 'string' ? JSON.parse(fi) : fi\n ) as UploadFileInfo[];\n } else if (typeof raw === 'string') {\n const parsed = JSON.parse(raw);\n // Handle case where a single string contains a JSON array\n parsedFileInfo = (Array.isArray(parsed) ? parsed : [parsed]) as UploadFileInfo[];\n } else {\n parsedFileInfo = [raw as UploadFileInfo];\n }\n }\n\n const uploadErrors: FileUploadError[] = [];\n const successfulFiles: any[] = [];\n\n // Process each file sequentially with inline validation\n for (let i = 0; i < filesArray.length; i += 1) {\n const file = filesArray[i];\n const fileName = file.originalFilename || 'unknown';\n const fileInfo: UploadFileInfo = parsedFileInfo[i] || {\n name: fileName,\n caption: null,\n alternativeText: null,\n folder: null,\n };\n\n writeSSE('file:uploading', { name: fileName, index: i, total, size: file.size || 0 });\n\n try {\n // Validate this single file using security checks\n const { validFiles, errors: validationErrors } = await prepareUploadRequest(\n file,\n { fileInfo: JSON.stringify(fileInfo) },\n strapi\n );\n\n if (validFiles.length === 0) {\n const errorMessage = validationErrors[0]?.message || 'Validation failed';\n uploadErrors.push({ name: fileName, message: errorMessage });\n writeSSE('file:error', { name: fileName, index: i, message: errorMessage });\n } else {\n // Validate using the already-parsed single fileInfo object directly\n const data = await validateUploadBody({ fileInfo }, false);\n const [uploadedFile] = await uploadService.upload(\n { data, files: [validFiles[0]] },\n { user }\n );\n\n // Sign file url\n const signedFile = await getService('file').signFileUrls(uploadedFile);\n successfulFiles.push(signedFile);\n\n writeSSE('file:complete', { name: fileName, index: i, file: signedFile });\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n uploadErrors.push({ name: fileName, message: errorMessage });\n writeSSE('file:error', { name: fileName, index: i, message: errorMessage });\n }\n }\n\n // Track image upload metric once if any images were uploaded\n if (successfulFiles.some((file) => file.mime?.startsWith('image/'))) {\n await getService('metrics').trackUsage('didUploadImage');\n }\n\n // Send final stream summary\n writeSSE('stream:complete', {\n data: await pm.sanitizeOutput(successfulFiles, { action: ACTIONS.read }),\n errors: uploadErrors,\n });\n\n res.end();\n },\n\n /**\n * @experimental\n * Upload files from URLs with SSE streaming for per-file progress\n *\n * Accepts JSON body with URLs and fetches them server-side.\n * Streams Server-Sent Events as each URL is fetched and uploaded:\n * - file:fetching — when starting to fetch a URL\n * - file:uploading — when upload starts for a fetched file\n * - file:complete — when a file is successfully uploaded\n * - file:error — when a URL fetch or upload fails\n * - stream:complete — final summary with all results\n */\n async unstable_uploadFromUrls(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body },\n } = ctx;\n\n const uploadService = getService('upload');\n const fileService = getService('file');\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.create,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n // Parse and validate request body\n const { urls, folderId } = body as { urls?: string[]; folderId?: number | null };\n\n if (!urls || !Array.isArray(urls) || urls.length === 0) {\n throw new errors.ApplicationError('URLs are required');\n }\n\n if (urls.length > 20) {\n throw new errors.ApplicationError('Maximum 20 URLs allowed per request');\n }\n\n // Take manual control of the response for SSE streaming\n ctx.respond = false;\n const res = ctx.res;\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n });\n\n const writeSSE = (event: string, data: Record<string, unknown>) => {\n res.write(`event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`);\n };\n\n const total = urls.length;\n const uploadErrors: FileUploadError[] = [];\n const successfulFiles: any[] = [];\n\n // Create temp directory for fetched files\n const tmpWorkingDirectory = await fse.mkdtemp(path.join(os.tmpdir(), 'strapi-url-upload-'));\n const { sizeLimit } = strapi.config.get<Config>('plugin::upload');\n\n try {\n // Process each URL sequentially\n for (let i = 0; i < urls.length; i += 1) {\n const url = urls[i];\n\n writeSSE('file:fetching', { url, index: i, total });\n\n try {\n // Fetch URL to temp file\n const { file } = await fileService.fetchUrlToInputFile(\n url,\n tmpWorkingDirectory,\n sizeLimit\n );\n const fileName = file.originalFilename;\n\n writeSSE('file:uploading', {\n name: fileName,\n index: i,\n total,\n size: file.size,\n });\n\n // Validate using security checks\n const fileInfo: UploadFileInfo = {\n name: fileName,\n caption: null,\n alternativeText: null,\n folder: folderId ?? null,\n };\n\n const { validFiles, errors: validationErrors } = await prepareUploadRequest(\n file,\n { fileInfo: JSON.stringify(fileInfo) },\n strapi\n );\n\n if (validFiles.length === 0) {\n const errorMessage = validationErrors[0]?.message || 'Validation failed';\n uploadErrors.push({ name: fileName, message: errorMessage });\n writeSSE('file:error', { name: fileName, url, index: i, message: errorMessage });\n } else {\n // Upload the file\n const data = await validateUploadBody({ fileInfo }, false);\n const [uploadedFile] = await uploadService.upload(\n { data, files: [validFiles[0]] },\n { user }\n );\n\n // Sign file url\n const signedFile = await fileService.signFileUrls(uploadedFile);\n successfulFiles.push(signedFile);\n\n writeSSE('file:complete', { name: fileName, index: i, file: signedFile });\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n uploadErrors.push({ name: url, message: errorMessage });\n writeSSE('file:error', { url, index: i, message: errorMessage });\n }\n }\n\n // Track image upload metric once if any images were uploaded\n if (successfulFiles.some((file) => file.mime?.startsWith('image/'))) {\n await getService('metrics').trackUsage('didUploadImage');\n }\n\n // Send final stream summary\n writeSSE('stream:complete', {\n data: await pm.sanitizeOutput(successfulFiles, { action: ACTIONS.read }),\n errors: uploadErrors,\n });\n } finally {\n // Clean up temp directory\n await fse.remove(tmpWorkingDirectory);\n }\n\n res.end();\n },\n\n // TODO: split into multiple endpoints\n async upload(ctx: Context) {\n const {\n query: { id },\n request: { files: { files } = {} },\n } = ctx;\n\n if (_.isEmpty(files) || (!Array.isArray(files) && files.size === 0)) {\n if (id) {\n return this.updateFileInfo(ctx);\n }\n\n throw new errors.ApplicationError('Files are empty');\n }\n\n await (id ? this.replaceFile : this.uploadFiles)(ctx);\n },\n};\n"],"names":["bulkUpdateFileInfo","ctx","state","userAbility","user","request","body","updates","validateBulkUpdateBody","uploadService","getService","results","async","map","id","fileInfo","pm","findEntityAndCheckPermissions","ACTIONS","update","FILE_MODEL_UID","updated","updateFileInfo","sanitizeOutput","action","read","query","errors","ValidationError","data","validateUploadBody","file","replaceFile","files","Array","isArray","ApplicationError","validFiles","filteredBody","validationErrors","prepareUploadRequest","strapi","length","message","replacedFile","replace","signedFile","signFileUrls","uploadFiles","service","createPermissionsManager","ability","create","model","isAllowed","forbidden","isMultipleFiles","filesArray","alignedFilesArray","info","find","originalFilename","name","filter","Boolean","uploadedFiles","upload","some","mime","startsWith","trackUsage","aiMetadataService","isEnabled","metadataResults","processFiles","updateFilesWithAIMetadata","error","log","warn","Error","String","signedFiles","status","unstable_uploadFilesStream","_","isEmpty","size","respond","res","writeHead","Connection","writeSSE","event","write","JSON","stringify","total","parsedFileInfo","raw","fi","parse","parsed","uploadErrors","successfulFiles","i","fileName","caption","alternativeText","folder","index","errorMessage","push","uploadedFile","end","unstable_uploadFromUrls","fileService","urls","folderId","tmpWorkingDirectory","fse","mkdtemp","path","join","os","tmpdir","sizeLimit","config","get","url","fetchUrlToInputFile","remove"],"mappings":"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"}
1
+ {"version":3,"file":"admin-upload.mjs","sources":["../../../server/src/controllers/admin-upload.ts"],"sourcesContent":["import os from 'os';\nimport path from 'path';\nimport fse from 'fs-extra';\nimport _ from 'lodash';\nimport { errors, async } from '@strapi/utils';\n\nimport type { Context } from 'koa';\n\nimport { getService } from '../utils';\nimport { ACTIONS, FILE_MODEL_UID } from '../constants';\nimport { validateBulkUpdateBody, validateUploadBody } from './validation/admin/upload';\nimport { findEntityAndCheckPermissions } from './utils/find-entity-and-check-permissions';\nimport { Config, FileInfo } from '../types';\nimport { prepareUploadRequest, type FileUploadError } from '../utils/mime-validation';\nimport type { UploadFileInfo } from '../../../shared/contracts/files';\n\nexport default {\n async bulkUpdateFileInfo(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body },\n } = ctx;\n\n const { updates } = await validateBulkUpdateBody(body);\n const uploadService = getService('upload');\n\n const results = await async.map(\n updates,\n async ({ id, fileInfo }: { id: number; fileInfo: FileInfo }) => {\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const updated = await uploadService.updateFileInfo(id, fileInfo as any, { user });\n\n // Sign file urls for private providers\n const signedFile = await getService('file').signFileUrls(updated);\n\n return pm.sanitizeOutput(signedFile, { action: ACTIONS.read });\n }\n );\n\n ctx.body = results;\n },\n\n async updateFileInfo(ctx: Context) {\n const {\n state: { userAbility, user },\n query: { id },\n request: { body },\n } = ctx;\n\n if (typeof id !== 'string') {\n throw new errors.ValidationError('File id is required');\n }\n\n const uploadService = getService('upload');\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n const data = await validateUploadBody(body);\n\n const file = await uploadService.updateFileInfo(id, data.fileInfo as any, { user });\n\n // Sign file urls for private providers\n const signedFile = await getService('file').signFileUrls(file);\n\n ctx.body = await pm.sanitizeOutput(signedFile, { action: ACTIONS.read });\n },\n\n async replaceFile(ctx: Context) {\n const {\n state: { userAbility, user },\n query: { id },\n request: { body, files: { files } = {} },\n } = ctx;\n\n if (typeof id !== 'string') {\n throw new errors.ValidationError('File id is required');\n }\n\n const uploadService = getService('upload');\n const { pm } = await findEntityAndCheckPermissions(\n userAbility,\n ACTIONS.update,\n FILE_MODEL_UID,\n id\n );\n\n if (Array.isArray(files)) {\n throw new errors.ApplicationError('Cannot replace a file with multiple ones');\n }\n\n const {\n validFiles,\n filteredBody,\n errors: validationErrors,\n } = await prepareUploadRequest(files, body, strapi);\n if (validFiles.length === 0) {\n throw new errors.ValidationError(validationErrors[0].message);\n }\n\n const data = (await validateUploadBody(filteredBody)) as { fileInfo: FileInfo };\n const replacedFile = await uploadService.replace(id, { data, file: validFiles[0] }, { user });\n\n // Regenerate AI metadata for image replacements so the alt text / caption\n // reflect the new file content. Mirrors the post-upload hook in\n // `uploadFiles`; failure is logged and swallowed to keep the replace flow\n // resilient when the AI provider is unavailable.\n const aiMetadataService = getService('aiMetadata');\n if (replacedFile?.mime?.startsWith('image/') && (await aiMetadataService.isEnabled())) {\n try {\n const metadataResults = await aiMetadataService.processFiles([replacedFile]);\n await aiMetadataService.updateFilesWithAIMetadata([replacedFile], metadataResults, user);\n } catch (error) {\n strapi.log.warn('AI metadata generation failed on replace, proceeding without it', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // Sign file urls for private providers\n const signedFile = await getService('file').signFileUrls(replacedFile);\n\n ctx.body = await pm.sanitizeOutput(signedFile, { action: ACTIONS.read });\n },\n\n async uploadFiles(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body, files: { files } = {} },\n } = ctx;\n\n const uploadService = getService('upload');\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.create,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n const {\n validFiles,\n filteredBody,\n errors: validationErrors,\n } = await prepareUploadRequest(files, body, strapi);\n if (validFiles.length === 0) {\n throw new errors.ValidationError(validationErrors[0].message);\n }\n\n const isMultipleFiles = validFiles.length > 1;\n const data = await validateUploadBody(filteredBody, isMultipleFiles);\n\n let filesArray = validFiles;\n\n if (\n data.fileInfo &&\n Array.isArray(data.fileInfo) &&\n filesArray.length === data.fileInfo.length\n ) {\n // Reorder filesArray to match data.fileInfo order\n const alignedFilesArray = data.fileInfo\n .map((info) => {\n return filesArray.find((file) => file.originalFilename === info.name);\n })\n .filter(Boolean) as any[];\n\n filesArray = alignedFilesArray;\n }\n\n // Upload files first to get thumbnails\n const uploadedFiles = await uploadService.upload({ data, files: filesArray }, { user });\n if (uploadedFiles.some((file) => file.mime?.startsWith('image/'))) {\n await getService('metrics').trackUsage('didUploadImage');\n }\n\n const aiMetadataService = getService('aiMetadata');\n\n // AFTER upload - generate AI metadata for images\n if (await aiMetadataService.isEnabled()) {\n try {\n const metadataResults = await aiMetadataService.processFiles(uploadedFiles);\n // Update the uploaded files with AI metadata\n await aiMetadataService.updateFilesWithAIMetadata(uploadedFiles, metadataResults, user);\n } catch (error) {\n strapi.log.warn('AI metadata generation failed, proceeding without AI enhancements', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // Sign file urls for private providers\n const signedFiles = await async.map(uploadedFiles, getService('file').signFileUrls);\n\n ctx.body = await pm.sanitizeOutput(signedFiles, { action: ACTIONS.read });\n ctx.status = 201;\n },\n\n /**\n * @experimental\n * Upload a single file and return the created File.\n *\n * Accepts one file per request (multipart `files` + `fileInfo`) and returns a\n * single `File` object. Unlike `uploadFiles`, it does **not** run AI metadata\n * generation inline — that responsibility is decoupled and will be handled by a\n * background job. Auth and permission checks mirror `POST /upload`.\n */\n async unstable_uploadFile(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body, files: { files } = {} },\n } = ctx;\n\n const uploadService = getService('upload');\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.create,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n if (_.isEmpty(files) || (!Array.isArray(files) && files.size === 0)) {\n throw new errors.ApplicationError('Files are empty');\n }\n\n // Accept a single file per request; ignore any extras defensively.\n const file = Array.isArray(files) ? files[0] : files;\n const fileName = file.originalFilename || 'unknown';\n\n // Parse the single fileInfo object from the multipart body.\n let fileInfo: UploadFileInfo = {\n name: fileName,\n caption: null,\n alternativeText: null,\n folder: null,\n };\n if (body?.fileInfo) {\n const raw = body.fileInfo;\n if (typeof raw === 'string') {\n fileInfo = JSON.parse(raw);\n } else if (Array.isArray(raw)) {\n fileInfo = (typeof raw[0] === 'string' ? JSON.parse(raw[0]) : raw[0]) as UploadFileInfo;\n } else {\n fileInfo = raw as UploadFileInfo;\n }\n }\n\n // Validate this single file using security checks.\n const { validFiles, errors: validationErrors } = await prepareUploadRequest(\n file,\n { fileInfo: JSON.stringify(fileInfo) },\n strapi\n );\n\n if (validFiles.length === 0) {\n throw new errors.ValidationError(validationErrors[0]?.message || 'Validation failed');\n }\n\n const data = await validateUploadBody({ fileInfo }, false);\n const [uploadedFile] = await uploadService.upload({ data, files: [validFiles[0]] }, { user });\n\n if (uploadedFile.mime?.startsWith('image/')) {\n await getService('metrics').trackUsage('didUploadImage');\n }\n\n // No inline AI metadata generation — intentionally decoupled for the async job.\n\n // Sign file url for private providers.\n const signedFile = await getService('file').signFileUrls(uploadedFile);\n\n ctx.body = await pm.sanitizeOutput(signedFile, { action: ACTIONS.read });\n ctx.status = 201;\n },\n\n /**\n * @experimental\n * Upload files from URLs with SSE streaming for per-file progress\n *\n * Accepts JSON body with URLs and fetches them server-side.\n * Streams Server-Sent Events as each URL is fetched and uploaded:\n * - file:fetching — when starting to fetch a URL\n * - file:uploading — when upload starts for a fetched file\n * - file:complete — when a file is successfully uploaded\n * - file:error — when a URL fetch or upload fails\n * - stream:complete — final summary with all results\n */\n async unstable_uploadFromUrls(ctx: Context) {\n const {\n state: { userAbility, user },\n request: { body },\n } = ctx;\n\n const uploadService = getService('upload');\n const fileService = getService('file');\n const pm = strapi.service('admin::permission').createPermissionsManager({\n ability: userAbility,\n action: ACTIONS.create,\n model: FILE_MODEL_UID,\n });\n\n if (!pm.isAllowed) {\n return ctx.forbidden();\n }\n\n // Parse and validate request body\n const { urls, folderId } = body as { urls?: string[]; folderId?: number | null };\n\n if (!urls || !Array.isArray(urls) || urls.length === 0) {\n throw new errors.ApplicationError('URLs are required');\n }\n\n if (urls.length > 20) {\n throw new errors.ApplicationError('Maximum 20 URLs allowed per request');\n }\n\n // Take manual control of the response for SSE streaming\n ctx.respond = false;\n const res = ctx.res;\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n });\n\n const writeSSE = (event: string, data: Record<string, unknown>) => {\n res.write(`event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`);\n };\n\n const total = urls.length;\n const uploadErrors: FileUploadError[] = [];\n const successfulFiles: any[] = [];\n\n // Create temp directory for fetched files\n const tmpWorkingDirectory = await fse.mkdtemp(path.join(os.tmpdir(), 'strapi-url-upload-'));\n const { sizeLimit } = strapi.config.get<Config>('plugin::upload');\n\n try {\n // Process each URL sequentially\n for (let i = 0; i < urls.length; i += 1) {\n const url = urls[i];\n\n writeSSE('file:fetching', { url, index: i, total });\n\n try {\n // Fetch URL to temp file\n const { file } = await fileService.fetchUrlToInputFile(\n url,\n tmpWorkingDirectory,\n sizeLimit\n );\n const fileName = file.originalFilename;\n\n writeSSE('file:uploading', {\n name: fileName,\n index: i,\n total,\n size: file.size,\n });\n\n // Validate using security checks\n const fileInfo: UploadFileInfo = {\n name: fileName,\n caption: null,\n alternativeText: null,\n folder: folderId ?? null,\n };\n\n const { validFiles, errors: validationErrors } = await prepareUploadRequest(\n file,\n { fileInfo: JSON.stringify(fileInfo) },\n strapi\n );\n\n if (validFiles.length === 0) {\n const errorMessage = validationErrors[0]?.message || 'Validation failed';\n uploadErrors.push({ name: fileName, message: errorMessage });\n writeSSE('file:error', { name: fileName, url, index: i, message: errorMessage });\n } else {\n // Upload the file\n const data = await validateUploadBody({ fileInfo }, false);\n const [uploadedFile] = await uploadService.upload(\n { data, files: [validFiles[0]] },\n { user }\n );\n\n // Sign file url\n const signedFile = await fileService.signFileUrls(uploadedFile);\n successfulFiles.push(signedFile);\n\n writeSSE('file:complete', { name: fileName, index: i, file: signedFile });\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n uploadErrors.push({ name: url, message: errorMessage });\n writeSSE('file:error', { url, index: i, message: errorMessage });\n }\n }\n\n // Track image upload metric once if any images were uploaded\n if (successfulFiles.some((file) => file.mime?.startsWith('image/'))) {\n await getService('metrics').trackUsage('didUploadImage');\n }\n\n // Send final stream summary\n writeSSE('stream:complete', {\n data: await pm.sanitizeOutput(successfulFiles, { action: ACTIONS.read }),\n errors: uploadErrors,\n });\n } finally {\n // Clean up temp directory\n await fse.remove(tmpWorkingDirectory);\n }\n\n res.end();\n },\n\n // TODO: split into multiple endpoints\n async upload(ctx: Context) {\n const {\n query: { id },\n request: { files: { files } = {} },\n } = ctx;\n\n if (_.isEmpty(files) || (!Array.isArray(files) && files.size === 0)) {\n if (id) {\n return this.updateFileInfo(ctx);\n }\n\n throw new errors.ApplicationError('Files are empty');\n }\n\n await (id ? this.replaceFile : this.uploadFiles)(ctx);\n },\n};\n"],"names":["bulkUpdateFileInfo","ctx","state","userAbility","user","request","body","updates","validateBulkUpdateBody","uploadService","getService","results","async","map","id","fileInfo","pm","findEntityAndCheckPermissions","ACTIONS","update","FILE_MODEL_UID","updated","updateFileInfo","signedFile","signFileUrls","sanitizeOutput","action","read","query","errors","ValidationError","data","validateUploadBody","file","replaceFile","files","Array","isArray","ApplicationError","validFiles","filteredBody","validationErrors","prepareUploadRequest","strapi","length","message","replacedFile","replace","aiMetadataService","mime","startsWith","isEnabled","metadataResults","processFiles","updateFilesWithAIMetadata","error","log","warn","Error","String","uploadFiles","service","createPermissionsManager","ability","create","model","isAllowed","forbidden","isMultipleFiles","filesArray","alignedFilesArray","info","find","originalFilename","name","filter","Boolean","uploadedFiles","upload","some","trackUsage","signedFiles","status","unstable_uploadFile","_","isEmpty","size","fileName","caption","alternativeText","folder","raw","JSON","parse","stringify","uploadedFile","unstable_uploadFromUrls","fileService","urls","folderId","respond","res","writeHead","Connection","writeSSE","event","write","total","uploadErrors","successfulFiles","tmpWorkingDirectory","fse","mkdtemp","path","join","os","tmpdir","sizeLimit","config","get","i","url","index","fetchUrlToInputFile","errorMessage","push","remove","end"],"mappings":"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"}
@@ -51,8 +51,8 @@ const routes = {
51
51
  },
52
52
  {
53
53
  method: 'POST',
54
- path: '/unstable/stream',
55
- handler: 'admin-upload.unstable_uploadFilesStream',
54
+ path: '/unstable/upload-file',
55
+ handler: 'admin-upload.unstable_uploadFile',
56
56
  config: {
57
57
  policies: [
58
58
  'admin::isAuthenticatedAdmin'
@@ -1 +1 @@
1
- {"version":3,"file":"admin.js","sources":["../../../server/src/routes/admin.ts"],"sourcesContent":["export const routes = {\n type: 'admin',\n routes: [\n {\n method: 'GET',\n path: '/settings',\n handler: 'admin-settings.getSettings',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.settings.read'],\n },\n },\n ],\n },\n },\n {\n method: 'PUT',\n path: '/settings',\n handler: 'admin-settings.updateSettings',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.settings.read'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/',\n handler: 'admin-upload.upload',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'POST',\n path: '/unstable/stream',\n handler: 'admin-upload.unstable_uploadFilesStream',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'POST',\n path: '/unstable/stream-from-urls',\n handler: 'admin-upload.unstable_uploadFromUrls',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n path: '/files',\n handler: 'admin-file.find',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.read'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/files/:id',\n handler: 'admin-file.findOne',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.read'],\n },\n },\n ],\n },\n },\n {\n method: 'DELETE',\n path: '/files/:id',\n handler: 'admin-file.destroy',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.assets.update'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/folders/:id',\n handler: 'admin-folder.findOne',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.read'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/folders',\n handler: 'admin-folder.find',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.read'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/folders',\n handler: 'admin-folder.create',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.assets.create'],\n },\n },\n ],\n },\n },\n {\n method: 'PUT',\n path: '/folders/:id',\n handler: 'admin-folder.update',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.assets.update'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/folder-structure',\n handler: 'admin-folder.getStructure',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.read'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/actions/bulk-delete',\n handler: 'admin-folder-file.deleteMany',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.assets.update'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/actions/bulk-move',\n handler: 'admin-folder-file.moveMany',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.assets.update'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/actions/bulk-update',\n handler: 'admin-upload.bulkUpdateFileInfo',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.assets.update'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/actions/generate-ai-metadata',\n handler: 'admin-file.generateAIMetadata',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.assets.update'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/actions/generate-ai-metadata/count',\n handler: 'admin-file.getAIMetadataCount',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.read'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/actions/generate-ai-metadata/latest',\n handler: 'admin-file.getLatestAIMetadataJob',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n ],\n};\n"],"names":["routes","type","method","path","handler","config","policies","name","actions"],"mappings":"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"}
1
+ {"version":3,"file":"admin.js","sources":["../../../server/src/routes/admin.ts"],"sourcesContent":["export const routes = {\n type: 'admin',\n routes: [\n {\n method: 'GET',\n path: '/settings',\n handler: 'admin-settings.getSettings',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.settings.read'],\n },\n },\n ],\n },\n },\n {\n method: 'PUT',\n path: '/settings',\n handler: 'admin-settings.updateSettings',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.settings.read'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/',\n handler: 'admin-upload.upload',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'POST',\n path: '/unstable/upload-file',\n handler: 'admin-upload.unstable_uploadFile',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'POST',\n path: '/unstable/stream-from-urls',\n handler: 'admin-upload.unstable_uploadFromUrls',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n {\n method: 'GET',\n path: '/files',\n handler: 'admin-file.find',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.read'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/files/:id',\n handler: 'admin-file.findOne',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.read'],\n },\n },\n ],\n },\n },\n {\n method: 'DELETE',\n path: '/files/:id',\n handler: 'admin-file.destroy',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.assets.update'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/folders/:id',\n handler: 'admin-folder.findOne',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.read'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/folders',\n handler: 'admin-folder.find',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.read'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/folders',\n handler: 'admin-folder.create',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.assets.create'],\n },\n },\n ],\n },\n },\n {\n method: 'PUT',\n path: '/folders/:id',\n handler: 'admin-folder.update',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.assets.update'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/folder-structure',\n handler: 'admin-folder.getStructure',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.read'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/actions/bulk-delete',\n handler: 'admin-folder-file.deleteMany',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.assets.update'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/actions/bulk-move',\n handler: 'admin-folder-file.moveMany',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.assets.update'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/actions/bulk-update',\n handler: 'admin-upload.bulkUpdateFileInfo',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.assets.update'],\n },\n },\n ],\n },\n },\n {\n method: 'POST',\n path: '/actions/generate-ai-metadata',\n handler: 'admin-file.generateAIMetadata',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.assets.update'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/actions/generate-ai-metadata/count',\n handler: 'admin-file.getAIMetadataCount',\n config: {\n policies: [\n 'admin::isAuthenticatedAdmin',\n {\n name: 'admin::hasPermissions',\n config: {\n actions: ['plugin::upload.read'],\n },\n },\n ],\n },\n },\n {\n method: 'GET',\n path: '/actions/generate-ai-metadata/latest',\n handler: 'admin-file.getLatestAIMetadataJob',\n config: {\n policies: ['admin::isAuthenticatedAdmin'],\n },\n },\n ],\n};\n"],"names":["routes","type","method","path","handler","config","policies","name","actions"],"mappings":"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"}