@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.
- package/dist/admin/ai/components/AIAssetCard.js +3 -2
- package/dist/admin/ai/components/AIAssetCard.js.map +1 -1
- package/dist/admin/ai/components/AIUploadModal.js +3 -2
- package/dist/admin/ai/components/AIUploadModal.js.map +1 -1
- package/dist/admin/components/AssetCard/UploadingAssetCard.js +3 -2
- package/dist/admin/components/AssetCard/UploadingAssetCard.js.map +1 -1
- package/dist/admin/components/AssetCard/VideoAssetCard.js +3 -2
- package/dist/admin/components/AssetCard/VideoAssetCard.js.map +1 -1
- package/dist/admin/components/AssetDialog/AssetDialog.js +3 -2
- package/dist/admin/components/AssetDialog/AssetDialog.js.map +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/Filters.js +3 -2
- package/dist/admin/components/AssetDialog/BrowseStep/Filters.js.map +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/PaginationFooter/Pagination.js +3 -2
- package/dist/admin/components/AssetDialog/BrowseStep/PaginationFooter/Pagination.js.map +1 -1
- package/dist/admin/components/AssetDialog/BrowseStep/SearchAsset/SearchAsset.js +3 -2
- package/dist/admin/components/AssetDialog/BrowseStep/SearchAsset/SearchAsset.js.map +1 -1
- package/dist/admin/components/AssetGridList/Draggable.js +3 -2
- package/dist/admin/components/AssetGridList/Draggable.js.map +1 -1
- package/dist/admin/components/Breadcrumbs/CrumbSimpleMenuAsync.js +3 -2
- package/dist/admin/components/Breadcrumbs/CrumbSimpleMenuAsync.js.map +1 -1
- package/dist/admin/components/BulkMoveDialog/BulkMoveDialog.js +5 -1
- package/dist/admin/components/BulkMoveDialog/BulkMoveDialog.js.map +1 -1
- package/dist/admin/components/EditAssetDialog/EditAssetContent.js +8 -4
- package/dist/admin/components/EditAssetDialog/EditAssetContent.js.map +1 -1
- package/dist/admin/components/EditAssetDialog/PreviewBox/AssetPreview.js +7 -3
- package/dist/admin/components/EditAssetDialog/PreviewBox/AssetPreview.js.map +1 -1
- package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.js +7 -3
- package/dist/admin/components/EditAssetDialog/PreviewBox/PreviewBox.js.map +1 -1
- package/dist/admin/components/EditAssetDialog/ReplaceMediaButton.js +3 -2
- package/dist/admin/components/EditAssetDialog/ReplaceMediaButton.js.map +1 -1
- package/dist/admin/components/EditFolderDialog/EditFolderDialog.js +8 -4
- package/dist/admin/components/EditFolderDialog/EditFolderDialog.js.map +1 -1
- package/dist/admin/components/FilterPopover/FilterPopover.js +3 -2
- package/dist/admin/components/FilterPopover/FilterPopover.js.map +1 -1
- package/dist/admin/components/FolderCard/FolderCard/FolderCard.js +3 -2
- package/dist/admin/components/FolderCard/FolderCard/FolderCard.js.map +1 -1
- package/dist/admin/components/MediaLibraryDialog/MediaLibraryDialog.js +5 -3
- package/dist/admin/components/MediaLibraryDialog/MediaLibraryDialog.js.map +1 -1
- package/dist/admin/components/MediaLibraryDialog/MediaLibraryDialog.mjs +2 -1
- package/dist/admin/components/MediaLibraryDialog/MediaLibraryDialog.mjs.map +1 -1
- package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAssets.js +3 -2
- package/dist/admin/components/MediaLibraryInput/Carousel/CarouselAssets.js.map +1 -1
- package/dist/admin/components/MediaLibraryInput/Carousel/EmptyStateAsset.js +3 -2
- package/dist/admin/components/MediaLibraryInput/Carousel/EmptyStateAsset.js.map +1 -1
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js +3 -2
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js.map +1 -1
- package/dist/admin/components/SelectTree/SelectTree.js +7 -3
- package/dist/admin/components/SelectTree/SelectTree.js.map +1 -1
- package/dist/admin/components/TableList/CellContent.js +5 -1
- package/dist/admin/components/TableList/CellContent.js.map +1 -1
- package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromComputerForm.js +3 -2
- package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromComputerForm.js.map +1 -1
- package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromUrlForm.js +3 -2
- package/dist/admin/components/UploadAssetDialog/AddAssetStep/FromUrlForm.js.map +1 -1
- package/dist/admin/components/UploadAssetDialog/PendingAssetStep/PendingAssetStep.js +3 -2
- package/dist/admin/components/UploadAssetDialog/PendingAssetStep/PendingAssetStep.js.map +1 -1
- package/dist/admin/components/UploadAssetDialog/UploadAssetDialog.js +3 -2
- package/dist/admin/components/UploadAssetDialog/UploadAssetDialog.js.map +1 -1
- package/dist/admin/future/components/Drawer.js +4 -3
- package/dist/admin/future/components/Drawer.js.map +1 -1
- package/dist/admin/future/pages/Assets/AssetsPage.js +29 -4
- package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
- package/dist/admin/future/pages/Assets/AssetsPage.mjs +28 -4
- package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +3 -2
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.js +3 -2
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetPreview.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZone.js +3 -2
- package/dist/admin/future/pages/Assets/components/DropZone/UploadDropZone.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js +389 -0
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js.map +1 -0
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs +387 -0
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/components/ImportFromUrlDialog.js +3 -2
- package/dist/admin/future/pages/Assets/components/ImportFromUrlDialog.js.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useFolderInfo.js +4 -4
- package/dist/admin/future/pages/Assets/hooks/useFolderInfo.js.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useFolderInfo.mjs +4 -4
- package/dist/admin/future/pages/Assets/hooks/useFolderInfo.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.js +48 -2
- package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.js.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.mjs +48 -2
- package/dist/admin/future/pages/Assets/hooks/useFolderNavigation.mjs.map +1 -1
- package/dist/admin/future/services/folders.js +28 -1
- package/dist/admin/future/services/folders.js.map +1 -1
- package/dist/admin/future/services/folders.mjs +28 -2
- package/dist/admin/future/services/folders.mjs.map +1 -1
- package/dist/admin/future/utils/files.js +5 -1
- package/dist/admin/future/utils/files.js.map +1 -1
- package/dist/admin/hooks/useAIMetadataJob.js +3 -2
- package/dist/admin/hooks/useAIMetadataJob.js.map +1 -1
- package/dist/admin/hooks/useAssets.js +3 -2
- package/dist/admin/hooks/useAssets.js.map +1 -1
- package/dist/admin/hooks/useCropImg.js +7 -3
- package/dist/admin/hooks/useCropImg.js.map +1 -1
- package/dist/admin/hooks/useEditAsset.js +3 -2
- package/dist/admin/hooks/useEditAsset.js.map +1 -1
- package/dist/admin/hooks/useFolders.js +3 -2
- package/dist/admin/hooks/useFolders.js.map +1 -1
- package/dist/admin/hooks/useModalQueryParams.js +3 -2
- package/dist/admin/hooks/useModalQueryParams.js.map +1 -1
- package/dist/admin/hooks/useSelectionState.js +3 -2
- package/dist/admin/hooks/useSelectionState.js.map +1 -1
- package/dist/admin/hooks/useUpload.js +3 -2
- package/dist/admin/hooks/useUpload.js.map +1 -1
- package/dist/admin/pages/App/App.js +3 -2
- package/dist/admin/pages/App/App.js.map +1 -1
- package/dist/admin/pages/App/ConfigureTheView/ConfigureTheView.js +7 -3
- package/dist/admin/pages/App/ConfigureTheView/ConfigureTheView.js.map +1 -1
- package/dist/admin/pages/App/ConfigureTheView/state/reducer.js +7 -2
- package/dist/admin/pages/App/ConfigureTheView/state/reducer.js.map +1 -1
- package/dist/admin/pages/App/MediaLibrary.js +3 -2
- package/dist/admin/pages/App/MediaLibrary.js.map +1 -1
- package/dist/admin/pages/App/components/BulkMoveButton.js +3 -2
- package/dist/admin/pages/App/components/BulkMoveButton.js.map +1 -1
- package/dist/admin/pages/App/components/Filters.js +3 -2
- package/dist/admin/pages/App/components/Filters.js.map +1 -1
- package/dist/admin/pages/SettingsPage/SettingsPage.js +7 -3
- package/dist/admin/pages/SettingsPage/SettingsPage.js.map +1 -1
- package/dist/admin/pages/SettingsPage/reducer.js +5 -1
- package/dist/admin/pages/SettingsPage/reducer.js.map +1 -1
- package/dist/admin/src/components/MediaLibraryDialog/MediaLibraryDialog.d.ts +2 -1
- package/dist/admin/src/future/pages/Assets/components/FolderTree/FolderTree.d.ts +19 -0
- package/dist/admin/src/future/pages/Assets/hooks/useFolderNavigation.d.ts +2 -0
- package/dist/admin/src/future/services/folders.d.ts +2 -2
- package/dist/admin/translations/en.json.js +10 -1
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +10 -1
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/admin/utils/formatBytes.js +5 -1
- package/dist/admin/utils/formatBytes.js.map +1 -1
- package/dist/admin/utils/urlYupSchema.js +3 -2
- package/dist/admin/utils/urlYupSchema.js.map +1 -1
- package/dist/server/controllers/admin-upload.js +11 -4
- package/dist/server/controllers/admin-upload.js.map +1 -1
- package/dist/server/controllers/content-api.js +19 -2
- package/dist/server/controllers/content-api.js.map +1 -1
- package/dist/server/controllers/content-api.mjs +12 -0
- package/dist/server/controllers/content-api.mjs.map +1 -1
- package/dist/server/controllers/utils/find-entity-and-check-permissions.js +7 -3
- package/dist/server/controllers/utils/find-entity-and-check-permissions.js.map +1 -1
- package/dist/server/middlewares/upload.js +7 -2
- package/dist/server/middlewares/upload.js.map +1 -1
- package/dist/server/register.js +9 -4
- package/dist/server/register.js.map +1 -1
- package/dist/server/routes/content-api.js +18 -2
- package/dist/server/routes/content-api.js.map +1 -1
- package/dist/server/routes/content-api.mjs +15 -0
- package/dist/server/routes/content-api.mjs.map +1 -1
- package/dist/server/routes/validation/upload.js +31 -2
- package/dist/server/routes/validation/upload.js.map +1 -1
- package/dist/server/routes/validation/upload.mjs +28 -0
- package/dist/server/routes/validation/upload.mjs.map +1 -1
- package/dist/server/services/file.js +13 -6
- package/dist/server/services/file.js.map +1 -1
- package/dist/server/services/image-manipulation.js +18 -12
- package/dist/server/services/image-manipulation.js.map +1 -1
- package/dist/server/services/provider.js +24 -0
- package/dist/server/services/provider.js.map +1 -1
- package/dist/server/services/provider.mjs +24 -0
- package/dist/server/services/provider.mjs.map +1 -1
- package/dist/server/services/upload.js +187 -31
- package/dist/server/services/upload.js.map +1 -1
- package/dist/server/services/upload.mjs +159 -11
- package/dist/server/services/upload.mjs.map +1 -1
- package/dist/server/src/controllers/content-api.d.ts +1 -0
- package/dist/server/src/controllers/content-api.d.ts.map +1 -1
- package/dist/server/src/controllers/index.d.ts +1 -0
- package/dist/server/src/controllers/index.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +6 -0
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/routes/content-api.d.ts.map +1 -1
- package/dist/server/src/routes/validation/upload.d.ts +45 -0
- package/dist/server/src/routes/validation/upload.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +5 -0
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/provider.d.ts +2 -1
- package/dist/server/src/services/provider.d.ts.map +1 -1
- package/dist/server/src/services/upload.d.ts +5 -0
- package/dist/server/src/services/upload.d.ts.map +1 -1
- package/dist/server/src/utils/mime-validation.d.ts.map +1 -1
- package/dist/server/utils/mime-validation.js +8 -2
- package/dist/server/utils/mime-validation.js.map +1 -1
- package/dist/server/utils/mime-validation.mjs +9 -3
- package/dist/server/utils/mime-validation.mjs.map +1 -1
- 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;
|
|
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
|
|
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__*/
|
|
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":"
|
|
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":";;;AAMA;;;;;IAMO,MAAMA,oBAAAA,SAA6BC,sBAAAA,CAAAA;AAQxC;;;AAGC,MACD,IAAIC,IAAAA,GAAO;QACT,OAAOC,CAAAA,CAAEC,MAAM,CAAC;YACdC,EAAAA,EAAI,IAAI,CAACC,MAAM;AACfC,YAAAA,UAAAA,EAAYJ,EAAEK,IAAI,EAAA;AAClBC,YAAAA,IAAAA,EAAMN,EAAEO,MAAM,EAAA;AACdC,YAAAA,eAAAA,EAAiBR,CAAAA,CAAEO,MAAM,EAAA,CAAGE,QAAQ,GAAGC,QAAQ,EAAA;AAC/CC,YAAAA,OAAAA,EAASX,CAAAA,CAAEO,MAAM,EAAA,CAAGE,QAAQ,GAAGC,QAAQ,EAAA;AACvCE,YAAAA,KAAAA,EAAOZ,CAAAA,CAAEa,MAAM,EAAA,CAAGC,GAAG,GAAGJ,QAAQ,EAAA;AAChCK,YAAAA,MAAAA,EAAQf,CAAAA,CAAEa,MAAM,EAAA,CAAGC,GAAG,GAAGJ,QAAQ,EAAA;YACjCM,OAAAA,EAAShB,CAAAA,CAAEiB,MAAM,CAACjB,CAAAA,CAAEO,MAAM,EAAA,EAAIP,CAAAA,CAAEkB,OAAO,EAAA,CAAA,CAAIR,QAAQ,EAAA;AACnDS,YAAAA,IAAAA,EAAMnB,EAAEO,MAAM,EAAA;YACda,GAAAA,EAAKpB,CAAAA,CAAEO,MAAM,EAAA,CAAGG,QAAQ,EAAA;AACxBW,YAAAA,IAAAA,EAAMrB,EAAEO,MAAM,EAAA;AACde,YAAAA,IAAAA,EAAMtB,EAAEa,MAAM,EAAA;AACdU,YAAAA,GAAAA,EAAKvB,EAAEO,MAAM,EAAA;AACbiB,YAAAA,UAAAA,EAAYxB,CAAAA,CAAEO,MAAM,EAAA,CAAGE,QAAQ,GAAGC,QAAQ,EAAA;YAC1Ce,MAAAA,EAAQzB,CAAAA,CAAEa,MAAM,EAAA,CAAGH,QAAQ,EAAA;AAC3BgB,YAAAA,UAAAA,EAAY1B,EAAEO,MAAM,EAAA;AACpBoB,YAAAA,QAAAA,EAAU3B,EAAEO,MAAM,EAAA;YAClBqB,iBAAAA,EAAmB5B,CAAAA,CAAEiB,MAAM,CAACjB,CAAAA,CAAEO,MAAM,EAAA,EAAIP,CAAAA,CAAEkB,OAAO,EAAA,CAAA,CAAIT,QAAQ,EAAA,CAAGC,QAAQ,EAAA;AACxEmB,YAAAA,SAAAA,EAAW7B,EAAEO,MAAM,EAAA;AACnBuB,YAAAA,SAAAA,EAAW9B,EAAEO,MAAM,EAAA;YACnBwB,SAAAA,EAAW/B,CAAAA,CAAEa,MAAM,EAAA,CAAGH,QAAQ,EAAA;YAC9BsB,SAAAA,EAAWhC,CAAAA,CAAEa,MAAM,EAAA,CAAGH,QAAQ;AAChC,SAAA,CAAA;AACF,IAAA;AAEA;;AAEC,MACD,IAAIuB,KAAAA,GAAQ;AACV,QAAA,OAAOjC,CAAAA,CAAEkC,KAAK,CAAC,IAAI,CAACnC,IAAI,CAAA;AAC1B,IAAA;AAEA;;AAEC,MACD,
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
114
|
-
await
|
|
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":"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"}
|
|
@@ -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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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: ()=>
|
|
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 =
|
|
124
|
+
transformer = sharp__default.default({
|
|
119
125
|
animated: true
|
|
120
126
|
});
|
|
121
127
|
} else {
|
|
122
|
-
transformer =
|
|
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 = ()=>
|
|
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 =
|
|
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
|
|
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 = ()=>
|
|
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":"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"}
|
|
@@ -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;;;;"}
|