@strapi/upload 5.51.2 → 5.52.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 (193) hide show
  1. package/dist/admin/future/App.js +3 -3
  2. package/dist/admin/future/App.js.map +1 -1
  3. package/dist/admin/future/App.mjs +4 -4
  4. package/dist/admin/future/App.mjs.map +1 -1
  5. package/dist/admin/future/components/BetaNotice.js +72 -0
  6. package/dist/admin/future/components/BetaNotice.js.map +1 -0
  7. package/dist/admin/future/components/BetaNotice.mjs +70 -0
  8. package/dist/admin/future/components/BetaNotice.mjs.map +1 -0
  9. package/dist/admin/future/components/Drawer.js +16 -3
  10. package/dist/admin/future/components/Drawer.js.map +1 -1
  11. package/dist/admin/future/components/Drawer.mjs +16 -3
  12. package/dist/admin/future/components/Drawer.mjs.map +1 -1
  13. package/dist/admin/future/hooks/useAIMetadataEnabled.js +39 -0
  14. package/dist/admin/future/hooks/useAIMetadataEnabled.js.map +1 -0
  15. package/dist/admin/future/hooks/useAIMetadataEnabled.mjs +37 -0
  16. package/dist/admin/future/hooks/useAIMetadataEnabled.mjs.map +1 -0
  17. package/dist/admin/future/pages/Assets/AssetsPage.js +297 -139
  18. package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
  19. package/dist/admin/future/pages/Assets/AssetsPage.mjs +301 -143
  20. package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
  21. package/dist/admin/future/pages/Assets/components/ActionsMenuContent.js +46 -0
  22. package/dist/admin/future/pages/Assets/components/ActionsMenuContent.js.map +1 -0
  23. package/dist/admin/future/pages/Assets/components/ActionsMenuContent.mjs +44 -0
  24. package/dist/admin/future/pages/Assets/components/ActionsMenuContent.mjs.map +1 -0
  25. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js +325 -0
  26. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js.map +1 -0
  27. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs +323 -0
  28. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs.map +1 -0
  29. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.js +35 -14
  30. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.js.map +1 -1
  31. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.mjs +35 -14
  32. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.mjs.map +1 -1
  33. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +54 -53
  34. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
  35. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +54 -54
  36. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
  37. package/dist/admin/future/pages/Assets/components/AssetsGrid.js +89 -24
  38. package/dist/admin/future/pages/Assets/components/AssetsGrid.js.map +1 -1
  39. package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs +91 -26
  40. package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs.map +1 -1
  41. package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js +15 -3
  42. package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js.map +1 -1
  43. package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs +16 -4
  44. package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs.map +1 -1
  45. package/dist/admin/future/pages/Assets/components/AssetsTable.js +168 -58
  46. package/dist/admin/future/pages/Assets/components/AssetsTable.js.map +1 -1
  47. package/dist/admin/future/pages/Assets/components/AssetsTable.mjs +171 -61
  48. package/dist/admin/future/pages/Assets/components/AssetsTable.mjs.map +1 -1
  49. package/dist/admin/future/pages/Assets/components/BulkActionsBar.js +64 -132
  50. package/dist/admin/future/pages/Assets/components/BulkActionsBar.js.map +1 -1
  51. package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs +64 -132
  52. package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs.map +1 -1
  53. package/dist/admin/future/pages/Assets/components/BulkMoveDialog.js +123 -76
  54. package/dist/admin/future/pages/Assets/components/BulkMoveDialog.js.map +1 -1
  55. package/dist/admin/future/pages/Assets/components/BulkMoveDialog.mjs +126 -79
  56. package/dist/admin/future/pages/Assets/components/BulkMoveDialog.mjs.map +1 -1
  57. package/dist/admin/future/pages/Assets/components/BusyOverlay.js +36 -0
  58. package/dist/admin/future/pages/Assets/components/BusyOverlay.js.map +1 -0
  59. package/dist/admin/future/pages/Assets/components/BusyOverlay.mjs +34 -0
  60. package/dist/admin/future/pages/Assets/components/BusyOverlay.mjs.map +1 -0
  61. package/dist/admin/future/pages/Assets/components/DeleteItemsDialog.js +131 -0
  62. package/dist/admin/future/pages/Assets/components/DeleteItemsDialog.js.map +1 -0
  63. package/dist/admin/future/pages/Assets/components/DeleteItemsDialog.mjs +129 -0
  64. package/dist/admin/future/pages/Assets/components/DeleteItemsDialog.mjs.map +1 -0
  65. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js +27 -17
  66. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js.map +1 -1
  67. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs +28 -18
  68. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs.map +1 -1
  69. package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.js +28 -31
  70. package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.js.map +1 -1
  71. package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.mjs +28 -31
  72. package/dist/admin/future/pages/Assets/components/Dnd/buildDragSet.mjs.map +1 -1
  73. package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.js +10 -15
  74. package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.js.map +1 -1
  75. package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.mjs +10 -15
  76. package/dist/admin/future/pages/Assets/components/Dnd/useAssetDnd.mjs.map +1 -1
  77. package/dist/admin/future/pages/Assets/components/FilterBadges.js +13 -4
  78. package/dist/admin/future/pages/Assets/components/FilterBadges.js.map +1 -1
  79. package/dist/admin/future/pages/Assets/components/FilterBadges.mjs +13 -4
  80. package/dist/admin/future/pages/Assets/components/FilterBadges.mjs.map +1 -1
  81. package/dist/admin/future/pages/Assets/components/FilterMenu.js +241 -61
  82. package/dist/admin/future/pages/Assets/components/FilterMenu.js.map +1 -1
  83. package/dist/admin/future/pages/Assets/components/FilterMenu.mjs +244 -64
  84. package/dist/admin/future/pages/Assets/components/FilterMenu.mjs.map +1 -1
  85. package/dist/admin/future/pages/Assets/components/FolderActionsMenu.js +144 -0
  86. package/dist/admin/future/pages/Assets/components/FolderActionsMenu.js.map +1 -0
  87. package/dist/admin/future/pages/Assets/components/FolderActionsMenu.mjs +142 -0
  88. package/dist/admin/future/pages/Assets/components/FolderActionsMenu.mjs.map +1 -0
  89. package/dist/admin/future/pages/Assets/components/{CreateFolderDialog.js → FolderFormDialog.js} +50 -16
  90. package/dist/admin/future/pages/Assets/components/FolderFormDialog.js.map +1 -0
  91. package/dist/admin/future/pages/Assets/components/{CreateFolderDialog.mjs → FolderFormDialog.mjs} +52 -18
  92. package/dist/admin/future/pages/Assets/components/FolderFormDialog.mjs.map +1 -0
  93. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js +111 -191
  94. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
  95. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs +114 -194
  96. package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
  97. package/dist/admin/future/pages/Assets/hooks/useBusyAssets.js +47 -0
  98. package/dist/admin/future/pages/Assets/hooks/useBusyAssets.js.map +1 -0
  99. package/dist/admin/future/pages/Assets/hooks/useBusyAssets.mjs +44 -0
  100. package/dist/admin/future/pages/Assets/hooks/useBusyAssets.mjs.map +1 -0
  101. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.js +203 -62
  102. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.js.map +1 -1
  103. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.mjs +204 -63
  104. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.mjs.map +1 -1
  105. package/dist/admin/future/pages/Assets/hooks/useInfiniteScrollSentinel.js +75 -0
  106. package/dist/admin/future/pages/Assets/hooks/useInfiniteScrollSentinel.js.map +1 -0
  107. package/dist/admin/future/pages/Assets/hooks/useInfiniteScrollSentinel.mjs +73 -0
  108. package/dist/admin/future/pages/Assets/hooks/useInfiniteScrollSentinel.mjs.map +1 -0
  109. package/dist/admin/future/services/api.js +24 -0
  110. package/dist/admin/future/services/api.js.map +1 -1
  111. package/dist/admin/future/services/api.mjs +24 -0
  112. package/dist/admin/future/services/api.mjs.map +1 -1
  113. package/dist/admin/future/services/assets.js +11 -0
  114. package/dist/admin/future/services/assets.js.map +1 -1
  115. package/dist/admin/future/services/assets.mjs +11 -0
  116. package/dist/admin/future/services/assets.mjs.map +1 -1
  117. package/dist/admin/future/services/folders.js +37 -2
  118. package/dist/admin/future/services/folders.js.map +1 -1
  119. package/dist/admin/future/services/folders.mjs +37 -3
  120. package/dist/admin/future/services/folders.mjs.map +1 -1
  121. package/dist/admin/future/utils/buildDragSetFromSelection.js +7 -5
  122. package/dist/admin/future/utils/buildDragSetFromSelection.js.map +1 -1
  123. package/dist/admin/future/utils/buildDragSetFromSelection.mjs +7 -5
  124. package/dist/admin/future/utils/buildDragSetFromSelection.mjs.map +1 -1
  125. package/dist/admin/future/utils/formatMoveSuccessMessage.js +12 -1
  126. package/dist/admin/future/utils/formatMoveSuccessMessage.js.map +1 -1
  127. package/dist/admin/future/utils/formatMoveSuccessMessage.mjs +12 -1
  128. package/dist/admin/future/utils/formatMoveSuccessMessage.mjs.map +1 -1
  129. package/dist/admin/future/utils/getRelationId.js +24 -0
  130. package/dist/admin/future/utils/getRelationId.js.map +1 -0
  131. package/dist/admin/future/utils/getRelationId.mjs +22 -0
  132. package/dist/admin/future/utils/getRelationId.mjs.map +1 -0
  133. package/dist/admin/future/utils/isEventFromWithin.js +14 -0
  134. package/dist/admin/future/utils/isEventFromWithin.js.map +1 -0
  135. package/dist/admin/future/utils/isEventFromWithin.mjs +12 -0
  136. package/dist/admin/future/utils/isEventFromWithin.mjs.map +1 -0
  137. package/dist/admin/future/utils/itemLocations.js +40 -0
  138. package/dist/admin/future/utils/itemLocations.js.map +1 -0
  139. package/dist/admin/future/utils/itemLocations.mjs +36 -0
  140. package/dist/admin/future/utils/itemLocations.mjs.map +1 -0
  141. package/dist/admin/future/utils/itemSource.js +36 -0
  142. package/dist/admin/future/utils/itemSource.js.map +1 -0
  143. package/dist/admin/future/utils/itemSource.mjs +32 -0
  144. package/dist/admin/future/utils/itemSource.mjs.map +1 -0
  145. package/dist/admin/index.js +11 -17
  146. package/dist/admin/index.js.map +1 -1
  147. package/dist/admin/index.mjs +12 -18
  148. package/dist/admin/index.mjs.map +1 -1
  149. package/dist/admin/src/future/App.d.ts +1 -1
  150. package/dist/admin/src/future/components/BetaNotice.d.ts +11 -0
  151. package/dist/admin/src/future/components/Drawer.d.ts +5 -1
  152. package/dist/admin/src/future/hooks/useAIMetadataEnabled.d.ts +26 -0
  153. package/dist/admin/src/future/pages/Assets/components/ActionsMenuContent.d.ts +33 -0
  154. package/dist/admin/src/future/pages/Assets/components/AssetActionsMenu.d.ts +24 -0
  155. package/dist/admin/src/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.d.ts +16 -0
  156. package/dist/admin/src/future/pages/Assets/components/BulkActionsBar.d.ts +8 -1
  157. package/dist/admin/src/future/pages/Assets/components/BulkMoveDialog.d.ts +17 -6
  158. package/dist/admin/src/future/pages/Assets/components/BusyOverlay.d.ts +9 -0
  159. package/dist/admin/src/future/pages/Assets/components/DeleteItemsDialog.d.ts +27 -0
  160. package/dist/admin/src/future/pages/Assets/components/Dnd/AssetsDndProvider.d.ts +8 -1
  161. package/dist/admin/src/future/pages/Assets/components/Dnd/buildDragSet.d.ts +18 -3
  162. package/dist/admin/src/future/pages/Assets/components/Dnd/useAssetDnd.d.ts +2 -1
  163. package/dist/admin/src/future/pages/Assets/components/FilterBadges.d.ts +3 -1
  164. package/dist/admin/src/future/pages/Assets/components/FilterMenu.d.ts +4 -0
  165. package/dist/admin/src/future/pages/Assets/components/FolderActionsMenu.d.ts +20 -0
  166. package/dist/admin/src/future/pages/Assets/components/FolderFormDialog.d.ts +16 -0
  167. package/dist/admin/src/future/pages/Assets/hooks/useBusyAssets.d.ts +38 -0
  168. package/dist/admin/src/future/pages/Assets/hooks/useInfiniteAssets.d.ts +20 -6
  169. package/dist/admin/src/future/pages/Assets/hooks/useInfiniteScrollSentinel.d.ts +41 -0
  170. package/dist/admin/src/future/services/folders.d.ts +6 -1
  171. package/dist/admin/src/future/utils/buildDragSetFromSelection.d.ts +4 -3
  172. package/dist/admin/src/future/utils/formatMoveSuccessMessage.d.ts +7 -1
  173. package/dist/admin/src/future/utils/getRelationId.d.ts +11 -0
  174. package/dist/admin/src/future/utils/isEventFromWithin.d.ts +11 -0
  175. package/dist/admin/src/future/utils/itemLocations.d.ts +31 -0
  176. package/dist/admin/src/future/utils/itemSource.d.ts +22 -0
  177. package/dist/admin/translations/en.json.js +25 -4
  178. package/dist/admin/translations/en.json.js.map +1 -1
  179. package/dist/admin/translations/en.json.mjs +25 -4
  180. package/dist/admin/translations/en.json.mjs.map +1 -1
  181. package/dist/server/services/image-manipulation.js.map +1 -1
  182. package/dist/server/services/image-manipulation.mjs.map +1 -1
  183. package/dist/server/src/services/image-manipulation.d.ts +0 -5
  184. package/dist/server/src/services/image-manipulation.d.ts.map +1 -1
  185. package/package.json +9 -9
  186. package/dist/admin/future/pages/Assets/components/CreateFolderDialog.js.map +0 -1
  187. package/dist/admin/future/pages/Assets/components/CreateFolderDialog.mjs.map +0 -1
  188. package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.js +0 -33
  189. package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.js.map +0 -1
  190. package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.mjs +0 -31
  191. package/dist/admin/future/pages/Assets/components/FolderTree/filterFolderTree.mjs.map +0 -1
  192. package/dist/admin/src/future/pages/Assets/components/CreateFolderDialog.d.ts +0 -8
  193. package/dist/admin/src/future/pages/Assets/components/FolderTree/filterFolderTree.d.ts +0 -16
@@ -98,6 +98,9 @@ var en = {
98
98
  "upload.progress.maximize": "Maximize",
99
99
  "upload.progress.minimize": "Minimize",
100
100
  "upload.progress.close": "Close",
101
+ "beta.badge": "Beta",
102
+ "beta.notice.close": "Close",
103
+ "beta.notice.content": "This is a beta version of the Media Library. Some features are still in progress — please report any issue you run into.",
101
104
  "bulk.select.label": "Select all assets",
102
105
  "button.next": "Next",
103
106
  "new": "New",
@@ -114,6 +117,7 @@ var en = {
114
117
  "control-card.save-focal-point": "Save focal point",
115
118
  "control-card.download": "Download",
116
119
  "control-card.edit": "Edit",
120
+ "control-card.more-actions": "More actions",
117
121
  "control-card.remove-selection": "Remove from selection",
118
122
  "control-card.replace-media": "Replace Media",
119
123
  "control-card.save": "Save",
@@ -131,11 +135,16 @@ var en = {
131
135
  "header.actions.add-assets": "Add new assets",
132
136
  "header.actions.add-folder": "Add new folder",
133
137
  "folder.create.title": "New folder",
138
+ "folder.create.title-in": "New folder in {folderName}",
134
139
  "folder.form.name.label": "Folder name",
135
140
  "folder.create.submit": "Create folder",
136
141
  "folder.create.form.error.name-required": "Name is required",
137
142
  "folder.create.form.error.unknown": "An error occurred while creating the folder",
138
143
  "folder.create.success": "Folder has been created",
144
+ "folder.rename.title": "Rename folder",
145
+ "folder.rename.submit": "Save",
146
+ "folder.rename.form.error.unknown": "An error occurred while renaming the folder",
147
+ "folder.rename.success": "Folder has been renamed",
139
148
  "header.actions.add-assets.folder": "folder",
140
149
  "header.actions.upload-assets": "Upload assets",
141
150
  "header.actions.upload-new-asset": "Upload new asset",
@@ -221,8 +230,19 @@ var en = {
221
230
  "list.assets.preview-asset": "Preview for the video at path {path}",
222
231
  "list.assets.selected": "{numberFolders, plural, one {1 folder} other {# folders}} - {numberAssets, plural, one {1 asset} other {# assets}}",
223
232
  "list-assets-select": "Select {name} asset",
233
+ "list.assets.actions.replace": "Replace media",
234
+ "list.assets.actions.copy-link": "Copy link to media",
235
+ "list.assets.actions.download": "Download media",
236
+ "list.assets.actions.move": "Move to folder",
237
+ "list.assets.actions.delete": "Delete",
224
238
  "list.assets.type-not-allowed": "This type of file is not allowed.",
225
239
  "list.assets.to-upload": "{number, plural, =0 {No asset} one {1 asset} other {# assets}} ready to upload",
240
+ "list.folder.actions.copy-link": "Copy link to folder",
241
+ "list.folder.actions.copy-link.success": "Folder link copied.",
242
+ "list.folder.actions.copy-link.error": "Failed to copy the folder link.",
243
+ "list.folder.actions.rename": "Rename folder",
244
+ "list.folder.actions.move": "Move to folder",
245
+ "list.folder.actions.delete": "Delete folder",
226
246
  "list.folder.edit": "Edit folder",
227
247
  "list.folder.select": "Select {name} folder",
228
248
  "list.folder.subtitle": "{folderCount, plural, one {# folder} other {# folders}}, {filesCount, plural, one {# asset} other {# assets}}",
@@ -315,6 +335,7 @@ var en = {
315
335
  "list.table.header.sort": "Sort on {label}",
316
336
  "list.table.header.select-all": "Select all",
317
337
  "list.table.row.select": "Select {name}",
338
+ "list.table.row.metadata-missing": "This asset is missing metadata (caption or alternative text).",
318
339
  "list.table.content.empty-label": "This field is empty",
319
340
  "list.bulk-actions.label": "Bulk actions",
320
341
  "list.bulk-actions.selected-count": "{count, plural, =1 {# item selected} other {# items selected}}",
@@ -328,8 +349,11 @@ var en = {
328
349
  "list.bulk-actions.move": "Move",
329
350
  "list.bulk-actions.move.title": "Move elements to",
330
351
  "list.bulk-actions.move.location": "Location",
352
+ "list.bulk-actions.move.no-destination": "There is no other folder to move this to.",
353
+ "list.bulk-actions.move.load-error": "Couldn't load the folder list. Please try again.",
331
354
  "list.bulk-actions.move.submit": "Move",
332
355
  "list.bulk-actions.move.success": "{count, plural, =1 {# element has} other {# elements have}} been moved from {source} to {destination}",
356
+ "list.bulk-actions.move.success-multiple-sources": "{count, plural, =1 {# element has} other {# elements have}} been moved to {destination}",
333
357
  "list.bulk-actions.move.error": "An error occurred while moving the items.",
334
358
  "list.bulk-actions.delete": "Delete",
335
359
  "list.bulk-actions.delete.confirm.title": "Delete {count, plural, =1 {# item} other {# items}}?",
@@ -362,11 +386,8 @@ var en = {
362
386
  "sidebar.tree.expand": "Expand {name}",
363
387
  "sidebar.tree.collapse": "Collapse {name}",
364
388
  "sidebar.tree.empty": "No folders yet",
365
- "sidebar.tree.no-results": "No folders match \"{query}\"",
366
389
  "sidebar.tree.loading": "Loading folders...",
367
- "sidebar.tree.error": "Could not load folders.",
368
- "sidebar.search.label": "Search folders",
369
- "sidebar.search.placeholder": "Search folders"
390
+ "sidebar.tree.error": "Could not load folders."
370
391
  };
371
392
 
372
393
  export { en as default };
@@ -1 +1 @@
1
- {"version":3,"file":"en.json.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"en.json.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -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 {\n return true;\n }\n};\n\nconst isOptimizableImage = async (file: UploadableFile) => {\n let format;\n try {\n const metadata = await getMetadata(file);\n format = metadata.format;\n } catch {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_OPTIMIZE.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 {\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 {\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","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,OAAM;QACN,OAAO,IAAA;AACT,IAAA;AACF,CAAA;AAEA,MAAMC,qBAAqB,OAAOrE,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,OAAM;;QAEN,OAAO,KAAA;AACT,IAAA;IACA,OAAOA,MAAAA,IAAUF,mBAAAA,CAAoBI,QAAQ,CAACF,MAAAA,CAAAA;AAChD,CAAA;AAEA,MAAMqF,mBAAmB,OAAOtE,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,OAAM;;QAEN,OAAO,KAAA;AACT,IAAA;IACA,OAAOA,MAAAA,IAAUJ,iBAAAA,CAAkBM,QAAQ,CAACF,MAAAA,CAAAA;AAC9C,CAAA;AAEA,MAAMsF,UAAU,OAAOvE,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,OAAM;;QAEN,OAAO,KAAA;AACT,IAAA;IACA,OAAOA,MAAAA,IAAUH,kBAAAA,CAAmBK,QAAQ,CAACF,MAAAA,CAAAA;AAC/C,CAAA;AAEA,MAAMuF,mBAAmB,CAACzD,IAAAA,GAAAA;AACxB,IAAA,MAAM0D,eAAe,IAAMC,uBAAAA,CAAOC,WAAW,CAAC,CAAA,CAAA,CAAGC,QAAQ,CAAC,KAAA,CAAA;AAC1D,IAAA,MAAMC,QAAAA,GAAWC,aAAAA,CAAQC,UAAU,CAAChE,IAAAA,EAAM;QAAEiE,SAAAA,EAAW,GAAA;QAAKC,SAAAA,EAAW;AAAM,KAAA,CAAA;AAE7E,IAAA,OAAO,CAAA,EAAGJ,QAAAA,CAAS,CAAC,EAAEJ,YAAAA,EAAAA,CAAAA,CAAgB;AACxC,CAAA;AAEA,wBAAe;AACbN,IAAAA,aAAAA;AACAE,IAAAA,kBAAAA;AACAC,IAAAA,gBAAAA;AACAC,IAAAA,OAAAA;AACA/D,IAAAA,aAAAA;AACAgD,IAAAA,yBAAAA;AACArB,IAAAA,iBAAAA;AACAC,IAAAA,QAAAA;AACAoC,IAAAA;AACF,CAAA;;;;"}
1
+ {"version":3,"file":"image-manipulation.js","sources":["../../../server/src/services/image-manipulation.ts"],"sourcesContent":["import fs from 'fs';\nimport { join } from 'path';\nimport sharp, { type Metadata, type ResizeOptions } 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\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<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 ResizeOptions;\n\nconst resizeFileTo = async (\n file: UploadableFile,\n options: ResizeOptions,\n {\n name,\n hash,\n }: {\n name: string;\n hash: string;\n }\n) => {\n const filePath = file.tmpWorkingDirectory ? join(file.tmpWorkingDirectory, hash) : hash;\n\n let newInfo;\n if (!file.filepath) {\n const transform = sharp({ 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 {\n return true;\n }\n};\n\nconst isOptimizableImage = async (file: UploadableFile) => {\n let format;\n try {\n const metadata = await getMetadata(file);\n format = metadata.format;\n } catch {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_OPTIMIZE.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 {\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 {\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","isOptimizableImage","isResizableImage","isImage","generateFileName","randomSuffix","crypto","randomBytes","toString","baseName","strings","nameToSlug","separator","lowercase"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"image-manipulation.mjs","sources":["../../../server/src/services/image-manipulation.ts"],"sourcesContent":["import fs from 'fs';\nimport { join } from 'path';\nimport sharp 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 {\n return true;\n }\n};\n\nconst isOptimizableImage = async (file: UploadableFile) => {\n let format;\n try {\n const metadata = await getMetadata(file);\n format = metadata.format;\n } catch {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_OPTIMIZE.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 {\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 {\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","isOptimizableImage","isResizableImage","isImage","generateFileName","randomSuffix","crypto","randomBytes","toString","baseName","strings","nameToSlug","separator","lowercase"],"mappings":"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"}
1
+ {"version":3,"file":"image-manipulation.mjs","sources":["../../../server/src/services/image-manipulation.ts"],"sourcesContent":["import fs from 'fs';\nimport { join } from 'path';\nimport sharp, { type Metadata, type ResizeOptions } 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\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<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 ResizeOptions;\n\nconst resizeFileTo = async (\n file: UploadableFile,\n options: ResizeOptions,\n {\n name,\n hash,\n }: {\n name: string;\n hash: string;\n }\n) => {\n const filePath = file.tmpWorkingDirectory ? join(file.tmpWorkingDirectory, hash) : hash;\n\n let newInfo;\n if (!file.filepath) {\n const transform = sharp({ 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 {\n return true;\n }\n};\n\nconst isOptimizableImage = async (file: UploadableFile) => {\n let format;\n try {\n const metadata = await getMetadata(file);\n format = metadata.format;\n } catch {\n // throw when the file is not a supported image\n return false;\n }\n return format && FORMATS_TO_OPTIMIZE.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 {\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 {\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","isOptimizableImage","isResizableImage","isImage","generateFileName","randomSuffix","crypto","randomBytes","toString","baseName","strings","nameToSlug","separator","lowercase"],"mappings":"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"}
@@ -3,11 +3,6 @@ type Dimensions = {
3
3
  width: number | null;
4
4
  height: number | null;
5
5
  };
6
- declare module 'sharp' {
7
- interface OutputInfo {
8
- pageHeight?: number;
9
- }
10
- }
11
6
  declare const _default: {
12
7
  isFaultyImage: (file: UploadableFile) => Promise<unknown>;
13
8
  isOptimizableImage: (file: UploadableFile) => Promise<boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"image-manipulation.d.ts","sourceRoot":"","sources":["../../../../server/src/services/image-manipulation.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,KAAK,UAAU,GAAG;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAGF,OAAO,QAAQ,OAAO,CAAC;IACrB,UAAU,UAAU;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB;CACF;;0BA4OkC,cAAc;+BAiBT,cAAc;6BAYhB,cAAc;oBAYvB,cAAc;0BAlPR,cAAc,KAAG,OAAO,CAAC,UAAU,CAAC;sCAuJxB,cAAc;;;;8BA5FtB,cAAc;qBAqBvB,cAAc;6BA8KZ,MAAM;;AAOtC,wBAUE"}
1
+ {"version":3,"file":"image-manipulation.d.ts","sourceRoot":"","sources":["../../../../server/src/services/image-manipulation.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,KAAK,UAAU,GAAG;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;;0BA4OiC,cAAc;+BAiBT,cAAc;6BAYhB,cAAc;oBAYvB,cAAc;0BAlPR,cAAc,KAAG,OAAO,CAAC,UAAU,CAAC;sCAuJxB,cAAc;;;;8BA5FtB,cAAc;qBAqBvB,cAAc;6BA8KZ,MAAM;;AAOtC,wBAUE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi/upload",
3
- "version": "5.51.2",
3
+ "version": "5.52.0",
4
4
  "description": "Makes it easy to upload images and files to your Strapi Application.",
5
5
  "homepage": "https://strapi.io",
6
6
  "bugs": {
@@ -74,11 +74,11 @@
74
74
  "@radix-ui/react-dialog": "1.0.5",
75
75
  "@radix-ui/react-toggle-group": "1.1.11",
76
76
  "@reduxjs/toolkit": "1.9.7",
77
- "@strapi/database": "5.51.2",
78
- "@strapi/design-system": "2.2.3",
79
- "@strapi/icons": "2.2.3",
80
- "@strapi/provider-upload-local": "5.51.2",
81
- "@strapi/utils": "5.51.2",
77
+ "@strapi/database": "5.52.0",
78
+ "@strapi/design-system": "2.2.4",
79
+ "@strapi/icons": "2.2.4",
80
+ "@strapi/provider-upload-local": "5.52.0",
81
+ "@strapi/utils": "5.52.0",
82
82
  "byte-size": "8.1.1",
83
83
  "cropperjs": "1.6.2",
84
84
  "date-fns": "2.30.0",
@@ -97,13 +97,13 @@
97
97
  "react-query": "3.39.3",
98
98
  "react-redux": "8.1.3",
99
99
  "react-select": "5.8.0",
100
- "sharp": "0.34.5",
100
+ "sharp": "0.35.3",
101
101
  "yup": "0.32.9",
102
102
  "zod": "3.25.76"
103
103
  },
104
104
  "devDependencies": {
105
- "@strapi/admin": "5.51.2",
106
- "@strapi/types": "5.51.2",
105
+ "@strapi/admin": "5.52.0",
106
+ "@strapi/types": "5.52.0",
107
107
  "@testing-library/dom": "10.4.1",
108
108
  "@testing-library/jest-dom": "6.9.1",
109
109
  "@testing-library/react": "16.3.2",
@@ -1 +0,0 @@
1
- {"version":3,"file":"CreateFolderDialog.js","sources":["../../../../../../admin/src/future/pages/Assets/components/CreateFolderDialog.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\n\nimport { useNotification } from '@strapi/admin/strapi-admin';\nimport { Button, Field, Flex, Modal, TextInput } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport { useCreateFolderMutation } from '../../../services/folders';\nimport { getTranslationKey } from '../../../utils/translations';\n\ninterface CreateFolderDialogProps {\n open: boolean;\n folderName: string;\n parentFolderId: number | null;\n onClose: () => void;\n}\n\nconst StyledModalContent = styled(Modal.Content)`\n max-width: 51.6rem;\n`;\n\nexport const CreateFolderDialog = ({\n open,\n folderName,\n parentFolderId,\n onClose,\n}: CreateFolderDialogProps) => {\n const { formatMessage } = useIntl();\n const { toggleNotification } = useNotification();\n const [name, setName] = useState('');\n const [fieldError, setFieldError] = useState<string | undefined>();\n const [createFolder, { isLoading }] = useCreateFolderMutation();\n\n useEffect(() => {\n if (open) {\n setName('');\n setFieldError(undefined);\n }\n }, [open]);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n const trimmedName = name.trim();\n\n if (!trimmedName) {\n setFieldError(\n formatMessage({\n id: getTranslationKey('folder.create.form.error.name-required'),\n defaultMessage: 'Name is required',\n })\n );\n return;\n }\n\n try {\n await createFolder({ name: trimmedName, parent: parentFolderId }).unwrap();\n\n toggleNotification({\n type: 'success',\n message: formatMessage({\n id: getTranslationKey('folder.create.success'),\n defaultMessage: 'Folder has been created',\n }),\n });\n\n onClose();\n } catch (err) {\n const apiError = err as { message?: string };\n\n if (apiError?.message) {\n setFieldError(apiError.message);\n } else {\n toggleNotification({\n type: 'danger',\n message: formatMessage({\n id: getTranslationKey('folder.create.form.error.unknown'),\n defaultMessage: 'An error occurred while creating the folder',\n }),\n });\n }\n }\n };\n\n return (\n <Modal.Root open={open} onOpenChange={onClose}>\n <StyledModalContent>\n <Modal.Header>\n <Modal.Title>\n {formatMessage(\n {\n id: getTranslationKey('folder.create.title-in'),\n defaultMessage: 'New folder in {folderName}',\n },\n { folderName }\n )}\n </Modal.Title>\n </Modal.Header>\n <form onSubmit={handleSubmit}>\n <Modal.Body>\n <Field.Root error={fieldError} name=\"name\" required>\n <Field.Label>\n {formatMessage({\n id: getTranslationKey('folder.form.name.label'),\n defaultMessage: 'Folder name',\n })}\n </Field.Label>\n <TextInput\n value={name}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n setName(e.target.value);\n setFieldError(undefined);\n }}\n autoFocus\n />\n <Field.Error />\n </Field.Root>\n </Modal.Body>\n <Modal.Footer>\n <Flex gap={2} justifyContent=\"space-between\" width=\"100%\">\n <Button variant=\"tertiary\" onClick={onClose} type=\"button\">\n {formatMessage({ id: 'app.components.Button.cancel', defaultMessage: 'Cancel' })}\n </Button>\n <Button type=\"submit\" loading={isLoading}>\n {formatMessage({\n id: getTranslationKey('folder.create.submit'),\n defaultMessage: 'Create folder',\n })}\n </Button>\n </Flex>\n </Modal.Footer>\n </form>\n </StyledModalContent>\n </Modal.Root>\n );\n};\n"],"names":["StyledModalContent","styled","Modal","Content","CreateFolderDialog","open","folderName","parentFolderId","onClose","formatMessage","useIntl","toggleNotification","useNotification","name","setName","useState","fieldError","setFieldError","createFolder","isLoading","useCreateFolderMutation","useEffect","undefined","handleSubmit","e","preventDefault","trimmedName","trim","id","getTranslationKey","defaultMessage","parent","unwrap","type","message","err","apiError","_jsx","Root","onOpenChange","_jsxs","Header","Title","form","onSubmit","Body","Field","error","required","Label","TextInput","value","onChange","target","autoFocus","Error","Footer","Flex","gap","justifyContent","width","Button","variant","onClick","loading"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"CreateFolderDialog.mjs","sources":["../../../../../../admin/src/future/pages/Assets/components/CreateFolderDialog.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\n\nimport { useNotification } from '@strapi/admin/strapi-admin';\nimport { Button, Field, Flex, Modal, TextInput } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport { useCreateFolderMutation } from '../../../services/folders';\nimport { getTranslationKey } from '../../../utils/translations';\n\ninterface CreateFolderDialogProps {\n open: boolean;\n folderName: string;\n parentFolderId: number | null;\n onClose: () => void;\n}\n\nconst StyledModalContent = styled(Modal.Content)`\n max-width: 51.6rem;\n`;\n\nexport const CreateFolderDialog = ({\n open,\n folderName,\n parentFolderId,\n onClose,\n}: CreateFolderDialogProps) => {\n const { formatMessage } = useIntl();\n const { toggleNotification } = useNotification();\n const [name, setName] = useState('');\n const [fieldError, setFieldError] = useState<string | undefined>();\n const [createFolder, { isLoading }] = useCreateFolderMutation();\n\n useEffect(() => {\n if (open) {\n setName('');\n setFieldError(undefined);\n }\n }, [open]);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n const trimmedName = name.trim();\n\n if (!trimmedName) {\n setFieldError(\n formatMessage({\n id: getTranslationKey('folder.create.form.error.name-required'),\n defaultMessage: 'Name is required',\n })\n );\n return;\n }\n\n try {\n await createFolder({ name: trimmedName, parent: parentFolderId }).unwrap();\n\n toggleNotification({\n type: 'success',\n message: formatMessage({\n id: getTranslationKey('folder.create.success'),\n defaultMessage: 'Folder has been created',\n }),\n });\n\n onClose();\n } catch (err) {\n const apiError = err as { message?: string };\n\n if (apiError?.message) {\n setFieldError(apiError.message);\n } else {\n toggleNotification({\n type: 'danger',\n message: formatMessage({\n id: getTranslationKey('folder.create.form.error.unknown'),\n defaultMessage: 'An error occurred while creating the folder',\n }),\n });\n }\n }\n };\n\n return (\n <Modal.Root open={open} onOpenChange={onClose}>\n <StyledModalContent>\n <Modal.Header>\n <Modal.Title>\n {formatMessage(\n {\n id: getTranslationKey('folder.create.title-in'),\n defaultMessage: 'New folder in {folderName}',\n },\n { folderName }\n )}\n </Modal.Title>\n </Modal.Header>\n <form onSubmit={handleSubmit}>\n <Modal.Body>\n <Field.Root error={fieldError} name=\"name\" required>\n <Field.Label>\n {formatMessage({\n id: getTranslationKey('folder.form.name.label'),\n defaultMessage: 'Folder name',\n })}\n </Field.Label>\n <TextInput\n value={name}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) => {\n setName(e.target.value);\n setFieldError(undefined);\n }}\n autoFocus\n />\n <Field.Error />\n </Field.Root>\n </Modal.Body>\n <Modal.Footer>\n <Flex gap={2} justifyContent=\"space-between\" width=\"100%\">\n <Button variant=\"tertiary\" onClick={onClose} type=\"button\">\n {formatMessage({ id: 'app.components.Button.cancel', defaultMessage: 'Cancel' })}\n </Button>\n <Button type=\"submit\" loading={isLoading}>\n {formatMessage({\n id: getTranslationKey('folder.create.submit'),\n defaultMessage: 'Create folder',\n })}\n </Button>\n </Flex>\n </Modal.Footer>\n </form>\n </StyledModalContent>\n </Modal.Root>\n );\n};\n"],"names":["StyledModalContent","styled","Modal","Content","CreateFolderDialog","open","folderName","parentFolderId","onClose","formatMessage","useIntl","toggleNotification","useNotification","name","setName","useState","fieldError","setFieldError","createFolder","isLoading","useCreateFolderMutation","useEffect","undefined","handleSubmit","e","preventDefault","trimmedName","trim","id","getTranslationKey","defaultMessage","parent","unwrap","type","message","err","apiError","_jsx","Root","onOpenChange","_jsxs","Header","Title","form","onSubmit","Body","Field","error","required","Label","TextInput","value","onChange","target","autoFocus","Error","Footer","Flex","gap","justifyContent","width","Button","variant","onClick","loading"],"mappings":";;;;;;;;;AAiBA,MAAMA,kBAAAA,GAAqBC,MAAAA,CAAOC,KAAAA,CAAMC,OAAO,CAAC;;AAEhD,CAAC;AAEM,MAAMC,kBAAAA,GAAqB,CAAC,EACjCC,IAAI,EACJC,UAAU,EACVC,cAAc,EACdC,OAAO,EACiB,GAAA;IACxB,MAAM,EAAEC,aAAa,EAAE,GAAGC,OAAAA,EAAAA;IAC1B,MAAM,EAAEC,kBAAkB,EAAE,GAAGC,eAAAA,EAAAA;AAC/B,IAAA,MAAM,CAACC,IAAAA,EAAMC,OAAAA,CAAQ,GAAGC,QAAAA,CAAS,EAAA,CAAA;IACjC,MAAM,CAACC,UAAAA,EAAYC,aAAAA,CAAc,GAAGF,QAAAA,EAAAA;AACpC,IAAA,MAAM,CAACG,YAAAA,EAAc,EAAEC,SAAS,EAAE,CAAC,GAAGC,uBAAAA,EAAAA;IAEtCC,SAAAA,CAAU,IAAA;AACR,QAAA,IAAIhB,IAAAA,EAAM;YACRS,OAAAA,CAAQ,EAAA,CAAA;YACRG,aAAAA,CAAcK,SAAAA,CAAAA;AAChB,QAAA;IACF,CAAA,EAAG;AAACjB,QAAAA;AAAK,KAAA,CAAA;AAET,IAAA,MAAMkB,eAAe,OAAOC,CAAAA,GAAAA;AAC1BA,QAAAA,CAAAA,CAAEC,cAAc,EAAA;QAEhB,MAAMC,WAAAA,GAAcb,KAAKc,IAAI,EAAA;AAE7B,QAAA,IAAI,CAACD,WAAAA,EAAa;AAChBT,YAAAA,aAAAA,CACER,aAAAA,CAAc;AACZmB,gBAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,wCAAA,CAAA;gBACtBC,cAAAA,EAAgB;AAClB,aAAA,CAAA,CAAA;AAEF,YAAA;AACF,QAAA;QAEA,IAAI;AACF,YAAA,MAAMZ,YAAAA,CAAa;gBAAEL,IAAAA,EAAMa,WAAAA;gBAAaK,MAAAA,EAAQxB;AAAe,aAAA,CAAA,CAAGyB,MAAM,EAAA;YAExErB,kBAAAA,CAAmB;gBACjBsB,IAAAA,EAAM,SAAA;AACNC,gBAAAA,OAAAA,EAASzB,aAAAA,CAAc;AACrBmB,oBAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,uBAAA,CAAA;oBACtBC,cAAAA,EAAgB;AAClB,iBAAA;AACF,aAAA,CAAA;AAEAtB,YAAAA,OAAAA,EAAAA;AACF,QAAA,CAAA,CAAE,OAAO2B,GAAAA,EAAK;AACZ,YAAA,MAAMC,QAAAA,GAAWD,GAAAA;AAEjB,YAAA,IAAIC,UAAUF,OAAAA,EAAS;AACrBjB,gBAAAA,aAAAA,CAAcmB,SAASF,OAAO,CAAA;YAChC,CAAA,MAAO;gBACLvB,kBAAAA,CAAmB;oBACjBsB,IAAAA,EAAM,QAAA;AACNC,oBAAAA,OAAAA,EAASzB,aAAAA,CAAc;AACrBmB,wBAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,kCAAA,CAAA;wBACtBC,cAAAA,EAAgB;AAClB,qBAAA;AACF,iBAAA,CAAA;AACF,YAAA;AACF,QAAA;AACF,IAAA,CAAA;IAEA,qBACEO,GAAA,CAACnC,MAAMoC,IAAI,EAAA;QAACjC,IAAAA,EAAMA,IAAAA;QAAMkC,YAAAA,EAAc/B,OAAAA;AACpC,QAAA,QAAA,gBAAAgC,IAAA,CAACxC,kBAAAA,EAAAA;;AACC,8BAAAqC,GAAA,CAACnC,MAAMuC,MAAM,EAAA;4CACXJ,GAAA,CAACnC,MAAMwC,KAAK,EAAA;kCACTjC,aAAAA,CACC;AACEmB,4BAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,wBAAA,CAAA;4BACtBC,cAAAA,EAAgB;yBAClB,EACA;AAAExB,4BAAAA;AAAW,yBAAA;;;8BAInBkC,IAAA,CAACG,MAAAA,EAAAA;oBAAKC,QAAAA,EAAUrB,YAAAA;;AACd,sCAAAc,GAAA,CAACnC,MAAM2C,IAAI,EAAA;oDACTL,IAAA,CAACM,MAAMR,IAAI,EAAA;gCAACS,KAAAA,EAAO/B,UAAAA;gCAAYH,IAAAA,EAAK,MAAA;gCAAOmC,QAAQ,EAAA,IAAA;;AACjD,kDAAAX,GAAA,CAACS,MAAMG,KAAK,EAAA;kDACTxC,aAAAA,CAAc;AACbmB,4CAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,wBAAA,CAAA;4CACtBC,cAAAA,EAAgB;AAClB,yCAAA;;kDAEFO,GAAA,CAACa,SAAAA,EAAAA;wCACCC,KAAAA,EAAOtC,IAAAA;AACPuC,wCAAAA,QAAAA,EAAU,CAAC5B,CAAAA,GAAAA;4CACTV,OAAAA,CAAQU,CAAAA,CAAE6B,MAAM,CAACF,KAAK,CAAA;4CACtBlC,aAAAA,CAAcK,SAAAA,CAAAA;AAChB,wCAAA,CAAA;wCACAgC,SAAS,EAAA;;AAEX,kDAAAjB,GAAA,CAACS,MAAMS,KAAK,EAAA,EAAA;;;;AAGhB,sCAAAlB,GAAA,CAACnC,MAAMsD,MAAM,EAAA;AACX,4BAAA,QAAA,gBAAAhB,IAAA,CAACiB,IAAAA,EAAAA;gCAAKC,GAAAA,EAAK,CAAA;gCAAGC,cAAAA,EAAe,eAAA;gCAAgBC,KAAAA,EAAM,MAAA;;kDACjDvB,GAAA,CAACwB,MAAAA,EAAAA;wCAAOC,OAAAA,EAAQ,UAAA;wCAAWC,OAAAA,EAASvD,OAAAA;wCAASyB,IAAAA,EAAK,QAAA;kDAC/CxB,aAAAA,CAAc;4CAAEmB,EAAAA,EAAI,8BAAA;4CAAgCE,cAAAA,EAAgB;AAAS,yCAAA;;kDAEhFO,GAAA,CAACwB,MAAAA,EAAAA;wCAAO5B,IAAAA,EAAK,QAAA;wCAAS+B,OAAAA,EAAS7C,SAAAA;kDAC5BV,aAAAA,CAAc;AACbmB,4CAAAA,EAAAA,EAAIC,iBAAAA,CAAkB,sBAAA,CAAA;4CACtBC,cAAAA,EAAgB;AAClB,yCAAA;;;;;;;;;;AAQhB;;;;"}
@@ -1,33 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * Prunes the folder tree to nodes that match, or that have a matching
5
- * descendant, so a match deep in the hierarchy stays reachable with its ancestor
6
- * chain intact.
7
- */ const filterFolderTree = (nodes, matches)=>{
8
- const expandedIds = [];
9
- const prune = (candidates)=>candidates.reduce((retained, node)=>{
10
- const retainedChildren = prune(node.children ?? []);
11
- const isMatch = matches(node.name ?? '');
12
- if (!isMatch && retainedChildren.length === 0) {
13
- return retained;
14
- }
15
- // Only nodes kept for a descendant's sake need force-expanding; a leaf
16
- // match has nothing to reveal.
17
- if (retainedChildren.length > 0 && node.id != null) {
18
- expandedIds.push(node.id);
19
- }
20
- retained.push({
21
- ...node,
22
- children: retainedChildren
23
- });
24
- return retained;
25
- }, []);
26
- return {
27
- nodes: prune(nodes),
28
- expandedIds
29
- };
30
- };
31
-
32
- exports.filterFolderTree = filterFolderTree;
33
- //# sourceMappingURL=filterFolderTree.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"filterFolderTree.js","sources":["../../../../../../../admin/src/future/pages/Assets/components/FolderTree/filterFolderTree.ts"],"sourcesContent":["import type { FolderNode } from '../../../../../../../shared/contracts/folders';\n\ninterface FilterFolderTreeResult {\n nodes: FolderNode[];\n /**\n * Ancestors of a match, which have to be expanded for the match to be\n * reachable.\n */\n expandedIds: number[];\n}\n\n/**\n * Prunes the folder tree to nodes that match, or that have a matching\n * descendant, so a match deep in the hierarchy stays reachable with its ancestor\n * chain intact.\n */\nexport const filterFolderTree = (\n nodes: FolderNode[],\n matches: (name: string) => boolean\n): FilterFolderTreeResult => {\n const expandedIds: number[] = [];\n\n const prune = (candidates: FolderNode[]): FolderNode[] =>\n candidates.reduce<FolderNode[]>((retained, node) => {\n const retainedChildren = prune(node.children ?? []);\n const isMatch = matches(node.name ?? '');\n\n if (!isMatch && retainedChildren.length === 0) {\n return retained;\n }\n\n // Only nodes kept for a descendant's sake need force-expanding; a leaf\n // match has nothing to reveal.\n if (retainedChildren.length > 0 && node.id != null) {\n expandedIds.push(node.id);\n }\n\n retained.push({ ...node, children: retainedChildren });\n\n return retained;\n }, []);\n\n return { nodes: prune(nodes), expandedIds };\n};\n"],"names":["filterFolderTree","nodes","matches","expandedIds","prune","candidates","reduce","retained","node","retainedChildren","children","isMatch","name","length","id","push"],"mappings":";;AAWA;;;;AAIC,IACM,MAAMA,gBAAAA,GAAmB,CAC9BC,KAAAA,EACAC,OAAAA,GAAAA;AAEA,IAAA,MAAMC,cAAwB,EAAE;AAEhC,IAAA,MAAMC,QAAQ,CAACC,UAAAA,GACbA,WAAWC,MAAM,CAAe,CAACC,QAAAA,EAAUC,IAAAA,GAAAA;AACzC,YAAA,MAAMC,gBAAAA,GAAmBL,KAAAA,CAAMI,IAAAA,CAAKE,QAAQ,IAAI,EAAE,CAAA;AAClD,YAAA,MAAMC,OAAAA,GAAUT,OAAAA,CAAQM,IAAAA,CAAKI,IAAI,IAAI,EAAA,CAAA;AAErC,YAAA,IAAI,CAACD,OAAAA,IAAWF,gBAAAA,CAAiBI,MAAM,KAAK,CAAA,EAAG;gBAC7C,OAAON,QAAAA;AACT,YAAA;;;AAIA,YAAA,IAAIE,iBAAiBI,MAAM,GAAG,KAAKL,IAAAA,CAAKM,EAAE,IAAI,IAAA,EAAM;gBAClDX,WAAAA,CAAYY,IAAI,CAACP,IAAAA,CAAKM,EAAE,CAAA;AAC1B,YAAA;AAEAP,YAAAA,QAAAA,CAASQ,IAAI,CAAC;AAAE,gBAAA,GAAGP,IAAI;gBAAEE,QAAAA,EAAUD;AAAiB,aAAA,CAAA;YAEpD,OAAOF,QAAAA;AACT,QAAA,CAAA,EAAG,EAAE,CAAA;IAEP,OAAO;AAAEN,QAAAA,KAAAA,EAAOG,KAAAA,CAAMH,KAAAA,CAAAA;AAAQE,QAAAA;AAAY,KAAA;AAC5C;;;;"}
@@ -1,31 +0,0 @@
1
- /**
2
- * Prunes the folder tree to nodes that match, or that have a matching
3
- * descendant, so a match deep in the hierarchy stays reachable with its ancestor
4
- * chain intact.
5
- */ const filterFolderTree = (nodes, matches)=>{
6
- const expandedIds = [];
7
- const prune = (candidates)=>candidates.reduce((retained, node)=>{
8
- const retainedChildren = prune(node.children ?? []);
9
- const isMatch = matches(node.name ?? '');
10
- if (!isMatch && retainedChildren.length === 0) {
11
- return retained;
12
- }
13
- // Only nodes kept for a descendant's sake need force-expanding; a leaf
14
- // match has nothing to reveal.
15
- if (retainedChildren.length > 0 && node.id != null) {
16
- expandedIds.push(node.id);
17
- }
18
- retained.push({
19
- ...node,
20
- children: retainedChildren
21
- });
22
- return retained;
23
- }, []);
24
- return {
25
- nodes: prune(nodes),
26
- expandedIds
27
- };
28
- };
29
-
30
- export { filterFolderTree };
31
- //# sourceMappingURL=filterFolderTree.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"filterFolderTree.mjs","sources":["../../../../../../../admin/src/future/pages/Assets/components/FolderTree/filterFolderTree.ts"],"sourcesContent":["import type { FolderNode } from '../../../../../../../shared/contracts/folders';\n\ninterface FilterFolderTreeResult {\n nodes: FolderNode[];\n /**\n * Ancestors of a match, which have to be expanded for the match to be\n * reachable.\n */\n expandedIds: number[];\n}\n\n/**\n * Prunes the folder tree to nodes that match, or that have a matching\n * descendant, so a match deep in the hierarchy stays reachable with its ancestor\n * chain intact.\n */\nexport const filterFolderTree = (\n nodes: FolderNode[],\n matches: (name: string) => boolean\n): FilterFolderTreeResult => {\n const expandedIds: number[] = [];\n\n const prune = (candidates: FolderNode[]): FolderNode[] =>\n candidates.reduce<FolderNode[]>((retained, node) => {\n const retainedChildren = prune(node.children ?? []);\n const isMatch = matches(node.name ?? '');\n\n if (!isMatch && retainedChildren.length === 0) {\n return retained;\n }\n\n // Only nodes kept for a descendant's sake need force-expanding; a leaf\n // match has nothing to reveal.\n if (retainedChildren.length > 0 && node.id != null) {\n expandedIds.push(node.id);\n }\n\n retained.push({ ...node, children: retainedChildren });\n\n return retained;\n }, []);\n\n return { nodes: prune(nodes), expandedIds };\n};\n"],"names":["filterFolderTree","nodes","matches","expandedIds","prune","candidates","reduce","retained","node","retainedChildren","children","isMatch","name","length","id","push"],"mappings":"AAWA;;;;AAIC,IACM,MAAMA,gBAAAA,GAAmB,CAC9BC,KAAAA,EACAC,OAAAA,GAAAA;AAEA,IAAA,MAAMC,cAAwB,EAAE;AAEhC,IAAA,MAAMC,QAAQ,CAACC,UAAAA,GACbA,WAAWC,MAAM,CAAe,CAACC,QAAAA,EAAUC,IAAAA,GAAAA;AACzC,YAAA,MAAMC,gBAAAA,GAAmBL,KAAAA,CAAMI,IAAAA,CAAKE,QAAQ,IAAI,EAAE,CAAA;AAClD,YAAA,MAAMC,OAAAA,GAAUT,OAAAA,CAAQM,IAAAA,CAAKI,IAAI,IAAI,EAAA,CAAA;AAErC,YAAA,IAAI,CAACD,OAAAA,IAAWF,gBAAAA,CAAiBI,MAAM,KAAK,CAAA,EAAG;gBAC7C,OAAON,QAAAA;AACT,YAAA;;;AAIA,YAAA,IAAIE,iBAAiBI,MAAM,GAAG,KAAKL,IAAAA,CAAKM,EAAE,IAAI,IAAA,EAAM;gBAClDX,WAAAA,CAAYY,IAAI,CAACP,IAAAA,CAAKM,EAAE,CAAA;AAC1B,YAAA;AAEAP,YAAAA,QAAAA,CAASQ,IAAI,CAAC;AAAE,gBAAA,GAAGP,IAAI;gBAAEE,QAAAA,EAAUD;AAAiB,aAAA,CAAA;YAEpD,OAAOF,QAAAA;AACT,QAAA,CAAA,EAAG,EAAE,CAAA;IAEP,OAAO;AAAEN,QAAAA,KAAAA,EAAOG,KAAAA,CAAMH,KAAAA,CAAAA;AAAQE,QAAAA;AAAY,KAAA;AAC5C;;;;"}
@@ -1,8 +0,0 @@
1
- interface CreateFolderDialogProps {
2
- open: boolean;
3
- folderName: string;
4
- parentFolderId: number | null;
5
- onClose: () => void;
6
- }
7
- export declare const CreateFolderDialog: ({ open, folderName, parentFolderId, onClose, }: CreateFolderDialogProps) => import("react/jsx-runtime").JSX.Element;
8
- export {};
@@ -1,16 +0,0 @@
1
- import type { FolderNode } from '../../../../../../../shared/contracts/folders';
2
- interface FilterFolderTreeResult {
3
- nodes: FolderNode[];
4
- /**
5
- * Ancestors of a match, which have to be expanded for the match to be
6
- * reachable.
7
- */
8
- expandedIds: number[];
9
- }
10
- /**
11
- * Prunes the folder tree to nodes that match, or that have a matching
12
- * descendant, so a match deep in the hierarchy stays reachable with its ancestor
13
- * chain intact.
14
- */
15
- export declare const filterFolderTree: (nodes: FolderNode[], matches: (name: string) => boolean) => FilterFolderTreeResult;
16
- export {};