@strapi/upload 5.57.0 → 5.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/components/MediaLibraryInput/AddAssetMenu.js +141 -0
- package/dist/admin/components/MediaLibraryInput/AddAssetMenu.js.map +1 -0
- package/dist/admin/components/MediaLibraryInput/AddAssetMenu.mjs +139 -0
- package/dist/admin/components/MediaLibraryInput/AddAssetMenu.mjs.map +1 -0
- package/dist/admin/components/MediaLibraryInput/AssetDropZone.js +129 -0
- package/dist/admin/components/MediaLibraryInput/AssetDropZone.js.map +1 -0
- package/dist/admin/components/MediaLibraryInput/AssetDropZone.mjs +127 -0
- package/dist/admin/components/MediaLibraryInput/AssetDropZone.mjs.map +1 -0
- package/dist/admin/components/MediaLibraryInput/AssetRow.js +144 -0
- package/dist/admin/components/MediaLibraryInput/AssetRow.js.map +1 -0
- package/dist/admin/components/MediaLibraryInput/AssetRow.mjs +142 -0
- package/dist/admin/components/MediaLibraryInput/AssetRow.mjs.map +1 -0
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js +397 -0
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js.map +1 -0
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.mjs +395 -0
- package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.mjs.map +1 -0
- package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.js +45 -0
- package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.js.map +1 -0
- package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.mjs +43 -0
- package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.mjs.map +1 -0
- package/dist/admin/hooks/useAIMetadataAvailability.js +5 -1
- package/dist/admin/hooks/useAIMetadataAvailability.js.map +1 -1
- package/dist/admin/hooks/useAIMetadataAvailability.mjs +5 -1
- package/dist/admin/hooks/useAIMetadataAvailability.mjs.map +1 -1
- package/dist/admin/hooks/useAIMetadataEnabled.js +7 -1
- package/dist/admin/hooks/useAIMetadataEnabled.js.map +1 -1
- package/dist/admin/hooks/useAIMetadataEnabled.mjs +7 -1
- package/dist/admin/hooks/useAIMetadataEnabled.mjs.map +1 -1
- package/dist/admin/hooks/useMediaLibraryPermissions.js +4 -0
- package/dist/admin/hooks/useMediaLibraryPermissions.js.map +1 -1
- package/dist/admin/hooks/useMediaLibraryPermissions.mjs +4 -0
- package/dist/admin/hooks/useMediaLibraryPermissions.mjs.map +1 -1
- package/dist/admin/hooks/useTracking.js +5 -1
- package/dist/admin/hooks/useTracking.js.map +1 -1
- package/dist/admin/hooks/useTracking.mjs +5 -1
- package/dist/admin/hooks/useTracking.mjs.map +1 -1
- package/dist/admin/index.js +7 -2
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +7 -2
- package/dist/admin/index.mjs.map +1 -1
- package/dist/admin/legacy/components/AssetCard/AssetCardBase.js.map +1 -1
- package/dist/admin/legacy/components/AssetCard/AssetCardBase.mjs.map +1 -1
- package/dist/admin/legacy/components/AssetCard/UploadingAssetCard.js +9 -1
- package/dist/admin/legacy/components/AssetCard/UploadingAssetCard.js.map +1 -1
- package/dist/admin/legacy/components/AssetCard/UploadingAssetCard.mjs +9 -1
- package/dist/admin/legacy/components/AssetCard/UploadingAssetCard.mjs.map +1 -1
- package/dist/admin/legacy/components/AssetCard/VideoPreview.js +2 -1
- package/dist/admin/legacy/components/AssetCard/VideoPreview.js.map +1 -1
- package/dist/admin/legacy/components/AssetCard/VideoPreview.mjs +2 -1
- package/dist/admin/legacy/components/AssetCard/VideoPreview.mjs.map +1 -1
- package/dist/admin/legacy/components/AssetDialog/AssetDialog.js +3 -1
- package/dist/admin/legacy/components/AssetDialog/AssetDialog.js.map +1 -1
- package/dist/admin/legacy/components/AssetDialog/AssetDialog.mjs +3 -1
- package/dist/admin/legacy/components/AssetDialog/AssetDialog.mjs.map +1 -1
- package/dist/admin/legacy/components/AssetDialog/BrowseStep/BrowseStep.js +3 -1
- package/dist/admin/legacy/components/AssetDialog/BrowseStep/BrowseStep.js.map +1 -1
- package/dist/admin/legacy/components/AssetDialog/BrowseStep/BrowseStep.mjs +3 -1
- package/dist/admin/legacy/components/AssetDialog/BrowseStep/BrowseStep.mjs.map +1 -1
- package/dist/admin/legacy/components/AssetDialog/BrowseStep/Filters.js.map +1 -1
- package/dist/admin/legacy/components/AssetDialog/BrowseStep/Filters.mjs.map +1 -1
- package/dist/admin/legacy/components/AssetGridList/AssetGridList.js +7 -6
- package/dist/admin/legacy/components/AssetGridList/AssetGridList.js.map +1 -1
- package/dist/admin/legacy/components/AssetGridList/AssetGridList.mjs +7 -6
- package/dist/admin/legacy/components/AssetGridList/AssetGridList.mjs.map +1 -1
- package/dist/admin/legacy/components/Breadcrumbs/CrumbSimpleMenuAsync.js +2 -1
- package/dist/admin/legacy/components/Breadcrumbs/CrumbSimpleMenuAsync.js.map +1 -1
- package/dist/admin/legacy/components/Breadcrumbs/CrumbSimpleMenuAsync.mjs +2 -1
- package/dist/admin/legacy/components/Breadcrumbs/CrumbSimpleMenuAsync.mjs.map +1 -1
- package/dist/admin/legacy/components/BulkMoveDialog/BulkMoveDialog.js +2 -1
- package/dist/admin/legacy/components/BulkMoveDialog/BulkMoveDialog.js.map +1 -1
- package/dist/admin/legacy/components/BulkMoveDialog/BulkMoveDialog.mjs +2 -1
- package/dist/admin/legacy/components/BulkMoveDialog/BulkMoveDialog.mjs.map +1 -1
- package/dist/admin/legacy/components/EditAssetDialog/EditAssetContent.js +3 -1
- package/dist/admin/legacy/components/EditAssetDialog/EditAssetContent.js.map +1 -1
- package/dist/admin/legacy/components/EditAssetDialog/EditAssetContent.mjs +3 -1
- package/dist/admin/legacy/components/EditAssetDialog/EditAssetContent.mjs.map +1 -1
- package/dist/admin/legacy/components/EditAssetDialog/PreviewBox/PreviewBox.js +20 -6
- package/dist/admin/legacy/components/EditAssetDialog/PreviewBox/PreviewBox.js.map +1 -1
- package/dist/admin/legacy/components/EditAssetDialog/PreviewBox/PreviewBox.mjs +20 -6
- package/dist/admin/legacy/components/EditAssetDialog/PreviewBox/PreviewBox.mjs.map +1 -1
- package/dist/admin/legacy/components/FilterList/FilterList.js.map +1 -1
- package/dist/admin/legacy/components/FilterList/FilterList.mjs.map +1 -1
- package/dist/admin/legacy/components/FilterPopover/FilterPopover.js.map +1 -1
- package/dist/admin/legacy/components/FilterPopover/FilterPopover.mjs.map +1 -1
- package/dist/admin/legacy/components/FilterPopover/FilterValueInput.js +2 -1
- package/dist/admin/legacy/components/FilterPopover/FilterValueInput.js.map +1 -1
- package/dist/admin/legacy/components/FilterPopover/FilterValueInput.mjs +2 -1
- package/dist/admin/legacy/components/FilterPopover/FilterValueInput.mjs.map +1 -1
- package/dist/admin/legacy/components/MediaLibraryDialog/MediaLibraryDialog.js +4 -2
- package/dist/admin/legacy/components/MediaLibraryDialog/MediaLibraryDialog.js.map +1 -1
- package/dist/admin/legacy/components/MediaLibraryDialog/MediaLibraryDialog.mjs +4 -2
- package/dist/admin/legacy/components/MediaLibraryDialog/MediaLibraryDialog.mjs.map +1 -1
- package/dist/admin/legacy/components/MediaLibraryInput/MediaLibraryInput.js +2 -1
- package/dist/admin/legacy/components/MediaLibraryInput/MediaLibraryInput.js.map +1 -1
- package/dist/admin/legacy/components/MediaLibraryInput/MediaLibraryInput.mjs +2 -1
- package/dist/admin/legacy/components/MediaLibraryInput/MediaLibraryInput.mjs.map +1 -1
- package/dist/admin/legacy/components/SelectTree/SelectTree.js +3 -1
- package/dist/admin/legacy/components/SelectTree/SelectTree.js.map +1 -1
- package/dist/admin/legacy/components/SelectTree/SelectTree.mjs +3 -1
- package/dist/admin/legacy/components/SelectTree/SelectTree.mjs.map +1 -1
- package/dist/admin/legacy/components/TableList/TableList.js +3 -1
- package/dist/admin/legacy/components/TableList/TableList.js.map +1 -1
- package/dist/admin/legacy/components/TableList/TableList.mjs +3 -1
- package/dist/admin/legacy/components/TableList/TableList.mjs.map +1 -1
- package/dist/admin/legacy/components/TableList/TableRows.js +3 -1
- package/dist/admin/legacy/components/TableList/TableRows.js.map +1 -1
- package/dist/admin/legacy/components/TableList/TableRows.mjs +3 -1
- package/dist/admin/legacy/components/TableList/TableRows.mjs.map +1 -1
- package/dist/admin/legacy/components/UploadAssetDialog/UploadAssetDialog.js +3 -1
- package/dist/admin/legacy/components/UploadAssetDialog/UploadAssetDialog.js.map +1 -1
- package/dist/admin/legacy/components/UploadAssetDialog/UploadAssetDialog.mjs +3 -1
- package/dist/admin/legacy/components/UploadAssetDialog/UploadAssetDialog.mjs.map +1 -1
- package/dist/admin/legacy/hooks/useEditAsset.js +11 -6
- package/dist/admin/legacy/hooks/useEditAsset.js.map +1 -1
- package/dist/admin/legacy/hooks/useEditAsset.mjs +12 -7
- package/dist/admin/legacy/hooks/useEditAsset.mjs.map +1 -1
- package/dist/admin/legacy/hooks/useUpload.js +6 -4
- package/dist/admin/legacy/hooks/useUpload.js.map +1 -1
- package/dist/admin/legacy/hooks/useUpload.mjs +6 -4
- package/dist/admin/legacy/hooks/useUpload.mjs.map +1 -1
- package/dist/admin/legacy/pages/App/ConfigureTheView/ConfigureTheView.js.map +1 -1
- package/dist/admin/legacy/pages/App/ConfigureTheView/ConfigureTheView.mjs.map +1 -1
- package/dist/admin/legacy/pages/App/components/BulkActions.js +2 -1
- package/dist/admin/legacy/pages/App/components/BulkActions.js.map +1 -1
- package/dist/admin/legacy/pages/App/components/BulkActions.mjs +2 -1
- package/dist/admin/legacy/pages/App/components/BulkActions.mjs.map +1 -1
- package/dist/admin/legacy/pages/App/components/BulkMoveButton.js +2 -1
- package/dist/admin/legacy/pages/App/components/BulkMoveButton.js.map +1 -1
- package/dist/admin/legacy/pages/App/components/BulkMoveButton.mjs +2 -1
- package/dist/admin/legacy/pages/App/components/BulkMoveButton.mjs.map +1 -1
- package/dist/admin/pages/Assets/components/AssetsGrid.js +2 -1
- package/dist/admin/pages/Assets/components/AssetsGrid.js.map +1 -1
- package/dist/admin/pages/Assets/components/AssetsGrid.mjs +2 -1
- package/dist/admin/pages/Assets/components/AssetsGrid.mjs.map +1 -1
- package/dist/admin/pages/Assets/components/AssetsTable.js +2 -1
- package/dist/admin/pages/Assets/components/AssetsTable.js.map +1 -1
- package/dist/admin/pages/Assets/components/AssetsTable.mjs +2 -1
- package/dist/admin/pages/Assets/components/AssetsTable.mjs.map +1 -1
- package/dist/admin/pages/Assets/components/BulkActionsBar.js +3 -1
- package/dist/admin/pages/Assets/components/BulkActionsBar.js.map +1 -1
- package/dist/admin/pages/Assets/components/BulkActionsBar.mjs +3 -1
- package/dist/admin/pages/Assets/components/BulkActionsBar.mjs.map +1 -1
- package/dist/admin/pages/Assets/components/DateRangeCalendar.js +10 -7
- package/dist/admin/pages/Assets/components/DateRangeCalendar.js.map +1 -1
- package/dist/admin/pages/Assets/components/DateRangeCalendar.mjs +10 -7
- package/dist/admin/pages/Assets/components/DateRangeCalendar.mjs.map +1 -1
- package/dist/admin/pages/Assets/components/DropZone/UploadDropZoneContext.js +4 -2
- package/dist/admin/pages/Assets/components/DropZone/UploadDropZoneContext.js.map +1 -1
- package/dist/admin/pages/Assets/components/DropZone/UploadDropZoneContext.mjs +5 -3
- package/dist/admin/pages/Assets/components/DropZone/UploadDropZoneContext.mjs.map +1 -1
- package/dist/admin/pages/Assets/components/FilterBadges.js +32 -3
- package/dist/admin/pages/Assets/components/FilterBadges.js.map +1 -1
- package/dist/admin/pages/Assets/components/FilterBadges.mjs +33 -4
- package/dist/admin/pages/Assets/components/FilterBadges.mjs.map +1 -1
- package/dist/admin/services/api.js +15 -5
- package/dist/admin/services/api.js.map +1 -1
- package/dist/admin/services/api.mjs +15 -5
- package/dist/admin/services/api.mjs.map +1 -1
- package/dist/admin/src/components/MediaLibraryInput/AddAssetMenu.d.ts +19 -0
- package/dist/admin/src/components/MediaLibraryInput/AssetDropZone.d.ts +13 -0
- package/dist/admin/src/components/MediaLibraryInput/AssetRow.d.ts +15 -0
- package/dist/admin/src/components/MediaLibraryInput/MediaLibraryInput.d.ts +26 -0
- package/dist/admin/src/components/MediaLibraryInput/NoLibraryAccessDialog.d.ts +10 -0
- package/dist/admin/src/hooks/useMediaLibraryPermissions.d.ts +1 -0
- package/dist/admin/src/legacy/components/BulkMoveDialog/BulkMoveDialog.d.ts +1 -1
- package/dist/admin/src/legacy/hooks/useEditAsset.d.ts +13 -22
- package/dist/admin/src/legacy/hooks/useUpload.d.ts +1 -1
- package/dist/admin/src/legacy/pages/App/components/BulkActions.d.ts +1 -1
- package/dist/admin/src/services/api.d.ts +6 -0
- package/dist/admin/src/utils/allowedMediaTypes.d.ts +16 -0
- package/dist/admin/translations/ca.json.js +3 -3
- package/dist/admin/translations/ca.json.mjs +3 -3
- package/dist/admin/translations/da.json.js +1 -1
- package/dist/admin/translations/da.json.mjs +1 -1
- package/dist/admin/translations/de.json.js +1 -1
- package/dist/admin/translations/de.json.mjs +1 -1
- package/dist/admin/translations/en.json.js +9 -0
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +9 -0
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/admin/translations/es.json.js +1 -1
- package/dist/admin/translations/es.json.mjs +1 -1
- package/dist/admin/translations/sk.json.js +2 -2
- package/dist/admin/translations/sk.json.mjs +2 -2
- package/dist/admin/translations/tr.json.js +2 -2
- package/dist/admin/translations/tr.json.mjs +2 -2
- package/dist/admin/translations/zh-Hans.json.js +1 -1
- package/dist/admin/translations/zh-Hans.json.mjs +1 -1
- package/dist/admin/translations/zh.json.js +2 -2
- package/dist/admin/translations/zh.json.mjs +2 -2
- package/dist/admin/utils/allowedMediaTypes.js +42 -0
- package/dist/admin/utils/allowedMediaTypes.js.map +1 -0
- package/dist/admin/utils/allowedMediaTypes.mjs +39 -0
- package/dist/admin/utils/allowedMediaTypes.mjs.map +1 -0
- package/dist/server/config.js +6 -0
- package/dist/server/config.js.map +1 -1
- package/dist/server/config.mjs +6 -0
- package/dist/server/config.mjs.map +1 -1
- package/dist/server/controllers/validation/admin/upload.js.map +1 -1
- package/dist/server/controllers/validation/admin/upload.mjs.map +1 -1
- package/dist/server/controllers/validation/content-api/upload.js.map +1 -1
- package/dist/server/controllers/validation/content-api/upload.mjs.map +1 -1
- package/dist/server/mcp/ambient-instance.js +7 -5
- package/dist/server/mcp/ambient-instance.js.map +1 -1
- package/dist/server/mcp/ambient-instance.mjs +7 -5
- package/dist/server/mcp/ambient-instance.mjs.map +1 -1
- package/dist/server/mcp/handlers/folder-handlers.js +4 -16
- package/dist/server/mcp/handlers/folder-handlers.js.map +1 -1
- package/dist/server/mcp/handlers/folder-handlers.mjs +5 -17
- package/dist/server/mcp/handlers/folder-handlers.mjs.map +1 -1
- package/dist/server/mcp/handlers/read-handlers.js +6 -14
- package/dist/server/mcp/handlers/read-handlers.js.map +1 -1
- package/dist/server/mcp/handlers/read-handlers.mjs +7 -15
- package/dist/server/mcp/handlers/read-handlers.mjs.map +1 -1
- package/dist/server/mcp/handlers/write-handlers.js +3 -13
- package/dist/server/mcp/handlers/write-handlers.js.map +1 -1
- package/dist/server/mcp/handlers/write-handlers.mjs +3 -13
- package/dist/server/mcp/handlers/write-handlers.mjs.map +1 -1
- package/dist/server/mcp/register-upload-mcp-tools.js +215 -195
- package/dist/server/mcp/register-upload-mcp-tools.js.map +1 -1
- package/dist/server/mcp/register-upload-mcp-tools.mjs +215 -195
- package/dist/server/mcp/register-upload-mcp-tools.mjs.map +1 -1
- package/dist/server/services/extensions/utils.js +1 -1
- package/dist/server/services/extensions/utils.js.map +1 -1
- package/dist/server/services/extensions/utils.mjs +1 -1
- package/dist/server/services/extensions/utils.mjs.map +1 -1
- package/dist/server/services/image-manipulation.js +33 -14
- package/dist/server/services/image-manipulation.js.map +1 -1
- package/dist/server/services/image-manipulation.mjs +33 -14
- package/dist/server/services/image-manipulation.mjs.map +1 -1
- package/dist/server/src/config.d.ts +3 -0
- package/dist/server/src/config.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/admin/upload.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/content-api/upload.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +3 -0
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/mcp/ambient-instance.d.ts +7 -5
- package/dist/server/src/mcp/ambient-instance.d.ts.map +1 -1
- package/dist/server/src/mcp/handlers/folder-handlers.d.ts.map +1 -1
- package/dist/server/src/mcp/handlers/read-handlers.d.ts +3 -2
- package/dist/server/src/mcp/handlers/read-handlers.d.ts.map +1 -1
- package/dist/server/src/mcp/handlers/write-handlers.d.ts.map +1 -1
- package/dist/server/src/mcp/register-upload-mcp-tools.d.ts +9 -14
- package/dist/server/src/mcp/register-upload-mcp-tools.d.ts.map +1 -1
- package/dist/server/src/services/extensions/utils.d.ts +1 -1
- package/dist/server/src/services/image-manipulation.d.ts.map +1 -1
- package/dist/server/src/types.d.ts +1 -0
- package/dist/server/src/types.d.ts.map +1 -1
- package/dist/server/utils/mime-validation.js +1 -1
- package/dist/server/utils/mime-validation.js.map +1 -1
- package/dist/server/utils/mime-validation.mjs +1 -1
- package/dist/server/utils/mime-validation.mjs.map +1 -1
- package/package.json +7 -7
|
@@ -42,7 +42,7 @@ var da = {
|
|
|
42
42
|
"list.assets.loading-asset": "Henter forhåndsvisning for mediet: {path}",
|
|
43
43
|
"list.assets.not-supported-content": "Ingen forhåndsvisning mulig",
|
|
44
44
|
"list.assets.preview-asset": "Forhåndsvisning af videoen her {path}",
|
|
45
|
-
"list.assets.selected": "{
|
|
45
|
+
"list.assets.selected": "{numberFolders, plural, one {1 mappe} other {# mapper}} - {numberAssets, plural, one {1 medie} other {# medier}}",
|
|
46
46
|
"list.assets.type-not-allowed": "Filtypen er ikke tilladt.",
|
|
47
47
|
"mediaLibraryInput.actions.nextSlide": "Næste slide",
|
|
48
48
|
"mediaLibraryInput.actions.previousSlide": "Forrige slide",
|
|
@@ -55,7 +55,7 @@ var de = {
|
|
|
55
55
|
"list.assets.loading-asset": "Lade die Vorschau für Medien: {path}",
|
|
56
56
|
"list.assets.not-supported-content": "Keine Vorschau verfügbar",
|
|
57
57
|
"list.assets.preview-asset": "Vorschau für das Video unter {path}",
|
|
58
|
-
"list.assets.selected": "{
|
|
58
|
+
"list.assets.selected": "{numberFolders, plural, one {1 Ordner} other {# Ordner}} - {numberAssets, plural, one {1 Datei} other {# Dateien}}",
|
|
59
59
|
"list-assets-select": "Datei {name} auswählen",
|
|
60
60
|
"list.assets.type-not-allowed": "Dieser Dateityp ist nicht zulässig.",
|
|
61
61
|
"list.assets.to-upload": "{number, plural, =0 {Keine Datei} one {1 Datei} other {# Dateien}} bereit zum Hochladen",
|
|
@@ -53,7 +53,7 @@ var de = {
|
|
|
53
53
|
"list.assets.loading-asset": "Lade die Vorschau für Medien: {path}",
|
|
54
54
|
"list.assets.not-supported-content": "Keine Vorschau verfügbar",
|
|
55
55
|
"list.assets.preview-asset": "Vorschau für das Video unter {path}",
|
|
56
|
-
"list.assets.selected": "{
|
|
56
|
+
"list.assets.selected": "{numberFolders, plural, one {1 Ordner} other {# Ordner}} - {numberAssets, plural, one {1 Datei} other {# Dateien}}",
|
|
57
57
|
"list-assets-select": "Datei {name} auswählen",
|
|
58
58
|
"list.assets.type-not-allowed": "Dieser Dateityp ist nicht zulässig.",
|
|
59
59
|
"list.assets.to-upload": "{number, plural, =0 {Keine Datei} one {1 Datei} other {# Dateien}} bereit zum Hochladen",
|
|
@@ -70,6 +70,15 @@ var en = {
|
|
|
70
70
|
"asset-details.crop.error": "Failed to update the file.",
|
|
71
71
|
"asset-details.crop.loading": "Saving the copy…",
|
|
72
72
|
"asset-details.noPreview": "No preview available",
|
|
73
|
+
"content-manager.input.actions.copy-link": "Copy link to {name}",
|
|
74
|
+
"content-manager.input.actions.edit": "Edit {name}",
|
|
75
|
+
"content-manager.input.actions.remove": "Remove {name}",
|
|
76
|
+
"content-manager.input.notification.single-file": "This field accepts only one file.",
|
|
77
|
+
"content-manager.input.notification.not-attached": "{fileNames} {count, plural, one {was} other {were}} added to the Media Library, but this field only accepts {fileTypes}.",
|
|
78
|
+
"content-manager.input.add-asset": "Add asset",
|
|
79
|
+
"content-manager.input.add-asset.browse": "Browse library",
|
|
80
|
+
"content-manager.input.add-asset.device": "Upload from device",
|
|
81
|
+
"content-manager.input.add-asset.url": "Upload from URL",
|
|
73
82
|
"upload.generic-error": "An error occurred while uploading the file.",
|
|
74
83
|
"upload.progress": "Upload progress",
|
|
75
84
|
"upload.progress.description": "Shows upload progress and status",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"en.json.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -68,6 +68,15 @@ var en = {
|
|
|
68
68
|
"asset-details.crop.error": "Failed to update the file.",
|
|
69
69
|
"asset-details.crop.loading": "Saving the copy…",
|
|
70
70
|
"asset-details.noPreview": "No preview available",
|
|
71
|
+
"content-manager.input.actions.copy-link": "Copy link to {name}",
|
|
72
|
+
"content-manager.input.actions.edit": "Edit {name}",
|
|
73
|
+
"content-manager.input.actions.remove": "Remove {name}",
|
|
74
|
+
"content-manager.input.notification.single-file": "This field accepts only one file.",
|
|
75
|
+
"content-manager.input.notification.not-attached": "{fileNames} {count, plural, one {was} other {were}} added to the Media Library, but this field only accepts {fileTypes}.",
|
|
76
|
+
"content-manager.input.add-asset": "Add asset",
|
|
77
|
+
"content-manager.input.add-asset.browse": "Browse library",
|
|
78
|
+
"content-manager.input.add-asset.device": "Upload from device",
|
|
79
|
+
"content-manager.input.add-asset.url": "Upload from URL",
|
|
71
80
|
"upload.generic-error": "An error occurred while uploading the file.",
|
|
72
81
|
"upload.progress": "Upload progress",
|
|
73
82
|
"upload.progress.description": "Shows upload progress and status",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"en.json.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"en.json.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -49,7 +49,7 @@ var es = {
|
|
|
49
49
|
"list.assets.loading-asset": "Cargando la vista previa de los recursos: {path}",
|
|
50
50
|
"list.assets.not-supported-content": "No hay vista previa disponible",
|
|
51
51
|
"list.assets.preview-asset": "Vista previa del video en la ruta {path}",
|
|
52
|
-
"list.assets.selected": "{
|
|
52
|
+
"list.assets.selected": "{numberFolders, plural, one {1 carpeta} other {# carpetas}} - {numberAssets, plural, one {1 recurso} other {# recursos}}",
|
|
53
53
|
"list.assets.type-not-allowed": "Este tipo de archivo no está permitido.",
|
|
54
54
|
"mediaLibraryInput.actions.nextSlide": "Siguiente",
|
|
55
55
|
"mediaLibraryInput.actions.previousSlide": "Anterior",
|
|
@@ -47,7 +47,7 @@ var es = {
|
|
|
47
47
|
"list.assets.loading-asset": "Cargando la vista previa de los recursos: {path}",
|
|
48
48
|
"list.assets.not-supported-content": "No hay vista previa disponible",
|
|
49
49
|
"list.assets.preview-asset": "Vista previa del video en la ruta {path}",
|
|
50
|
-
"list.assets.selected": "{
|
|
50
|
+
"list.assets.selected": "{numberFolders, plural, one {1 carpeta} other {# carpetas}} - {numberAssets, plural, one {1 recurso} other {# recursos}}",
|
|
51
51
|
"list.assets.type-not-allowed": "Este tipo de archivo no está permitido.",
|
|
52
52
|
"mediaLibraryInput.actions.nextSlide": "Siguiente",
|
|
53
53
|
"mediaLibraryInput.actions.previousSlide": "Anterior",
|
|
@@ -101,7 +101,7 @@ var sk = {
|
|
|
101
101
|
"input.url.label": "URL",
|
|
102
102
|
"input.url.placeholder": "Prázdne",
|
|
103
103
|
"input.notification.not-supported": "Tento typ súboru nemôžete nahrať, akceptované sú iba nasledujúce typy – {fileTypes}",
|
|
104
|
-
"list.assets.title": "Súbory",
|
|
104
|
+
"list.assets.title": "Súbory ({count})",
|
|
105
105
|
"list.asset.at.finished": "Načítavanie súbor ukončené.",
|
|
106
106
|
"list.assets-empty.search": "Žiadne výsledky",
|
|
107
107
|
"list.assets-empty.subtitle": "Pridať jeden do zoznamu.",
|
|
@@ -122,7 +122,7 @@ var sk = {
|
|
|
122
122
|
"list.folder.edit": "Upraviť priečinok",
|
|
123
123
|
"list.folder.select": "Vybrať priečinok {name}",
|
|
124
124
|
"list.folder.subtitle": "{folderCount, plural, one {# priečinok} few {# priečinky} other {# priečinkov}}, {filesCount, plural, one {# súbor} few {# súbory} other {# súborov}}",
|
|
125
|
-
"list.folders.title": "Priečinky",
|
|
125
|
+
"list.folders.title": "Priečinky ({count})",
|
|
126
126
|
"list.folders.link-label": "Prístup k priečinku",
|
|
127
127
|
"mediaLibraryInput.actions.nextSlide": "Ďalší slide",
|
|
128
128
|
"mediaLibraryInput.actions.previousSlide": "Predošlý slide",
|
|
@@ -99,7 +99,7 @@ var sk = {
|
|
|
99
99
|
"input.url.label": "URL",
|
|
100
100
|
"input.url.placeholder": "Prázdne",
|
|
101
101
|
"input.notification.not-supported": "Tento typ súboru nemôžete nahrať, akceptované sú iba nasledujúce typy – {fileTypes}",
|
|
102
|
-
"list.assets.title": "Súbory",
|
|
102
|
+
"list.assets.title": "Súbory ({count})",
|
|
103
103
|
"list.asset.at.finished": "Načítavanie súbor ukončené.",
|
|
104
104
|
"list.assets-empty.search": "Žiadne výsledky",
|
|
105
105
|
"list.assets-empty.subtitle": "Pridať jeden do zoznamu.",
|
|
@@ -120,7 +120,7 @@ var sk = {
|
|
|
120
120
|
"list.folder.edit": "Upraviť priečinok",
|
|
121
121
|
"list.folder.select": "Vybrať priečinok {name}",
|
|
122
122
|
"list.folder.subtitle": "{folderCount, plural, one {# priečinok} few {# priečinky} other {# priečinkov}}, {filesCount, plural, one {# súbor} few {# súbory} other {# súborov}}",
|
|
123
|
-
"list.folders.title": "Priečinky",
|
|
123
|
+
"list.folders.title": "Priečinky ({count})",
|
|
124
124
|
"list.folders.link-label": "Prístup k priečinku",
|
|
125
125
|
"mediaLibraryInput.actions.nextSlide": "Ďalší slide",
|
|
126
126
|
"mediaLibraryInput.actions.previousSlide": "Predošlý slide",
|
|
@@ -40,7 +40,7 @@ var tr = {
|
|
|
40
40
|
"input.placeholder.icon": "Dosyayı bu bölgeye bırak",
|
|
41
41
|
"input.url.description": "URL bağlantıları arasına yeni bir satır ekle.",
|
|
42
42
|
"input.url.label": "URL",
|
|
43
|
-
"list.assets.title": "Dosyalar",
|
|
43
|
+
"list.assets.title": "Dosyalar ({count})",
|
|
44
44
|
"list.asset.at.finished": "Dosyaların yüklenmesi tamamlandı.",
|
|
45
45
|
"list.assets-empty.search": "Sonuç bulunamadı",
|
|
46
46
|
"list.assets-empty.subtitle": "Listeye bir tane ekle.",
|
|
@@ -57,7 +57,7 @@ var tr = {
|
|
|
57
57
|
"list.assets.to-upload": "{number} yüklenmeye hazır",
|
|
58
58
|
"list.folder.edit": "Klasörü düzenle",
|
|
59
59
|
"list.folder.subtitle": "{folderCount} klasör, {filesCount} dosya",
|
|
60
|
-
"list.folders.title": "Klasörler",
|
|
60
|
+
"list.folders.title": "Klasörler ({count})",
|
|
61
61
|
"mediaLibraryInput.actions.nextSlide": "Sonraki slayt",
|
|
62
62
|
"mediaLibraryInput.actions.previousSlide": "Önceki slayt",
|
|
63
63
|
"mediaLibraryInput.placeholder": "Dosya yüklemek için tıkla ya da bu alana sürükle ve bırak",
|
|
@@ -38,7 +38,7 @@ var tr = {
|
|
|
38
38
|
"input.placeholder.icon": "Dosyayı bu bölgeye bırak",
|
|
39
39
|
"input.url.description": "URL bağlantıları arasına yeni bir satır ekle.",
|
|
40
40
|
"input.url.label": "URL",
|
|
41
|
-
"list.assets.title": "Dosyalar",
|
|
41
|
+
"list.assets.title": "Dosyalar ({count})",
|
|
42
42
|
"list.asset.at.finished": "Dosyaların yüklenmesi tamamlandı.",
|
|
43
43
|
"list.assets-empty.search": "Sonuç bulunamadı",
|
|
44
44
|
"list.assets-empty.subtitle": "Listeye bir tane ekle.",
|
|
@@ -55,7 +55,7 @@ var tr = {
|
|
|
55
55
|
"list.assets.to-upload": "{number} yüklenmeye hazır",
|
|
56
56
|
"list.folder.edit": "Klasörü düzenle",
|
|
57
57
|
"list.folder.subtitle": "{folderCount} klasör, {filesCount} dosya",
|
|
58
|
-
"list.folders.title": "Klasörler",
|
|
58
|
+
"list.folders.title": "Klasörler ({count})",
|
|
59
59
|
"mediaLibraryInput.actions.nextSlide": "Sonraki slayt",
|
|
60
60
|
"mediaLibraryInput.actions.previousSlide": "Önceki slayt",
|
|
61
61
|
"mediaLibraryInput.placeholder": "Dosya yüklemek için tıkla ya da bu alana sürükle ve bırak",
|
|
@@ -42,7 +42,7 @@ var zhHans = {
|
|
|
42
42
|
"list.assets.loading-asset": "正在为媒体加载预览: {path}",
|
|
43
43
|
"list.assets.not-supported-content": "无可用预览",
|
|
44
44
|
"list.assets.preview-asset": "预览视频(路径:{path})",
|
|
45
|
-
"list.assets.selected": "{
|
|
45
|
+
"list.assets.selected": "{numberFolders, plural, other {# 个文件夹}} - {numberAssets, plural, other {# 个素材}}",
|
|
46
46
|
"list.assets.type-not-allowed": "文件类型不合法",
|
|
47
47
|
"list.table.header.actions": "操作",
|
|
48
48
|
"list.table.header.preview": "预览",
|
|
@@ -40,7 +40,7 @@ var zhHans = {
|
|
|
40
40
|
"list.assets.loading-asset": "正在为媒体加载预览: {path}",
|
|
41
41
|
"list.assets.not-supported-content": "无可用预览",
|
|
42
42
|
"list.assets.preview-asset": "预览视频(路径:{path})",
|
|
43
|
-
"list.assets.selected": "{
|
|
43
|
+
"list.assets.selected": "{numberFolders, plural, other {# 个文件夹}} - {numberAssets, plural, other {# 个素材}}",
|
|
44
44
|
"list.assets.type-not-allowed": "文件类型不合法",
|
|
45
45
|
"list.table.header.actions": "操作",
|
|
46
46
|
"list.table.header.preview": "预览",
|
|
@@ -43,7 +43,7 @@ var zh = {
|
|
|
43
43
|
"input.placeholder.icon": "將素材拖曳至此區域",
|
|
44
44
|
"input.url.description": "以跳行符號分隔連結",
|
|
45
45
|
"input.url.label": "連結",
|
|
46
|
-
"list.assets.title": "
|
|
46
|
+
"list.assets.title": "素材({count})",
|
|
47
47
|
"list.asset.at.finished": "素材已完成載入。",
|
|
48
48
|
"list.assets-empty.search": "找不到結果",
|
|
49
49
|
"list.assets-empty.subtitle": "從開頭新增",
|
|
@@ -60,7 +60,7 @@ var zh = {
|
|
|
60
60
|
"list.assets.to-upload": "{number, plural, =0 {沒有} one {1 個} other {# 個}}素材準備上傳",
|
|
61
61
|
"list.folder.edit": "編輯資料夾",
|
|
62
62
|
"list.folder.subtitle": "{folderCount, plural, =0 {# 資料夾} one {# 資料夾} other {# 資料夾}}, {filesCount, plural, =0 {# 素材} one {# 素材} other {# 素材}}",
|
|
63
|
-
"list.folders.title": "
|
|
63
|
+
"list.folders.title": "資料夾({count})",
|
|
64
64
|
"mediaLibraryInput.actions.nextSlide": "下一張投影片",
|
|
65
65
|
"mediaLibraryInput.actions.previousSlide": "上一張投影片",
|
|
66
66
|
"mediaLibraryInput.placeholder": "點擊以新增素材,或拖曳至此區域",
|
|
@@ -41,7 +41,7 @@ var zh = {
|
|
|
41
41
|
"input.placeholder.icon": "將素材拖曳至此區域",
|
|
42
42
|
"input.url.description": "以跳行符號分隔連結",
|
|
43
43
|
"input.url.label": "連結",
|
|
44
|
-
"list.assets.title": "
|
|
44
|
+
"list.assets.title": "素材({count})",
|
|
45
45
|
"list.asset.at.finished": "素材已完成載入。",
|
|
46
46
|
"list.assets-empty.search": "找不到結果",
|
|
47
47
|
"list.assets-empty.subtitle": "從開頭新增",
|
|
@@ -58,7 +58,7 @@ var zh = {
|
|
|
58
58
|
"list.assets.to-upload": "{number, plural, =0 {沒有} one {1 個} other {# 個}}素材準備上傳",
|
|
59
59
|
"list.folder.edit": "編輯資料夾",
|
|
60
60
|
"list.folder.subtitle": "{folderCount, plural, =0 {# 資料夾} one {# 資料夾} other {# 資料夾}}, {filesCount, plural, =0 {# 素材} one {# 素材} other {# 素材}}",
|
|
61
|
-
"list.folders.title": "
|
|
61
|
+
"list.folders.title": "資料夾({count})",
|
|
62
62
|
"mediaLibraryInput.actions.nextSlide": "下一張投影片",
|
|
63
63
|
"mediaLibraryInput.actions.previousSlide": "上一張投影片",
|
|
64
64
|
"mediaLibraryInput.placeholder": "點擊以新增素材,或拖曳至此區域",
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The `allowedTypes` values a `media` attribute can carry, and the mime prefix
|
|
5
|
+
* each one stands for. `files` is the catch-all: anything that is not an image,
|
|
6
|
+
* video or audio.
|
|
7
|
+
*/ const MEDIA_KINDS = [
|
|
8
|
+
'image',
|
|
9
|
+
'video',
|
|
10
|
+
'audio'
|
|
11
|
+
];
|
|
12
|
+
const SINGULAR = {
|
|
13
|
+
files: 'file',
|
|
14
|
+
images: 'image',
|
|
15
|
+
videos: 'video',
|
|
16
|
+
audios: 'audio'
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Whether a mime type satisfies a field's `allowedTypes`.
|
|
20
|
+
*
|
|
21
|
+
* No `allowedTypes` means the field takes anything. A file with no mime is only
|
|
22
|
+
* allowed where `files` is, since nothing places it in one of the three media
|
|
23
|
+
* kinds.
|
|
24
|
+
*/ const isMediaTypeAllowed = (allowedTypes, mime)=>{
|
|
25
|
+
if (!allowedTypes || allowedTypes.length === 0) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
const singularTypes = new Set(allowedTypes.map((type)=>SINGULAR[type]).filter((type)=>Boolean(type)));
|
|
29
|
+
const kind = mime?.split('/')[0];
|
|
30
|
+
if (!kind) {
|
|
31
|
+
return singularTypes.has('file');
|
|
32
|
+
}
|
|
33
|
+
if (singularTypes.has('file') && !MEDIA_KINDS.includes(kind)) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
return singularTypes.has(kind);
|
|
37
|
+
};
|
|
38
|
+
/** The subset of `files` this field accepts, in the order they were given. */ const filterAllowedFiles = (allowedTypes, files)=>files.filter((file)=>isMediaTypeAllowed(allowedTypes, file.type));
|
|
39
|
+
|
|
40
|
+
exports.filterAllowedFiles = filterAllowedFiles;
|
|
41
|
+
exports.isMediaTypeAllowed = isMediaTypeAllowed;
|
|
42
|
+
//# sourceMappingURL=allowedMediaTypes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"allowedMediaTypes.js","sources":["../../../admin/src/utils/allowedMediaTypes.ts"],"sourcesContent":["/**\n * The `allowedTypes` values a `media` attribute can carry, and the mime prefix\n * each one stands for. `files` is the catch-all: anything that is not an image,\n * video or audio.\n */\nexport type AllowedMediaType = 'files' | 'images' | 'videos' | 'audios';\n\nconst MEDIA_KINDS = ['image', 'video', 'audio'] as const;\n\nconst SINGULAR: Record<AllowedMediaType, string> = {\n files: 'file',\n images: 'image',\n videos: 'video',\n audios: 'audio',\n};\n\n/**\n * Whether a mime type satisfies a field's `allowedTypes`.\n *\n * No `allowedTypes` means the field takes anything. A file with no mime is only\n * allowed where `files` is, since nothing places it in one of the three media\n * kinds.\n */\nexport const isMediaTypeAllowed = (\n allowedTypes: AllowedMediaType[] | null | undefined,\n mime: string | undefined\n): boolean => {\n if (!allowedTypes || allowedTypes.length === 0) {\n return true;\n }\n\n const singularTypes = new Set(\n allowedTypes.map((type) => SINGULAR[type]).filter((type): type is string => Boolean(type))\n );\n const kind = mime?.split('/')[0];\n\n if (!kind) {\n return singularTypes.has('file');\n }\n\n if (singularTypes.has('file') && !MEDIA_KINDS.includes(kind as (typeof MEDIA_KINDS)[number])) {\n return true;\n }\n\n return singularTypes.has(kind);\n};\n\n/** The subset of `files` this field accepts, in the order they were given. */\nexport const filterAllowedFiles = (\n allowedTypes: AllowedMediaType[] | null | undefined,\n files: globalThis.File[]\n): globalThis.File[] => files.filter((file) => isMediaTypeAllowed(allowedTypes, file.type));\n"],"names":["MEDIA_KINDS","SINGULAR","files","images","videos","audios","isMediaTypeAllowed","allowedTypes","mime","length","singularTypes","Set","map","type","filter","Boolean","kind","split","has","includes","filterAllowedFiles","file"],"mappings":";;AAAA;;;;AAIC,IAGD,MAAMA,WAAAA,GAAc;AAAC,IAAA,OAAA;AAAS,IAAA,OAAA;AAAS,IAAA;AAAQ,CAAA;AAE/C,MAAMC,QAAAA,GAA6C;IACjDC,KAAAA,EAAO,MAAA;IACPC,MAAAA,EAAQ,OAAA;IACRC,MAAAA,EAAQ,OAAA;IACRC,MAAAA,EAAQ;AACV,CAAA;AAEA;;;;;;AAMC,IACM,MAAMC,kBAAAA,GAAqB,CAChCC,YAAAA,EACAC,IAAAA,GAAAA;AAEA,IAAA,IAAI,CAACD,YAAAA,IAAgBA,YAAAA,CAAaE,MAAM,KAAK,CAAA,EAAG;QAC9C,OAAO,IAAA;AACT,IAAA;AAEA,IAAA,MAAMC,gBAAgB,IAAIC,GAAAA,CACxBJ,YAAAA,CAAaK,GAAG,CAAC,CAACC,IAAAA,GAASZ,QAAQ,CAACY,KAAK,CAAA,CAAEC,MAAM,CAAC,CAACD,OAAyBE,OAAAA,CAAQF,IAAAA,CAAAA,CAAAA,CAAAA;AAEtF,IAAA,MAAMG,IAAAA,GAAOR,IAAAA,EAAMS,KAAAA,CAAM,GAAA,CAAI,CAAC,CAAA,CAAE;AAEhC,IAAA,IAAI,CAACD,IAAAA,EAAM;QACT,OAAON,aAAAA,CAAcQ,GAAG,CAAC,MAAA,CAAA;AAC3B,IAAA;IAEA,IAAIR,aAAAA,CAAcQ,GAAG,CAAC,MAAA,CAAA,IAAW,CAAClB,WAAAA,CAAYmB,QAAQ,CAACH,IAAAA,CAAAA,EAAuC;QAC5F,OAAO,IAAA;AACT,IAAA;IAEA,OAAON,aAAAA,CAAcQ,GAAG,CAACF,IAAAA,CAAAA;AAC3B;AAEA,+EACO,MAAMI,kBAAAA,GAAqB,CAChCb,cACAL,KAAAA,GACsBA,KAAAA,CAAMY,MAAM,CAAC,CAACO,IAAAA,GAASf,kBAAAA,CAAmBC,YAAAA,EAAcc,IAAAA,CAAKR,IAAI,CAAA;;;;;"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `allowedTypes` values a `media` attribute can carry, and the mime prefix
|
|
3
|
+
* each one stands for. `files` is the catch-all: anything that is not an image,
|
|
4
|
+
* video or audio.
|
|
5
|
+
*/ const MEDIA_KINDS = [
|
|
6
|
+
'image',
|
|
7
|
+
'video',
|
|
8
|
+
'audio'
|
|
9
|
+
];
|
|
10
|
+
const SINGULAR = {
|
|
11
|
+
files: 'file',
|
|
12
|
+
images: 'image',
|
|
13
|
+
videos: 'video',
|
|
14
|
+
audios: 'audio'
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Whether a mime type satisfies a field's `allowedTypes`.
|
|
18
|
+
*
|
|
19
|
+
* No `allowedTypes` means the field takes anything. A file with no mime is only
|
|
20
|
+
* allowed where `files` is, since nothing places it in one of the three media
|
|
21
|
+
* kinds.
|
|
22
|
+
*/ const isMediaTypeAllowed = (allowedTypes, mime)=>{
|
|
23
|
+
if (!allowedTypes || allowedTypes.length === 0) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
const singularTypes = new Set(allowedTypes.map((type)=>SINGULAR[type]).filter((type)=>Boolean(type)));
|
|
27
|
+
const kind = mime?.split('/')[0];
|
|
28
|
+
if (!kind) {
|
|
29
|
+
return singularTypes.has('file');
|
|
30
|
+
}
|
|
31
|
+
if (singularTypes.has('file') && !MEDIA_KINDS.includes(kind)) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
return singularTypes.has(kind);
|
|
35
|
+
};
|
|
36
|
+
/** The subset of `files` this field accepts, in the order they were given. */ const filterAllowedFiles = (allowedTypes, files)=>files.filter((file)=>isMediaTypeAllowed(allowedTypes, file.type));
|
|
37
|
+
|
|
38
|
+
export { filterAllowedFiles, isMediaTypeAllowed };
|
|
39
|
+
//# sourceMappingURL=allowedMediaTypes.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"allowedMediaTypes.mjs","sources":["../../../admin/src/utils/allowedMediaTypes.ts"],"sourcesContent":["/**\n * The `allowedTypes` values a `media` attribute can carry, and the mime prefix\n * each one stands for. `files` is the catch-all: anything that is not an image,\n * video or audio.\n */\nexport type AllowedMediaType = 'files' | 'images' | 'videos' | 'audios';\n\nconst MEDIA_KINDS = ['image', 'video', 'audio'] as const;\n\nconst SINGULAR: Record<AllowedMediaType, string> = {\n files: 'file',\n images: 'image',\n videos: 'video',\n audios: 'audio',\n};\n\n/**\n * Whether a mime type satisfies a field's `allowedTypes`.\n *\n * No `allowedTypes` means the field takes anything. A file with no mime is only\n * allowed where `files` is, since nothing places it in one of the three media\n * kinds.\n */\nexport const isMediaTypeAllowed = (\n allowedTypes: AllowedMediaType[] | null | undefined,\n mime: string | undefined\n): boolean => {\n if (!allowedTypes || allowedTypes.length === 0) {\n return true;\n }\n\n const singularTypes = new Set(\n allowedTypes.map((type) => SINGULAR[type]).filter((type): type is string => Boolean(type))\n );\n const kind = mime?.split('/')[0];\n\n if (!kind) {\n return singularTypes.has('file');\n }\n\n if (singularTypes.has('file') && !MEDIA_KINDS.includes(kind as (typeof MEDIA_KINDS)[number])) {\n return true;\n }\n\n return singularTypes.has(kind);\n};\n\n/** The subset of `files` this field accepts, in the order they were given. */\nexport const filterAllowedFiles = (\n allowedTypes: AllowedMediaType[] | null | undefined,\n files: globalThis.File[]\n): globalThis.File[] => files.filter((file) => isMediaTypeAllowed(allowedTypes, file.type));\n"],"names":["MEDIA_KINDS","SINGULAR","files","images","videos","audios","isMediaTypeAllowed","allowedTypes","mime","length","singularTypes","Set","map","type","filter","Boolean","kind","split","has","includes","filterAllowedFiles","file"],"mappings":"AAAA;;;;AAIC,IAGD,MAAMA,WAAAA,GAAc;AAAC,IAAA,OAAA;AAAS,IAAA,OAAA;AAAS,IAAA;AAAQ,CAAA;AAE/C,MAAMC,QAAAA,GAA6C;IACjDC,KAAAA,EAAO,MAAA;IACPC,MAAAA,EAAQ,OAAA;IACRC,MAAAA,EAAQ,OAAA;IACRC,MAAAA,EAAQ;AACV,CAAA;AAEA;;;;;;AAMC,IACM,MAAMC,kBAAAA,GAAqB,CAChCC,YAAAA,EACAC,IAAAA,GAAAA;AAEA,IAAA,IAAI,CAACD,YAAAA,IAAgBA,YAAAA,CAAaE,MAAM,KAAK,CAAA,EAAG;QAC9C,OAAO,IAAA;AACT,IAAA;AAEA,IAAA,MAAMC,gBAAgB,IAAIC,GAAAA,CACxBJ,YAAAA,CAAaK,GAAG,CAAC,CAACC,IAAAA,GAASZ,QAAQ,CAACY,KAAK,CAAA,CAAEC,MAAM,CAAC,CAACD,OAAyBE,OAAAA,CAAQF,IAAAA,CAAAA,CAAAA,CAAAA;AAEtF,IAAA,MAAMG,IAAAA,GAAOR,IAAAA,EAAMS,KAAAA,CAAM,GAAA,CAAI,CAAC,CAAA,CAAE;AAEhC,IAAA,IAAI,CAACD,IAAAA,EAAM;QACT,OAAON,aAAAA,CAAcQ,GAAG,CAAC,MAAA,CAAA;AAC3B,IAAA;IAEA,IAAIR,aAAAA,CAAcQ,GAAG,CAAC,MAAA,CAAA,IAAW,CAAClB,WAAAA,CAAYmB,QAAQ,CAACH,IAAAA,CAAAA,EAAuC;QAC5F,OAAO,IAAA;AACT,IAAA;IAEA,OAAON,aAAAA,CAAcQ,GAAG,CAACF,IAAAA,CAAAA;AAC3B;AAEA,+EACO,MAAMI,kBAAAA,GAAqB,CAChCb,cACAL,KAAAA,GACsBA,KAAAA,CAAMY,MAAM,CAAC,CAACO,IAAAA,GAASf,kBAAAA,CAAmBC,YAAAA,EAAcc,IAAAA,CAAKR,IAAI,CAAA;;;;"}
|
package/dist/server/config.js
CHANGED
|
@@ -26,6 +26,12 @@ const config = {
|
|
|
26
26
|
assertPositiveInteger('concurrentUploadSize', config.concurrentUploadSize);
|
|
27
27
|
// Client-side parallelism: upload requests the admin fires at once.
|
|
28
28
|
assertPositiveInteger('concurrentUploadRequests', config.concurrentUploadRequests);
|
|
29
|
+
// Sharp throws on anything else at every image call, which the upload flow
|
|
30
|
+
// reads as "not an image" and skips processing silently.
|
|
31
|
+
const limitInputPixels = config.sharp?.limitInputPixels;
|
|
32
|
+
if (limitInputPixels != null && typeof limitInputPixels !== 'boolean' && !(Number.isInteger(limitInputPixels) && limitInputPixels >= 0)) {
|
|
33
|
+
throw new Error('upload plugin config: "sharp.limitInputPixels" must be a boolean or an integer greater than or equal to 0 (use env.int() to read it from the environment)');
|
|
34
|
+
}
|
|
29
35
|
}
|
|
30
36
|
};
|
|
31
37
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sources":["../../server/src/config.ts"],"sourcesContent":["export const config = {\n default: {\n enabled: true,\n provider: 'local',\n sizeLimit: 1000000000, // 1GB\n actionOptions: {},\n sharp: {\n cache: false,\n concurrency: 1,\n },\n concurrentUploadSize: 1,\n concurrentUploadRequests: 1,\n },\n validator(config: {
|
|
1
|
+
{"version":3,"file":"config.js","sources":["../../server/src/config.ts"],"sourcesContent":["export const config = {\n default: {\n enabled: true,\n provider: 'local',\n sizeLimit: 1000000000, // 1GB\n actionOptions: {},\n sharp: {\n cache: false,\n concurrency: 1,\n },\n concurrentUploadSize: 1,\n concurrentUploadRequests: 1,\n },\n validator(config: {\n concurrentUploadSize?: unknown;\n concurrentUploadRequests?: unknown;\n sharp?: { limitInputPixels?: unknown } | null;\n }) {\n const assertPositiveInteger = (key: string, value: unknown) => {\n if (value === undefined) {\n return;\n }\n if (typeof value !== 'number' || !Number.isInteger(value) || value < 1) {\n throw new Error(\n `upload plugin config: \"${key}\" must be an integer greater than or equal to 1`\n );\n }\n };\n\n // Server-side ceiling: files processed in parallel within one request.\n assertPositiveInteger('concurrentUploadSize', config.concurrentUploadSize);\n // Client-side parallelism: upload requests the admin fires at once.\n assertPositiveInteger('concurrentUploadRequests', config.concurrentUploadRequests);\n\n // Sharp throws on anything else at every image call, which the upload flow\n // reads as \"not an image\" and skips processing silently.\n const limitInputPixels = config.sharp?.limitInputPixels;\n if (\n limitInputPixels != null &&\n typeof limitInputPixels !== 'boolean' &&\n !(Number.isInteger(limitInputPixels) && (limitInputPixels as number) >= 0)\n ) {\n throw new Error(\n 'upload plugin config: \"sharp.limitInputPixels\" must be a boolean or an integer greater than or equal to 0 (use env.int() to read it from the environment)'\n );\n }\n },\n};\n"],"names":["config","default","enabled","provider","sizeLimit","actionOptions","sharp","cache","concurrency","concurrentUploadSize","concurrentUploadRequests","validator","assertPositiveInteger","key","value","undefined","Number","isInteger","Error","limitInputPixels"],"mappings":";;MAAaA,MAAAA,GAAS;IACpBC,OAAAA,EAAS;QACPC,OAAAA,EAAS,IAAA;QACTC,QAAAA,EAAU,OAAA;QACVC,SAAAA,EAAW,UAAA;AACXC,QAAAA,aAAAA,EAAe,EAAC;QAChBC,KAAAA,EAAO;YACLC,KAAAA,EAAO,KAAA;YACPC,WAAAA,EAAa;AACf,SAAA;QACAC,oBAAAA,EAAsB,CAAA;QACtBC,wBAAAA,EAA0B;AAC5B,KAAA;AACAC,IAAAA,SAAAA,CAAAA,CAAUX,MAIT,EAAA;QACC,MAAMY,qBAAAA,GAAwB,CAACC,GAAAA,EAAaC,KAAAA,GAAAA;AAC1C,YAAA,IAAIA,UAAUC,SAAAA,EAAW;AACvB,gBAAA;AACF,YAAA;YACA,IAAI,OAAOD,UAAU,QAAA,IAAY,CAACE,OAAOC,SAAS,CAACH,KAAAA,CAAAA,IAAUA,KAAAA,GAAQ,CAAA,EAAG;AACtE,gBAAA,MAAM,IAAII,KAAAA,CACR,CAAC,uBAAuB,EAAEL,GAAAA,CAAI,+CAA+C,CAAC,CAAA;AAElF,YAAA;AACF,QAAA,CAAA;;QAGAD,qBAAAA,CAAsB,sBAAA,EAAwBZ,OAAOS,oBAAoB,CAAA;;QAEzEG,qBAAAA,CAAsB,0BAAA,EAA4BZ,OAAOU,wBAAwB,CAAA;;;QAIjF,MAAMS,gBAAAA,GAAmBnB,MAAAA,CAAOM,KAAK,EAAEa,gBAAAA;AACvC,QAAA,IACEA,gBAAAA,IAAoB,IAAA,IACpB,OAAOA,gBAAAA,KAAqB,aAC5B,EAAEH,MAAAA,CAAOC,SAAS,CAACE,gBAAAA,CAAAA,IAAqB,gBAACA,IAA+B,CAAA,CAAA,EACxE;AACA,YAAA,MAAM,IAAID,KAAAA,CACR,2JAAA,CAAA;AAEJ,QAAA;AACF,IAAA;AACF;;;;"}
|
package/dist/server/config.mjs
CHANGED
|
@@ -24,6 +24,12 @@ const config = {
|
|
|
24
24
|
assertPositiveInteger('concurrentUploadSize', config.concurrentUploadSize);
|
|
25
25
|
// Client-side parallelism: upload requests the admin fires at once.
|
|
26
26
|
assertPositiveInteger('concurrentUploadRequests', config.concurrentUploadRequests);
|
|
27
|
+
// Sharp throws on anything else at every image call, which the upload flow
|
|
28
|
+
// reads as "not an image" and skips processing silently.
|
|
29
|
+
const limitInputPixels = config.sharp?.limitInputPixels;
|
|
30
|
+
if (limitInputPixels != null && typeof limitInputPixels !== 'boolean' && !(Number.isInteger(limitInputPixels) && limitInputPixels >= 0)) {
|
|
31
|
+
throw new Error('upload plugin config: "sharp.limitInputPixels" must be a boolean or an integer greater than or equal to 0 (use env.int() to read it from the environment)');
|
|
32
|
+
}
|
|
27
33
|
}
|
|
28
34
|
};
|
|
29
35
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.mjs","sources":["../../server/src/config.ts"],"sourcesContent":["export const config = {\n default: {\n enabled: true,\n provider: 'local',\n sizeLimit: 1000000000, // 1GB\n actionOptions: {},\n sharp: {\n cache: false,\n concurrency: 1,\n },\n concurrentUploadSize: 1,\n concurrentUploadRequests: 1,\n },\n validator(config: {
|
|
1
|
+
{"version":3,"file":"config.mjs","sources":["../../server/src/config.ts"],"sourcesContent":["export const config = {\n default: {\n enabled: true,\n provider: 'local',\n sizeLimit: 1000000000, // 1GB\n actionOptions: {},\n sharp: {\n cache: false,\n concurrency: 1,\n },\n concurrentUploadSize: 1,\n concurrentUploadRequests: 1,\n },\n validator(config: {\n concurrentUploadSize?: unknown;\n concurrentUploadRequests?: unknown;\n sharp?: { limitInputPixels?: unknown } | null;\n }) {\n const assertPositiveInteger = (key: string, value: unknown) => {\n if (value === undefined) {\n return;\n }\n if (typeof value !== 'number' || !Number.isInteger(value) || value < 1) {\n throw new Error(\n `upload plugin config: \"${key}\" must be an integer greater than or equal to 1`\n );\n }\n };\n\n // Server-side ceiling: files processed in parallel within one request.\n assertPositiveInteger('concurrentUploadSize', config.concurrentUploadSize);\n // Client-side parallelism: upload requests the admin fires at once.\n assertPositiveInteger('concurrentUploadRequests', config.concurrentUploadRequests);\n\n // Sharp throws on anything else at every image call, which the upload flow\n // reads as \"not an image\" and skips processing silently.\n const limitInputPixels = config.sharp?.limitInputPixels;\n if (\n limitInputPixels != null &&\n typeof limitInputPixels !== 'boolean' &&\n !(Number.isInteger(limitInputPixels) && (limitInputPixels as number) >= 0)\n ) {\n throw new Error(\n 'upload plugin config: \"sharp.limitInputPixels\" must be a boolean or an integer greater than or equal to 0 (use env.int() to read it from the environment)'\n );\n }\n },\n};\n"],"names":["config","default","enabled","provider","sizeLimit","actionOptions","sharp","cache","concurrency","concurrentUploadSize","concurrentUploadRequests","validator","assertPositiveInteger","key","value","undefined","Number","isInteger","Error","limitInputPixels"],"mappings":"MAAaA,MAAAA,GAAS;IACpBC,OAAAA,EAAS;QACPC,OAAAA,EAAS,IAAA;QACTC,QAAAA,EAAU,OAAA;QACVC,SAAAA,EAAW,UAAA;AACXC,QAAAA,aAAAA,EAAe,EAAC;QAChBC,KAAAA,EAAO;YACLC,KAAAA,EAAO,KAAA;YACPC,WAAAA,EAAa;AACf,SAAA;QACAC,oBAAAA,EAAsB,CAAA;QACtBC,wBAAAA,EAA0B;AAC5B,KAAA;AACAC,IAAAA,SAAAA,CAAAA,CAAUX,MAIT,EAAA;QACC,MAAMY,qBAAAA,GAAwB,CAACC,GAAAA,EAAaC,KAAAA,GAAAA;AAC1C,YAAA,IAAIA,UAAUC,SAAAA,EAAW;AACvB,gBAAA;AACF,YAAA;YACA,IAAI,OAAOD,UAAU,QAAA,IAAY,CAACE,OAAOC,SAAS,CAACH,KAAAA,CAAAA,IAAUA,KAAAA,GAAQ,CAAA,EAAG;AACtE,gBAAA,MAAM,IAAII,KAAAA,CACR,CAAC,uBAAuB,EAAEL,GAAAA,CAAI,+CAA+C,CAAC,CAAA;AAElF,YAAA;AACF,QAAA,CAAA;;QAGAD,qBAAAA,CAAsB,sBAAA,EAAwBZ,OAAOS,oBAAoB,CAAA;;QAEzEG,qBAAAA,CAAsB,0BAAA,EAA4BZ,OAAOU,wBAAwB,CAAA;;;QAIjF,MAAMS,gBAAAA,GAAmBnB,MAAAA,CAAOM,KAAK,EAAEa,gBAAAA;AACvC,QAAA,IACEA,gBAAAA,IAAoB,IAAA,IACpB,OAAOA,gBAAAA,KAAqB,aAC5B,EAAEH,MAAAA,CAAOC,SAAS,CAACE,gBAAAA,CAAAA,IAAqB,gBAACA,IAA+B,CAAA,CAAA,EACxE;AACA,YAAA,MAAM,IAAID,KAAAA,CACR,2JAAA,CAAA;AAEJ,QAAA;AACF,IAAA;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload.js","sources":["../../../../../server/src/controllers/validation/admin/upload.ts"],"sourcesContent":["import { yup, validateYupSchema } from '@strapi/utils';\nimport { getService } from '../../../utils';\n\nconst focalPointSchema = yup\n .object({\n x: yup.number().min(0).max(100).required(),\n y: yup.number().min(0).max(100).required(),\n })\n .nullable()\n .default(null);\n\nconst fileInfoSchema = yup.object({\n name: yup.string().nullable(),\n alternativeText: yup.string().nullable(),\n caption: yup.string().nullable(),\n focalPoint: focalPointSchema,\n folder: yup\n .strapiID()\n .nullable()\n .test('folder-exists', 'the folder does not exist', async (folderId) => {\n if (folderId == null) {\n return true;\n }\n\n const exists = await getService('folder').exists({ id: folderId });\n\n return exists;\n }),\n});\n\nconst uploadSchema = yup.object({\n fileInfo: fileInfoSchema,\n});\n\nconst multiUploadSchema = yup.object({\n fileInfo: yup.array().of(fileInfoSchema),\n});\n\nconst validateUploadBody = (data = {}, isMulti = false) => {\n const schema = isMulti ? multiUploadSchema : uploadSchema;\n\n return validateYupSchema(schema, { strict: false })(data);\n};\n\nexport { validateUploadBody };\n\nexport type UploadBody =\n
|
|
1
|
+
{"version":3,"file":"upload.js","sources":["../../../../../server/src/controllers/validation/admin/upload.ts"],"sourcesContent":["import { yup, validateYupSchema } from '@strapi/utils';\nimport { getService } from '../../../utils';\n\nconst focalPointSchema = yup\n .object({\n x: yup.number().min(0).max(100).required(),\n y: yup.number().min(0).max(100).required(),\n })\n .nullable()\n .default(null);\n\nconst fileInfoSchema = yup.object({\n name: yup.string().nullable(),\n alternativeText: yup.string().nullable(),\n caption: yup.string().nullable(),\n focalPoint: focalPointSchema,\n folder: yup\n .strapiID()\n .nullable()\n .test('folder-exists', 'the folder does not exist', async (folderId) => {\n if (folderId == null) {\n return true;\n }\n\n const exists = await getService('folder').exists({ id: folderId });\n\n return exists;\n }),\n});\n\nconst uploadSchema = yup.object({\n fileInfo: fileInfoSchema,\n});\n\nconst multiUploadSchema = yup.object({\n fileInfo: yup.array().of(fileInfoSchema),\n});\n\nconst validateUploadBody = (data = {}, isMulti = false) => {\n const schema = isMulti ? multiUploadSchema : uploadSchema;\n\n return validateYupSchema(schema, { strict: false })(data);\n};\n\nexport { validateUploadBody };\n\nexport type UploadBody =\n yup.InferType<typeof uploadSchema> | yup.InferType<typeof multiUploadSchema>;\n\nconst bulkUpdatesSchema = yup.object({\n updates: yup\n .array()\n .of(\n yup.object({\n id: yup.number().required(),\n fileInfo: fileInfoSchema.required(),\n })\n )\n .min(1)\n .required(),\n});\n\nexport const validateBulkUpdateBody = validateYupSchema(bulkUpdatesSchema);\n"],"names":["focalPointSchema","yup","object","x","number","min","max","required","y","nullable","default","fileInfoSchema","name","string","alternativeText","caption","focalPoint","folder","strapiID","test","folderId","exists","getService","id","uploadSchema","fileInfo","multiUploadSchema","array","of","validateUploadBody","data","isMulti","schema","validateYupSchema","strict","bulkUpdatesSchema","updates","validateBulkUpdateBody"],"mappings":";;;;;AAGA,MAAMA,gBAAAA,GAAmBC,SAAAA,CACtBC,MAAM,CAAC;IACNC,CAAAA,EAAGF,SAAAA,CAAIG,MAAM,EAAA,CAAGC,GAAG,CAAC,CAAA,CAAA,CAAGC,GAAG,CAAC,GAAA,CAAA,CAAKC,QAAQ,EAAA;IACxCC,CAAAA,EAAGP,SAAAA,CAAIG,MAAM,EAAA,CAAGC,GAAG,CAAC,CAAA,CAAA,CAAGC,GAAG,CAAC,GAAA,CAAA,CAAKC,QAAQ;AAC1C,CAAA,CAAA,CACCE,QAAQ,EAAA,CACRC,OAAO,CAAC,IAAA,CAAA;AAEX,MAAMC,cAAAA,GAAiBV,SAAAA,CAAIC,MAAM,CAAC;IAChCU,IAAAA,EAAMX,SAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IAC3BK,eAAAA,EAAiBb,SAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IACtCM,OAAAA,EAASd,SAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IAC9BO,UAAAA,EAAYhB,gBAAAA;IACZiB,MAAAA,EAAQhB,SAAAA,CACLiB,QAAQ,EAAA,CACRT,QAAQ,GACRU,IAAI,CAAC,eAAA,EAAiB,2BAAA,EAA6B,OAAOC,QAAAA,GAAAA;AACzD,QAAA,IAAIA,YAAY,IAAA,EAAM;YACpB,OAAO,IAAA;AACT,QAAA;AAEA,QAAA,MAAMC,MAAAA,GAAS,MAAMC,gBAAAA,CAAW,QAAA,CAAA,CAAUD,MAAM,CAAC;YAAEE,EAAAA,EAAIH;AAAS,SAAA,CAAA;QAEhE,OAAOC,MAAAA;AACT,IAAA,CAAA;AACJ,CAAA,CAAA;AAEA,MAAMG,YAAAA,GAAevB,SAAAA,CAAIC,MAAM,CAAC;IAC9BuB,QAAAA,EAAUd;AACZ,CAAA,CAAA;AAEA,MAAMe,iBAAAA,GAAoBzB,SAAAA,CAAIC,MAAM,CAAC;AACnCuB,IAAAA,QAAAA,EAAUxB,SAAAA,CAAI0B,KAAK,EAAA,CAAGC,EAAE,CAACjB,cAAAA;AAC3B,CAAA,CAAA;AAEA,MAAMkB,qBAAqB,CAACC,IAAAA,GAAO,EAAE,EAAEC,UAAU,KAAK,GAAA;IACpD,MAAMC,MAAAA,GAASD,UAAUL,iBAAAA,GAAoBF,YAAAA;AAE7C,IAAA,OAAOS,wBAAkBD,MAAAA,EAAQ;QAAEE,MAAAA,EAAQ;KAAM,CAAA,CAAGJ,IAAAA,CAAAA;AACtD;AAOA,MAAMK,iBAAAA,GAAoBlC,SAAAA,CAAIC,MAAM,CAAC;AACnCkC,IAAAA,OAAAA,EAASnC,UACN0B,KAAK,EAAA,CACLC,EAAE,CACD3B,SAAAA,CAAIC,MAAM,CAAC;QACTqB,EAAAA,EAAItB,SAAAA,CAAIG,MAAM,EAAA,CAAGG,QAAQ,EAAA;AACzBkB,QAAAA,QAAAA,EAAUd,eAAeJ,QAAQ;KACnC,CAAA,CAAA,CAEDF,GAAG,CAAC,CAAA,CAAA,CACJE,QAAQ;AACb,CAAA,CAAA;AAEO,MAAM8B,sBAAAA,GAAyBJ,uBAAAA,CAAkBE,iBAAAA;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload.mjs","sources":["../../../../../server/src/controllers/validation/admin/upload.ts"],"sourcesContent":["import { yup, validateYupSchema } from '@strapi/utils';\nimport { getService } from '../../../utils';\n\nconst focalPointSchema = yup\n .object({\n x: yup.number().min(0).max(100).required(),\n y: yup.number().min(0).max(100).required(),\n })\n .nullable()\n .default(null);\n\nconst fileInfoSchema = yup.object({\n name: yup.string().nullable(),\n alternativeText: yup.string().nullable(),\n caption: yup.string().nullable(),\n focalPoint: focalPointSchema,\n folder: yup\n .strapiID()\n .nullable()\n .test('folder-exists', 'the folder does not exist', async (folderId) => {\n if (folderId == null) {\n return true;\n }\n\n const exists = await getService('folder').exists({ id: folderId });\n\n return exists;\n }),\n});\n\nconst uploadSchema = yup.object({\n fileInfo: fileInfoSchema,\n});\n\nconst multiUploadSchema = yup.object({\n fileInfo: yup.array().of(fileInfoSchema),\n});\n\nconst validateUploadBody = (data = {}, isMulti = false) => {\n const schema = isMulti ? multiUploadSchema : uploadSchema;\n\n return validateYupSchema(schema, { strict: false })(data);\n};\n\nexport { validateUploadBody };\n\nexport type UploadBody =\n
|
|
1
|
+
{"version":3,"file":"upload.mjs","sources":["../../../../../server/src/controllers/validation/admin/upload.ts"],"sourcesContent":["import { yup, validateYupSchema } from '@strapi/utils';\nimport { getService } from '../../../utils';\n\nconst focalPointSchema = yup\n .object({\n x: yup.number().min(0).max(100).required(),\n y: yup.number().min(0).max(100).required(),\n })\n .nullable()\n .default(null);\n\nconst fileInfoSchema = yup.object({\n name: yup.string().nullable(),\n alternativeText: yup.string().nullable(),\n caption: yup.string().nullable(),\n focalPoint: focalPointSchema,\n folder: yup\n .strapiID()\n .nullable()\n .test('folder-exists', 'the folder does not exist', async (folderId) => {\n if (folderId == null) {\n return true;\n }\n\n const exists = await getService('folder').exists({ id: folderId });\n\n return exists;\n }),\n});\n\nconst uploadSchema = yup.object({\n fileInfo: fileInfoSchema,\n});\n\nconst multiUploadSchema = yup.object({\n fileInfo: yup.array().of(fileInfoSchema),\n});\n\nconst validateUploadBody = (data = {}, isMulti = false) => {\n const schema = isMulti ? multiUploadSchema : uploadSchema;\n\n return validateYupSchema(schema, { strict: false })(data);\n};\n\nexport { validateUploadBody };\n\nexport type UploadBody =\n yup.InferType<typeof uploadSchema> | yup.InferType<typeof multiUploadSchema>;\n\nconst bulkUpdatesSchema = yup.object({\n updates: yup\n .array()\n .of(\n yup.object({\n id: yup.number().required(),\n fileInfo: fileInfoSchema.required(),\n })\n )\n .min(1)\n .required(),\n});\n\nexport const validateBulkUpdateBody = validateYupSchema(bulkUpdatesSchema);\n"],"names":["focalPointSchema","yup","object","x","number","min","max","required","y","nullable","default","fileInfoSchema","name","string","alternativeText","caption","focalPoint","folder","strapiID","test","folderId","exists","getService","id","uploadSchema","fileInfo","multiUploadSchema","array","of","validateUploadBody","data","isMulti","schema","validateYupSchema","strict","bulkUpdatesSchema","updates","validateBulkUpdateBody"],"mappings":";;;AAGA,MAAMA,gBAAAA,GAAmBC,GAAAA,CACtBC,MAAM,CAAC;IACNC,CAAAA,EAAGF,GAAAA,CAAIG,MAAM,EAAA,CAAGC,GAAG,CAAC,CAAA,CAAA,CAAGC,GAAG,CAAC,GAAA,CAAA,CAAKC,QAAQ,EAAA;IACxCC,CAAAA,EAAGP,GAAAA,CAAIG,MAAM,EAAA,CAAGC,GAAG,CAAC,CAAA,CAAA,CAAGC,GAAG,CAAC,GAAA,CAAA,CAAKC,QAAQ;AAC1C,CAAA,CAAA,CACCE,QAAQ,EAAA,CACRC,OAAO,CAAC,IAAA,CAAA;AAEX,MAAMC,cAAAA,GAAiBV,GAAAA,CAAIC,MAAM,CAAC;IAChCU,IAAAA,EAAMX,GAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IAC3BK,eAAAA,EAAiBb,GAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IACtCM,OAAAA,EAASd,GAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IAC9BO,UAAAA,EAAYhB,gBAAAA;IACZiB,MAAAA,EAAQhB,GAAAA,CACLiB,QAAQ,EAAA,CACRT,QAAQ,GACRU,IAAI,CAAC,eAAA,EAAiB,2BAAA,EAA6B,OAAOC,QAAAA,GAAAA;AACzD,QAAA,IAAIA,YAAY,IAAA,EAAM;YACpB,OAAO,IAAA;AACT,QAAA;AAEA,QAAA,MAAMC,MAAAA,GAAS,MAAMC,UAAAA,CAAW,QAAA,CAAA,CAAUD,MAAM,CAAC;YAAEE,EAAAA,EAAIH;AAAS,SAAA,CAAA;QAEhE,OAAOC,MAAAA;AACT,IAAA,CAAA;AACJ,CAAA,CAAA;AAEA,MAAMG,YAAAA,GAAevB,GAAAA,CAAIC,MAAM,CAAC;IAC9BuB,QAAAA,EAAUd;AACZ,CAAA,CAAA;AAEA,MAAMe,iBAAAA,GAAoBzB,GAAAA,CAAIC,MAAM,CAAC;AACnCuB,IAAAA,QAAAA,EAAUxB,GAAAA,CAAI0B,KAAK,EAAA,CAAGC,EAAE,CAACjB,cAAAA;AAC3B,CAAA,CAAA;AAEA,MAAMkB,qBAAqB,CAACC,IAAAA,GAAO,EAAE,EAAEC,UAAU,KAAK,GAAA;IACpD,MAAMC,MAAAA,GAASD,UAAUL,iBAAAA,GAAoBF,YAAAA;AAE7C,IAAA,OAAOS,kBAAkBD,MAAAA,EAAQ;QAAEE,MAAAA,EAAQ;KAAM,CAAA,CAAGJ,IAAAA,CAAAA;AACtD;AAOA,MAAMK,iBAAAA,GAAoBlC,GAAAA,CAAIC,MAAM,CAAC;AACnCkC,IAAAA,OAAAA,EAASnC,IACN0B,KAAK,EAAA,CACLC,EAAE,CACD3B,GAAAA,CAAIC,MAAM,CAAC;QACTqB,EAAAA,EAAItB,GAAAA,CAAIG,MAAM,EAAA,CAAGG,QAAQ,EAAA;AACzBkB,QAAAA,QAAAA,EAAUd,eAAeJ,QAAQ;KACnC,CAAA,CAAA,CAEDF,GAAG,CAAC,CAAA,CAAA,CACJE,QAAQ;AACb,CAAA,CAAA;AAEO,MAAM8B,sBAAAA,GAAyBJ,iBAAAA,CAAkBE,iBAAAA;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload.js","sources":["../../../../../server/src/controllers/validation/content-api/upload.ts"],"sourcesContent":["import { yup, validateYupSchema } from '@strapi/utils';\n\nconst focalPointSchema = yup\n .object({\n x: yup.number().min(0).max(100).required(),\n y: yup.number().min(0).max(100).required(),\n })\n .nullable()\n .default(null);\n\nconst fileInfoSchema = yup\n .object({\n name: yup.string().nullable(),\n alternativeText: yup.string().nullable(),\n caption: yup.string().nullable(),\n focalPoint: focalPointSchema,\n })\n .noUnknown();\n\nconst uploadSchema = yup.object({\n fileInfo: fileInfoSchema,\n});\n\nconst multiUploadSchema = yup.object({\n fileInfo: yup.array().of(fileInfoSchema),\n});\n\nconst validateUploadBody = (data = {}, isMulti = false) => {\n const schema = isMulti ? multiUploadSchema : uploadSchema;\n\n return validateYupSchema(schema, { strict: false })(data);\n};\n\nexport { validateUploadBody };\n\nexport type UploadBody =\n
|
|
1
|
+
{"version":3,"file":"upload.js","sources":["../../../../../server/src/controllers/validation/content-api/upload.ts"],"sourcesContent":["import { yup, validateYupSchema } from '@strapi/utils';\n\nconst focalPointSchema = yup\n .object({\n x: yup.number().min(0).max(100).required(),\n y: yup.number().min(0).max(100).required(),\n })\n .nullable()\n .default(null);\n\nconst fileInfoSchema = yup\n .object({\n name: yup.string().nullable(),\n alternativeText: yup.string().nullable(),\n caption: yup.string().nullable(),\n focalPoint: focalPointSchema,\n })\n .noUnknown();\n\nconst uploadSchema = yup.object({\n fileInfo: fileInfoSchema,\n});\n\nconst multiUploadSchema = yup.object({\n fileInfo: yup.array().of(fileInfoSchema),\n});\n\nconst validateUploadBody = (data = {}, isMulti = false) => {\n const schema = isMulti ? multiUploadSchema : uploadSchema;\n\n return validateYupSchema(schema, { strict: false })(data);\n};\n\nexport { validateUploadBody };\n\nexport type UploadBody =\n yup.InferType<typeof uploadSchema> | yup.InferType<typeof multiUploadSchema>;\n"],"names":["focalPointSchema","yup","object","x","number","min","max","required","y","nullable","default","fileInfoSchema","name","string","alternativeText","caption","focalPoint","noUnknown","uploadSchema","fileInfo","multiUploadSchema","array","of","validateUploadBody","data","isMulti","schema","validateYupSchema","strict"],"mappings":";;;;AAEA,MAAMA,gBAAAA,GAAmBC,SAAAA,CACtBC,MAAM,CAAC;IACNC,CAAAA,EAAGF,SAAAA,CAAIG,MAAM,EAAA,CAAGC,GAAG,CAAC,CAAA,CAAA,CAAGC,GAAG,CAAC,GAAA,CAAA,CAAKC,QAAQ,EAAA;IACxCC,CAAAA,EAAGP,SAAAA,CAAIG,MAAM,EAAA,CAAGC,GAAG,CAAC,CAAA,CAAA,CAAGC,GAAG,CAAC,GAAA,CAAA,CAAKC,QAAQ;AAC1C,CAAA,CAAA,CACCE,QAAQ,EAAA,CACRC,OAAO,CAAC,IAAA,CAAA;AAEX,MAAMC,cAAAA,GAAiBV,SAAAA,CACpBC,MAAM,CAAC;IACNU,IAAAA,EAAMX,SAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IAC3BK,eAAAA,EAAiBb,SAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IACtCM,OAAAA,EAASd,SAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IAC9BO,UAAAA,EAAYhB;AACd,CAAA,CAAA,CACCiB,SAAS,EAAA;AAEZ,MAAMC,YAAAA,GAAejB,SAAAA,CAAIC,MAAM,CAAC;IAC9BiB,QAAAA,EAAUR;AACZ,CAAA,CAAA;AAEA,MAAMS,iBAAAA,GAAoBnB,SAAAA,CAAIC,MAAM,CAAC;AACnCiB,IAAAA,QAAAA,EAAUlB,SAAAA,CAAIoB,KAAK,EAAA,CAAGC,EAAE,CAACX,cAAAA;AAC3B,CAAA,CAAA;AAEA,MAAMY,qBAAqB,CAACC,IAAAA,GAAO,EAAE,EAAEC,UAAU,KAAK,GAAA;IACpD,MAAMC,MAAAA,GAASD,UAAUL,iBAAAA,GAAoBF,YAAAA;AAE7C,IAAA,OAAOS,wBAAkBD,MAAAA,EAAQ;QAAEE,MAAAA,EAAQ;KAAM,CAAA,CAAGJ,IAAAA,CAAAA;AACtD;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload.mjs","sources":["../../../../../server/src/controllers/validation/content-api/upload.ts"],"sourcesContent":["import { yup, validateYupSchema } from '@strapi/utils';\n\nconst focalPointSchema = yup\n .object({\n x: yup.number().min(0).max(100).required(),\n y: yup.number().min(0).max(100).required(),\n })\n .nullable()\n .default(null);\n\nconst fileInfoSchema = yup\n .object({\n name: yup.string().nullable(),\n alternativeText: yup.string().nullable(),\n caption: yup.string().nullable(),\n focalPoint: focalPointSchema,\n })\n .noUnknown();\n\nconst uploadSchema = yup.object({\n fileInfo: fileInfoSchema,\n});\n\nconst multiUploadSchema = yup.object({\n fileInfo: yup.array().of(fileInfoSchema),\n});\n\nconst validateUploadBody = (data = {}, isMulti = false) => {\n const schema = isMulti ? multiUploadSchema : uploadSchema;\n\n return validateYupSchema(schema, { strict: false })(data);\n};\n\nexport { validateUploadBody };\n\nexport type UploadBody =\n
|
|
1
|
+
{"version":3,"file":"upload.mjs","sources":["../../../../../server/src/controllers/validation/content-api/upload.ts"],"sourcesContent":["import { yup, validateYupSchema } from '@strapi/utils';\n\nconst focalPointSchema = yup\n .object({\n x: yup.number().min(0).max(100).required(),\n y: yup.number().min(0).max(100).required(),\n })\n .nullable()\n .default(null);\n\nconst fileInfoSchema = yup\n .object({\n name: yup.string().nullable(),\n alternativeText: yup.string().nullable(),\n caption: yup.string().nullable(),\n focalPoint: focalPointSchema,\n })\n .noUnknown();\n\nconst uploadSchema = yup.object({\n fileInfo: fileInfoSchema,\n});\n\nconst multiUploadSchema = yup.object({\n fileInfo: yup.array().of(fileInfoSchema),\n});\n\nconst validateUploadBody = (data = {}, isMulti = false) => {\n const schema = isMulti ? multiUploadSchema : uploadSchema;\n\n return validateYupSchema(schema, { strict: false })(data);\n};\n\nexport { validateUploadBody };\n\nexport type UploadBody =\n yup.InferType<typeof uploadSchema> | yup.InferType<typeof multiUploadSchema>;\n"],"names":["focalPointSchema","yup","object","x","number","min","max","required","y","nullable","default","fileInfoSchema","name","string","alternativeText","caption","focalPoint","noUnknown","uploadSchema","fileInfo","multiUploadSchema","array","of","validateUploadBody","data","isMulti","schema","validateYupSchema","strict"],"mappings":";;AAEA,MAAMA,gBAAAA,GAAmBC,GAAAA,CACtBC,MAAM,CAAC;IACNC,CAAAA,EAAGF,GAAAA,CAAIG,MAAM,EAAA,CAAGC,GAAG,CAAC,CAAA,CAAA,CAAGC,GAAG,CAAC,GAAA,CAAA,CAAKC,QAAQ,EAAA;IACxCC,CAAAA,EAAGP,GAAAA,CAAIG,MAAM,EAAA,CAAGC,GAAG,CAAC,CAAA,CAAA,CAAGC,GAAG,CAAC,GAAA,CAAA,CAAKC,QAAQ;AAC1C,CAAA,CAAA,CACCE,QAAQ,EAAA,CACRC,OAAO,CAAC,IAAA,CAAA;AAEX,MAAMC,cAAAA,GAAiBV,GAAAA,CACpBC,MAAM,CAAC;IACNU,IAAAA,EAAMX,GAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IAC3BK,eAAAA,EAAiBb,GAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IACtCM,OAAAA,EAASd,GAAAA,CAAIY,MAAM,EAAA,CAAGJ,QAAQ,EAAA;IAC9BO,UAAAA,EAAYhB;AACd,CAAA,CAAA,CACCiB,SAAS,EAAA;AAEZ,MAAMC,YAAAA,GAAejB,GAAAA,CAAIC,MAAM,CAAC;IAC9BiB,QAAAA,EAAUR;AACZ,CAAA,CAAA;AAEA,MAAMS,iBAAAA,GAAoBnB,GAAAA,CAAIC,MAAM,CAAC;AACnCiB,IAAAA,QAAAA,EAAUlB,GAAAA,CAAIoB,KAAK,EAAA,CAAGC,EAAE,CAACX,cAAAA;AAC3B,CAAA,CAAA;AAEA,MAAMY,qBAAqB,CAACC,IAAAA,GAAO,EAAE,EAAEC,UAAU,KAAK,GAAA;IACpD,MAAMC,MAAAA,GAASD,UAAUL,iBAAAA,GAAoBF,YAAAA;AAE7C,IAAA,OAAOS,kBAAkBD,MAAAA,EAAQ;QAAEE,MAAAA,EAAQ;KAAM,CAAA,CAAGJ,IAAAA,CAAAA;AACtD;;;;"}
|
|
@@ -21,9 +21,11 @@ var index = require('../utils/index.js');
|
|
|
21
21
|
* `strapi.getModel`, `update` runs a multi-statement transaction, and every admin controller and
|
|
22
22
|
* validator already depends on the ambient form.
|
|
23
23
|
*
|
|
24
|
-
* So the dependency is made explicit and asserted instead.
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* So the dependency is made explicit and asserted instead. `buildUploadMcpToolDefinitions`
|
|
25
|
+
* wraps every tool's `createHandler` in this check, so it applies to the whole media surface by
|
|
26
|
+
* construction rather than by each factory remembering to call it. It runs at handler
|
|
27
|
+
* construction, not per call, so a mismatch fails while the tool is being registered rather
|
|
28
|
+
* than surfacing to an agent as tool output mid-conversation.
|
|
27
29
|
*
|
|
28
30
|
* A single-app server is unaffected: `createStrapi` assigns its instance to `global.strapi`, so
|
|
29
31
|
* the two agree. If they ever diverge — a second Strapi instance in one process — this throws
|
|
@@ -37,8 +39,8 @@ var index = require('../utils/index.js');
|
|
|
37
39
|
* Resolves the `folder` service for an MCP handler.
|
|
38
40
|
*
|
|
39
41
|
* A bare `getService('folder', strapi)` reads as instance-bound but is not — see
|
|
40
|
-
* `assertAmbientInstance` for why
|
|
41
|
-
*
|
|
42
|
+
* `assertAmbientInstance` for why, and for where that is enforced. This keeps the resolution
|
|
43
|
+
* behind a named helper so the call sites do not reintroduce the misleading form.
|
|
42
44
|
*/ const getFolderService = (strapi)=>index.getService('folder', strapi);
|
|
43
45
|
|
|
44
46
|
exports.assertAmbientInstance = assertAmbientInstance;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ambient-instance.js","sources":["../../../server/src/mcp/ambient-instance.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport { getService } from '../utils';\n\n/**\n * Asserts that an MCP handler's Strapi instance is the ambient `global.strapi`.\n *\n * Two of the upload plugin's services — `folder` and `file` — are registered as plain object\n * literals rather than factories (see `services/index.ts`), so their methods close over the\n * module-scope ambient `strapi` and query `global.strapi.db` regardless of which instance is\n * passed to `getService`. Passing an instance therefore selects the right plugin registry but\n * does *not* bind the queries to it.\n *\n * The folder tools reach `folder` directly. The asset write tools reach `file` transitively:\n * `upload.updateFileInfo` resolves it with a bare `getService('file')` (`services/upload.ts`),\n * and `file.getFolderPath` then queries the ambient `strapi.db`. So a handler that looks\n * instance-bound can still mix ambient reads with instance-bound writes.\n *\n * Threading an instance through both services is a broader refactor than the MCP surface should\n * carry: `create`, `update` and `deleteByIds` reach for `strapi.db`, `strapi.eventHub` and\n * `strapi.getModel`, `update` runs a multi-statement transaction, and every admin controller and\n * validator already depends on the ambient form.\n *\n * So the dependency is made explicit and asserted instead.
|
|
1
|
+
{"version":3,"file":"ambient-instance.js","sources":["../../../server/src/mcp/ambient-instance.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport { getService } from '../utils';\n\n/**\n * Asserts that an MCP handler's Strapi instance is the ambient `global.strapi`.\n *\n * Two of the upload plugin's services — `folder` and `file` — are registered as plain object\n * literals rather than factories (see `services/index.ts`), so their methods close over the\n * module-scope ambient `strapi` and query `global.strapi.db` regardless of which instance is\n * passed to `getService`. Passing an instance therefore selects the right plugin registry but\n * does *not* bind the queries to it.\n *\n * The folder tools reach `folder` directly. The asset write tools reach `file` transitively:\n * `upload.updateFileInfo` resolves it with a bare `getService('file')` (`services/upload.ts`),\n * and `file.getFolderPath` then queries the ambient `strapi.db`. So a handler that looks\n * instance-bound can still mix ambient reads with instance-bound writes.\n *\n * Threading an instance through both services is a broader refactor than the MCP surface should\n * carry: `create`, `update` and `deleteByIds` reach for `strapi.db`, `strapi.eventHub` and\n * `strapi.getModel`, `update` runs a multi-statement transaction, and every admin controller and\n * validator already depends on the ambient form.\n *\n * So the dependency is made explicit and asserted instead. `buildUploadMcpToolDefinitions`\n * wraps every tool's `createHandler` in this check, so it applies to the whole media surface by\n * construction rather than by each factory remembering to call it. It runs at handler\n * construction, not per call, so a mismatch fails while the tool is being registered rather\n * than surfacing to an agent as tool output mid-conversation.\n *\n * A single-app server is unaffected: `createStrapi` assigns its instance to `global.strapi`, so\n * the two agree. If they ever diverge — a second Strapi instance in one process — this throws\n * rather than silently reading or writing the wrong app's media library.\n */\nexport const assertAmbientInstance = (strapi: Core.Strapi) => {\n if (strapi !== global.strapi) {\n throw new Error(\n 'The upload `folder` and `file` services are bound to the ambient `global.strapi`, but an ' +\n 'MCP handler was constructed with a different Strapi instance. Media queries would run ' +\n 'against the wrong app. Convert those services to factories before serving MCP from a ' +\n 'non-global instance.'\n );\n }\n};\n\n/**\n * Resolves the `folder` service for an MCP handler.\n *\n * A bare `getService('folder', strapi)` reads as instance-bound but is not — see\n * `assertAmbientInstance` for why, and for where that is enforced. This keeps the resolution\n * behind a named helper so the call sites do not reintroduce the misleading form.\n */\nexport const getFolderService = (strapi: Core.Strapi) => getService('folder', strapi);\n"],"names":["assertAmbientInstance","strapi","global","Error","getFolderService","getService"],"mappings":";;;;AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA6BO,MAAMA,qBAAAA,GAAwB,CAACC,MAAAA,GAAAA;IACpC,IAAIA,MAAAA,KAAWC,MAAAA,CAAOD,MAAM,EAAE;AAC5B,QAAA,MAAM,IAAIE,KAAAA,CACR,2FAAA,GACE,wFAAA,GACA,uFAAA,GACA,sBAAA,CAAA;AAEN,IAAA;AACF;AAEA;;;;;;AAMC,IACM,MAAMC,gBAAAA,GAAmB,CAACH,MAAAA,GAAwBI,gBAAAA,CAAW,UAAUJ,MAAAA;;;;;"}
|
|
@@ -19,9 +19,11 @@ import { getService } from '../utils/index.mjs';
|
|
|
19
19
|
* `strapi.getModel`, `update` runs a multi-statement transaction, and every admin controller and
|
|
20
20
|
* validator already depends on the ambient form.
|
|
21
21
|
*
|
|
22
|
-
* So the dependency is made explicit and asserted instead.
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* So the dependency is made explicit and asserted instead. `buildUploadMcpToolDefinitions`
|
|
23
|
+
* wraps every tool's `createHandler` in this check, so it applies to the whole media surface by
|
|
24
|
+
* construction rather than by each factory remembering to call it. It runs at handler
|
|
25
|
+
* construction, not per call, so a mismatch fails while the tool is being registered rather
|
|
26
|
+
* than surfacing to an agent as tool output mid-conversation.
|
|
25
27
|
*
|
|
26
28
|
* A single-app server is unaffected: `createStrapi` assigns its instance to `global.strapi`, so
|
|
27
29
|
* the two agree. If they ever diverge — a second Strapi instance in one process — this throws
|
|
@@ -35,8 +37,8 @@ import { getService } from '../utils/index.mjs';
|
|
|
35
37
|
* Resolves the `folder` service for an MCP handler.
|
|
36
38
|
*
|
|
37
39
|
* A bare `getService('folder', strapi)` reads as instance-bound but is not — see
|
|
38
|
-
* `assertAmbientInstance` for why
|
|
39
|
-
*
|
|
40
|
+
* `assertAmbientInstance` for why, and for where that is enforced. This keeps the resolution
|
|
41
|
+
* behind a named helper so the call sites do not reintroduce the misleading form.
|
|
40
42
|
*/ const getFolderService = (strapi)=>getService('folder', strapi);
|
|
41
43
|
|
|
42
44
|
export { assertAmbientInstance, getFolderService };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ambient-instance.mjs","sources":["../../../server/src/mcp/ambient-instance.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport { getService } from '../utils';\n\n/**\n * Asserts that an MCP handler's Strapi instance is the ambient `global.strapi`.\n *\n * Two of the upload plugin's services — `folder` and `file` — are registered as plain object\n * literals rather than factories (see `services/index.ts`), so their methods close over the\n * module-scope ambient `strapi` and query `global.strapi.db` regardless of which instance is\n * passed to `getService`. Passing an instance therefore selects the right plugin registry but\n * does *not* bind the queries to it.\n *\n * The folder tools reach `folder` directly. The asset write tools reach `file` transitively:\n * `upload.updateFileInfo` resolves it with a bare `getService('file')` (`services/upload.ts`),\n * and `file.getFolderPath` then queries the ambient `strapi.db`. So a handler that looks\n * instance-bound can still mix ambient reads with instance-bound writes.\n *\n * Threading an instance through both services is a broader refactor than the MCP surface should\n * carry: `create`, `update` and `deleteByIds` reach for `strapi.db`, `strapi.eventHub` and\n * `strapi.getModel`, `update` runs a multi-statement transaction, and every admin controller and\n * validator already depends on the ambient form.\n *\n * So the dependency is made explicit and asserted instead.
|
|
1
|
+
{"version":3,"file":"ambient-instance.mjs","sources":["../../../server/src/mcp/ambient-instance.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport { getService } from '../utils';\n\n/**\n * Asserts that an MCP handler's Strapi instance is the ambient `global.strapi`.\n *\n * Two of the upload plugin's services — `folder` and `file` — are registered as plain object\n * literals rather than factories (see `services/index.ts`), so their methods close over the\n * module-scope ambient `strapi` and query `global.strapi.db` regardless of which instance is\n * passed to `getService`. Passing an instance therefore selects the right plugin registry but\n * does *not* bind the queries to it.\n *\n * The folder tools reach `folder` directly. The asset write tools reach `file` transitively:\n * `upload.updateFileInfo` resolves it with a bare `getService('file')` (`services/upload.ts`),\n * and `file.getFolderPath` then queries the ambient `strapi.db`. So a handler that looks\n * instance-bound can still mix ambient reads with instance-bound writes.\n *\n * Threading an instance through both services is a broader refactor than the MCP surface should\n * carry: `create`, `update` and `deleteByIds` reach for `strapi.db`, `strapi.eventHub` and\n * `strapi.getModel`, `update` runs a multi-statement transaction, and every admin controller and\n * validator already depends on the ambient form.\n *\n * So the dependency is made explicit and asserted instead. `buildUploadMcpToolDefinitions`\n * wraps every tool's `createHandler` in this check, so it applies to the whole media surface by\n * construction rather than by each factory remembering to call it. It runs at handler\n * construction, not per call, so a mismatch fails while the tool is being registered rather\n * than surfacing to an agent as tool output mid-conversation.\n *\n * A single-app server is unaffected: `createStrapi` assigns its instance to `global.strapi`, so\n * the two agree. If they ever diverge — a second Strapi instance in one process — this throws\n * rather than silently reading or writing the wrong app's media library.\n */\nexport const assertAmbientInstance = (strapi: Core.Strapi) => {\n if (strapi !== global.strapi) {\n throw new Error(\n 'The upload `folder` and `file` services are bound to the ambient `global.strapi`, but an ' +\n 'MCP handler was constructed with a different Strapi instance. Media queries would run ' +\n 'against the wrong app. Convert those services to factories before serving MCP from a ' +\n 'non-global instance.'\n );\n }\n};\n\n/**\n * Resolves the `folder` service for an MCP handler.\n *\n * A bare `getService('folder', strapi)` reads as instance-bound but is not — see\n * `assertAmbientInstance` for why, and for where that is enforced. This keeps the resolution\n * behind a named helper so the call sites do not reintroduce the misleading form.\n */\nexport const getFolderService = (strapi: Core.Strapi) => getService('folder', strapi);\n"],"names":["assertAmbientInstance","strapi","global","Error","getFolderService","getService"],"mappings":";;AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA6BO,MAAMA,qBAAAA,GAAwB,CAACC,MAAAA,GAAAA;IACpC,IAAIA,MAAAA,KAAWC,MAAAA,CAAOD,MAAM,EAAE;AAC5B,QAAA,MAAM,IAAIE,KAAAA,CACR,2FAAA,GACE,wFAAA,GACA,uFAAA,GACA,sBAAA,CAAA;AAEN,IAAA;AACF;AAEA;;;;;;AAMC,IACM,MAAMC,gBAAAA,GAAmB,CAACH,MAAAA,GAAwBI,UAAAA,CAAW,UAAUJ,MAAAA;;;;"}
|