@strapi/upload 5.48.0 → 5.49.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 (187) hide show
  1. package/dist/admin/ai/components/AIAssetCard.js +3 -2
  2. package/dist/admin/ai/components/AIAssetCard.js.map +1 -1
  3. package/dist/admin/ai/components/AIUploadModal.js +3 -2
  4. package/dist/admin/ai/components/AIUploadModal.js.map +1 -1
  5. package/dist/admin/components/AssetCard/UploadingAssetCard.js +3 -2
  6. package/dist/admin/components/AssetCard/UploadingAssetCard.js.map +1 -1
  7. package/dist/admin/components/AssetCard/VideoAssetCard.js +3 -2
  8. package/dist/admin/components/AssetCard/VideoAssetCard.js.map +1 -1
  9. package/dist/admin/components/AssetDialog/AssetDialog.js +3 -2
  10. package/dist/admin/components/AssetDialog/AssetDialog.js.map +1 -1
  11. package/dist/admin/components/AssetDialog/BrowseStep/Filters.js +3 -2
  12. package/dist/admin/components/AssetDialog/BrowseStep/Filters.js.map +1 -1
  13. package/dist/admin/components/AssetDialog/BrowseStep/PaginationFooter/Pagination.js +3 -2
  14. package/dist/admin/components/AssetDialog/BrowseStep/PaginationFooter/Pagination.js.map +1 -1
  15. package/dist/admin/components/AssetDialog/BrowseStep/SearchAsset/SearchAsset.js +3 -2
  16. package/dist/admin/components/AssetDialog/BrowseStep/SearchAsset/SearchAsset.js.map +1 -1
  17. package/dist/admin/components/AssetGridList/Draggable.js +3 -2
  18. package/dist/admin/components/AssetGridList/Draggable.js.map +1 -1
  19. package/dist/admin/components/Breadcrumbs/CrumbSimpleMenuAsync.js +3 -2
  20. package/dist/admin/components/Breadcrumbs/CrumbSimpleMenuAsync.js.map +1 -1
  21. package/dist/admin/components/BulkMoveDialog/BulkMoveDialog.js +5 -1
  22. package/dist/admin/components/BulkMoveDialog/BulkMoveDialog.js.map +1 -1
  23. package/dist/admin/components/EditAssetDialog/EditAssetContent.js +8 -4
  24. package/dist/admin/components/EditAssetDialog/EditAssetContent.js.map +1 -1
  25. package/dist/admin/components/EditAssetDialog/PreviewBox/AssetPreview.js +7 -3
  26. package/dist/admin/components/EditAssetDialog/PreviewBox/AssetPreview.js.map +1 -1
  27. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.js +7 -3
  28. package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.js.map +1 -1
  29. package/dist/admin/components/EditAssetDialog/ReplaceMediaButton.js +3 -2
  30. package/dist/admin/components/EditAssetDialog/ReplaceMediaButton.js.map +1 -1
  31. package/dist/admin/components/EditFolderDialog/EditFolderDialog.js +8 -4
  32. package/dist/admin/components/EditFolderDialog/EditFolderDialog.js.map +1 -1
  33. package/dist/admin/components/FilterPopover/FilterPopover.js +3 -2
  34. package/dist/admin/components/FilterPopover/FilterPopover.js.map +1 -1
  35. package/dist/admin/components/FolderCard/FolderCard/FolderCard.js +3 -2
  36. package/dist/admin/components/FolderCard/FolderCard/FolderCard.js.map +1 -1
  37. package/dist/admin/components/MediaLibraryDialog/MediaLibraryDialog.js +5 -3
  38. package/dist/admin/components/MediaLibraryDialog/MediaLibraryDialog.js.map +1 -1
  39. package/dist/admin/components/MediaLibraryDialog/MediaLibraryDialog.mjs +2 -1
  40. package/dist/admin/components/MediaLibraryDialog/MediaLibraryDialog.mjs.map +1 -1
  41. package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAssets.js +3 -2
  42. package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAssets.js.map +1 -1
  43. package/dist/admin/components/MediaLibraryInput/Carousel/EmptyStateAsset.js +3 -2
  44. package/dist/admin/components/MediaLibraryInput/Carousel/EmptyStateAsset.js.map +1 -1
  45. package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js +3 -2
  46. package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js.map +1 -1
  47. package/dist/admin/components/SelectTree/SelectTree.js +7 -3
  48. package/dist/admin/components/SelectTree/SelectTree.js.map +1 -1
  49. package/dist/admin/components/TableList/CellContent.js +5 -1
  50. package/dist/admin/components/TableList/CellContent.js.map +1 -1
  51. package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromComputerForm.js +3 -2
  52. package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromComputerForm.js.map +1 -1
  53. package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromUrlForm.js +3 -2
  54. package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromUrlForm.js.map +1 -1
  55. package/dist/admin/components/UploadAssetDialog/PendingAssetStep/PendingAssetStep.js +3 -2
  56. package/dist/admin/components/UploadAssetDialog/PendingAssetStep/PendingAssetStep.js.map +1 -1
  57. package/dist/admin/components/UploadAssetDialog/UploadAssetDialog.js +3 -2
  58. package/dist/admin/components/UploadAssetDialog/UploadAssetDialog.js.map +1 -1
  59. package/dist/admin/future/components/Drawer.js +4 -3
  60. package/dist/admin/future/components/Drawer.js.map +1 -1
  61. package/dist/admin/future/pages/Assets/AssetsPage.js +29 -4
  62. package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
  63. package/dist/admin/future/pages/Assets/AssetsPage.mjs +28 -4
  64. package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
  65. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +3 -2
  66. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
  67. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.js +3 -2
  68. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.js.map +1 -1
  69. package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZone.js +3 -2
  70. package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZone.js.map +1 -1
  71. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js +389 -0
  72. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js.map +1 -0
  73. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs +387 -0
  74. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -0
  75. package/dist/admin/future/pages/Assets/components/ImportFromUrlDialog.js +3 -2
  76. package/dist/admin/future/pages/Assets/components/ImportFromUrlDialog.js.map +1 -1
  77. package/dist/admin/future/pages/Assets/hooks/useFolderInfo.js +4 -4
  78. package/dist/admin/future/pages/Assets/hooks/useFolderInfo.js.map +1 -1
  79. package/dist/admin/future/pages/Assets/hooks/useFolderInfo.mjs +4 -4
  80. package/dist/admin/future/pages/Assets/hooks/useFolderInfo.mjs.map +1 -1
  81. package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.js +48 -2
  82. package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.js.map +1 -1
  83. package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.mjs +48 -2
  84. package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.mjs.map +1 -1
  85. package/dist/admin/future/services/folders.js +28 -1
  86. package/dist/admin/future/services/folders.js.map +1 -1
  87. package/dist/admin/future/services/folders.mjs +28 -2
  88. package/dist/admin/future/services/folders.mjs.map +1 -1
  89. package/dist/admin/future/utils/files.js +5 -1
  90. package/dist/admin/future/utils/files.js.map +1 -1
  91. package/dist/admin/hooks/useAIMetadataJob.js +3 -2
  92. package/dist/admin/hooks/useAIMetadataJob.js.map +1 -1
  93. package/dist/admin/hooks/useAssets.js +3 -2
  94. package/dist/admin/hooks/useAssets.js.map +1 -1
  95. package/dist/admin/hooks/useCropImg.js +7 -3
  96. package/dist/admin/hooks/useCropImg.js.map +1 -1
  97. package/dist/admin/hooks/useEditAsset.js +3 -2
  98. package/dist/admin/hooks/useEditAsset.js.map +1 -1
  99. package/dist/admin/hooks/useFolders.js +3 -2
  100. package/dist/admin/hooks/useFolders.js.map +1 -1
  101. package/dist/admin/hooks/useModalQueryParams.js +3 -2
  102. package/dist/admin/hooks/useModalQueryParams.js.map +1 -1
  103. package/dist/admin/hooks/useSelectionState.js +3 -2
  104. package/dist/admin/hooks/useSelectionState.js.map +1 -1
  105. package/dist/admin/hooks/useUpload.js +3 -2
  106. package/dist/admin/hooks/useUpload.js.map +1 -1
  107. package/dist/admin/pages/App/App.js +3 -2
  108. package/dist/admin/pages/App/App.js.map +1 -1
  109. package/dist/admin/pages/App/ConfigureTheView/ConfigureTheView.js +7 -3
  110. package/dist/admin/pages/App/ConfigureTheView/ConfigureTheView.js.map +1 -1
  111. package/dist/admin/pages/App/ConfigureTheView/state/reducer.js +7 -2
  112. package/dist/admin/pages/App/ConfigureTheView/state/reducer.js.map +1 -1
  113. package/dist/admin/pages/App/MediaLibrary.js +3 -2
  114. package/dist/admin/pages/App/MediaLibrary.js.map +1 -1
  115. package/dist/admin/pages/App/components/BulkMoveButton.js +3 -2
  116. package/dist/admin/pages/App/components/BulkMoveButton.js.map +1 -1
  117. package/dist/admin/pages/App/components/Filters.js +3 -2
  118. package/dist/admin/pages/App/components/Filters.js.map +1 -1
  119. package/dist/admin/pages/SettingsPage/SettingsPage.js +7 -3
  120. package/dist/admin/pages/SettingsPage/SettingsPage.js.map +1 -1
  121. package/dist/admin/pages/SettingsPage/reducer.js +5 -1
  122. package/dist/admin/pages/SettingsPage/reducer.js.map +1 -1
  123. package/dist/admin/src/components/MediaLibraryDialog/MediaLibraryDialog.d.ts +2 -1
  124. package/dist/admin/src/future/pages/Assets/components/FolderTree/FolderTree.d.ts +19 -0
  125. package/dist/admin/src/future/pages/Assets/hooks/useFolderNavigation.d.ts +2 -0
  126. package/dist/admin/src/future/services/folders.d.ts +2 -2
  127. package/dist/admin/translations/en.json.js +10 -1
  128. package/dist/admin/translations/en.json.js.map +1 -1
  129. package/dist/admin/translations/en.json.mjs +10 -1
  130. package/dist/admin/translations/en.json.mjs.map +1 -1
  131. package/dist/admin/utils/formatBytes.js +5 -1
  132. package/dist/admin/utils/formatBytes.js.map +1 -1
  133. package/dist/admin/utils/urlYupSchema.js +3 -2
  134. package/dist/admin/utils/urlYupSchema.js.map +1 -1
  135. package/dist/server/controllers/admin-upload.js +11 -4
  136. package/dist/server/controllers/admin-upload.js.map +1 -1
  137. package/dist/server/controllers/content-api.js +19 -2
  138. package/dist/server/controllers/content-api.js.map +1 -1
  139. package/dist/server/controllers/content-api.mjs +12 -0
  140. package/dist/server/controllers/content-api.mjs.map +1 -1
  141. package/dist/server/controllers/utils/find-entity-and-check-permissions.js +7 -3
  142. package/dist/server/controllers/utils/find-entity-and-check-permissions.js.map +1 -1
  143. package/dist/server/middlewares/upload.js +7 -2
  144. package/dist/server/middlewares/upload.js.map +1 -1
  145. package/dist/server/register.js +9 -4
  146. package/dist/server/register.js.map +1 -1
  147. package/dist/server/routes/content-api.js +18 -2
  148. package/dist/server/routes/content-api.js.map +1 -1
  149. package/dist/server/routes/content-api.mjs +15 -0
  150. package/dist/server/routes/content-api.mjs.map +1 -1
  151. package/dist/server/routes/validation/upload.js +31 -2
  152. package/dist/server/routes/validation/upload.js.map +1 -1
  153. package/dist/server/routes/validation/upload.mjs +28 -0
  154. package/dist/server/routes/validation/upload.mjs.map +1 -1
  155. package/dist/server/services/file.js +13 -6
  156. package/dist/server/services/file.js.map +1 -1
  157. package/dist/server/services/image-manipulation.js +18 -12
  158. package/dist/server/services/image-manipulation.js.map +1 -1
  159. package/dist/server/services/provider.js +24 -0
  160. package/dist/server/services/provider.js.map +1 -1
  161. package/dist/server/services/provider.mjs +24 -0
  162. package/dist/server/services/provider.mjs.map +1 -1
  163. package/dist/server/services/upload.js +187 -31
  164. package/dist/server/services/upload.js.map +1 -1
  165. package/dist/server/services/upload.mjs +159 -11
  166. package/dist/server/services/upload.mjs.map +1 -1
  167. package/dist/server/src/controllers/content-api.d.ts +1 -0
  168. package/dist/server/src/controllers/content-api.d.ts.map +1 -1
  169. package/dist/server/src/controllers/index.d.ts +1 -0
  170. package/dist/server/src/controllers/index.d.ts.map +1 -1
  171. package/dist/server/src/index.d.ts +6 -0
  172. package/dist/server/src/index.d.ts.map +1 -1
  173. package/dist/server/src/routes/content-api.d.ts.map +1 -1
  174. package/dist/server/src/routes/validation/upload.d.ts +45 -0
  175. package/dist/server/src/routes/validation/upload.d.ts.map +1 -1
  176. package/dist/server/src/services/index.d.ts +5 -0
  177. package/dist/server/src/services/index.d.ts.map +1 -1
  178. package/dist/server/src/services/provider.d.ts +2 -1
  179. package/dist/server/src/services/provider.d.ts.map +1 -1
  180. package/dist/server/src/services/upload.d.ts +5 -0
  181. package/dist/server/src/services/upload.d.ts.map +1 -1
  182. package/dist/server/src/utils/mime-validation.d.ts.map +1 -1
  183. package/dist/server/utils/mime-validation.js +8 -2
  184. package/dist/server/utils/mime-validation.js.map +1 -1
  185. package/dist/server/utils/mime-validation.mjs +9 -3
  186. package/dist/server/utils/mime-validation.mjs.map +1 -1
  187. package/package.json +7 -7
@@ -34,6 +34,21 @@ const createRoutes = createContentApiRoutesFactory(()=>{
34
34
  },
35
35
  response: validator.files
36
36
  },
37
+ {
38
+ method: 'GET',
39
+ path: '/files/page',
40
+ handler: 'content-api.findPage',
41
+ request: {
42
+ query: {
43
+ fields: validator.queryFields.optional(),
44
+ populate: validator.queryPopulate.optional(),
45
+ sort: validator.querySort.optional(),
46
+ pagination: validator.pagination.optional(),
47
+ filters: validator.filters.optional()
48
+ }
49
+ },
50
+ response: validator.paginatedFiles
51
+ },
37
52
  {
38
53
  method: 'GET',
39
54
  path: '/files/:id',
@@ -1 +1 @@
1
- {"version":3,"file":"content-api.mjs","sources":["../../../server/src/routes/content-api.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport * as z from 'zod/v4';\nimport { createContentApiRoutesFactory } from '@strapi/utils';\nimport { UploadRouteValidator } from './validation';\n\nconst createRoutes = createContentApiRoutesFactory((): Core.RouterInput['routes'] => {\n const validator = new UploadRouteValidator(strapi);\n\n return [\n {\n method: 'POST',\n path: '/',\n handler: 'content-api.upload',\n request: {\n query: { id: validator.fileId.optional() },\n // Note: multipart/form-data is handled by Koa middleware, not Zod\n },\n response: z.union([validator.file, validator.files]),\n },\n {\n method: 'GET',\n path: '/files',\n handler: 'content-api.find',\n request: {\n query: {\n fields: validator.queryFields.optional(),\n populate: validator.queryPopulate.optional(),\n sort: validator.querySort.optional(),\n pagination: validator.pagination.optional(),\n filters: validator.filters.optional(),\n },\n },\n response: validator.files,\n },\n {\n method: 'GET',\n path: '/files/:id',\n handler: 'content-api.findOne',\n request: {\n params: { id: validator.fileId },\n query: {\n fields: validator.queryFields.optional(),\n populate: validator.queryPopulate.optional(),\n },\n },\n response: validator.file,\n },\n {\n method: 'DELETE',\n path: '/files/:id',\n handler: 'content-api.destroy',\n request: {\n params: { id: validator.fileId },\n },\n response: validator.file,\n },\n ];\n});\n\nexport const routes = createRoutes;\n"],"names":["createRoutes","createContentApiRoutesFactory","validator","UploadRouteValidator","strapi","method","path","handler","request","query","id","fileId","optional","response","z","union","file","files","fields","queryFields","populate","queryPopulate","sort","querySort","pagination","filters","params","routes"],"mappings":";;;;AAKA,MAAMA,eAAeC,6BAAAA,CAA8B,IAAA;IACjD,MAAMC,SAAAA,GAAY,IAAIC,oBAAAA,CAAqBC,MAAAA,CAAAA;IAE3C,OAAO;AACL,QAAA;YACEC,MAAAA,EAAQ,MAAA;YACRC,IAAAA,EAAM,GAAA;YACNC,OAAAA,EAAS,oBAAA;YACTC,OAAAA,EAAS;gBACPC,KAAAA,EAAO;oBAAEC,EAAAA,EAAIR,SAAAA,CAAUS,MAAM,CAACC,QAAQ;AAAG;AAE3C,aAAA;YACAC,QAAAA,EAAUC,CAAAA,CAAEC,KAAK,CAAC;AAACb,gBAAAA,SAAAA,CAAUc,IAAI;AAAEd,gBAAAA,SAAAA,CAAUe;AAAM,aAAA;AACrD,SAAA;AACA,QAAA;YACEZ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,QAAA;YACNC,OAAAA,EAAS,kBAAA;YACTC,OAAAA,EAAS;gBACPC,KAAAA,EAAO;oBACLS,MAAAA,EAAQhB,SAAAA,CAAUiB,WAAW,CAACP,QAAQ,EAAA;oBACtCQ,QAAAA,EAAUlB,SAAAA,CAAUmB,aAAa,CAACT,QAAQ,EAAA;oBAC1CU,IAAAA,EAAMpB,SAAAA,CAAUqB,SAAS,CAACX,QAAQ,EAAA;oBAClCY,UAAAA,EAAYtB,SAAAA,CAAUsB,UAAU,CAACZ,QAAQ,EAAA;oBACzCa,OAAAA,EAASvB,SAAAA,CAAUuB,OAAO,CAACb,QAAQ;AACrC;AACF,aAAA;AACAC,YAAAA,QAAAA,EAAUX,UAAUe;AACtB,SAAA;AACA,QAAA;YACEZ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,YAAA;YACNC,OAAAA,EAAS,qBAAA;YACTC,OAAAA,EAAS;gBACPkB,MAAAA,EAAQ;AAAEhB,oBAAAA,EAAAA,EAAIR,UAAUS;AAAO,iBAAA;gBAC/BF,KAAAA,EAAO;oBACLS,MAAAA,EAAQhB,SAAAA,CAAUiB,WAAW,CAACP,QAAQ,EAAA;oBACtCQ,QAAAA,EAAUlB,SAAAA,CAAUmB,aAAa,CAACT,QAAQ;AAC5C;AACF,aAAA;AACAC,YAAAA,QAAAA,EAAUX,UAAUc;AACtB,SAAA;AACA,QAAA;YACEX,MAAAA,EAAQ,QAAA;YACRC,IAAAA,EAAM,YAAA;YACNC,OAAAA,EAAS,qBAAA;YACTC,OAAAA,EAAS;gBACPkB,MAAAA,EAAQ;AAAEhB,oBAAAA,EAAAA,EAAIR,UAAUS;AAAO;AACjC,aAAA;AACAE,YAAAA,QAAAA,EAAUX,UAAUc;AACtB;AACD,KAAA;AACH,CAAA,CAAA;AAEO,MAAMW,SAAS3B;;;;"}
1
+ {"version":3,"file":"content-api.mjs","sources":["../../../server/src/routes/content-api.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport * as z from 'zod/v4';\nimport { createContentApiRoutesFactory } from '@strapi/utils';\nimport { UploadRouteValidator } from './validation';\n\nconst createRoutes = createContentApiRoutesFactory((): Core.RouterInput['routes'] => {\n const validator = new UploadRouteValidator(strapi);\n\n return [\n {\n method: 'POST',\n path: '/',\n handler: 'content-api.upload',\n request: {\n query: { id: validator.fileId.optional() },\n // Note: multipart/form-data is handled by Koa middleware, not Zod\n },\n response: z.union([validator.file, validator.files]),\n },\n {\n method: 'GET',\n path: '/files',\n handler: 'content-api.find',\n request: {\n query: {\n fields: validator.queryFields.optional(),\n populate: validator.queryPopulate.optional(),\n sort: validator.querySort.optional(),\n pagination: validator.pagination.optional(),\n filters: validator.filters.optional(),\n },\n },\n response: validator.files,\n },\n {\n method: 'GET',\n path: '/files/page',\n handler: 'content-api.findPage',\n request: {\n query: {\n fields: validator.queryFields.optional(),\n populate: validator.queryPopulate.optional(),\n sort: validator.querySort.optional(),\n pagination: validator.pagination.optional(),\n filters: validator.filters.optional(),\n },\n },\n response: validator.paginatedFiles,\n },\n {\n method: 'GET',\n path: '/files/:id',\n handler: 'content-api.findOne',\n request: {\n params: { id: validator.fileId },\n query: {\n fields: validator.queryFields.optional(),\n populate: validator.queryPopulate.optional(),\n },\n },\n response: validator.file,\n },\n {\n method: 'DELETE',\n path: '/files/:id',\n handler: 'content-api.destroy',\n request: {\n params: { id: validator.fileId },\n },\n response: validator.file,\n },\n ];\n});\n\nexport const routes = createRoutes;\n"],"names":["createRoutes","createContentApiRoutesFactory","validator","UploadRouteValidator","strapi","method","path","handler","request","query","id","fileId","optional","response","z","union","file","files","fields","queryFields","populate","queryPopulate","sort","querySort","pagination","filters","paginatedFiles","params","routes"],"mappings":";;;;AAKA,MAAMA,eAAeC,6BAAAA,CAA8B,IAAA;IACjD,MAAMC,SAAAA,GAAY,IAAIC,oBAAAA,CAAqBC,MAAAA,CAAAA;IAE3C,OAAO;AACL,QAAA;YACEC,MAAAA,EAAQ,MAAA;YACRC,IAAAA,EAAM,GAAA;YACNC,OAAAA,EAAS,oBAAA;YACTC,OAAAA,EAAS;gBACPC,KAAAA,EAAO;oBAAEC,EAAAA,EAAIR,SAAAA,CAAUS,MAAM,CAACC,QAAQ;AAAG;AAE3C,aAAA;YACAC,QAAAA,EAAUC,CAAAA,CAAEC,KAAK,CAAC;AAACb,gBAAAA,SAAAA,CAAUc,IAAI;AAAEd,gBAAAA,SAAAA,CAAUe;AAAM,aAAA;AACrD,SAAA;AACA,QAAA;YACEZ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,QAAA;YACNC,OAAAA,EAAS,kBAAA;YACTC,OAAAA,EAAS;gBACPC,KAAAA,EAAO;oBACLS,MAAAA,EAAQhB,SAAAA,CAAUiB,WAAW,CAACP,QAAQ,EAAA;oBACtCQ,QAAAA,EAAUlB,SAAAA,CAAUmB,aAAa,CAACT,QAAQ,EAAA;oBAC1CU,IAAAA,EAAMpB,SAAAA,CAAUqB,SAAS,CAACX,QAAQ,EAAA;oBAClCY,UAAAA,EAAYtB,SAAAA,CAAUsB,UAAU,CAACZ,QAAQ,EAAA;oBACzCa,OAAAA,EAASvB,SAAAA,CAAUuB,OAAO,CAACb,QAAQ;AACrC;AACF,aAAA;AACAC,YAAAA,QAAAA,EAAUX,UAAUe;AACtB,SAAA;AACA,QAAA;YACEZ,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,aAAA;YACNC,OAAAA,EAAS,sBAAA;YACTC,OAAAA,EAAS;gBACPC,KAAAA,EAAO;oBACLS,MAAAA,EAAQhB,SAAAA,CAAUiB,WAAW,CAACP,QAAQ,EAAA;oBACtCQ,QAAAA,EAAUlB,SAAAA,CAAUmB,aAAa,CAACT,QAAQ,EAAA;oBAC1CU,IAAAA,EAAMpB,SAAAA,CAAUqB,SAAS,CAACX,QAAQ,EAAA;oBAClCY,UAAAA,EAAYtB,SAAAA,CAAUsB,UAAU,CAACZ,QAAQ,EAAA;oBACzCa,OAAAA,EAASvB,SAAAA,CAAUuB,OAAO,CAACb,QAAQ;AACrC;AACF,aAAA;AACAC,YAAAA,QAAAA,EAAUX,UAAUwB;AACtB,SAAA;AACA,QAAA;YACErB,MAAAA,EAAQ,KAAA;YACRC,IAAAA,EAAM,YAAA;YACNC,OAAAA,EAAS,qBAAA;YACTC,OAAAA,EAAS;gBACPmB,MAAAA,EAAQ;AAAEjB,oBAAAA,EAAAA,EAAIR,UAAUS;AAAO,iBAAA;gBAC/BF,KAAAA,EAAO;oBACLS,MAAAA,EAAQhB,SAAAA,CAAUiB,WAAW,CAACP,QAAQ,EAAA;oBACtCQ,QAAAA,EAAUlB,SAAAA,CAAUmB,aAAa,CAACT,QAAQ;AAC5C;AACF,aAAA;AACAC,YAAAA,QAAAA,EAAUX,UAAUc;AACtB,SAAA;AACA,QAAA;YACEX,MAAAA,EAAQ,QAAA;YACRC,IAAAA,EAAM,YAAA;YACNC,OAAAA,EAAS,qBAAA;YACTC,OAAAA,EAAS;gBACPmB,MAAAA,EAAQ;AAAEjB,oBAAAA,EAAAA,EAAIR,UAAUS;AAAO;AACjC,aAAA;AACAE,YAAAA,QAAAA,EAAUX,UAAUc;AACtB;AACD,KAAA;AACH,CAAA,CAAA;AAEO,MAAMY,SAAS5B;;;;"}
@@ -3,7 +3,8 @@
3
3
  var utils = require('@strapi/utils');
4
4
  var z = require('zod/v4');
5
5
 
6
- function _interopNamespaceDefault(e) {
6
+ function _interopNamespace(e) {
7
+ if (e && e.__esModule) return e;
7
8
  var n = Object.create(null);
8
9
  if (e) {
9
10
  Object.keys(e).forEach(function (k) {
@@ -20,7 +21,7 @@ function _interopNamespaceDefault(e) {
20
21
  return Object.freeze(n);
21
22
  }
22
23
 
23
- var z__namespace = /*#__PURE__*/_interopNamespaceDefault(z);
24
+ var z__namespace = /*#__PURE__*/_interopNamespace(z);
24
25
 
25
26
  /**
26
27
  * UploadRouteValidator provides validation for upload/file routes.
@@ -63,6 +64,34 @@ var z__namespace = /*#__PURE__*/_interopNamespaceDefault(z);
63
64
  return z__namespace.array(this.file);
64
65
  }
65
66
  /**
67
+ * Paginated files response schema: `{ data, meta: { pagination } }`.
68
+ *
69
+ * Pagination meta is either page-based (`page`/`pageSize`) or offset-based
70
+ * (`start`/`limit`), and `total`/`pageCount` are omitted when
71
+ * `pagination[withCount]=false`.
72
+ */ get paginatedFiles() {
73
+ const pagedPagination = z__namespace.object({
74
+ page: z__namespace.number().int(),
75
+ pageSize: z__namespace.number().int(),
76
+ pageCount: z__namespace.number().int().optional(),
77
+ total: z__namespace.number().int().optional()
78
+ });
79
+ const offsetPagination = z__namespace.object({
80
+ start: z__namespace.number().int(),
81
+ limit: z__namespace.number().int(),
82
+ total: z__namespace.number().int().optional()
83
+ });
84
+ return z__namespace.object({
85
+ data: this.files,
86
+ meta: z__namespace.object({
87
+ pagination: z__namespace.union([
88
+ pagedPagination,
89
+ offsetPagination
90
+ ])
91
+ })
92
+ });
93
+ }
94
+ /**
66
95
  * File ID parameter validation
67
96
  */ get fileId() {
68
97
  return z__namespace.number().int().positive();
@@ -1 +1 @@
1
- {"version":3,"file":"upload.js","sources":["../../../../server/src/routes/validation/upload.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport { AbstractRouteValidator, type QueryParam } from '@strapi/utils';\nimport * as z from 'zod/v4';\n\nexport type FileQueryParam = QueryParam;\n\n/**\n * UploadRouteValidator provides validation for upload/file routes.\n *\n * Extends the AbstractRouteValidator to inherit common query parameter validation\n * while adding file-specific validation schemas.\n */\nexport class UploadRouteValidator extends AbstractRouteValidator {\n protected readonly _strapi: Core.Strapi;\n\n public constructor(strapi: Core.Strapi) {\n super();\n this._strapi = strapi;\n }\n\n /**\n * File schema for upload responses\n * Defines the structure of a file object returned by the upload API\n */\n get file() {\n return z.object({\n id: this.fileId,\n documentId: z.uuid(),\n name: z.string(),\n alternativeText: z.string().nullable().optional(),\n caption: z.string().nullable().optional(),\n width: z.number().int().optional(),\n height: z.number().int().optional(),\n formats: z.record(z.string(), z.unknown()).optional(),\n hash: z.string(),\n ext: z.string().optional(),\n mime: z.string(),\n size: z.number(),\n url: z.string(),\n previewUrl: z.string().nullable().optional(),\n folder: z.number().optional(),\n folderPath: z.string(),\n provider: z.string(),\n provider_metadata: z.record(z.string(), z.unknown()).nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n createdBy: z.number().optional(),\n updatedBy: z.number().optional(),\n });\n }\n\n /**\n * Array of files schema\n */\n get files() {\n return z.array(this.file);\n }\n\n /**\n * File ID parameter validation\n */\n get fileId() {\n return z.number().int().positive();\n }\n\n /**\n * Upload request body schema for single file uploads\n */\n get uploadBody() {\n return z.object({\n fileInfo: z\n .object({\n name: z.string().optional(),\n alternativeText: z.string().optional(),\n caption: z.string().optional(),\n })\n .optional(),\n });\n }\n\n /**\n * Upload request body schema for multiple file uploads\n */\n get multiUploadBody() {\n return z.object({\n fileInfo: z\n .array(\n z.object({\n name: z.string().optional(),\n alternativeText: z.string().optional(),\n caption: z.string().optional(),\n })\n )\n .optional(),\n });\n }\n\n // Note: queryParams() method is inherited from AbstractRouteValidator\n // and provides validation for ['fields', 'populate', 'sort', 'pagination', 'filters']\n}\n"],"names":["UploadRouteValidator","AbstractRouteValidator","file","z","object","id","fileId","documentId","uuid","name","string","alternativeText","nullable","optional","caption","width","number","int","height","formats","record","unknown","hash","ext","mime","size","url","previewUrl","folder","folderPath","provider","provider_metadata","createdAt","updatedAt","createdBy","updatedBy","files","array","positive","uploadBody","fileInfo","multiUploadBody","strapi","_strapi"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAMA;;;;;IAMO,MAAMA,oBAAAA,SAA6BC,4BAAAA,CAAAA;AAQxC;;;AAGC,MACD,IAAIC,IAAAA,GAAO;QACT,OAAOC,YAAAA,CAAEC,MAAM,CAAC;YACdC,EAAAA,EAAI,IAAI,CAACC,MAAM;AACfC,YAAAA,UAAAA,EAAYJ,aAAEK,IAAI,EAAA;AAClBC,YAAAA,IAAAA,EAAMN,aAAEO,MAAM,EAAA;AACdC,YAAAA,eAAAA,EAAiBR,YAAAA,CAAEO,MAAM,EAAA,CAAGE,QAAQ,GAAGC,QAAQ,EAAA;AAC/CC,YAAAA,OAAAA,EAASX,YAAAA,CAAEO,MAAM,EAAA,CAAGE,QAAQ,GAAGC,QAAQ,EAAA;AACvCE,YAAAA,KAAAA,EAAOZ,YAAAA,CAAEa,MAAM,EAAA,CAAGC,GAAG,GAAGJ,QAAQ,EAAA;AAChCK,YAAAA,MAAAA,EAAQf,YAAAA,CAAEa,MAAM,EAAA,CAAGC,GAAG,GAAGJ,QAAQ,EAAA;YACjCM,OAAAA,EAAShB,YAAAA,CAAEiB,MAAM,CAACjB,YAAAA,CAAEO,MAAM,EAAA,EAAIP,YAAAA,CAAEkB,OAAO,EAAA,CAAA,CAAIR,QAAQ,EAAA;AACnDS,YAAAA,IAAAA,EAAMnB,aAAEO,MAAM,EAAA;YACda,GAAAA,EAAKpB,YAAAA,CAAEO,MAAM,EAAA,CAAGG,QAAQ,EAAA;AACxBW,YAAAA,IAAAA,EAAMrB,aAAEO,MAAM,EAAA;AACde,YAAAA,IAAAA,EAAMtB,aAAEa,MAAM,EAAA;AACdU,YAAAA,GAAAA,EAAKvB,aAAEO,MAAM,EAAA;AACbiB,YAAAA,UAAAA,EAAYxB,YAAAA,CAAEO,MAAM,EAAA,CAAGE,QAAQ,GAAGC,QAAQ,EAAA;YAC1Ce,MAAAA,EAAQzB,YAAAA,CAAEa,MAAM,EAAA,CAAGH,QAAQ,EAAA;AAC3BgB,YAAAA,UAAAA,EAAY1B,aAAEO,MAAM,EAAA;AACpBoB,YAAAA,QAAAA,EAAU3B,aAAEO,MAAM,EAAA;YAClBqB,iBAAAA,EAAmB5B,YAAAA,CAAEiB,MAAM,CAACjB,YAAAA,CAAEO,MAAM,EAAA,EAAIP,YAAAA,CAAEkB,OAAO,EAAA,CAAA,CAAIT,QAAQ,EAAA,CAAGC,QAAQ,EAAA;AACxEmB,YAAAA,SAAAA,EAAW7B,aAAEO,MAAM,EAAA;AACnBuB,YAAAA,SAAAA,EAAW9B,aAAEO,MAAM,EAAA;YACnBwB,SAAAA,EAAW/B,YAAAA,CAAEa,MAAM,EAAA,CAAGH,QAAQ,EAAA;YAC9BsB,SAAAA,EAAWhC,YAAAA,CAAEa,MAAM,EAAA,CAAGH,QAAQ;AAChC,SAAA,CAAA;AACF,IAAA;AAEA;;AAEC,MACD,IAAIuB,KAAAA,GAAQ;AACV,QAAA,OAAOjC,YAAAA,CAAEkC,KAAK,CAAC,IAAI,CAACnC,IAAI,CAAA;AAC1B,IAAA;AAEA;;AAEC,MACD,IAAII,MAAAA,GAAS;AACX,QAAA,OAAOH,YAAAA,CAAEa,MAAM,EAAA,CAAGC,GAAG,GAAGqB,QAAQ,EAAA;AAClC,IAAA;AAEA;;AAEC,MACD,IAAIC,UAAAA,GAAa;QACf,OAAOpC,YAAAA,CAAEC,MAAM,CAAC;YACdoC,QAAAA,EAAUrC,YAAAA,CACPC,MAAM,CAAC;gBACNK,IAAAA,EAAMN,YAAAA,CAAEO,MAAM,EAAA,CAAGG,QAAQ,EAAA;gBACzBF,eAAAA,EAAiBR,YAAAA,CAAEO,MAAM,EAAA,CAAGG,QAAQ,EAAA;gBACpCC,OAAAA,EAASX,YAAAA,CAAEO,MAAM,EAAA,CAAGG,QAAQ;AAC9B,aAAA,CAAA,CACCA,QAAQ;AACb,SAAA,CAAA;AACF,IAAA;AAEA;;AAEC,MACD,IAAI4B,eAAAA,GAAkB;QACpB,OAAOtC,YAAAA,CAAEC,MAAM,CAAC;AACdoC,YAAAA,QAAAA,EAAUrC,YAAAA,CACPkC,KAAK,CACJlC,YAAAA,CAAEC,MAAM,CAAC;gBACPK,IAAAA,EAAMN,YAAAA,CAAEO,MAAM,EAAA,CAAGG,QAAQ,EAAA;gBACzBF,eAAAA,EAAiBR,YAAAA,CAAEO,MAAM,EAAA,CAAGG,QAAQ,EAAA;gBACpCC,OAAAA,EAASX,YAAAA,CAAEO,MAAM,EAAA,CAAGG,QAAQ;AAC9B,aAAA,CAAA,CAAA,CAEDA,QAAQ;AACb,SAAA,CAAA;AACF,IAAA;AAhFA,IAAA,WAAA,CAAmB6B,MAAmB,CAAE;QACtC,KAAK,EAAA;QACL,IAAI,CAACC,OAAO,GAAGD,MAAAA;AACjB,IAAA;AAiFF;;;;"}
1
+ {"version":3,"file":"upload.js","sources":["../../../../server/src/routes/validation/upload.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport { AbstractRouteValidator, type QueryParam } from '@strapi/utils';\nimport * as z from 'zod/v4';\n\nexport type FileQueryParam = QueryParam;\n\n/**\n * UploadRouteValidator provides validation for upload/file routes.\n *\n * Extends the AbstractRouteValidator to inherit common query parameter validation\n * while adding file-specific validation schemas.\n */\nexport class UploadRouteValidator extends AbstractRouteValidator {\n protected readonly _strapi: Core.Strapi;\n\n public constructor(strapi: Core.Strapi) {\n super();\n this._strapi = strapi;\n }\n\n /**\n * File schema for upload responses\n * Defines the structure of a file object returned by the upload API\n */\n get file() {\n return z.object({\n id: this.fileId,\n documentId: z.uuid(),\n name: z.string(),\n alternativeText: z.string().nullable().optional(),\n caption: z.string().nullable().optional(),\n width: z.number().int().optional(),\n height: z.number().int().optional(),\n formats: z.record(z.string(), z.unknown()).optional(),\n hash: z.string(),\n ext: z.string().optional(),\n mime: z.string(),\n size: z.number(),\n url: z.string(),\n previewUrl: z.string().nullable().optional(),\n folder: z.number().optional(),\n folderPath: z.string(),\n provider: z.string(),\n provider_metadata: z.record(z.string(), z.unknown()).nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n createdBy: z.number().optional(),\n updatedBy: z.number().optional(),\n });\n }\n\n /**\n * Array of files schema\n */\n get files() {\n return z.array(this.file);\n }\n\n /**\n * Paginated files response schema: `{ data, meta: { pagination } }`.\n *\n * Pagination meta is either page-based (`page`/`pageSize`) or offset-based\n * (`start`/`limit`), and `total`/`pageCount` are omitted when\n * `pagination[withCount]=false`.\n */\n get paginatedFiles() {\n const pagedPagination = z.object({\n page: z.number().int(),\n pageSize: z.number().int(),\n pageCount: z.number().int().optional(),\n total: z.number().int().optional(),\n });\n\n const offsetPagination = z.object({\n start: z.number().int(),\n limit: z.number().int(),\n total: z.number().int().optional(),\n });\n\n return z.object({\n data: this.files,\n meta: z.object({\n pagination: z.union([pagedPagination, offsetPagination]),\n }),\n });\n }\n\n /**\n * File ID parameter validation\n */\n get fileId() {\n return z.number().int().positive();\n }\n\n /**\n * Upload request body schema for single file uploads\n */\n get uploadBody() {\n return z.object({\n fileInfo: z\n .object({\n name: z.string().optional(),\n alternativeText: z.string().optional(),\n caption: z.string().optional(),\n })\n .optional(),\n });\n }\n\n /**\n * Upload request body schema for multiple file uploads\n */\n get multiUploadBody() {\n return z.object({\n fileInfo: z\n .array(\n z.object({\n name: z.string().optional(),\n alternativeText: z.string().optional(),\n caption: z.string().optional(),\n })\n )\n .optional(),\n });\n }\n\n // Note: queryParams() method is inherited from AbstractRouteValidator\n // and provides validation for ['fields', 'populate', 'sort', 'pagination', 'filters']\n}\n"],"names":["UploadRouteValidator","AbstractRouteValidator","file","z","object","id","fileId","documentId","uuid","name","string","alternativeText","nullable","optional","caption","width","number","int","height","formats","record","unknown","hash","ext","mime","size","url","previewUrl","folder","folderPath","provider","provider_metadata","createdAt","updatedAt","createdBy","updatedBy","files","array","paginatedFiles","pagedPagination","page","pageSize","pageCount","total","offsetPagination","start","limit","data","meta","pagination","union","positive","uploadBody","fileInfo","multiUploadBody","strapi","_strapi"],"mappings":"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"}
@@ -42,6 +42,34 @@ import * as z from 'zod/v4';
42
42
  return z.array(this.file);
43
43
  }
44
44
  /**
45
+ * Paginated files response schema: `{ data, meta: { pagination } }`.
46
+ *
47
+ * Pagination meta is either page-based (`page`/`pageSize`) or offset-based
48
+ * (`start`/`limit`), and `total`/`pageCount` are omitted when
49
+ * `pagination[withCount]=false`.
50
+ */ get paginatedFiles() {
51
+ const pagedPagination = z.object({
52
+ page: z.number().int(),
53
+ pageSize: z.number().int(),
54
+ pageCount: z.number().int().optional(),
55
+ total: z.number().int().optional()
56
+ });
57
+ const offsetPagination = z.object({
58
+ start: z.number().int(),
59
+ limit: z.number().int(),
60
+ total: z.number().int().optional()
61
+ });
62
+ return z.object({
63
+ data: this.files,
64
+ meta: z.object({
65
+ pagination: z.union([
66
+ pagedPagination,
67
+ offsetPagination
68
+ ])
69
+ })
70
+ });
71
+ }
72
+ /**
45
73
  * File ID parameter validation
46
74
  */ get fileId() {
47
75
  return z.number().int().positive();
@@ -1 +1 @@
1
- {"version":3,"file":"upload.mjs","sources":["../../../../server/src/routes/validation/upload.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport { AbstractRouteValidator, type QueryParam } from '@strapi/utils';\nimport * as z from 'zod/v4';\n\nexport type FileQueryParam = QueryParam;\n\n/**\n * UploadRouteValidator provides validation for upload/file routes.\n *\n * Extends the AbstractRouteValidator to inherit common query parameter validation\n * while adding file-specific validation schemas.\n */\nexport class UploadRouteValidator extends AbstractRouteValidator {\n protected readonly _strapi: Core.Strapi;\n\n public constructor(strapi: Core.Strapi) {\n super();\n this._strapi = strapi;\n }\n\n /**\n * File schema for upload responses\n * Defines the structure of a file object returned by the upload API\n */\n get file() {\n return z.object({\n id: this.fileId,\n documentId: z.uuid(),\n name: z.string(),\n alternativeText: z.string().nullable().optional(),\n caption: z.string().nullable().optional(),\n width: z.number().int().optional(),\n height: z.number().int().optional(),\n formats: z.record(z.string(), z.unknown()).optional(),\n hash: z.string(),\n ext: z.string().optional(),\n mime: z.string(),\n size: z.number(),\n url: z.string(),\n previewUrl: z.string().nullable().optional(),\n folder: z.number().optional(),\n folderPath: z.string(),\n provider: z.string(),\n provider_metadata: z.record(z.string(), z.unknown()).nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n createdBy: z.number().optional(),\n updatedBy: z.number().optional(),\n });\n }\n\n /**\n * Array of files schema\n */\n get files() {\n return z.array(this.file);\n }\n\n /**\n * File ID parameter validation\n */\n get fileId() {\n return z.number().int().positive();\n }\n\n /**\n * Upload request body schema for single file uploads\n */\n get uploadBody() {\n return z.object({\n fileInfo: z\n .object({\n name: z.string().optional(),\n alternativeText: z.string().optional(),\n caption: z.string().optional(),\n })\n .optional(),\n });\n }\n\n /**\n * Upload request body schema for multiple file uploads\n */\n get multiUploadBody() {\n return z.object({\n fileInfo: z\n .array(\n z.object({\n name: z.string().optional(),\n alternativeText: z.string().optional(),\n caption: z.string().optional(),\n })\n )\n .optional(),\n });\n }\n\n // Note: queryParams() method is inherited from AbstractRouteValidator\n // and provides validation for ['fields', 'populate', 'sort', 'pagination', 'filters']\n}\n"],"names":["UploadRouteValidator","AbstractRouteValidator","file","z","object","id","fileId","documentId","uuid","name","string","alternativeText","nullable","optional","caption","width","number","int","height","formats","record","unknown","hash","ext","mime","size","url","previewUrl","folder","folderPath","provider","provider_metadata","createdAt","updatedAt","createdBy","updatedBy","files","array","positive","uploadBody","fileInfo","multiUploadBody","strapi","_strapi"],"mappings":"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"}
1
+ {"version":3,"file":"upload.mjs","sources":["../../../../server/src/routes/validation/upload.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\nimport { AbstractRouteValidator, type QueryParam } from '@strapi/utils';\nimport * as z from 'zod/v4';\n\nexport type FileQueryParam = QueryParam;\n\n/**\n * UploadRouteValidator provides validation for upload/file routes.\n *\n * Extends the AbstractRouteValidator to inherit common query parameter validation\n * while adding file-specific validation schemas.\n */\nexport class UploadRouteValidator extends AbstractRouteValidator {\n protected readonly _strapi: Core.Strapi;\n\n public constructor(strapi: Core.Strapi) {\n super();\n this._strapi = strapi;\n }\n\n /**\n * File schema for upload responses\n * Defines the structure of a file object returned by the upload API\n */\n get file() {\n return z.object({\n id: this.fileId,\n documentId: z.uuid(),\n name: z.string(),\n alternativeText: z.string().nullable().optional(),\n caption: z.string().nullable().optional(),\n width: z.number().int().optional(),\n height: z.number().int().optional(),\n formats: z.record(z.string(), z.unknown()).optional(),\n hash: z.string(),\n ext: z.string().optional(),\n mime: z.string(),\n size: z.number(),\n url: z.string(),\n previewUrl: z.string().nullable().optional(),\n folder: z.number().optional(),\n folderPath: z.string(),\n provider: z.string(),\n provider_metadata: z.record(z.string(), z.unknown()).nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n createdBy: z.number().optional(),\n updatedBy: z.number().optional(),\n });\n }\n\n /**\n * Array of files schema\n */\n get files() {\n return z.array(this.file);\n }\n\n /**\n * Paginated files response schema: `{ data, meta: { pagination } }`.\n *\n * Pagination meta is either page-based (`page`/`pageSize`) or offset-based\n * (`start`/`limit`), and `total`/`pageCount` are omitted when\n * `pagination[withCount]=false`.\n */\n get paginatedFiles() {\n const pagedPagination = z.object({\n page: z.number().int(),\n pageSize: z.number().int(),\n pageCount: z.number().int().optional(),\n total: z.number().int().optional(),\n });\n\n const offsetPagination = z.object({\n start: z.number().int(),\n limit: z.number().int(),\n total: z.number().int().optional(),\n });\n\n return z.object({\n data: this.files,\n meta: z.object({\n pagination: z.union([pagedPagination, offsetPagination]),\n }),\n });\n }\n\n /**\n * File ID parameter validation\n */\n get fileId() {\n return z.number().int().positive();\n }\n\n /**\n * Upload request body schema for single file uploads\n */\n get uploadBody() {\n return z.object({\n fileInfo: z\n .object({\n name: z.string().optional(),\n alternativeText: z.string().optional(),\n caption: z.string().optional(),\n })\n .optional(),\n });\n }\n\n /**\n * Upload request body schema for multiple file uploads\n */\n get multiUploadBody() {\n return z.object({\n fileInfo: z\n .array(\n z.object({\n name: z.string().optional(),\n alternativeText: z.string().optional(),\n caption: z.string().optional(),\n })\n )\n .optional(),\n });\n }\n\n // Note: queryParams() method is inherited from AbstractRouteValidator\n // and provides validation for ['fields', 'populate', 'sort', 'pagination', 'filters']\n}\n"],"names":["UploadRouteValidator","AbstractRouteValidator","file","z","object","id","fileId","documentId","uuid","name","string","alternativeText","nullable","optional","caption","width","number","int","height","formats","record","unknown","hash","ext","mime","size","url","previewUrl","folder","folderPath","provider","provider_metadata","createdAt","updatedAt","createdBy","updatedBy","files","array","paginatedFiles","pagedPagination","page","pageSize","pageCount","total","offsetPagination","start","limit","data","meta","pagination","union","positive","uploadBody","fileInfo","multiUploadBody","strapi","_strapi"],"mappings":"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"}
@@ -9,10 +9,17 @@ var utils = require('@strapi/utils');
9
9
  var constants = require('../constants.js');
10
10
  var index = require('../utils/index.js');
11
11
 
12
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
13
+
14
+ var path__default = /*#__PURE__*/_interopDefault(path);
15
+ var dns__default = /*#__PURE__*/_interopDefault(dns);
16
+ var net__default = /*#__PURE__*/_interopDefault(net);
17
+ var fse__default = /*#__PURE__*/_interopDefault(fse);
18
+
12
19
  const { ApplicationError } = utils.errors;
13
20
  const FETCH_TIMEOUT_MS = 60000; // 60 seconds
14
21
  // Blocks loopback, link-local (cloud metadata), and RFC-1918 private ranges to prevent SSRF
15
- const SSRF_BLOCK_LIST = new net.BlockList();
22
+ const SSRF_BLOCK_LIST = new net__default.default.BlockList();
16
23
  SSRF_BLOCK_LIST.addSubnet('127.0.0.0', 8); // loopback
17
24
  SSRF_BLOCK_LIST.addSubnet('10.0.0.0', 8); // RFC-1918
18
25
  SSRF_BLOCK_LIST.addSubnet('172.16.0.0', 12); // RFC-1918
@@ -30,7 +37,7 @@ SSRF_BLOCK_LIST.addSubnet('fe80::', 10, 'ipv6'); // IPv6 link-local
30
37
  const filenameMatch = contentDisposition.match(/filename\*?=['"]?(?:UTF-\d['"]*)?([^;\r\n"']*)['"]?/i);
31
38
  if (filenameMatch?.[1]) {
32
39
  // Use path.basename to prevent path traversal attacks
33
- return path.basename(decodeURIComponent(filenameMatch[1]));
40
+ return path__default.default.basename(decodeURIComponent(filenameMatch[1]));
34
41
  }
35
42
  }
36
43
  // Fall back to URL path
@@ -40,7 +47,7 @@ SSRF_BLOCK_LIST.addSubnet('fe80::', 10, 'ipv6'); // IPv6 link-local
40
47
  const filename = pathname.split('/').pop();
41
48
  if (filename && filename.length > 0) {
42
49
  // Use path.basename to prevent path traversal attacks (e.g., URL-encoded separators)
43
- return path.basename(decodeURIComponent(filename));
50
+ return path__default.default.basename(decodeURIComponent(filename));
44
51
  }
45
52
  } catch {
46
53
  // Invalid URL, use default
@@ -70,7 +77,7 @@ SSRF_BLOCK_LIST.addSubnet('fe80::', 10, 'ipv6'); // IPv6 link-local
70
77
  }
71
78
  // Resolve hostname and block private/internal IP ranges to prevent SSRF
72
79
  try {
73
- const { address, family } = await dns.lookup(parsedUrl.hostname);
80
+ const { address, family } = await dns__default.default.lookup(parsedUrl.hostname);
74
81
  const type = family === 6 ? 'ipv6' : 'ipv4';
75
82
  if (SSRF_BLOCK_LIST.check(address, type)) {
76
83
  throw new ApplicationError(`URL resolves to a blocked address: ${url}`);
@@ -110,8 +117,8 @@ SSRF_BLOCK_LIST.addSubnet('fe80::', 10, 'ipv6'); // IPv6 link-local
110
117
  const arrayBuffer = await response.arrayBuffer();
111
118
  const buffer = Buffer.from(arrayBuffer);
112
119
  // Write to temp file
113
- const tmpFilePath = path.join(tmpWorkingDirectory, filename);
114
- await fse.writeFile(tmpFilePath, buffer);
120
+ const tmpFilePath = path__default.default.join(tmpWorkingDirectory, filename);
121
+ await fse__default.default.writeFile(tmpFilePath, buffer);
115
122
  // Create file object compatible with upload pipeline
116
123
  const fetchedFile = {
117
124
  filepath: tmpFilePath,
@@ -1 +1 @@
1
- {"version":3,"file":"file.js","sources":["../../../server/src/services/file.ts"],"sourcesContent":["import path from 'path';\nimport dns from 'dns/promises';\nimport net from 'net';\nimport fse from 'fs-extra';\nimport { cloneDeep } from 'lodash/fp';\nimport { async, errors } from '@strapi/utils';\n\nimport { FOLDER_MODEL_UID, FILE_MODEL_UID } from '../constants';\nimport { getService } from '../utils';\n\nimport { Config, type File } from '../types';\n\nconst { ApplicationError } = errors;\n\nconst FETCH_TIMEOUT_MS = 60_000; // 60 seconds\n\n// Blocks loopback, link-local (cloud metadata), and RFC-1918 private ranges to prevent SSRF\nconst SSRF_BLOCK_LIST = new net.BlockList();\nSSRF_BLOCK_LIST.addSubnet('127.0.0.0', 8); // loopback\nSSRF_BLOCK_LIST.addSubnet('10.0.0.0', 8); // RFC-1918\nSSRF_BLOCK_LIST.addSubnet('172.16.0.0', 12); // RFC-1918\nSSRF_BLOCK_LIST.addSubnet('192.168.0.0', 16); // RFC-1918\nSSRF_BLOCK_LIST.addSubnet('169.254.0.0', 16); // link-local / cloud metadata (AWS, GCP, Azure)\nSSRF_BLOCK_LIST.addSubnet('::1', 128, 'ipv6'); // IPv6 loopback\nSSRF_BLOCK_LIST.addSubnet('fc00::', 7, 'ipv6'); // IPv6 unique local\nSSRF_BLOCK_LIST.addSubnet('fe80::', 10, 'ipv6'); // IPv6 link-local\n\n/**\n * Represents a file fetched from a URL, compatible with the upload pipeline\n */\ninterface UrlFetchedFile {\n filepath: string;\n originalFilename: string;\n mimetype: string;\n size: number;\n tmpWorkingDirectory?: string;\n}\n\ninterface FetchUrlResult {\n file: UrlFetchedFile;\n}\n\n/**\n * Extracts filename from a URL path or Content-Disposition header\n */\nconst getFilenameFromUrl = (url: string, contentDisposition?: string | null): string => {\n // Try Content-Disposition header first\n if (contentDisposition) {\n // Extracts filename from Content-Disposition header (e.g. filename=\"photo.jpg\" or filename*=UTF-8''photo.jpg)\n const filenameMatch = contentDisposition.match(\n /filename\\*?=['\"]?(?:UTF-\\d['\"]*)?([^;\\r\\n\"']*)['\"]?/i\n );\n if (filenameMatch?.[1]) {\n // Use path.basename to prevent path traversal attacks\n return path.basename(decodeURIComponent(filenameMatch[1]));\n }\n }\n\n // Fall back to URL path\n try {\n const urlObj = new URL(url);\n const pathname = urlObj.pathname;\n const filename = pathname.split('/').pop();\n if (filename && filename.length > 0) {\n // Use path.basename to prevent path traversal attacks (e.g., URL-encoded separators)\n return path.basename(decodeURIComponent(filename));\n }\n } catch {\n // Invalid URL, use default\n }\n\n // Generate a timestamp-based default filename\n const now = new Date();\n const date = now.toISOString().split('T')[0]; // 2024-02-23\n const time = now.toTimeString().split(' ')[0].replace(/:/g, ''); // 143052\n return `untitled_${date}_${time}`;\n};\n\n/**\n * Fetches a URL and saves it as a temporary file\n * Returns an InputFile-compatible object for use with the upload pipeline\n */\nconst fetchUrlToInputFile = async (\n url: string,\n tmpWorkingDirectory: string,\n sizeLimit?: number\n): Promise<FetchUrlResult> => {\n // Validate URL protocol\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(url);\n } catch {\n throw new ApplicationError(`Invalid URL: ${url}`);\n }\n\n if (!['http:', 'https:'].includes(parsedUrl.protocol)) {\n throw new ApplicationError(`Invalid URL protocol. Only http and https are allowed: ${url}`);\n }\n\n // Resolve hostname and block private/internal IP ranges to prevent SSRF\n try {\n const { address, family } = await dns.lookup(parsedUrl.hostname);\n const type = family === 6 ? 'ipv6' : 'ipv4';\n if (SSRF_BLOCK_LIST.check(address, type)) {\n throw new ApplicationError(`URL resolves to a blocked address: ${url}`);\n }\n } catch (error) {\n if (error instanceof ApplicationError) throw error;\n throw new ApplicationError(`Could not resolve hostname: ${parsedUrl.hostname}`);\n }\n\n // use strapi.fetch so we can intercept requests and support proxy settings\n const doFetch = typeof strapi?.fetch === 'function' ? strapi.fetch : fetch;\n let response: Response;\n try {\n response = await doFetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n } catch (error) {\n if (error instanceof Error && error.name === 'TimeoutError') {\n throw new ApplicationError(`Request timed out while fetching URL: ${url}`);\n }\n throw error;\n }\n\n if (!response.ok) {\n throw new ApplicationError(\n `Failed to fetch URL: ${url} (${response.status} ${response.statusText})`\n );\n }\n\n // Check Content-Length header for early rejection of large files\n if (sizeLimit) {\n const contentLength = response.headers.get('content-length');\n if (contentLength && parseInt(contentLength, 10) > sizeLimit) {\n throw new ApplicationError(\n `File too large: maximum allowed size is ${Math.round(sizeLimit / (1024 * 1024))}MB`\n );\n }\n }\n\n // Get content type and filename\n const contentType =\n response.headers.get('content-type')?.split(';')[0] || 'application/octet-stream';\n const contentDisposition = response.headers.get('content-disposition');\n const filename = getFilenameFromUrl(response.url, contentDisposition);\n\n // Read response body\n const arrayBuffer = await response.arrayBuffer();\n const buffer = Buffer.from(arrayBuffer);\n\n // Write to temp file\n const tmpFilePath = path.join(tmpWorkingDirectory, filename);\n await fse.writeFile(tmpFilePath, buffer);\n\n // Create file object compatible with upload pipeline\n const fetchedFile: UrlFetchedFile = {\n filepath: tmpFilePath,\n originalFilename: filename,\n mimetype: contentType,\n size: buffer.length,\n tmpWorkingDirectory,\n };\n\n return { file: fetchedFile };\n};\n\nconst getFolderPath = async (folderId?: number | null) => {\n if (!folderId) return '/';\n\n const parentFolder = await strapi.db.query(FOLDER_MODEL_UID).findOne({ where: { id: folderId } });\n\n return parentFolder.path;\n};\n\nconst deleteByIds = async (ids: number[] = []) => {\n const filesToDelete = await strapi.db\n .query(FILE_MODEL_UID)\n .findMany({ where: { id: { $in: ids } } });\n\n await Promise.all(filesToDelete.map((file: File) => getService('upload').remove(file)));\n\n return filesToDelete;\n};\n\nconst signFileUrls = async (file: File) => {\n const { provider } = strapi.plugins.upload;\n const { provider: providerConfig } = strapi.config.get<Config>('plugin::upload');\n const isPrivate = await provider.isPrivate();\n file.isUrlSigned = false;\n\n // Check file provider and if provider is private\n if (file.provider !== providerConfig || !isPrivate) {\n return file;\n }\n\n const signUrl = async (file: File) => {\n const signedUrl = await provider.getSignedUrl(file);\n file.url = signedUrl.url;\n file.isUrlSigned = true;\n };\n\n const signedFile = cloneDeep(file);\n\n // Sign each file format\n await signUrl(signedFile);\n if (file.formats) {\n await async.map(Object.values(signedFile.formats ?? {}), signUrl);\n }\n\n return signedFile;\n};\n\nexport type { UrlFetchedFile, FetchUrlResult };\nexport default { getFolderPath, deleteByIds, signFileUrls, fetchUrlToInputFile };\n"],"names":["ApplicationError","errors","FETCH_TIMEOUT_MS","SSRF_BLOCK_LIST","net","BlockList","addSubnet","getFilenameFromUrl","url","contentDisposition","filenameMatch","match","path","basename","decodeURIComponent","urlObj","URL","pathname","filename","split","pop","length","now","Date","date","toISOString","time","toTimeString","replace","fetchUrlToInputFile","tmpWorkingDirectory","sizeLimit","parsedUrl","includes","protocol","address","family","dns","lookup","hostname","type","check","error","doFetch","strapi","fetch","response","signal","AbortSignal","timeout","Error","name","ok","status","statusText","contentLength","headers","get","parseInt","Math","round","contentType","arrayBuffer","buffer","Buffer","from","tmpFilePath","join","fse","writeFile","fetchedFile","filepath","originalFilename","mimetype","size","file","getFolderPath","folderId","parentFolder","db","query","FOLDER_MODEL_UID","findOne","where","id","deleteByIds","ids","filesToDelete","FILE_MODEL_UID","findMany","$in","Promise","all","map","getService","remove","signFileUrls","provider","plugins","upload","providerConfig","config","isPrivate","isUrlSigned","signUrl","signedUrl","getSignedUrl","signedFile","cloneDeep","formats","async","Object","values"],"mappings":"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"}
1
+ {"version":3,"file":"file.js","sources":["../../../server/src/services/file.ts"],"sourcesContent":["import path from 'path';\nimport dns from 'dns/promises';\nimport net from 'net';\nimport fse from 'fs-extra';\nimport { cloneDeep } from 'lodash/fp';\nimport { async, errors } from '@strapi/utils';\n\nimport { FOLDER_MODEL_UID, FILE_MODEL_UID } from '../constants';\nimport { getService } from '../utils';\n\nimport { Config, type File } from '../types';\n\nconst { ApplicationError } = errors;\n\nconst FETCH_TIMEOUT_MS = 60_000; // 60 seconds\n\n// Blocks loopback, link-local (cloud metadata), and RFC-1918 private ranges to prevent SSRF\nconst SSRF_BLOCK_LIST = new net.BlockList();\nSSRF_BLOCK_LIST.addSubnet('127.0.0.0', 8); // loopback\nSSRF_BLOCK_LIST.addSubnet('10.0.0.0', 8); // RFC-1918\nSSRF_BLOCK_LIST.addSubnet('172.16.0.0', 12); // RFC-1918\nSSRF_BLOCK_LIST.addSubnet('192.168.0.0', 16); // RFC-1918\nSSRF_BLOCK_LIST.addSubnet('169.254.0.0', 16); // link-local / cloud metadata (AWS, GCP, Azure)\nSSRF_BLOCK_LIST.addSubnet('::1', 128, 'ipv6'); // IPv6 loopback\nSSRF_BLOCK_LIST.addSubnet('fc00::', 7, 'ipv6'); // IPv6 unique local\nSSRF_BLOCK_LIST.addSubnet('fe80::', 10, 'ipv6'); // IPv6 link-local\n\n/**\n * Represents a file fetched from a URL, compatible with the upload pipeline\n */\ninterface UrlFetchedFile {\n filepath: string;\n originalFilename: string;\n mimetype: string;\n size: number;\n tmpWorkingDirectory?: string;\n}\n\ninterface FetchUrlResult {\n file: UrlFetchedFile;\n}\n\n/**\n * Extracts filename from a URL path or Content-Disposition header\n */\nconst getFilenameFromUrl = (url: string, contentDisposition?: string | null): string => {\n // Try Content-Disposition header first\n if (contentDisposition) {\n // Extracts filename from Content-Disposition header (e.g. filename=\"photo.jpg\" or filename*=UTF-8''photo.jpg)\n const filenameMatch = contentDisposition.match(\n /filename\\*?=['\"]?(?:UTF-\\d['\"]*)?([^;\\r\\n\"']*)['\"]?/i\n );\n if (filenameMatch?.[1]) {\n // Use path.basename to prevent path traversal attacks\n return path.basename(decodeURIComponent(filenameMatch[1]));\n }\n }\n\n // Fall back to URL path\n try {\n const urlObj = new URL(url);\n const pathname = urlObj.pathname;\n const filename = pathname.split('/').pop();\n if (filename && filename.length > 0) {\n // Use path.basename to prevent path traversal attacks (e.g., URL-encoded separators)\n return path.basename(decodeURIComponent(filename));\n }\n } catch {\n // Invalid URL, use default\n }\n\n // Generate a timestamp-based default filename\n const now = new Date();\n const date = now.toISOString().split('T')[0]; // 2024-02-23\n const time = now.toTimeString().split(' ')[0].replace(/:/g, ''); // 143052\n return `untitled_${date}_${time}`;\n};\n\n/**\n * Fetches a URL and saves it as a temporary file\n * Returns an InputFile-compatible object for use with the upload pipeline\n */\nconst fetchUrlToInputFile = async (\n url: string,\n tmpWorkingDirectory: string,\n sizeLimit?: number\n): Promise<FetchUrlResult> => {\n // Validate URL protocol\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(url);\n } catch {\n throw new ApplicationError(`Invalid URL: ${url}`);\n }\n\n if (!['http:', 'https:'].includes(parsedUrl.protocol)) {\n throw new ApplicationError(`Invalid URL protocol. Only http and https are allowed: ${url}`);\n }\n\n // Resolve hostname and block private/internal IP ranges to prevent SSRF\n try {\n const { address, family } = await dns.lookup(parsedUrl.hostname);\n const type = family === 6 ? 'ipv6' : 'ipv4';\n if (SSRF_BLOCK_LIST.check(address, type)) {\n throw new ApplicationError(`URL resolves to a blocked address: ${url}`);\n }\n } catch (error) {\n if (error instanceof ApplicationError) throw error;\n throw new ApplicationError(`Could not resolve hostname: ${parsedUrl.hostname}`);\n }\n\n // use strapi.fetch so we can intercept requests and support proxy settings\n const doFetch = typeof strapi?.fetch === 'function' ? strapi.fetch : fetch;\n let response: Response;\n try {\n response = await doFetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n } catch (error) {\n if (error instanceof Error && error.name === 'TimeoutError') {\n throw new ApplicationError(`Request timed out while fetching URL: ${url}`);\n }\n throw error;\n }\n\n if (!response.ok) {\n throw new ApplicationError(\n `Failed to fetch URL: ${url} (${response.status} ${response.statusText})`\n );\n }\n\n // Check Content-Length header for early rejection of large files\n if (sizeLimit) {\n const contentLength = response.headers.get('content-length');\n if (contentLength && parseInt(contentLength, 10) > sizeLimit) {\n throw new ApplicationError(\n `File too large: maximum allowed size is ${Math.round(sizeLimit / (1024 * 1024))}MB`\n );\n }\n }\n\n // Get content type and filename\n const contentType =\n response.headers.get('content-type')?.split(';')[0] || 'application/octet-stream';\n const contentDisposition = response.headers.get('content-disposition');\n const filename = getFilenameFromUrl(response.url, contentDisposition);\n\n // Read response body\n const arrayBuffer = await response.arrayBuffer();\n const buffer = Buffer.from(arrayBuffer);\n\n // Write to temp file\n const tmpFilePath = path.join(tmpWorkingDirectory, filename);\n await fse.writeFile(tmpFilePath, buffer);\n\n // Create file object compatible with upload pipeline\n const fetchedFile: UrlFetchedFile = {\n filepath: tmpFilePath,\n originalFilename: filename,\n mimetype: contentType,\n size: buffer.length,\n tmpWorkingDirectory,\n };\n\n return { file: fetchedFile };\n};\n\nconst getFolderPath = async (folderId?: number | null) => {\n if (!folderId) return '/';\n\n const parentFolder = await strapi.db.query(FOLDER_MODEL_UID).findOne({ where: { id: folderId } });\n\n return parentFolder.path;\n};\n\nconst deleteByIds = async (ids: number[] = []) => {\n const filesToDelete = await strapi.db\n .query(FILE_MODEL_UID)\n .findMany({ where: { id: { $in: ids } } });\n\n await Promise.all(filesToDelete.map((file: File) => getService('upload').remove(file)));\n\n return filesToDelete;\n};\n\nconst signFileUrls = async (file: File) => {\n const { provider } = strapi.plugins.upload;\n const { provider: providerConfig } = strapi.config.get<Config>('plugin::upload');\n const isPrivate = await provider.isPrivate();\n file.isUrlSigned = false;\n\n // Check file provider and if provider is private\n if (file.provider !== providerConfig || !isPrivate) {\n return file;\n }\n\n const signUrl = async (file: File) => {\n const signedUrl = await provider.getSignedUrl(file);\n file.url = signedUrl.url;\n file.isUrlSigned = true;\n };\n\n const signedFile = cloneDeep(file);\n\n // Sign each file format\n await signUrl(signedFile);\n if (file.formats) {\n await async.map(Object.values(signedFile.formats ?? {}), signUrl);\n }\n\n return signedFile;\n};\n\nexport type { UrlFetchedFile, FetchUrlResult };\nexport default { getFolderPath, deleteByIds, signFileUrls, fetchUrlToInputFile };\n"],"names":["ApplicationError","errors","FETCH_TIMEOUT_MS","SSRF_BLOCK_LIST","net","BlockList","addSubnet","getFilenameFromUrl","url","contentDisposition","filenameMatch","match","path","basename","decodeURIComponent","urlObj","URL","pathname","filename","split","pop","length","now","Date","date","toISOString","time","toTimeString","replace","fetchUrlToInputFile","tmpWorkingDirectory","sizeLimit","parsedUrl","includes","protocol","address","family","dns","lookup","hostname","type","check","error","doFetch","strapi","fetch","response","signal","AbortSignal","timeout","Error","name","ok","status","statusText","contentLength","headers","get","parseInt","Math","round","contentType","arrayBuffer","buffer","Buffer","from","tmpFilePath","join","fse","writeFile","fetchedFile","filepath","originalFilename","mimetype","size","file","getFolderPath","folderId","parentFolder","db","query","FOLDER_MODEL_UID","findOne","where","id","deleteByIds","ids","filesToDelete","FILE_MODEL_UID","findMany","$in","Promise","all","map","getService","remove","signFileUrls","provider","plugins","upload","providerConfig","config","isPrivate","isUrlSigned","signUrl","signedUrl","getSignedUrl","signedFile","cloneDeep","formats","async","Object","values"],"mappings":";;;;;;;;;;;;;;;;;;AAYA,MAAM,EAAEA,gBAAgB,EAAE,GAAGC,YAAAA;AAE7B,MAAMC,gBAAAA,GAAmB;AAEzB;AACA,MAAMC,eAAAA,GAAkB,IAAIC,oBAAAA,CAAIC,SAAS,EAAA;AACzCF,eAAAA,CAAgBG,SAAS,CAAC,WAAA,EAAa,CAAA,CAAA,CAAA;AACvCH,eAAAA,CAAgBG,SAAS,CAAC,UAAA,EAAY,CAAA,CAAA,CAAA;AACtCH,eAAAA,CAAgBG,SAAS,CAAC,YAAA,EAAc,EAAA,CAAA,CAAA;AACxCH,eAAAA,CAAgBG,SAAS,CAAC,aAAA,EAAe,EAAA,CAAA,CAAA;AACzCH,eAAAA,CAAgBG,SAAS,CAAC,aAAA,EAAe,EAAA,CAAA,CAAA;AACzCH,eAAAA,CAAgBG,SAAS,CAAC,KAAA,EAAO,GAAA,EAAK;AACtCH,eAAAA,CAAgBG,SAAS,CAAC,QAAA,EAAU,CAAA,EAAG;AACvCH,eAAAA,CAAgBG,SAAS,CAAC,QAAA,EAAU,EAAA,EAAI;AAiBxC;;IAGA,MAAMC,kBAAAA,GAAqB,CAACC,GAAAA,EAAaC,kBAAAA,GAAAA;;AAEvC,IAAA,IAAIA,kBAAAA,EAAoB;;QAEtB,MAAMC,aAAAA,GAAgBD,kBAAAA,CAAmBE,KAAK,CAC5C,sDAAA,CAAA;QAEF,IAAID,aAAAA,GAAgB,CAAA,CAAE,EAAE;;AAEtB,YAAA,OAAOE,sBAAKC,QAAQ,CAACC,kBAAAA,CAAmBJ,aAAa,CAAC,CAAA,CAAE,CAAA,CAAA;AAC1D,QAAA;AACF,IAAA;;IAGA,IAAI;QACF,MAAMK,MAAAA,GAAS,IAAIC,GAAAA,CAAIR,GAAAA,CAAAA;QACvB,MAAMS,QAAAA,GAAWF,OAAOE,QAAQ;AAChC,QAAA,MAAMC,QAAAA,GAAWD,QAAAA,CAASE,KAAK,CAAC,KAAKC,GAAG,EAAA;AACxC,QAAA,IAAIF,QAAAA,IAAYA,QAAAA,CAASG,MAAM,GAAG,CAAA,EAAG;;YAEnC,OAAOT,qBAAAA,CAAKC,QAAQ,CAACC,kBAAAA,CAAmBI,QAAAA,CAAAA,CAAAA;AAC1C,QAAA;AACF,IAAA,CAAA,CAAE,OAAM;;AAER,IAAA;;AAGA,IAAA,MAAMI,MAAM,IAAIC,IAAAA,EAAAA;IAChB,MAAMC,IAAAA,GAAOF,GAAAA,CAAIG,WAAW,EAAA,CAAGN,KAAK,CAAC,GAAA,CAAI,CAAC,CAAA,CAAE,CAAA;AAC5C,IAAA,MAAMO,IAAAA,GAAOJ,GAAAA,CAAIK,YAAY,EAAA,CAAGR,KAAK,CAAC,GAAA,CAAI,CAAC,CAAA,CAAE,CAACS,OAAO,CAAC,IAAA,EAAM;AAC5D,IAAA,OAAO,CAAC,SAAS,EAAEJ,IAAAA,CAAK,CAAC,EAAEE,IAAAA,CAAAA,CAAM;AACnC,CAAA;AAEA;;;AAGC,IACD,MAAMG,mBAAAA,GAAsB,OAC1BrB,GAAAA,EACAsB,mBAAAA,EACAC,SAAAA,GAAAA;;IAGA,IAAIC,SAAAA;IACJ,IAAI;AACFA,QAAAA,SAAAA,GAAY,IAAIhB,GAAAA,CAAIR,GAAAA,CAAAA;AACtB,IAAA,CAAA,CAAE,OAAM;AACN,QAAA,MAAM,IAAIR,gBAAAA,CAAiB,CAAC,aAAa,EAAEQ,GAAAA,CAAAA,CAAK,CAAA;AAClD,IAAA;AAEA,IAAA,IAAI,CAAC;AAAC,QAAA,OAAA;AAAS,QAAA;AAAS,KAAA,CAACyB,QAAQ,CAACD,SAAAA,CAAUE,QAAQ,CAAA,EAAG;AACrD,QAAA,MAAM,IAAIlC,gBAAAA,CAAiB,CAAC,uDAAuD,EAAEQ,GAAAA,CAAAA,CAAK,CAAA;AAC5F,IAAA;;IAGA,IAAI;QACF,MAAM,EAAE2B,OAAO,EAAEC,MAAM,EAAE,GAAG,MAAMC,oBAAAA,CAAIC,MAAM,CAACN,SAAAA,CAAUO,QAAQ,CAAA;QAC/D,MAAMC,IAAAA,GAAOJ,MAAAA,KAAW,CAAA,GAAI,MAAA,GAAS,MAAA;AACrC,QAAA,IAAIjC,eAAAA,CAAgBsC,KAAK,CAACN,OAAAA,EAASK,IAAAA,CAAAA,EAAO;AACxC,YAAA,MAAM,IAAIxC,gBAAAA,CAAiB,CAAC,mCAAmC,EAAEQ,GAAAA,CAAAA,CAAK,CAAA;AACxE,QAAA;AACF,IAAA,CAAA,CAAE,OAAOkC,KAAAA,EAAO;QACd,IAAIA,KAAAA,YAAiB1C,kBAAkB,MAAM0C,KAAAA;AAC7C,QAAA,MAAM,IAAI1C,gBAAAA,CAAiB,CAAC,4BAA4B,EAAEgC,SAAAA,CAAUO,QAAQ,CAAA,CAAE,CAAA;AAChF,IAAA;;AAGA,IAAA,MAAMI,UAAU,OAAOC,MAAAA,EAAQC,UAAU,UAAA,GAAaD,MAAAA,CAAOC,KAAK,GAAGA,KAAAA;IACrE,IAAIC,QAAAA;IACJ,IAAI;QACFA,QAAAA,GAAW,MAAMH,QAAQnC,GAAAA,EAAK;YAAEuC,MAAAA,EAAQC,WAAAA,CAAYC,OAAO,CAAC/C,gBAAAA;AAAkB,SAAA,CAAA;AAChF,IAAA,CAAA,CAAE,OAAOwC,KAAAA,EAAO;AACd,QAAA,IAAIA,KAAAA,YAAiBQ,KAAAA,IAASR,KAAAA,CAAMS,IAAI,KAAK,cAAA,EAAgB;AAC3D,YAAA,MAAM,IAAInD,gBAAAA,CAAiB,CAAC,sCAAsC,EAAEQ,GAAAA,CAAAA,CAAK,CAAA;AAC3E,QAAA;QACA,MAAMkC,KAAAA;AACR,IAAA;IAEA,IAAI,CAACI,QAAAA,CAASM,EAAE,EAAE;AAChB,QAAA,MAAM,IAAIpD,gBAAAA,CACR,CAAC,qBAAqB,EAAEQ,IAAI,EAAE,EAAEsC,QAAAA,CAASO,MAAM,CAAC,CAAC,EAAEP,SAASQ,UAAU,CAAC,CAAC,CAAC,CAAA;AAE7E,IAAA;;AAGA,IAAA,IAAIvB,SAAAA,EAAW;AACb,QAAA,MAAMwB,aAAAA,GAAgBT,QAAAA,CAASU,OAAO,CAACC,GAAG,CAAC,gBAAA,CAAA;AAC3C,QAAA,IAAIF,aAAAA,IAAiBG,QAAAA,CAASH,aAAAA,EAAe,EAAA,CAAA,GAAMxB,SAAAA,EAAW;AAC5D,YAAA,MAAM,IAAI/B,gBAAAA,CACR,CAAC,wCAAwC,EAAE2D,IAAAA,CAAKC,KAAK,CAAC7B,SAAAA,IAAa,IAAA,GAAO,IAAG,CAAA,CAAA,CAAI,EAAE,CAAC,CAAA;AAExF,QAAA;AACF,IAAA;;IAGA,MAAM8B,WAAAA,GACJf,QAAAA,CAASU,OAAO,CAACC,GAAG,CAAC,cAAA,CAAA,EAAiBtC,KAAAA,CAAM,GAAA,CAAI,CAAC,CAAA,CAAE,IAAI,0BAAA;AACzD,IAAA,MAAMV,kBAAAA,GAAqBqC,QAAAA,CAASU,OAAO,CAACC,GAAG,CAAC,qBAAA,CAAA;AAChD,IAAA,MAAMvC,QAAAA,GAAWX,kBAAAA,CAAmBuC,QAAAA,CAAStC,GAAG,EAAEC,kBAAAA,CAAAA;;IAGlD,MAAMqD,WAAAA,GAAc,MAAMhB,QAAAA,CAASgB,WAAW,EAAA;IAC9C,MAAMC,MAAAA,GAASC,MAAAA,CAAOC,IAAI,CAACH,WAAAA,CAAAA;;AAG3B,IAAA,MAAMI,WAAAA,GAActD,qBAAAA,CAAKuD,IAAI,CAACrC,mBAAAA,EAAqBZ,QAAAA,CAAAA;IACnD,MAAMkD,oBAAAA,CAAIC,SAAS,CAACH,WAAAA,EAAaH,MAAAA,CAAAA;;AAGjC,IAAA,MAAMO,WAAAA,GAA8B;QAClCC,QAAAA,EAAUL,WAAAA;QACVM,gBAAAA,EAAkBtD,QAAAA;QAClBuD,QAAAA,EAAUZ,WAAAA;AACVa,QAAAA,IAAAA,EAAMX,OAAO1C,MAAM;AACnBS,QAAAA;AACF,KAAA;IAEA,OAAO;QAAE6C,IAAAA,EAAML;AAAY,KAAA;AAC7B,CAAA;AAEA,MAAMM,gBAAgB,OAAOC,QAAAA,GAAAA;IAC3B,IAAI,CAACA,UAAU,OAAO,GAAA;IAEtB,MAAMC,YAAAA,GAAe,MAAMlC,MAAAA,CAAOmC,EAAE,CAACC,KAAK,CAACC,0BAAAA,CAAAA,CAAkBC,OAAO,CAAC;QAAEC,KAAAA,EAAO;YAAEC,EAAAA,EAAIP;AAAS;AAAE,KAAA,CAAA;AAE/F,IAAA,OAAOC,aAAalE,IAAI;AAC1B,CAAA;AAEA,MAAMyE,WAAAA,GAAc,OAAOC,GAAAA,GAAgB,EAAE,GAAA;IAC3C,MAAMC,aAAAA,GAAgB,MAAM3C,MAAAA,CAAOmC,EAAE,CAClCC,KAAK,CAACQ,wBAAAA,CAAAA,CACNC,QAAQ,CAAC;QAAEN,KAAAA,EAAO;YAAEC,EAAAA,EAAI;gBAAEM,GAAAA,EAAKJ;AAAI;AAAE;AAAE,KAAA,CAAA;IAE1C,MAAMK,OAAAA,CAAQC,GAAG,CAACL,aAAAA,CAAcM,GAAG,CAAC,CAAClB,IAAAA,GAAemB,gBAAAA,CAAW,QAAA,CAAA,CAAUC,MAAM,CAACpB,IAAAA,CAAAA,CAAAA,CAAAA;IAEhF,OAAOY,aAAAA;AACT,CAAA;AAEA,MAAMS,eAAe,OAAOrB,IAAAA,GAAAA;AAC1B,IAAA,MAAM,EAAEsB,QAAQ,EAAE,GAAGrD,MAAAA,CAAOsD,OAAO,CAACC,MAAM;IAC1C,MAAM,EAAEF,UAAUG,cAAc,EAAE,GAAGxD,MAAAA,CAAOyD,MAAM,CAAC5C,GAAG,CAAS,gBAAA,CAAA;IAC/D,MAAM6C,SAAAA,GAAY,MAAML,QAAAA,CAASK,SAAS,EAAA;AAC1C3B,IAAAA,IAAAA,CAAK4B,WAAW,GAAG,KAAA;;AAGnB,IAAA,IAAI5B,IAAAA,CAAKsB,QAAQ,KAAKG,cAAAA,IAAkB,CAACE,SAAAA,EAAW;QAClD,OAAO3B,IAAAA;AACT,IAAA;AAEA,IAAA,MAAM6B,UAAU,OAAO7B,IAAAA,GAAAA;AACrB,QAAA,MAAM8B,SAAAA,GAAY,MAAMR,QAAAA,CAASS,YAAY,CAAC/B,IAAAA,CAAAA;QAC9CA,IAAAA,CAAKnE,GAAG,GAAGiG,SAAAA,CAAUjG,GAAG;AACxBmE,QAAAA,IAAAA,CAAK4B,WAAW,GAAG,IAAA;AACrB,IAAA,CAAA;AAEA,IAAA,MAAMI,aAAaC,YAAAA,CAAUjC,IAAAA,CAAAA;;AAG7B,IAAA,MAAM6B,OAAAA,CAAQG,UAAAA,CAAAA;IACd,IAAIhC,IAAAA,CAAKkC,OAAO,EAAE;QAChB,MAAMC,WAAAA,CAAMjB,GAAG,CAACkB,MAAAA,CAAOC,MAAM,CAACL,UAAAA,CAAWE,OAAO,IAAI,EAAC,CAAA,EAAIL,OAAAA,CAAAA;AAC3D,IAAA;IAEA,OAAOG,UAAAA;AACT,CAAA;AAGA,WAAe;AAAE/B,IAAAA,aAAAA;AAAeS,IAAAA,WAAAA;AAAaW,IAAAA,YAAAA;AAAcnE,IAAAA;AAAoB,CAAA;;;;"}
@@ -7,6 +7,12 @@ var crypto = require('crypto');
7
7
  var utils = require('@strapi/utils');
8
8
  var index = require('../utils/index.js');
9
9
 
10
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
+
12
+ var fs__default = /*#__PURE__*/_interopDefault(fs);
13
+ var sharp__default = /*#__PURE__*/_interopDefault(sharp);
14
+ var crypto__default = /*#__PURE__*/_interopDefault(crypto);
15
+
10
16
  const { bytesToKbytes } = utils.file;
11
17
  const FORMATS_TO_RESIZE = [
12
18
  'jpeg',
@@ -33,7 +39,7 @@ const FORMATS_TO_OPTIMIZE = [
33
39
  ];
34
40
  const isOptimizableFormat = (format)=>format !== undefined && FORMATS_TO_OPTIMIZE.includes(format);
35
41
  const writeStreamToFile = (stream, path)=>new Promise((resolve, reject)=>{
36
- const writeStream = fs.createWriteStream(path);
42
+ const writeStream = fs__default.default.createWriteStream(path);
37
43
  // Reject promise if there is an error with the provided stream
38
44
  stream.on('error', reject);
39
45
  stream.pipe(writeStream);
@@ -43,12 +49,12 @@ const writeStreamToFile = (stream, path)=>new Promise((resolve, reject)=>{
43
49
  const getMetadata = (file)=>{
44
50
  if (!file.filepath) {
45
51
  return new Promise((resolve, reject)=>{
46
- const pipeline = sharp();
52
+ const pipeline = sharp__default.default();
47
53
  pipeline.metadata().then(resolve).catch(reject);
48
54
  file.getStream().pipe(pipeline);
49
55
  });
50
56
  }
51
- return sharp(file.filepath).metadata();
57
+ return sharp__default.default(file.filepath).metadata();
52
58
  };
53
59
  const getDimensions = async (file)=>{
54
60
  const { width = null, height = null } = await getMetadata(file);
@@ -66,14 +72,14 @@ const resizeFileTo = async (file, options, { name, hash })=>{
66
72
  const filePath = file.tmpWorkingDirectory ? path.join(file.tmpWorkingDirectory, hash) : hash;
67
73
  let newInfo;
68
74
  if (!file.filepath) {
69
- const transform = sharp({
75
+ const transform = sharp__default.default({
70
76
  animated: true
71
77
  }).resize(options).on('info', (info)=>{
72
78
  newInfo = info;
73
79
  });
74
80
  await writeStreamToFile(file.getStream().pipe(transform), filePath);
75
81
  } else {
76
- newInfo = await sharp(file.filepath, {
82
+ newInfo = await sharp__default.default(file.filepath, {
77
83
  animated: true
78
84
  }).resize(options).toFile(filePath);
79
85
  }
@@ -85,7 +91,7 @@ const resizeFileTo = async (file, options, { name, hash })=>{
85
91
  mime: file.mime,
86
92
  filepath: filePath,
87
93
  path: file.path || null,
88
- getStream: ()=>fs.createReadStream(filePath)
94
+ getStream: ()=>fs__default.default.createReadStream(filePath)
89
95
  };
90
96
  Object.assign(newFile, {
91
97
  width,
@@ -115,11 +121,11 @@ const generateThumbnail = async (file)=>{
115
121
  if ((sizeOptimization || autoOrientation) && isOptimizableFormat(format)) {
116
122
  let transformer;
117
123
  if (!file.filepath) {
118
- transformer = sharp({
124
+ transformer = sharp__default.default({
119
125
  animated: true
120
126
  });
121
127
  } else {
122
- transformer = sharp(file.filepath, {
128
+ transformer = sharp__default.default(file.filepath, {
123
129
  animated: true
124
130
  });
125
131
  }
@@ -145,7 +151,7 @@ const generateThumbnail = async (file)=>{
145
151
  const newFile = {
146
152
  ...file
147
153
  };
148
- newFile.getStream = ()=>fs.createReadStream(filePath);
154
+ newFile.getStream = ()=>fs__default.default.createReadStream(filePath);
149
155
  newFile.filepath = filePath;
150
156
  if (newSize && size && newSize > size) {
151
157
  // Ignore optimization if output is bigger than original
@@ -205,13 +211,13 @@ const breakpointSmallerThan = (breakpoint, { width, height })=>{
205
211
  */ const isFaultyImage = async (file)=>{
206
212
  if (!file.filepath) {
207
213
  return new Promise((resolve, reject)=>{
208
- const pipeline = sharp();
214
+ const pipeline = sharp__default.default();
209
215
  pipeline.stats().then(resolve).catch(reject);
210
216
  file.getStream().pipe(pipeline);
211
217
  });
212
218
  }
213
219
  try {
214
- await sharp(file.filepath).stats();
220
+ await sharp__default.default(file.filepath).stats();
215
221
  return false;
216
222
  } catch (e) {
217
223
  return true;
@@ -251,7 +257,7 @@ const isImage = async (file)=>{
251
257
  return format && FORMATS_TO_PROCESS.includes(format);
252
258
  };
253
259
  const generateFileName = (name)=>{
254
- const randomSuffix = ()=>crypto.randomBytes(5).toString('hex');
260
+ const randomSuffix = ()=>crypto__default.default.randomBytes(5).toString('hex');
255
261
  const baseName = utils.strings.nameToSlug(name, {
256
262
  separator: '_',
257
263
  lowercase: false
@@ -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 from 'sharp';\nimport crypto from 'crypto';\nimport { strings, file as fileUtils } from '@strapi/utils';\n\nimport { getService } from '../utils';\n\nimport type { UploadableFile } from '../types';\n\ntype Dimensions = {\n width: number | null;\n height: number | null;\n};\n\n// TODO: remove after upgrading sharp to >=0.34.2 (pageHeight added to OutputInfo types)\ndeclare module 'sharp' {\n interface OutputInfo {\n pageHeight?: number;\n }\n}\n\nconst { bytesToKbytes } = fileUtils;\n\nconst FORMATS_TO_RESIZE = ['jpeg', 'png', 'webp', 'tiff', 'gif'];\nconst FORMATS_TO_PROCESS = ['jpeg', 'png', 'webp', 'tiff', 'svg', 'gif', 'avif'];\nconst FORMATS_TO_OPTIMIZE = ['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.includes(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<sharp.Metadata> => {\n if (!file.filepath) {\n return new Promise((resolve, reject) => {\n const pipeline = sharp();\n pipeline.metadata().then(resolve).catch(reject);\n file.getStream().pipe(pipeline);\n });\n }\n\n return sharp(file.filepath).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 sharp.ResizeOptions;\n\nconst resizeFileTo = async (\n file: UploadableFile,\n options: sharp.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({ 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, { animated: true }).resize(options).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({ animated: true });\n } else {\n transformer = sharp(file.filepath, { 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 if (!file.filepath) {\n return new Promise((resolve, reject) => {\n const pipeline = sharp();\n pipeline.stats().then(resolve).catch(reject);\n file.getStream().pipe(pipeline);\n });\n }\n\n try {\n await sharp(file.filepath).stats();\n return false;\n } catch (e) {\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 (e) {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_OPTIMIZE.includes(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 (e) {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_RESIZE.includes(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 (e) {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_PROCESS.includes(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","FORMATS_TO_RESIZE","FORMATS_TO_PROCESS","FORMATS_TO_OPTIMIZE","isOptimizableFormat","format","undefined","includes","writeStreamToFile","stream","path","Promise","resolve","reject","writeStream","fs","createWriteStream","on","pipe","getMetadata","file","filepath","pipeline","sharp","metadata","then","catch","getStream","getDimensions","width","height","THUMBNAIL_RESIZE_OPTIONS","fit","resizeFileTo","options","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","strapi","config","get","generateResponsiveFormats","responsiveDimensions","originalDimensions","breakpoints","results","key","keys","breakpoint","breakpointSmallerThan","push","generateBreakpoint","isFaultyImage","stats","e","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 from 'sharp';\nimport crypto from 'crypto';\nimport { strings, file as fileUtils } from '@strapi/utils';\n\nimport { getService } from '../utils';\n\nimport type { UploadableFile } from '../types';\n\ntype Dimensions = {\n width: number | null;\n height: number | null;\n};\n\n// TODO: remove after upgrading sharp to >=0.34.2 (pageHeight added to OutputInfo types)\ndeclare module 'sharp' {\n interface OutputInfo {\n pageHeight?: number;\n }\n}\n\nconst { bytesToKbytes } = fileUtils;\n\nconst FORMATS_TO_RESIZE = ['jpeg', 'png', 'webp', 'tiff', 'gif'];\nconst FORMATS_TO_PROCESS = ['jpeg', 'png', 'webp', 'tiff', 'svg', 'gif', 'avif'];\nconst FORMATS_TO_OPTIMIZE = ['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.includes(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<sharp.Metadata> => {\n if (!file.filepath) {\n return new Promise((resolve, reject) => {\n const pipeline = sharp();\n pipeline.metadata().then(resolve).catch(reject);\n file.getStream().pipe(pipeline);\n });\n }\n\n return sharp(file.filepath).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 sharp.ResizeOptions;\n\nconst resizeFileTo = async (\n file: UploadableFile,\n options: sharp.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({ 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, { animated: true }).resize(options).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({ animated: true });\n } else {\n transformer = sharp(file.filepath, { 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 if (!file.filepath) {\n return new Promise((resolve, reject) => {\n const pipeline = sharp();\n pipeline.stats().then(resolve).catch(reject);\n file.getStream().pipe(pipeline);\n });\n }\n\n try {\n await sharp(file.filepath).stats();\n return false;\n } catch (e) {\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 (e) {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_OPTIMIZE.includes(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 (e) {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_RESIZE.includes(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 (e) {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_PROCESS.includes(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","FORMATS_TO_RESIZE","FORMATS_TO_PROCESS","FORMATS_TO_OPTIMIZE","isOptimizableFormat","format","undefined","includes","writeStreamToFile","stream","path","Promise","resolve","reject","writeStream","fs","createWriteStream","on","pipe","getMetadata","file","filepath","pipeline","sharp","metadata","then","catch","getStream","getDimensions","width","height","THUMBNAIL_RESIZE_OPTIONS","fit","resizeFileTo","options","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","strapi","config","get","generateResponsiveFormats","responsiveDimensions","originalDimensions","breakpoints","results","key","keys","breakpoint","breakpointSmallerThan","push","generateBreakpoint","isFaultyImage","stats","e","isOptimizableImage","isResizableImage","isImage","generateFileName","randomSuffix","crypto","randomBytes","toString","baseName","strings","nameToSlug","separator","lowercase"],"mappings":";;;;;;;;;;;;;;;AAsBA,MAAM,EAAEA,aAAa,EAAE,GAAGC,UAAAA;AAE1B,MAAMC,iBAAAA,GAAoB;AAAC,IAAA,MAAA;AAAQ,IAAA,KAAA;AAAO,IAAA,MAAA;AAAQ,IAAA,MAAA;AAAQ,IAAA;AAAM,CAAA;AAChE,MAAMC,kBAAAA,GAAqB;AAAC,IAAA,MAAA;AAAQ,IAAA,KAAA;AAAO,IAAA,MAAA;AAAQ,IAAA,MAAA;AAAQ,IAAA,KAAA;AAAO,IAAA,KAAA;AAAO,IAAA;AAAO,CAAA;AAChF,MAAMC,mBAAAA,GAAsB;AAAC,IAAA,MAAA;AAAQ,IAAA,KAAA;AAAO,IAAA,MAAA;AAAQ,IAAA,MAAA;AAAQ,IAAA;AAAO,CAAA;AAEnE,MAAMC,sBAAsB,CAC1BC,MAAAA,GAEAA,WAAWC,SAAAA,IAAaH,mBAAAA,CAAoBI,QAAQ,CAACF,MAAAA,CAAAA;AAEvD,MAAMG,oBAAoB,CAACC,MAAAA,EAAgCC,OACzD,IAAIC,OAAAA,CAAc,CAACC,OAAAA,EAASC,MAAAA,GAAAA;QAC1B,MAAMC,WAAAA,GAAcC,mBAAAA,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;IACnB,IAAI,CAACA,IAAAA,CAAKC,QAAQ,EAAE;QAClB,OAAO,IAAIV,OAAAA,CAAQ,CAACC,OAAAA,EAASC,MAAAA,GAAAA;AAC3B,YAAA,MAAMS,QAAAA,GAAWC,sBAAAA,EAAAA;AACjBD,YAAAA,QAAAA,CAASE,QAAQ,EAAA,CAAGC,IAAI,CAACb,OAAAA,CAAAA,CAASc,KAAK,CAACb,MAAAA,CAAAA;YACxCO,IAAAA,CAAKO,SAAS,EAAA,CAAGT,IAAI,CAACI,QAAAA,CAAAA;AACxB,QAAA,CAAA,CAAA;AACF,IAAA;AAEA,IAAA,OAAOC,sBAAAA,CAAMH,IAAAA,CAAKC,QAAQ,CAAA,CAAEG,QAAQ,EAAA;AACtC,CAAA;AAEA,MAAMI,gBAAgB,OAAOR,IAAAA,GAAAA;IAC3B,MAAM,EAAES,QAAQ,IAAI,EAAEC,SAAS,IAAI,EAAE,GAAG,MAAMX,WAAAA,CAAYC,IAAAA,CAAAA;IAE1D,OAAO;AAAES,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,OACnBb,IAAAA,EACAc,OAAAA,EACA,EACEC,IAAI,EACJC,IAAI,EAIL,GAAA;IAED,MAAMC,QAAAA,GAAWjB,KAAKkB,mBAAmB,GAAGC,UAAKnB,IAAAA,CAAKkB,mBAAmB,EAAEF,IAAAA,CAAAA,GAAQA,IAAAA;IAEnF,IAAII,OAAAA;IACJ,IAAI,CAACpB,IAAAA,CAAKC,QAAQ,EAAE;AAClB,QAAA,MAAMoB,YAAYlB,sBAAAA,CAAM;YAAEmB,QAAAA,EAAU;AAAK,SAAA,CAAA,CACtCC,MAAM,CAACT,OAAAA,CAAAA,CACPjB,EAAE,CAAC,QAAQ,CAAC2B,IAAAA,GAAAA;YACXJ,OAAAA,GAAUI,IAAAA;AACZ,QAAA,CAAA,CAAA;AAEF,QAAA,MAAMpC,kBAAkBY,IAAAA,CAAKO,SAAS,EAAA,CAAGT,IAAI,CAACuB,SAAAA,CAAAA,EAAYJ,QAAAA,CAAAA;IAC5D,CAAA,MAAO;AACLG,QAAAA,OAAAA,GAAU,MAAMjB,sBAAAA,CAAMH,IAAAA,CAAKC,QAAQ,EAAE;YAAEqB,QAAAA,EAAU;AAAK,SAAA,CAAA,CAAGC,MAAM,CAACT,OAAAA,CAAAA,CAASW,MAAM,CAACR,QAAAA,CAAAA;AAClF,IAAA;IAEA,MAAM,EAAER,KAAK,EAAEC,MAAM,EAAEgB,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;QACf7B,QAAAA,EAAUgB,QAAAA;QACV3B,IAAAA,EAAMU,IAAAA,CAAKV,IAAI,IAAI,IAAA;QACnBiB,SAAAA,EAAW,IAAMZ,mBAAAA,CAAGoC,gBAAgB,CAACd,QAAAA;AACvC,KAAA;IAEAe,MAAAA,CAAOC,MAAM,CAACL,OAAAA,EAAS;AACrBnB,QAAAA,KAAAA;AACAC,QAAAA,MAAAA,EAAQiB,UAAAA,IAAcjB,MAAAA;QACtBgB,IAAAA,EAAMA,IAAAA,GAAO/C,cAAc+C,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,KAAKS,KAAK,IACVT,KAAKU,MAAM,KACVV,IAAAA,CAAKS,KAAK,GAAGE,wBAAAA,CAAyBF,KAAK,IAAIT,IAAAA,CAAKU,MAAM,GAAGC,wBAAAA,CAAyBD,MAAM,CAAD,EAC5F;QACA,OAAOG,YAAAA,CAAab,MAAMW,wBAAAA,EAA0B;AAClDI,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,gBAAAA,CAAW,QAAA,CAAA,CAAUC,WAAW,MAAO,EAAC;AAEjD,IAAA,MAAM,EAAEvD,MAAM,EAAEyC,IAAI,EAAE,GAAG,MAAM3B,WAAAA,CAAYC,IAAAA,CAAAA;AAE3C,IAAA,IAAI,CAACqC,gBAAAA,IAAoBC,eAAc,KAAMtD,oBAAoBC,MAAAA,CAAAA,EAAS;QACxE,IAAIwD,WAAAA;QACJ,IAAI,CAACzC,IAAAA,CAAKC,QAAQ,EAAE;AAClBwC,YAAAA,WAAAA,GAActC,sBAAAA,CAAM;gBAAEmB,QAAAA,EAAU;AAAK,aAAA,CAAA;QACvC,CAAA,MAAO;YACLmB,WAAAA,GAActC,sBAAAA,CAAMH,IAAAA,CAAKC,QAAQ,EAAE;gBAAEqB,QAAAA,EAAU;AAAK,aAAA,CAAA;AACtD,QAAA;;QAEAmB,WAAW,CAACxD,OAAO,CAAC;AAAEyD,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,UAAKnB,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,CAAKC,QAAQ,EAAE;YAClBwC,WAAAA,CAAY5C,EAAE,CAAC,MAAA,EAAQ,CAAC2B,IAAAA,GAAAA;gBACtBJ,OAAAA,GAAUI,IAAAA;AACZ,YAAA,CAAA,CAAA;AAEA,YAAA,MAAMpC,kBAAkBY,IAAAA,CAAKO,SAAS,EAAA,CAAGT,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,EACJR,KAAAA,EAAOmC,QAAQ,EACflC,QAAQmC,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,CAAQrB,SAAS,GAAG,IAAMZ,mBAAAA,CAAGoC,gBAAgB,CAACd,QAAAA,CAAAA;AAC9CW,QAAAA,OAAAA,CAAQ3B,QAAQ,GAAGgB,QAAAA;QAEnB,IAAI6B,OAAAA,IAAWpB,IAAAA,IAAQoB,OAAAA,GAAUpB,IAAAA,EAAM;;YAErC,OAAO1B,IAAAA;AACT,QAAA;QAEA,OAAOgC,MAAAA,CAAOC,MAAM,CAACL,OAAAA,EAAS;YAC5BnB,KAAAA,EAAOmC,QAAAA;AACPlC,YAAAA,MAAAA,EAAQqC,aAAAA,IAAiBF,SAAAA;YACzBnB,IAAAA,EAAMoB,OAAAA,GAAUnE,cAAcmE,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,IACrBC,MAAAA,CAAOC,MAAM,CAACC,GAAG,CAAyB,4BAAA,EAA8BP,mBAAAA,CAAAA;AAE1E,MAAMQ,4BAA4B,OAAOxD,IAAAA,GAAAA;IACvC,MAAM,EAAEyD,oBAAAA,GAAuB,KAAK,EAAE,GAAG,MAAOlB,gBAAAA,CAAW,QAAA,CAAA,CAAUC,WAAW,EAAA,IAAO,EAAC;IAExF,IAAI,CAACiB,oBAAAA,EAAsB,OAAO,EAAE;IAEpC,MAAMC,kBAAAA,GAAqB,MAAMlD,aAAAA,CAAcR,IAAAA,CAAAA;AAE/C,IAAA,MAAM2D,WAAAA,GAAcP,cAAAA,EAAAA;AACpB,IAAA,MAAMQ,UAAU,EAAE;AAElB,IAAA,KAAK,MAAMC,GAAAA,IAAO7B,MAAAA,CAAO8B,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;AAAE7D,gBAAAA,IAAAA;AAAM+D,gBAAAA;AAAW,aAAA,CAAA,CAAA;AAChE,QAAA;AACF,IAAA;IAEA,OAAOH,OAAAA;AACT,CAAA;AAEA,MAAMM,qBAAqB,OACzBL,GAAAA,EACA,EAAE7D,IAAI,EAAE+D,UAAU,EAAgD,GAAA;IAElE,MAAMnC,OAAAA,GAAU,MAAMf,YAAAA,CACpBb,IAAAA,EACA;QACES,KAAAA,EAAOsD,UAAAA;QACPrD,MAAAA,EAAQqD,UAAAA;QACRnD,GAAAA,EAAK;KACP,EACA;AACEG,QAAAA,IAAAA,EAAM,GAAG8C,GAAAA,CAAI,CAAC,EAAE7D,IAAAA,CAAKe,IAAI,CAAA,CAAE;AAC3BC,QAAAA,IAAAA,EAAM,GAAG6C,GAAAA,CAAI,CAAC,EAAE7D,IAAAA,CAAKgB,IAAI,CAAA;AAC3B,KAAA,CAAA;IAEF,OAAO;AACL6C,QAAAA,GAAAA;QACA7D,IAAAA,EAAM4B;AACR,KAAA;AACF,CAAA;AAEA,MAAMoC,wBAAwB,CAACD,UAAAA,EAAoB,EAAEtD,KAAK,EAAEC,MAAM,EAAc,GAAA;IAC9E,OAAOqD,UAAAA,IAActD,KAAAA,IAAS,CAAA,KAAMsD,UAAAA,IAAcrD,UAAU,CAAA,CAAA;AAC9D,CAAA;AAEA;;IAGA,MAAMyD,gBAAgB,OAAOnE,IAAAA,GAAAA;IAC3B,IAAI,CAACA,IAAAA,CAAKC,QAAQ,EAAE;QAClB,OAAO,IAAIV,OAAAA,CAAQ,CAACC,OAAAA,EAASC,MAAAA,GAAAA;AAC3B,YAAA,MAAMS,QAAAA,GAAWC,sBAAAA,EAAAA;AACjBD,YAAAA,QAAAA,CAASkE,KAAK,EAAA,CAAG/D,IAAI,CAACb,OAAAA,CAAAA,CAASc,KAAK,CAACb,MAAAA,CAAAA;YACrCO,IAAAA,CAAKO,SAAS,EAAA,CAAGT,IAAI,CAACI,QAAAA,CAAAA;AACxB,QAAA,CAAA,CAAA;AACF,IAAA;IAEA,IAAI;AACF,QAAA,MAAMC,sBAAAA,CAAMH,IAAAA,CAAKC,QAAQ,CAAA,CAAEmE,KAAK,EAAA;QAChC,OAAO,KAAA;AACT,IAAA,CAAA,CAAE,OAAOC,CAAAA,EAAG;QACV,OAAO,IAAA;AACT,IAAA;AACF,CAAA;AAEA,MAAMC,qBAAqB,OAAOtE,IAAAA,GAAAA;IAChC,IAAIf,MAAAA;IACJ,IAAI;QACF,MAAMmB,QAAAA,GAAW,MAAML,WAAAA,CAAYC,IAAAA,CAAAA;AACnCf,QAAAA,MAAAA,GAASmB,SAASnB,MAAM;AAC1B,IAAA,CAAA,CAAE,OAAOoF,CAAAA,EAAG;;QAEV,OAAO,KAAA;AACT,IAAA;IACA,OAAOpF,MAAAA,IAAUF,mBAAAA,CAAoBI,QAAQ,CAACF,MAAAA,CAAAA;AAChD,CAAA;AAEA,MAAMsF,mBAAmB,OAAOvE,IAAAA,GAAAA;IAC9B,IAAIf,MAAAA;IACJ,IAAI;QACF,MAAMmB,QAAAA,GAAW,MAAML,WAAAA,CAAYC,IAAAA,CAAAA;AACnCf,QAAAA,MAAAA,GAASmB,SAASnB,MAAM;AAC1B,IAAA,CAAA,CAAE,OAAOoF,CAAAA,EAAG;;QAEV,OAAO,KAAA;AACT,IAAA;IACA,OAAOpF,MAAAA,IAAUJ,iBAAAA,CAAkBM,QAAQ,CAACF,MAAAA,CAAAA;AAC9C,CAAA;AAEA,MAAMuF,UAAU,OAAOxE,IAAAA,GAAAA;IACrB,IAAIf,MAAAA;IACJ,IAAI;QACF,MAAMmB,QAAAA,GAAW,MAAML,WAAAA,CAAYC,IAAAA,CAAAA;AACnCf,QAAAA,MAAAA,GAASmB,SAASnB,MAAM;AAC1B,IAAA,CAAA,CAAE,OAAOoF,CAAAA,EAAG;;QAEV,OAAO,KAAA;AACT,IAAA;IACA,OAAOpF,MAAAA,IAAUH,kBAAAA,CAAmBK,QAAQ,CAACF,MAAAA,CAAAA;AAC/C,CAAA;AAEA,MAAMwF,mBAAmB,CAAC1D,IAAAA,GAAAA;AACxB,IAAA,MAAM2D,eAAe,IAAMC,uBAAAA,CAAOC,WAAW,CAAC,CAAA,CAAA,CAAGC,QAAQ,CAAC,KAAA,CAAA;AAC1D,IAAA,MAAMC,QAAAA,GAAWC,aAAAA,CAAQC,UAAU,CAACjE,IAAAA,EAAM;QAAEkE,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;AACbP,IAAAA,aAAAA;AACAG,IAAAA,kBAAAA;AACAC,IAAAA,gBAAAA;AACAC,IAAAA,OAAAA;AACAhE,IAAAA,aAAAA;AACAgD,IAAAA,yBAAAA;AACArB,IAAAA,iBAAAA;AACAC,IAAAA,QAAAA;AACAqC,IAAAA;AACF,CAAA;;;;"}
@@ -26,6 +26,30 @@ var provider = (({ strapi })=>({
26
26
  delete file.filepath;
27
27
  }
28
28
  }
29
+ },
30
+ async replace (newFile, oldFile) {
31
+ const provider = strapi.plugin('upload').provider;
32
+ if (fp.isFunction(provider.replaceStream)) {
33
+ newFile.stream = newFile.getStream();
34
+ await provider.replaceStream(newFile, oldFile);
35
+ delete newFile.stream;
36
+ if ('filepath' in newFile) {
37
+ delete newFile.filepath;
38
+ }
39
+ return;
40
+ }
41
+ if (fp.isFunction(provider.replace)) {
42
+ newFile.buffer = await utils.file.streamToBuffer(newFile.getStream());
43
+ await provider.replace(newFile, oldFile);
44
+ delete newFile.buffer;
45
+ if ('filepath' in newFile) {
46
+ delete newFile.filepath;
47
+ }
48
+ return;
49
+ }
50
+ // Fallback: delete old then upload new — preserves current behavior for the file.
51
+ await provider.delete(oldFile);
52
+ await this.upload(newFile);
29
53
  }
30
54
  }));
31
55
 
@@ -1 +1 @@
1
- {"version":3,"file":"provider.js","sources":["../../../server/src/services/provider.ts"],"sourcesContent":["import { isFunction } from 'lodash/fp';\nimport { file as fileUtils } from '@strapi/utils';\nimport type { Core } from '@strapi/types';\n\nimport { Config, UploadableFile } from '../types';\n\nexport default ({ strapi }: { strapi: Core.Strapi }) => ({\n async checkFileSize(file: UploadableFile) {\n const { sizeLimit } = strapi.config.get<Config>('plugin::upload');\n await strapi.plugin('upload').provider.checkFileSize(file, { sizeLimit });\n },\n\n async upload(file: UploadableFile) {\n if (isFunction(strapi.plugin('upload').provider.uploadStream)) {\n file.stream = file.getStream();\n await strapi.plugin('upload').provider.uploadStream(file);\n\n delete file.stream;\n\n if ('filepath' in file) {\n delete file.filepath;\n }\n } else {\n file.buffer = await fileUtils.streamToBuffer(file.getStream());\n await strapi.plugin('upload').provider.upload(file);\n\n delete file.buffer;\n\n if ('filepath' in file) {\n delete file.filepath;\n }\n }\n },\n});\n"],"names":["strapi","checkFileSize","file","sizeLimit","config","get","plugin","provider","upload","isFunction","uploadStream","stream","getStream","filepath","buffer","fileUtils","streamToBuffer"],"mappings":";;;;;AAMA,eAAe,CAAA,CAAC,EAAEA,MAAM,EAA2B,IAAM;AACvD,QAAA,MAAMC,eAAcC,IAAoB,EAAA;YACtC,MAAM,EAAEC,SAAS,EAAE,GAAGH,OAAOI,MAAM,CAACC,GAAG,CAAS,gBAAA,CAAA;YAChD,MAAML,MAAAA,CAAOM,MAAM,CAAC,QAAA,CAAA,CAAUC,QAAQ,CAACN,aAAa,CAACC,IAAAA,EAAM;AAAEC,gBAAAA;AAAU,aAAA,CAAA;AACzE,QAAA,CAAA;AAEA,QAAA,MAAMK,QAAON,IAAoB,EAAA;YAC/B,IAAIO,aAAAA,CAAWT,OAAOM,MAAM,CAAC,UAAUC,QAAQ,CAACG,YAAY,CAAA,EAAG;gBAC7DR,IAAAA,CAAKS,MAAM,GAAGT,IAAAA,CAAKU,SAAS,EAAA;AAC5B,gBAAA,MAAMZ,OAAOM,MAAM,CAAC,UAAUC,QAAQ,CAACG,YAAY,CAACR,IAAAA,CAAAA;AAEpD,gBAAA,OAAOA,KAAKS,MAAM;AAElB,gBAAA,IAAI,cAAcT,IAAAA,EAAM;AACtB,oBAAA,OAAOA,KAAKW,QAAQ;AACtB,gBAAA;YACF,CAAA,MAAO;AACLX,gBAAAA,IAAAA,CAAKY,MAAM,GAAG,MAAMC,WAAUC,cAAc,CAACd,KAAKU,SAAS,EAAA,CAAA;AAC3D,gBAAA,MAAMZ,OAAOM,MAAM,CAAC,UAAUC,QAAQ,CAACC,MAAM,CAACN,IAAAA,CAAAA;AAE9C,gBAAA,OAAOA,KAAKY,MAAM;AAElB,gBAAA,IAAI,cAAcZ,IAAAA,EAAM;AACtB,oBAAA,OAAOA,KAAKW,QAAQ;AACtB,gBAAA;AACF,YAAA;AACF,QAAA;AACF,KAAA,CAAC;;;;"}
1
+ {"version":3,"file":"provider.js","sources":["../../../server/src/services/provider.ts"],"sourcesContent":["import { isFunction } from 'lodash/fp';\nimport { file as fileUtils } from '@strapi/utils';\nimport type { Core } from '@strapi/types';\n\nimport { Config, File, UploadableFile } from '../types';\n\nexport default ({ strapi }: { strapi: Core.Strapi }) => ({\n async checkFileSize(file: UploadableFile) {\n const { sizeLimit } = strapi.config.get<Config>('plugin::upload');\n await strapi.plugin('upload').provider.checkFileSize(file, { sizeLimit });\n },\n\n async upload(file: UploadableFile) {\n if (isFunction(strapi.plugin('upload').provider.uploadStream)) {\n file.stream = file.getStream();\n await strapi.plugin('upload').provider.uploadStream(file);\n\n delete file.stream;\n\n if ('filepath' in file) {\n delete file.filepath;\n }\n } else {\n file.buffer = await fileUtils.streamToBuffer(file.getStream());\n await strapi.plugin('upload').provider.upload(file);\n\n delete file.buffer;\n\n if ('filepath' in file) {\n delete file.filepath;\n }\n }\n },\n\n async replace(newFile: UploadableFile, oldFile: File) {\n const provider = strapi.plugin('upload').provider;\n\n if (isFunction(provider.replaceStream)) {\n newFile.stream = newFile.getStream();\n await provider.replaceStream(newFile, oldFile);\n\n delete newFile.stream;\n\n if ('filepath' in newFile) {\n delete newFile.filepath;\n }\n return;\n }\n\n if (isFunction(provider.replace)) {\n newFile.buffer = await fileUtils.streamToBuffer(newFile.getStream());\n await provider.replace(newFile, oldFile);\n\n delete newFile.buffer;\n\n if ('filepath' in newFile) {\n delete newFile.filepath;\n }\n return;\n }\n\n // Fallback: delete old then upload new — preserves current behavior for the file.\n await provider.delete(oldFile);\n await this.upload(newFile);\n },\n});\n"],"names":["strapi","checkFileSize","file","sizeLimit","config","get","plugin","provider","upload","isFunction","uploadStream","stream","getStream","filepath","buffer","fileUtils","streamToBuffer","replace","newFile","oldFile","replaceStream","delete"],"mappings":";;;;;AAMA,eAAe,CAAA,CAAC,EAAEA,MAAM,EAA2B,IAAM;AACvD,QAAA,MAAMC,eAAcC,IAAoB,EAAA;YACtC,MAAM,EAAEC,SAAS,EAAE,GAAGH,OAAOI,MAAM,CAACC,GAAG,CAAS,gBAAA,CAAA;YAChD,MAAML,MAAAA,CAAOM,MAAM,CAAC,QAAA,CAAA,CAAUC,QAAQ,CAACN,aAAa,CAACC,IAAAA,EAAM;AAAEC,gBAAAA;AAAU,aAAA,CAAA;AACzE,QAAA,CAAA;AAEA,QAAA,MAAMK,QAAON,IAAoB,EAAA;YAC/B,IAAIO,aAAAA,CAAWT,OAAOM,MAAM,CAAC,UAAUC,QAAQ,CAACG,YAAY,CAAA,EAAG;gBAC7DR,IAAAA,CAAKS,MAAM,GAAGT,IAAAA,CAAKU,SAAS,EAAA;AAC5B,gBAAA,MAAMZ,OAAOM,MAAM,CAAC,UAAUC,QAAQ,CAACG,YAAY,CAACR,IAAAA,CAAAA;AAEpD,gBAAA,OAAOA,KAAKS,MAAM;AAElB,gBAAA,IAAI,cAAcT,IAAAA,EAAM;AACtB,oBAAA,OAAOA,KAAKW,QAAQ;AACtB,gBAAA;YACF,CAAA,MAAO;AACLX,gBAAAA,IAAAA,CAAKY,MAAM,GAAG,MAAMC,WAAUC,cAAc,CAACd,KAAKU,SAAS,EAAA,CAAA;AAC3D,gBAAA,MAAMZ,OAAOM,MAAM,CAAC,UAAUC,QAAQ,CAACC,MAAM,CAACN,IAAAA,CAAAA;AAE9C,gBAAA,OAAOA,KAAKY,MAAM;AAElB,gBAAA,IAAI,cAAcZ,IAAAA,EAAM;AACtB,oBAAA,OAAOA,KAAKW,QAAQ;AACtB,gBAAA;AACF,YAAA;AACF,QAAA,CAAA;QAEA,MAAMI,OAAAA,CAAAA,CAAQC,OAAuB,EAAEC,OAAa,EAAA;AAClD,YAAA,MAAMZ,QAAAA,GAAWP,MAAAA,CAAOM,MAAM,CAAC,UAAUC,QAAQ;YAEjD,IAAIE,aAAAA,CAAWF,QAAAA,CAASa,aAAa,CAAA,EAAG;gBACtCF,OAAAA,CAAQP,MAAM,GAAGO,OAAAA,CAAQN,SAAS,EAAA;gBAClC,MAAML,QAAAA,CAASa,aAAa,CAACF,OAAAA,EAASC,OAAAA,CAAAA;AAEtC,gBAAA,OAAOD,QAAQP,MAAM;AAErB,gBAAA,IAAI,cAAcO,OAAAA,EAAS;AACzB,oBAAA,OAAOA,QAAQL,QAAQ;AACzB,gBAAA;AACA,gBAAA;AACF,YAAA;YAEA,IAAIJ,aAAAA,CAAWF,QAAAA,CAASU,OAAO,CAAA,EAAG;AAChCC,gBAAAA,OAAAA,CAAQJ,MAAM,GAAG,MAAMC,WAAUC,cAAc,CAACE,QAAQN,SAAS,EAAA,CAAA;gBACjE,MAAML,QAAAA,CAASU,OAAO,CAACC,OAAAA,EAASC,OAAAA,CAAAA;AAEhC,gBAAA,OAAOD,QAAQJ,MAAM;AAErB,gBAAA,IAAI,cAAcI,OAAAA,EAAS;AACzB,oBAAA,OAAOA,QAAQL,QAAQ;AACzB,gBAAA;AACA,gBAAA;AACF,YAAA;;YAGA,MAAMN,QAAAA,CAASc,MAAM,CAACF,OAAAA,CAAAA;YACtB,MAAM,IAAI,CAACX,MAAM,CAACU,OAAAA,CAAAA;AACpB,QAAA;AACF,KAAA,CAAC;;;;"}