@strapi/upload 5.52.0 → 5.52.2
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/future/components/TruncatedText.js +76 -0
- package/dist/admin/future/components/TruncatedText.js.map +1 -0
- package/dist/admin/future/components/TruncatedText.mjs +74 -0
- package/dist/admin/future/components/TruncatedText.mjs.map +1 -0
- package/dist/admin/future/components/UploadProgressDialog.js +36 -1
- package/dist/admin/future/components/UploadProgressDialog.js.map +1 -1
- package/dist/admin/future/components/UploadProgressDialog.mjs +37 -2
- package/dist/admin/future/components/UploadProgressDialog.mjs.map +1 -1
- package/dist/admin/future/hooks/useApiErrorMessage.js +61 -0
- package/dist/admin/future/hooks/useApiErrorMessage.js.map +1 -0
- package/dist/admin/future/hooks/useApiErrorMessage.mjs +39 -0
- package/dist/admin/future/hooks/useApiErrorMessage.mjs.map +1 -0
- package/dist/admin/future/hooks/useTracking.js +57 -0
- package/dist/admin/future/hooks/useTracking.js.map +1 -0
- package/dist/admin/future/hooks/useTracking.mjs +53 -0
- package/dist/admin/future/hooks/useTracking.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/AssetsPage.js +31 -0
- package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
- package/dist/admin/future/pages/Assets/AssetsPage.mjs +31 -0
- package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js +13 -11
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs +13 -11
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +62 -51
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +62 -51
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsGrid.js +3 -4
- package/dist/admin/future/pages/Assets/components/AssetsGrid.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs +4 -5
- package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js +11 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs +11 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsTable.js +6 -4
- package/dist/admin/future/pages/Assets/components/AssetsTable.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsTable.mjs +6 -4
- package/dist/admin/future/pages/Assets/components/AssetsTable.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.js +10 -1
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs +10 -1
- package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.js +3 -2
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.mjs +3 -2
- package/dist/admin/future/pages/Assets/components/BulkMoveDialog.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js +4 -2
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs +4 -2
- package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FilterMenu.js +18 -2
- package/dist/admin/future/pages/Assets/components/FilterMenu.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FilterMenu.mjs +18 -2
- package/dist/admin/future/pages/Assets/components/FilterMenu.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.js +9 -7
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.mjs +9 -7
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderFormDialog.js +12 -0
- package/dist/admin/future/pages/Assets/components/FolderFormDialog.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderFormDialog.mjs +12 -0
- package/dist/admin/future/pages/Assets/components/FolderFormDialog.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js +21 -38
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs +23 -40
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/SortMenu.js +14 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/SortMenu.mjs +14 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js +5 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs +6 -1
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useIsAssetDetailsOpen.js +30 -0
- package/dist/admin/future/pages/Assets/hooks/useIsAssetDetailsOpen.js.map +1 -0
- package/dist/admin/future/pages/Assets/hooks/useIsAssetDetailsOpen.mjs +26 -0
- package/dist/admin/future/pages/Assets/hooks/useIsAssetDetailsOpen.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/utils/selection.js +17 -0
- package/dist/admin/future/pages/Assets/utils/selection.js.map +1 -1
- package/dist/admin/future/pages/Assets/utils/selection.mjs +17 -1
- package/dist/admin/future/pages/Assets/utils/selection.mjs.map +1 -1
- package/dist/admin/future/services/api.js +123 -19
- package/dist/admin/future/services/api.js.map +1 -1
- package/dist/admin/future/services/api.mjs +125 -21
- package/dist/admin/future/services/api.mjs.map +1 -1
- package/dist/admin/future/services/assets.js +11 -23
- package/dist/admin/future/services/assets.js.map +1 -1
- package/dist/admin/future/services/assets.mjs +11 -23
- package/dist/admin/future/services/assets.mjs.map +1 -1
- package/dist/admin/future/services/uploadFileViaXHR.js +9 -3
- package/dist/admin/future/services/uploadFileViaXHR.js.map +1 -1
- package/dist/admin/future/services/uploadFileViaXHR.mjs +9 -3
- package/dist/admin/future/services/uploadFileViaXHR.mjs.map +1 -1
- package/dist/admin/future/store/uploadProgress.js +44 -5
- package/dist/admin/future/store/uploadProgress.js.map +1 -1
- package/dist/admin/future/store/uploadProgress.mjs +43 -6
- package/dist/admin/future/store/uploadProgress.mjs.map +1 -1
- package/dist/admin/future/utils/getApiErrorMessage.js +20 -0
- package/dist/admin/future/utils/getApiErrorMessage.js.map +1 -0
- package/dist/admin/future/utils/getApiErrorMessage.mjs +18 -0
- package/dist/admin/future/utils/getApiErrorMessage.mjs.map +1 -0
- package/dist/admin/hooks/useAIMetadataJob.js +1 -1
- package/dist/admin/hooks/useAIMetadataJob.js.map +1 -1
- package/dist/admin/hooks/useAIMetadataJob.mjs +1 -1
- package/dist/admin/hooks/useAIMetadataJob.mjs.map +1 -1
- package/dist/admin/pages/SettingsPage/SettingsPage.js +2 -2
- package/dist/admin/pages/SettingsPage/SettingsPage.js.map +1 -1
- package/dist/admin/pages/SettingsPage/SettingsPage.mjs +2 -2
- package/dist/admin/pages/SettingsPage/SettingsPage.mjs.map +1 -1
- package/dist/admin/src/future/components/TruncatedText.d.ts +32 -0
- package/dist/admin/src/future/hooks/useApiErrorMessage.d.ts +17 -0
- package/dist/admin/src/future/hooks/useTracking.d.ts +29 -0
- package/dist/admin/src/future/pages/Assets/components/AssetActionsMenu.d.ts +5 -3
- package/dist/admin/src/future/pages/Assets/components/FolderActionsMenu.d.ts +5 -4
- package/dist/admin/src/future/pages/Assets/hooks/useAssetSelection.d.ts +2 -0
- package/dist/admin/src/future/pages/Assets/hooks/useIsAssetDetailsOpen.d.ts +18 -0
- package/dist/admin/src/future/pages/Assets/utils/selection.d.ts +10 -0
- package/dist/admin/src/future/services/api.d.ts +6 -7
- package/dist/admin/src/future/services/uploadFileViaXHR.d.ts +6 -1
- package/dist/admin/src/future/store/uploadProgress.d.ts +16 -1
- package/dist/admin/src/future/utils/getApiErrorMessage.d.ts +1 -0
- package/dist/admin/translations/ca.json.js +1 -1
- package/dist/admin/translations/ca.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 +2 -1
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +2 -1
- 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/fr.json.js +1 -1
- package/dist/admin/translations/fr.json.mjs +1 -1
- package/dist/admin/translations/ja.json.js +1 -1
- package/dist/admin/translations/ja.json.mjs +1 -1
- package/dist/admin/translations/ko.json.js +1 -1
- package/dist/admin/translations/ko.json.mjs +1 -1
- package/dist/admin/translations/nl.json.js +1 -1
- package/dist/admin/translations/nl.json.mjs +1 -1
- package/dist/admin/translations/pl.json.js +1 -1
- package/dist/admin/translations/pl.json.mjs +1 -1
- package/dist/admin/translations/pt-BR.json.js +1 -1
- package/dist/admin/translations/pt-BR.json.mjs +1 -1
- package/dist/admin/translations/ru.json.js +1 -1
- package/dist/admin/translations/ru.json.mjs +1 -1
- package/dist/admin/translations/sk.json.js +1 -1
- package/dist/admin/translations/sk.json.mjs +1 -1
- package/dist/admin/translations/tr.json.js +1 -1
- package/dist/admin/translations/tr.json.mjs +1 -1
- package/dist/admin/translations/uk.json.js +1 -1
- package/dist/admin/translations/uk.json.mjs +1 -1
- 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 +1 -1
- package/dist/admin/translations/zh.json.mjs +1 -1
- package/dist/server/controllers/admin-file.js +27 -9
- package/dist/server/controllers/admin-file.js.map +1 -1
- package/dist/server/controllers/admin-file.mjs +27 -9
- package/dist/server/controllers/admin-file.mjs.map +1 -1
- package/dist/server/controllers/admin-upload.js +24 -8
- package/dist/server/controllers/admin-upload.js.map +1 -1
- package/dist/server/controllers/admin-upload.mjs +24 -8
- package/dist/server/controllers/admin-upload.mjs.map +1 -1
- package/dist/server/routes/admin.js +41 -21
- package/dist/server/routes/admin.js.map +1 -1
- package/dist/server/routes/admin.mjs +41 -21
- package/dist/server/routes/admin.mjs.map +1 -1
- package/dist/server/services/ai-metadata.js +25 -5
- package/dist/server/services/ai-metadata.js.map +1 -1
- package/dist/server/services/ai-metadata.mjs +1 -1
- package/dist/server/services/ai-metadata.mjs.map +1 -1
- package/dist/server/services/upload.js +4 -0
- package/dist/server/services/upload.js.map +1 -1
- package/dist/server/services/upload.mjs +4 -0
- package/dist/server/services/upload.mjs.map +1 -1
- package/dist/server/src/controllers/admin-file.d.ts +29 -8
- package/dist/server/src/controllers/admin-file.d.ts.map +1 -1
- package/dist/server/src/controllers/admin-upload.d.ts +20 -4
- package/dist/server/src/controllers/admin-upload.d.ts.map +1 -1
- package/dist/server/src/controllers/index.d.ts +4 -4
- package/dist/server/src/index.d.ts +4 -4
- package/dist/server/src/routes/admin.d.ts.map +1 -1
- package/dist/server/src/services/ai-metadata.d.ts +2 -2
- package/dist/server/src/services/ai-metadata.d.ts.map +1 -1
- package/dist/server/src/services/upload.d.ts.map +1 -1
- package/dist/shared/contracts/ai-metadata-jobs.d.ts +10 -32
- package/dist/shared/contracts/ai-metadata-jobs.d.ts.map +1 -1
- package/dist/shared/contracts/files.d.ts +10 -10
- package/dist/shared/contracts/files.d.ts.map +1 -1
- package/package.json +7 -7
- package/dist/admin/future/utils/getBulkMoveErrorMessage.js +0 -23
- package/dist/admin/future/utils/getBulkMoveErrorMessage.js.map +0 -1
- package/dist/admin/future/utils/getBulkMoveErrorMessage.mjs +0 -21
- package/dist/admin/future/utils/getBulkMoveErrorMessage.mjs.map +0 -1
- package/dist/admin/src/future/utils/getBulkMoveErrorMessage.d.ts +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { adminApi } from '@strapi/admin/strapi-admin';
|
|
2
|
-
import { openUploadProgress, setUploadFailed, retryCancelledFiles, setFileError, setFileComplete, setFileUploading, setFileMetadataGenerating, setFileMetadataResult, setFileProgress } from '../store/uploadProgress.mjs';
|
|
2
|
+
import { openUploadProgress, setUploadFailed, retryCancelledFiles, isUploadInFlight, appendUploadFiles, setFileError, setFileComplete, setFileUploading, setFileMetadataGenerating, setFileMetadataResult, setFileProgress } from '../store/uploadProgress.mjs';
|
|
3
3
|
import { createRafBatcher } from '../utils/createRafBatcher.mjs';
|
|
4
4
|
import { getFilenameFromUrl } from '../utils/files.mjs';
|
|
5
|
-
import { uploadFileViaXHR, UploadAbortedError } from './uploadFileViaXHR.mjs';
|
|
5
|
+
import { uploadFileViaXHR, UploadFileError, UploadAbortedError } from './uploadFileViaXHR.mjs';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Stores the original upload batch (keyed by uploadId) to enable retry.
|
|
@@ -41,6 +41,22 @@ const unregisterAbortController = (uploadId)=>{
|
|
|
41
41
|
unregisterAbortController(uploadId);
|
|
42
42
|
}
|
|
43
43
|
};
|
|
44
|
+
/**
|
|
45
|
+
* Runs are chained per batch rather than started in parallel: a second pool
|
|
46
|
+
* alongside the first would double the files in flight and make `concurrency`
|
|
47
|
+
* stop meaning anything.
|
|
48
|
+
*/ const poolTails = new Map();
|
|
49
|
+
const trackPoolRun = (uploadId, run)=>{
|
|
50
|
+
// Not swallowed: the caller still gets the real result from `run`.
|
|
51
|
+
const tail = run.catch(()=>undefined);
|
|
52
|
+
poolTails.set(uploadId, tail);
|
|
53
|
+
tail.then(()=>{
|
|
54
|
+
// Leave the entry alone if another run has queued behind us in the meantime.
|
|
55
|
+
if (poolTails.get(uploadId) === tail) {
|
|
56
|
+
poolTails.delete(uploadId);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
};
|
|
44
60
|
/** Maps a server per-file outcome onto the row's terminal metadata status. */ const METADATA_STATUS_BY_RESULT = {
|
|
45
61
|
success: 'generated',
|
|
46
62
|
skipped: 'skipped',
|
|
@@ -97,7 +113,7 @@ const unregisterAbortController = (uploadId)=>{
|
|
|
97
113
|
* "complete" or "error". Each file is wrapped in its own try/catch so one failure
|
|
98
114
|
* does not stop the batch. An abort stops the loop without starting further files.
|
|
99
115
|
*/ const runUploadPool = async ({ entries, indices, token, uploadId, abortController, dispatch, concurrency = 1, generateAiMetadata })=>{
|
|
100
|
-
const url = `${window.strapi.backendURL}/upload/
|
|
116
|
+
const url = `${window.strapi.backendURL}/upload/files`;
|
|
101
117
|
const uploaded = [];
|
|
102
118
|
// Shared queue: each worker shifts the next index when it frees up, so N
|
|
103
119
|
// files are in flight at any moment (not N-sized waves). With concurrency 1
|
|
@@ -114,7 +130,8 @@ const unregisterAbortController = (uploadId)=>{
|
|
|
114
130
|
dispatch(setFileUploading({
|
|
115
131
|
name: fileName,
|
|
116
132
|
index,
|
|
117
|
-
size: entry.file.size
|
|
133
|
+
size: entry.file.size,
|
|
134
|
+
uploadId
|
|
118
135
|
}));
|
|
119
136
|
const formData = new FormData();
|
|
120
137
|
formData.append('files', entry.file);
|
|
@@ -123,7 +140,8 @@ const unregisterAbortController = (uploadId)=>{
|
|
|
123
140
|
const batcher = createRafBatcher((bytes)=>{
|
|
124
141
|
dispatch(setFileProgress({
|
|
125
142
|
index,
|
|
126
|
-
bytes
|
|
143
|
+
bytes,
|
|
144
|
+
uploadId
|
|
127
145
|
}));
|
|
128
146
|
});
|
|
129
147
|
try {
|
|
@@ -132,7 +150,8 @@ const unregisterAbortController = (uploadId)=>{
|
|
|
132
150
|
uploaded.push(file);
|
|
133
151
|
dispatch(setFileComplete({
|
|
134
152
|
index,
|
|
135
|
-
file
|
|
153
|
+
file,
|
|
154
|
+
uploadId
|
|
136
155
|
}));
|
|
137
156
|
// Not awaited: overlaps with the next file's upload and can't fail the batch.
|
|
138
157
|
maybeGenerateMetadata({
|
|
@@ -153,7 +172,8 @@ const unregisterAbortController = (uploadId)=>{
|
|
|
153
172
|
dispatch(setFileError({
|
|
154
173
|
index,
|
|
155
174
|
name: fileName,
|
|
156
|
-
message
|
|
175
|
+
message,
|
|
176
|
+
uploadId
|
|
157
177
|
}));
|
|
158
178
|
}
|
|
159
179
|
};
|
|
@@ -183,6 +203,44 @@ const unregisterAbortController = (uploadId)=>{
|
|
|
183
203
|
data: uploaded
|
|
184
204
|
};
|
|
185
205
|
};
|
|
206
|
+
/**
|
|
207
|
+
* Reuses the batch's AbortController so one Cancel stops both drops.
|
|
208
|
+
* `runUploadPool` unregisters it on finish, hence the re-register below.
|
|
209
|
+
*
|
|
210
|
+
* Resolves with the whole batch's files, not just this leg's: the mutation
|
|
211
|
+
* models one drop, and after a merge the drop is the batch. The earlier leg's
|
|
212
|
+
* files come from the tail this run queued behind.
|
|
213
|
+
*/ const runMergedUploadPool = async ({ entries, indices, token, uploadId, dispatch, concurrency, generateAiMetadata })=>{
|
|
214
|
+
const abortController = abortControllers.get(uploadId) ?? new AbortController();
|
|
215
|
+
const run = (poolTails.get(uploadId) ?? Promise.resolve(undefined)).then((previous)=>{
|
|
216
|
+
// A failed earlier leg contributes no files; its error already reached the
|
|
217
|
+
// store, and this leg still has files of its own to upload.
|
|
218
|
+
const earlier = previous?.data ?? [];
|
|
219
|
+
if (abortController.signal.aborted) {
|
|
220
|
+
return {
|
|
221
|
+
data: earlier
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
registerAbortController(uploadId, abortController);
|
|
225
|
+
return runUploadPool({
|
|
226
|
+
entries,
|
|
227
|
+
indices,
|
|
228
|
+
token,
|
|
229
|
+
uploadId,
|
|
230
|
+
abortController,
|
|
231
|
+
dispatch,
|
|
232
|
+
concurrency,
|
|
233
|
+
generateAiMetadata
|
|
234
|
+
}).then((result)=>result.error ? result : {
|
|
235
|
+
data: [
|
|
236
|
+
...earlier,
|
|
237
|
+
...result.data ?? []
|
|
238
|
+
]
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
trackPoolRun(uploadId, run);
|
|
242
|
+
return run;
|
|
243
|
+
};
|
|
186
244
|
/* -------------------------------------------------------------------------------------------------
|
|
187
245
|
* URL upload flow (SSE) — kept as-is for this iteration
|
|
188
246
|
* -----------------------------------------------------------------------------------------------*/ /**
|
|
@@ -225,7 +283,7 @@ const unregisterAbortController = (uploadId)=>{
|
|
|
225
283
|
if (token) {
|
|
226
284
|
headers.Authorization = `Bearer ${token}`;
|
|
227
285
|
}
|
|
228
|
-
return fetch(`${backendURL}/upload/
|
|
286
|
+
return fetch(`${backendURL}/upload/actions/upload-from-urls`, {
|
|
229
287
|
method: 'POST',
|
|
230
288
|
headers,
|
|
231
289
|
body: JSON.stringify({
|
|
@@ -269,7 +327,8 @@ const unregisterAbortController = (uploadId)=>{
|
|
|
269
327
|
dispatch(setFileUploading({
|
|
270
328
|
name: parsed.url,
|
|
271
329
|
index,
|
|
272
|
-
size: 0
|
|
330
|
+
size: 0,
|
|
331
|
+
uploadId
|
|
273
332
|
}));
|
|
274
333
|
break;
|
|
275
334
|
}
|
|
@@ -279,7 +338,8 @@ const unregisterAbortController = (uploadId)=>{
|
|
|
279
338
|
dispatch(setFileUploading({
|
|
280
339
|
name: payload.name,
|
|
281
340
|
index,
|
|
282
|
-
size: payload.size
|
|
341
|
+
size: payload.size,
|
|
342
|
+
uploadId
|
|
283
343
|
}));
|
|
284
344
|
break;
|
|
285
345
|
}
|
|
@@ -288,7 +348,8 @@ const unregisterAbortController = (uploadId)=>{
|
|
|
288
348
|
const payload = parsed;
|
|
289
349
|
dispatch(setFileComplete({
|
|
290
350
|
index,
|
|
291
|
-
file: payload.file
|
|
351
|
+
file: payload.file,
|
|
352
|
+
uploadId
|
|
292
353
|
}));
|
|
293
354
|
// Same fire-and-forget semantics as the file flow.
|
|
294
355
|
maybeGenerateMetadata({
|
|
@@ -306,7 +367,8 @@ const unregisterAbortController = (uploadId)=>{
|
|
|
306
367
|
dispatch(setFileError({
|
|
307
368
|
index,
|
|
308
369
|
name: payload.name,
|
|
309
|
-
message: payload.message
|
|
370
|
+
message: payload.message,
|
|
371
|
+
uploadId
|
|
310
372
|
}));
|
|
311
373
|
break;
|
|
312
374
|
}
|
|
@@ -334,10 +396,9 @@ const uploadApi = adminApi.enhanceEndpoints({
|
|
|
334
396
|
}).injectEndpoints({
|
|
335
397
|
endpoints: (builder)=>({
|
|
336
398
|
/**
|
|
337
|
-
* Upload files to `/upload/
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
* `XHR.upload.onprogress`.
|
|
399
|
+
* Upload files to `/upload/files`, one request per file, through a worker
|
|
400
|
+
* pool of `concurrency` parallel requests (default 1 = sequential). Real
|
|
401
|
+
* per-file byte progress comes from `XHR.upload.onprogress`.
|
|
341
402
|
*/ uploadFiles: builder.mutation({
|
|
342
403
|
queryFn: async ({ formData, totalFiles, concurrency = 1, generateAiMetadata }, { dispatch, getState })=>{
|
|
343
404
|
const token = getState().admin_app?.token;
|
|
@@ -356,6 +417,38 @@ const uploadApi = adminApi.enhanceEndpoints({
|
|
|
356
417
|
}));
|
|
357
418
|
const fileNames = entries.map((entry)=>entry.fileInfo.name ?? entry.file.name);
|
|
358
419
|
const fileSizes = entries.map((entry)=>entry.file.size);
|
|
420
|
+
// `uploadFromUrls` also leaves rows `pending`, but registers no batch —
|
|
421
|
+
// so an unregistered batch is not ours to merge into, and appending would
|
|
422
|
+
// land on top of its rows.
|
|
423
|
+
const progress = getState().uploadProgress;
|
|
424
|
+
const batch = getUploadEntries(progress.uploadId);
|
|
425
|
+
const isMerge = batch !== undefined && isUploadInFlight(progress.files);
|
|
426
|
+
if (isMerge) {
|
|
427
|
+
const { uploadId } = progress;
|
|
428
|
+
const offset = batch.entries.length;
|
|
429
|
+
// No `totalFiles`: the reducer derives it from the rows it appends.
|
|
430
|
+
dispatch(appendUploadFiles({
|
|
431
|
+
uploadId,
|
|
432
|
+
fileNames,
|
|
433
|
+
fileSizes
|
|
434
|
+
}));
|
|
435
|
+
const mergedEntries = [
|
|
436
|
+
...batch.entries,
|
|
437
|
+
...entries
|
|
438
|
+
];
|
|
439
|
+
// Merged files adopt the batch's flags: a new concurrency would raise
|
|
440
|
+
// the ceiling it exists to impose.
|
|
441
|
+
registerUploadEntries(uploadId, mergedEntries, batch.generateAiMetadata, batch.concurrency);
|
|
442
|
+
return runMergedUploadPool({
|
|
443
|
+
entries: mergedEntries,
|
|
444
|
+
indices: entries.map((_, index)=>offset + index),
|
|
445
|
+
token,
|
|
446
|
+
uploadId,
|
|
447
|
+
dispatch,
|
|
448
|
+
concurrency: batch.concurrency,
|
|
449
|
+
generateAiMetadata: batch.generateAiMetadata
|
|
450
|
+
});
|
|
451
|
+
}
|
|
359
452
|
// Open the progress dialog
|
|
360
453
|
dispatch(openUploadProgress({
|
|
361
454
|
totalFiles,
|
|
@@ -369,7 +462,7 @@ const uploadApi = adminApi.enhanceEndpoints({
|
|
|
369
462
|
// One AbortController per batch
|
|
370
463
|
const abortController = new AbortController();
|
|
371
464
|
registerAbortController(uploadId, abortController);
|
|
372
|
-
|
|
465
|
+
const run = runUploadPool({
|
|
373
466
|
entries,
|
|
374
467
|
indices: entries.map((_, index)=>index),
|
|
375
468
|
token,
|
|
@@ -379,6 +472,8 @@ const uploadApi = adminApi.enhanceEndpoints({
|
|
|
379
472
|
concurrency,
|
|
380
473
|
generateAiMetadata
|
|
381
474
|
});
|
|
475
|
+
trackPoolRun(uploadId, run);
|
|
476
|
+
return run;
|
|
382
477
|
},
|
|
383
478
|
// `Folder, LIST` refreshes the folder header count, which changes when
|
|
384
479
|
// files are added to it.
|
|
@@ -402,7 +497,7 @@ const uploadApi = adminApi.enhanceEndpoints({
|
|
|
402
497
|
*/ uploadFileSilently: builder.mutation({
|
|
403
498
|
queryFn: async ({ file, fileInfo }, { getState })=>{
|
|
404
499
|
const token = getState().admin_app?.token;
|
|
405
|
-
const url = `${window.strapi.backendURL}/upload/
|
|
500
|
+
const url = `${window.strapi.backendURL}/upload/files`;
|
|
406
501
|
const formData = new FormData();
|
|
407
502
|
formData.append('files', file);
|
|
408
503
|
formData.append('fileInfo', JSON.stringify(fileInfo));
|
|
@@ -412,7 +507,11 @@ const uploadApi = adminApi.enhanceEndpoints({
|
|
|
412
507
|
data: uploaded
|
|
413
508
|
};
|
|
414
509
|
} catch (err) {
|
|
415
|
-
|
|
510
|
+
// Only pass on text the server actually sent. The XHR layer's own
|
|
511
|
+
// fallbacks are hardcoded English, and callers here (crop → "Save
|
|
512
|
+
// as copy") have a localized message of their own; an empty string
|
|
513
|
+
// reads as "nothing usable" and lets theirs win.
|
|
514
|
+
const message = err instanceof UploadFileError && err.isServerMessage ? err.message : '';
|
|
416
515
|
return {
|
|
417
516
|
error: {
|
|
418
517
|
name: 'UnknownError',
|
|
@@ -465,7 +564,7 @@ const uploadApi = adminApi.enhanceEndpoints({
|
|
|
465
564
|
// Fresh AbortController for the retry run
|
|
466
565
|
const abortController = new AbortController();
|
|
467
566
|
registerAbortController(uploadId, abortController);
|
|
468
|
-
|
|
567
|
+
const run = runUploadPool({
|
|
469
568
|
entries: batch.entries,
|
|
470
569
|
indices: cancelledIndices,
|
|
471
570
|
token,
|
|
@@ -476,6 +575,11 @@ const uploadApi = adminApi.enhanceEndpoints({
|
|
|
476
575
|
concurrency: batch.concurrency,
|
|
477
576
|
generateAiMetadata: batch.generateAiMetadata
|
|
478
577
|
});
|
|
578
|
+
// Retried rows are `pending` again, so a drop lands on the merge branch.
|
|
579
|
+
// Untracked, that merge would find no tail to queue behind and run its
|
|
580
|
+
// pool beside this one — two pools of `concurrency` each.
|
|
581
|
+
trackPoolRun(uploadId, run);
|
|
582
|
+
return run;
|
|
479
583
|
},
|
|
480
584
|
// `Folder, LIST` refreshes the folder header count, which changes when
|
|
481
585
|
// files are added to it.
|
|
@@ -606,7 +710,7 @@ const uploadApi = adminApi.enhanceEndpoints({
|
|
|
606
710
|
* Re-exported from `assets.ts` for the components that consume the hook.
|
|
607
711
|
*/ generateAiMetadata: builder.mutation({
|
|
608
712
|
query: ({ fileIds })=>({
|
|
609
|
-
url: '/upload/
|
|
713
|
+
url: '/upload/actions/generate-ai-metadata',
|
|
610
714
|
method: 'POST',
|
|
611
715
|
data: {
|
|
612
716
|
fileIds
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.mjs","sources":["../../../../admin/src/future/services/api.ts"],"sourcesContent":["import { Dispatch } from '@reduxjs/toolkit';\nimport { adminApi } from '@strapi/admin/strapi-admin';\n\nimport {\n openUploadProgress,\n setFileUploading,\n setFileProgress,\n setFileComplete,\n setFileError,\n setFileMetadataGenerating,\n setFileMetadataResult,\n setUploadFailed,\n retryCancelledFiles,\n} from '../store/uploadProgress';\nimport { createRafBatcher } from '../utils/createRafBatcher';\nimport { getFilenameFromUrl } from '../utils/files';\n\nimport { uploadFileViaXHR, UploadAbortedError } from './uploadFileViaXHR';\n\nimport type {\n CreateFilesStream,\n CreateFilesStreamEvents,\n File as UploadedFile,\n UnstableGenerateAIMetadata,\n UploadFileInfo,\n} from '../../../../shared/contracts/files';\nimport type { FileMetadataResultStatus } from '../store/uploadProgress';\n\ninterface UploadFilesArgs {\n formData: FormData;\n totalFiles: number;\n /**\n * How many files to upload in parallel — the `concurrentUploadRequests`\n * settings value. Defaults to 1 (sequential).\n */\n concurrency?: number;\n /** Whether AI metadata generation is enabled (EE AI available + `settings.aiMetadata`). */\n generateAiMetadata: boolean;\n}\n\ninterface UploadFromUrlsArgs {\n urls: string[];\n folderId: number | null;\n generateAiMetadata: boolean;\n}\n\ninterface RootState {\n admin_app: {\n token?: string | null;\n };\n uploadProgress: {\n uploadId: number;\n files: Array<{\n index: number;\n name: string;\n size: number;\n status: 'pending' | 'uploading' | 'complete' | 'error' | 'cancelled';\n }>;\n };\n}\n\n/**\n * A single file plus the `fileInfo` it was queued with.\n * Retained in {@link uploadRegistry} so cancelled files can be retried without\n * the user re-selecting them. `File`/`AbortController` are non-serializable, so\n * they live here rather than in Redux.\n */\ninterface UploadEntry {\n file: File;\n fileInfo: UploadFileInfo;\n}\n\n/**\n * Everything a batch needs to be replayed on retry: the original entries plus the\n * flags it was started with (AI-metadata and upload concurrency). These live here\n * rather than in Redux because `retryCancelledFiles` takes no args and the page\n * that owns `useAIAvailability` / the settings value is not involved in the retry.\n */\ninterface UploadBatch {\n entries: UploadEntry[];\n generateAiMetadata: boolean;\n concurrency: number;\n}\n\n/**\n * Stores the original upload batch (keyed by uploadId) to enable retry.\n */\nconst uploadRegistry = new Map<number, UploadBatch>();\n\nconst registerUploadEntries = (\n uploadId: number,\n entries: UploadEntry[],\n generateAiMetadata: boolean,\n concurrency: number\n) => {\n uploadRegistry.set(uploadId, { entries, generateAiMetadata, concurrency });\n};\n\nconst getUploadEntries = (uploadId: number): UploadBatch | undefined => {\n return uploadRegistry.get(uploadId);\n};\n\n/**\n * Manages abort controllers for in-flight uploads.\n *\n * Design decision: Uses a Map to track uploads by their unique uploadId.\n * Redux state cannot store function references (abort controllers), RTK Query's\n * signal is only accessible within the queryFn, and the upload is triggered in\n * AssetsPage but cancelled from UploadProgressDialog.\n */\nconst abortControllers = new Map<number, AbortController>();\n\nconst registerAbortController = (uploadId: number, controller: AbortController) => {\n abortControllers.set(uploadId, controller);\n};\n\nconst unregisterAbortController = (uploadId: number) => {\n abortControllers.delete(uploadId);\n};\n\n/**\n * Aborts an upload by its uploadId.\n * Called from the UploadProgressDialog when the user clicks cancel or close.\n */\nexport const abortUpload = (uploadId: number) => {\n const controller = abortControllers.get(uploadId);\n if (controller) {\n controller.abort();\n unregisterAbortController(uploadId);\n }\n};\n\n/**\n * Error shape returned by upload operations.\n * Matches RTK Query's expected return type for queryFn.\n */\ninterface UploadError {\n name: 'UnknownError';\n message: string;\n status?: number;\n}\n\n/**\n * The store's dispatch also accepts thunks, which is what RTK Query's\n * `endpoint.initiate(...)` returns — the plain `Dispatch` action type can't express that.\n */\ntype AppDispatch = Dispatch &\n (<T>(thunk: T) => T extends (...args: never[]) => infer R ? R : never);\n\ntype UploadPoolResult =\n | { data: UploadedFile[]; error?: undefined }\n | { error: UploadError; data?: undefined };\n\n/** Maps a server per-file outcome onto the row's terminal metadata status. */\nconst METADATA_STATUS_BY_RESULT: Record<\n UnstableGenerateAIMetadata.FileStatus,\n FileMetadataResultStatus\n> = {\n success: 'generated',\n skipped: 'skipped',\n error: 'failed',\n};\n\n/**\n * Kicks off AI metadata generation for a freshly uploaded file.\n *\n * Deliberately fire-and-forget — the caller must NOT await it:\n * - generation for file N overlaps the upload of file N+1;\n * - a generation failure can never affect the upload result (the upload already\n * succeeded), which is why the promise is fully swallowed here.\n *\n * Every uploaded file is sent, including non-images: the server already classifies\n * them (`ai-metadata.generateForFiles` returns `skipped` for anything whose mime\n * isn't `image/*`) and duplicating that rule here would let the two drift apart.\n * The upshot is that a non-image now reports \"Metadata generation skipped\" rather\n * than silently showing no metadata state at all.\n */\nexport const maybeGenerateMetadata = ({\n file,\n index,\n uploadId,\n enabled,\n dispatch,\n}: {\n file: UploadedFile;\n index: number;\n uploadId: number;\n enabled: boolean;\n dispatch: Dispatch;\n}): void => {\n if (!enabled || typeof file.id !== 'number') {\n return;\n }\n\n dispatch(setFileMetadataGenerating({ index, uploadId }));\n\n // `uploadApi` is declared below but only read at call time, long after the module\n // has finished evaluating.\n const promise = (dispatch as AppDispatch)(\n uploadApi.endpoints.generateAiMetadata.initiate({ fileIds: [file.id] })\n );\n\n promise\n .unwrap()\n .then((results) => {\n const result = results?.find((r) => r.id === file.id) ?? results?.[0];\n dispatch(\n setFileMetadataResult({\n index,\n uploadId,\n status: result ? METADATA_STATUS_BY_RESULT[result.status] : 'failed',\n })\n );\n })\n .catch(() => {\n dispatch(setFileMetadataResult({ index, uploadId, status: 'failed' }));\n });\n};\n\n/**\n * Uploads the given entry indices one at a time through the single-file endpoint.\n *\n * For each file: dispatches \"uploading\", wires `XHR.upload.onprogress` through a\n * per-frame batcher to `setFileProgress`, awaits the XHR, then dispatches\n * \"complete\" or \"error\". Each file is wrapped in its own try/catch so one failure\n * does not stop the batch. An abort stops the loop without starting further files.\n */\nconst runUploadPool = async ({\n entries,\n indices,\n token,\n uploadId,\n abortController,\n dispatch,\n concurrency = 1,\n generateAiMetadata,\n}: {\n entries: UploadEntry[];\n indices: number[];\n token: string | null | undefined;\n uploadId: number;\n abortController: AbortController;\n dispatch: Dispatch;\n /** Parallel workers pulling from the queue. 1 (the default) = sequential. */\n concurrency?: number;\n generateAiMetadata: boolean;\n}): Promise<UploadPoolResult> => {\n const url = `${window.strapi.backendURL}/upload/unstable/upload-file`;\n const uploaded: UploadedFile[] = [];\n\n // Shared queue: each worker shifts the next index when it frees up, so N\n // files are in flight at any moment (not N-sized waves). With concurrency 1\n // this degenerates to the original strictly sequential loop.\n const queue = [...indices];\n\n const uploadOne = async (index: number) => {\n const entry = entries[index];\n if (!entry) {\n return;\n }\n\n const fileName = entry.fileInfo?.name ?? entry.file.name;\n\n dispatch(setFileUploading({ name: fileName, index, size: entry.file.size }));\n\n const formData = new FormData();\n formData.append('files', entry.file);\n formData.append('fileInfo', JSON.stringify(entry.fileInfo));\n\n // Coalesce high-frequency progress events into one dispatch per frame.\n const batcher = createRafBatcher<number>((bytes) => {\n dispatch(setFileProgress({ index, bytes }));\n });\n\n try {\n const file = await uploadFileViaXHR(url, token, formData, abortController.signal, (bytes) =>\n batcher.schedule(bytes)\n );\n batcher.cancel();\n uploaded.push(file);\n dispatch(setFileComplete({ index, file }));\n\n // Not awaited: overlaps with the next file's upload and can't fail the batch.\n maybeGenerateMetadata({\n file,\n index,\n uploadId,\n enabled: generateAiMetadata,\n dispatch,\n });\n } catch (err) {\n batcher.cancel();\n\n if (err instanceof UploadAbortedError) {\n // Batch was cancelled — the worker loop checks the signal and stops.\n // cancelUpload (dispatched from the dialog) marks the remaining rows.\n return;\n }\n\n const message = err instanceof Error ? err.message : 'Upload failed';\n dispatch(setFileError({ index, name: fileName, message }));\n }\n };\n\n // Guard non-finite/invalid values (NaN, Infinity, <1): `Math.floor(NaN)`\n // would propagate through Math.max to `Array.from({ length: NaN })` = zero\n // workers, silently uploading nothing. Anything invalid falls back to 1.\n const requested = Number.isFinite(concurrency) ? Math.floor(concurrency) : 1;\n const workerCount = Math.min(Math.max(1, requested), queue.length);\n\n const worker = async () => {\n while (queue.length > 0) {\n if (abortController.signal.aborted) {\n break;\n }\n\n const index = queue.shift();\n if (index === undefined) {\n break;\n }\n\n // eslint-disable-next-line no-await-in-loop\n await uploadOne(index);\n }\n };\n\n await Promise.all(Array.from({ length: workerCount }, () => worker()));\n\n unregisterAbortController(uploadId);\n\n return { data: uploaded };\n};\n\n/* -------------------------------------------------------------------------------------------------\n * URL upload flow (SSE) — kept as-is for this iteration\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * Parses a raw SSE text chunk into event/data pairs.\n *\n * SSE format:\n * event: <eventName>\\n\n * data: <json>\\n\n * \\n\n */\nconst parseSSEEvents = (chunk: string): Array<{ event: string; data: string }> => {\n const events: Array<{ event: string; data: string }> = [];\n const blocks = chunk.split('\\n\\n').filter(Boolean);\n\n for (const block of blocks) {\n let event = '';\n let data = '';\n\n for (const line of block.split('\\n')) {\n if (line.startsWith('event: ')) {\n event = line.slice(7);\n } else if (line.startsWith('data: ')) {\n data = line.slice(6);\n }\n }\n\n if (event && data) {\n events.push({ event, data });\n }\n }\n\n return events;\n};\n\n/**\n * Makes a streaming upload-from-URLs request to the server.\n * Sends URLs as JSON body instead of FormData.\n */\nconst fetchUrlUploadStream = async ({\n token,\n urls,\n folderId,\n signal,\n}: {\n token: string | null | undefined;\n urls: string[];\n folderId: number | null;\n signal: AbortSignal;\n}): Promise<Response> => {\n const backendURL = window.strapi.backendURL;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n\n return fetch(`${backendURL}/upload/unstable/stream-from-urls`, {\n method: 'POST',\n headers,\n body: JSON.stringify({ urls, folderId }),\n signal,\n });\n};\n\n/**\n * Processes an SSE stream from the URL upload endpoint.\n * Dispatches Redux actions for each file event and returns the final result.\n */\nconst processSSEStream = async ({\n response,\n dispatch,\n uploadId,\n generateAiMetadata,\n}: {\n response: Response;\n dispatch: Dispatch;\n uploadId: number;\n generateAiMetadata: boolean;\n}): Promise<CreateFilesStream.Response | null> => {\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n let streamResult: CreateFilesStream.Response | null = null;\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n\n // Process complete SSE events from the buffer\n const lastDoubleNewline = buffer.lastIndexOf('\\n\\n');\n if (lastDoubleNewline === -1) {\n // No complete events yet, keep buffering\n // eslint-disable-next-line no-continue\n continue;\n }\n\n const completePart = buffer.slice(0, lastDoubleNewline + 2);\n buffer = buffer.slice(lastDoubleNewline + 2);\n\n const events = parseSSEEvents(completePart);\n\n for (const { event, data } of events) {\n const parsed = JSON.parse(data);\n const index = parsed.index as number;\n\n switch (event) {\n case 'file:fetching': {\n // URL is being fetched server-side - mark as uploading (processing)\n dispatch(setFileUploading({ name: parsed.url as string, index, size: 0 }));\n break;\n }\n case 'file:uploading': {\n const payload = parsed as CreateFilesStreamEvents.FileUploadingEvent;\n dispatch(setFileUploading({ name: payload.name, index, size: payload.size }));\n break;\n }\n case 'file:complete': {\n const payload = parsed as CreateFilesStreamEvents.FileCompleteEvent;\n dispatch(setFileComplete({ index, file: payload.file }));\n\n // Same fire-and-forget semantics as the file flow.\n maybeGenerateMetadata({\n file: payload.file,\n index,\n uploadId,\n enabled: generateAiMetadata,\n dispatch,\n });\n break;\n }\n case 'file:error': {\n const payload = parsed as CreateFilesStreamEvents.FileErrorEvent;\n dispatch(setFileError({ index, name: payload.name, message: payload.message }));\n break;\n }\n case 'stream:complete': {\n const payload = parsed as CreateFilesStreamEvents.StreamCompleteEvent;\n streamResult = {\n data: payload.data,\n errors: payload.errors,\n };\n break;\n }\n default:\n console.error(`[SSE Upload] unknown event: ${event}`, parsed);\n }\n }\n }\n\n return streamResult;\n};\n\nconst uploadApi = adminApi\n .enhanceEndpoints({\n addTagTypes: ['Asset', 'Folder'],\n })\n .injectEndpoints({\n endpoints: (builder) => ({\n /**\n * Upload files to `/upload/unstable/upload-file`, one request per file,\n * through a worker pool of `concurrency` parallel requests (default 1 =\n * sequential). Real per-file byte progress comes from\n * `XHR.upload.onprogress`.\n */\n uploadFiles: builder.mutation<UploadedFile[], UploadFilesArgs>({\n queryFn: async (\n { formData, totalFiles, concurrency = 1, generateAiMetadata },\n { dispatch, getState }\n ) => {\n const token = (getState() as RootState).admin_app?.token;\n\n // Extract the original files and their per-file fileInfo from the combined FormData.\n const files = formData.getAll('files') as File[];\n const fileInfoJson = formData.get('fileInfo') as string;\n const fileInfoArray = JSON.parse(fileInfoJson) as UploadFileInfo[];\n\n const entries: UploadEntry[] = files.map((file, index) => ({\n file,\n fileInfo: fileInfoArray[index] ?? {\n name: file.name,\n caption: null,\n alternativeText: null,\n folder: null,\n },\n }));\n\n const fileNames = entries.map((entry) => entry.fileInfo.name ?? entry.file.name);\n const fileSizes = entries.map((entry) => entry.file.size);\n\n // Open the progress dialog\n dispatch(openUploadProgress({ totalFiles, fileNames, fileSizes }));\n\n // Get the uploadId from state after dispatching\n const uploadId = (getState() as RootState).uploadProgress.uploadId;\n\n // Store original entries for retry functionality\n registerUploadEntries(uploadId, entries, generateAiMetadata, concurrency);\n\n // One AbortController per batch\n const abortController = new AbortController();\n registerAbortController(uploadId, abortController);\n\n return runUploadPool({\n entries,\n indices: entries.map((_, index) => index),\n token,\n uploadId,\n abortController,\n dispatch,\n concurrency,\n generateAiMetadata,\n });\n },\n // `Folder, LIST` refreshes the folder header count, which changes when\n // files are added to it.\n invalidatesTags: [\n { type: 'Asset', id: 'LIST' },\n { type: 'Folder', id: 'LIST' },\n ],\n }),\n\n /**\n * Upload a single, already-prepared file WITHOUT opening the global\n * upload-progress dialog. For flows that create one asset programmatically\n * (e.g. crop → \"Save as copy\"), where the bulk-upload progress UI is\n * inappropriate. Same endpoint as `uploadFiles`, minus the progress/retry\n * machinery.\n */\n uploadFileSilently: builder.mutation<UploadedFile, UploadEntry>({\n queryFn: async ({ file, fileInfo }, { getState }) => {\n const token = (getState() as RootState).admin_app?.token;\n const url = `${window.strapi.backendURL}/upload/unstable/upload-file`;\n\n const formData = new FormData();\n formData.append('files', file);\n formData.append('fileInfo', JSON.stringify(fileInfo));\n\n try {\n const uploaded = await uploadFileViaXHR(\n url,\n token,\n formData,\n new AbortController().signal,\n () => {}\n );\n return { data: uploaded };\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Upload failed';\n return { error: { name: 'UnknownError', message } };\n }\n },\n // `Folder, LIST` refreshes the folder header count, which changes when\n // files are added to it.\n invalidatesTags: [\n { type: 'Asset', id: 'LIST' },\n { type: 'Folder', id: 'LIST' },\n ],\n }),\n\n /**\n * Retry uploading cancelled files.\n * Maps cancelled rows back to their original entries and re-runs only those\n * through the same upload pool with a fresh AbortController.\n */\n retryCancelledFiles: builder.mutation<UploadedFile[], void>({\n queryFn: async (_arg, { dispatch, getState }) => {\n const { uploadId, files: stateFiles } = (getState() as RootState).uploadProgress;\n const token = (getState() as RootState).admin_app?.token;\n\n const cancelledIndices = stateFiles\n .filter((f) => f.status === 'cancelled')\n .map((f) => f.index);\n\n if (cancelledIndices.length === 0) {\n return { error: { name: 'UnknownError', message: 'No cancelled files to retry' } };\n }\n\n const batch = getUploadEntries(uploadId);\n if (!batch) {\n return { error: { name: 'UnknownError', message: 'Original files not found' } };\n }\n\n // Reset cancelled files back to pending\n dispatch(retryCancelledFiles());\n\n // Fresh AbortController for the retry run\n const abortController = new AbortController();\n registerAbortController(uploadId, abortController);\n\n return runUploadPool({\n entries: batch.entries,\n indices: cancelledIndices,\n token,\n uploadId,\n abortController,\n dispatch,\n // Replay the retried rows with the flags the batch was started with.\n concurrency: batch.concurrency,\n generateAiMetadata: batch.generateAiMetadata,\n });\n },\n // `Folder, LIST` refreshes the folder header count, which changes when\n // files are added to it.\n invalidatesTags: [\n { type: 'Asset', id: 'LIST' },\n { type: 'Folder', id: 'LIST' },\n ],\n }),\n\n /**\n * Upload files from URLs.\n * Sends URLs to the server which fetches and uploads them (SSE flow, unchanged).\n */\n uploadFromUrls: builder.mutation<CreateFilesStream.Response, UploadFromUrlsArgs>({\n queryFn: async ({ urls, folderId, generateAiMetadata }, { dispatch, getState }) => {\n const token = (getState() as RootState).admin_app?.token;\n\n // Extract filenames from URLs for the progress dialog\n const fileNames = urls.map((url) => getFilenameFromUrl(url));\n\n // Open progress dialog with all URLs as pending files\n dispatch(\n openUploadProgress({\n totalFiles: urls.length,\n fileNames,\n })\n );\n\n // Get the uploadId from state after dispatching\n const uploadId = (getState() as RootState).uploadProgress.uploadId;\n\n // Create abort controller for this upload\n const abortController = new AbortController();\n registerAbortController(uploadId, abortController);\n\n try {\n // Send URLs to server for fetching and uploading\n const response = await fetchUrlUploadStream({\n token,\n urls,\n folderId,\n signal: abortController.signal,\n });\n\n if (!response.ok || !response.body) {\n unregisterAbortController(uploadId);\n\n let errorMessage = 'Upload request failed';\n try {\n const errorData = await response.json();\n if (errorData.error?.message) {\n errorMessage = errorData.error.message;\n } else if (errorData.message) {\n errorMessage = errorData.message;\n }\n } catch {\n errorMessage = `Upload failed with status ${response.status}`;\n }\n\n dispatch(setUploadFailed({ message: errorMessage }));\n\n return {\n error: {\n name: 'UnknownError' as const,\n message: errorMessage,\n status: response.status,\n },\n };\n }\n\n // Process SSE stream from server\n const streamResult = await processSSEStream({\n response,\n dispatch,\n uploadId,\n generateAiMetadata,\n });\n\n unregisterAbortController(uploadId);\n\n if (streamResult && streamResult.data.length > 0) {\n return { data: streamResult };\n }\n\n return { data: { data: [], errors: [] } };\n } catch (err) {\n unregisterAbortController(uploadId);\n\n if (err instanceof DOMException && err.name === 'AbortError') {\n return { error: { name: 'UnknownError' as const, message: 'Upload cancelled' } };\n }\n\n const errorMessage = err instanceof Error ? err.message : 'Network error occurred';\n dispatch(setUploadFailed({ message: errorMessage }));\n\n return {\n error: {\n name: 'UnknownError' as const,\n message: errorMessage,\n },\n };\n }\n },\n // `Folder, LIST` refreshes the folder header count, which changes when\n // files are added to it.\n invalidatesTags: [\n { type: 'Asset', id: 'LIST' },\n { type: 'Folder', id: 'LIST' },\n ],\n }),\n\n /**\n * Generate AI metadata (alt text + caption) for the given assets.\n * Synchronous: resolves once every file has been processed and reports the\n * outcome per file, so non-images and individual failures don't fail the\n * whole batch. Existing alt text and captions are never overwritten.\n *\n * Lives here rather than in `assets.ts` because the upload flows dispatch it\n * directly via `initiate()` after each file completes, and `assets.ts` already\n * imports from this module — defining it there would be a circular import.\n * Re-exported from `assets.ts` for the components that consume the hook.\n */\n generateAiMetadata: builder.mutation<\n UnstableGenerateAIMetadata.Response['data'],\n { fileIds: number[] }\n >({\n query: ({ fileIds }) => ({\n url: '/upload/unstable/generate-ai-metadata',\n method: 'POST',\n data: { fileIds },\n }),\n transformResponse: (response: { data: UnstableGenerateAIMetadata.Response['data'] }) =>\n response.data,\n invalidatesTags: (_result, _error, { fileIds }) => [\n ...fileIds.map((id) => ({ type: 'Asset' as const, id })),\n { type: 'Asset' as const, id: 'LIST' },\n ],\n }),\n }),\n });\n\nexport const {\n useUploadFilesMutation,\n useUploadFileSilentlyMutation,\n useRetryCancelledFilesMutation,\n useUploadFromUrlsMutation,\n useGenerateAiMetadataMutation,\n} = uploadApi;\nexport { uploadApi };\n"],"names":["uploadRegistry","Map","registerUploadEntries","uploadId","entries","generateAiMetadata","concurrency","set","getUploadEntries","get","abortControllers","registerAbortController","controller","unregisterAbortController","delete","abortUpload","abort","METADATA_STATUS_BY_RESULT","success","skipped","error","maybeGenerateMetadata","file","index","enabled","dispatch","id","setFileMetadataGenerating","promise","uploadApi","endpoints","initiate","fileIds","unwrap","then","results","result","find","r","setFileMetadataResult","status","catch","runUploadPool","indices","token","abortController","url","window","strapi","backendURL","uploaded","queue","uploadOne","entry","fileName","fileInfo","name","setFileUploading","size","formData","FormData","append","JSON","stringify","batcher","createRafBatcher","bytes","setFileProgress","uploadFileViaXHR","signal","schedule","cancel","push","setFileComplete","err","UploadAbortedError","message","Error","setFileError","requested","Number","isFinite","Math","floor","workerCount","min","max","length","worker","aborted","shift","undefined","Promise","all","Array","from","data","parseSSEEvents","chunk","events","blocks","split","filter","Boolean","block","event","line","startsWith","slice","fetchUrlUploadStream","urls","folderId","headers","Authorization","fetch","method","body","processSSEStream","response","reader","getReader","decoder","TextDecoder","streamResult","buffer","done","value","read","decode","stream","lastDoubleNewline","lastIndexOf","completePart","parsed","parse","payload","errors","console","adminApi","enhanceEndpoints","addTagTypes","injectEndpoints","builder","uploadFiles","mutation","queryFn","totalFiles","getState","admin_app","files","getAll","fileInfoJson","fileInfoArray","map","caption","alternativeText","folder","fileNames","fileSizes","openUploadProgress","uploadProgress","AbortController","_","invalidatesTags","type","uploadFileSilently","retryCancelledFiles","_arg","stateFiles","cancelledIndices","f","batch","uploadFromUrls","getFilenameFromUrl","ok","errorMessage","errorData","json","setUploadFailed","DOMException","query","transformResponse","_result","_error","useUploadFilesMutation","useUploadFileSilentlyMutation","useRetryCancelledFilesMutation","useUploadFromUrlsMutation","useGenerateAiMetadataMutation"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"api.mjs","sources":["../../../../admin/src/future/services/api.ts"],"sourcesContent":["import { Dispatch } from '@reduxjs/toolkit';\nimport { adminApi } from '@strapi/admin/strapi-admin';\n\nimport {\n openUploadProgress,\n appendUploadFiles,\n isUploadInFlight,\n setFileUploading,\n setFileProgress,\n setFileComplete,\n setFileError,\n setFileMetadataGenerating,\n setFileMetadataResult,\n setUploadFailed,\n retryCancelledFiles,\n} from '../store/uploadProgress';\nimport { createRafBatcher } from '../utils/createRafBatcher';\nimport { getFilenameFromUrl } from '../utils/files';\n\nimport { uploadFileViaXHR, UploadAbortedError, UploadFileError } from './uploadFileViaXHR';\n\nimport type {\n CreateFilesStream,\n CreateFilesStreamEvents,\n File as UploadedFile,\n GenerateAIMetadata,\n UploadFileInfo,\n} from '../../../../shared/contracts/files';\nimport type { FileMetadataResultStatus } from '../store/uploadProgress';\n\ninterface UploadFilesArgs {\n formData: FormData;\n totalFiles: number;\n /**\n * How many files to upload in parallel — the `concurrentUploadRequests`\n * settings value. Defaults to 1 (sequential).\n */\n concurrency?: number;\n /** Whether AI metadata generation is enabled (EE AI available + `settings.aiMetadata`). */\n generateAiMetadata: boolean;\n}\n\ninterface UploadFromUrlsArgs {\n urls: string[];\n folderId: number | null;\n generateAiMetadata: boolean;\n}\n\ninterface RootState {\n admin_app: {\n token?: string | null;\n };\n uploadProgress: {\n uploadId: number;\n files: Array<{\n index: number;\n name: string;\n size: number;\n status: 'pending' | 'uploading' | 'complete' | 'error' | 'cancelled';\n }>;\n };\n}\n\n/**\n * A single file plus the `fileInfo` it was queued with.\n * Retained in {@link uploadRegistry} so cancelled files can be retried without\n * the user re-selecting them. `File`/`AbortController` are non-serializable, so\n * they live here rather than in Redux.\n */\ninterface UploadEntry {\n file: File;\n fileInfo: UploadFileInfo;\n}\n\n/**\n * Everything a batch needs to be replayed on retry: the original entries plus the\n * flags it was started with (AI-metadata and upload concurrency). These live here\n * rather than in Redux because `retryCancelledFiles` takes no args and the page\n * that owns `useAIAvailability` / the settings value is not involved in the retry.\n */\ninterface UploadBatch {\n entries: UploadEntry[];\n generateAiMetadata: boolean;\n concurrency: number;\n}\n\n/**\n * Stores the original upload batch (keyed by uploadId) to enable retry.\n */\nconst uploadRegistry = new Map<number, UploadBatch>();\n\nconst registerUploadEntries = (\n uploadId: number,\n entries: UploadEntry[],\n generateAiMetadata: boolean,\n concurrency: number\n) => {\n uploadRegistry.set(uploadId, { entries, generateAiMetadata, concurrency });\n};\n\nconst getUploadEntries = (uploadId: number): UploadBatch | undefined => {\n return uploadRegistry.get(uploadId);\n};\n\n/**\n * Manages abort controllers for in-flight uploads.\n *\n * Design decision: Uses a Map to track uploads by their unique uploadId.\n * Redux state cannot store function references (abort controllers), RTK Query's\n * signal is only accessible within the queryFn, and the upload is triggered in\n * AssetsPage but cancelled from UploadProgressDialog.\n */\nconst abortControllers = new Map<number, AbortController>();\n\nconst registerAbortController = (uploadId: number, controller: AbortController) => {\n abortControllers.set(uploadId, controller);\n};\n\nconst unregisterAbortController = (uploadId: number) => {\n abortControllers.delete(uploadId);\n};\n\n/**\n * Aborts an upload by its uploadId.\n * Called from the UploadProgressDialog when the user clicks cancel or close.\n */\nexport const abortUpload = (uploadId: number) => {\n const controller = abortControllers.get(uploadId);\n if (controller) {\n controller.abort();\n unregisterAbortController(uploadId);\n }\n};\n\n/**\n * Runs are chained per batch rather than started in parallel: a second pool\n * alongside the first would double the files in flight and make `concurrency`\n * stop meaning anything.\n */\nconst poolTails = new Map<number, Promise<UploadPoolResult | undefined>>();\n\nconst trackPoolRun = (uploadId: number, run: Promise<UploadPoolResult>) => {\n // Not swallowed: the caller still gets the real result from `run`.\n const tail = run.catch(() => undefined);\n\n poolTails.set(uploadId, tail);\n\n tail.then(() => {\n // Leave the entry alone if another run has queued behind us in the meantime.\n if (poolTails.get(uploadId) === tail) {\n poolTails.delete(uploadId);\n }\n });\n};\n\n/**\n * Error shape returned by upload operations.\n * Matches RTK Query's expected return type for queryFn.\n */\ninterface UploadError {\n name: 'UnknownError';\n message: string;\n status?: number;\n}\n\n/**\n * The store's dispatch also accepts thunks, which is what RTK Query's\n * `endpoint.initiate(...)` returns — the plain `Dispatch` action type can't express that.\n */\ntype AppDispatch = Dispatch &\n (<T>(thunk: T) => T extends (...args: never[]) => infer R ? R : never);\n\ntype UploadPoolResult =\n | { data: UploadedFile[]; error?: undefined }\n | { error: UploadError; data?: undefined };\n\n/** Maps a server per-file outcome onto the row's terminal metadata status. */\nconst METADATA_STATUS_BY_RESULT: Record<GenerateAIMetadata.FileStatus, FileMetadataResultStatus> = {\n success: 'generated',\n skipped: 'skipped',\n error: 'failed',\n};\n\n/**\n * Kicks off AI metadata generation for a freshly uploaded file.\n *\n * Deliberately fire-and-forget — the caller must NOT await it:\n * - generation for file N overlaps the upload of file N+1;\n * - a generation failure can never affect the upload result (the upload already\n * succeeded), which is why the promise is fully swallowed here.\n *\n * Every uploaded file is sent, including non-images: the server already classifies\n * them (`ai-metadata.generateForFiles` returns `skipped` for anything whose mime\n * isn't `image/*`) and duplicating that rule here would let the two drift apart.\n * The upshot is that a non-image now reports \"Metadata generation skipped\" rather\n * than silently showing no metadata state at all.\n */\nexport const maybeGenerateMetadata = ({\n file,\n index,\n uploadId,\n enabled,\n dispatch,\n}: {\n file: UploadedFile;\n index: number;\n uploadId: number;\n enabled: boolean;\n dispatch: Dispatch;\n}): void => {\n if (!enabled || typeof file.id !== 'number') {\n return;\n }\n\n dispatch(setFileMetadataGenerating({ index, uploadId }));\n\n // `uploadApi` is declared below but only read at call time, long after the module\n // has finished evaluating.\n const promise = (dispatch as AppDispatch)(\n uploadApi.endpoints.generateAiMetadata.initiate({ fileIds: [file.id] })\n );\n\n promise\n .unwrap()\n .then((results) => {\n const result = results?.find((r) => r.id === file.id) ?? results?.[0];\n dispatch(\n setFileMetadataResult({\n index,\n uploadId,\n status: result ? METADATA_STATUS_BY_RESULT[result.status] : 'failed',\n })\n );\n })\n .catch(() => {\n dispatch(setFileMetadataResult({ index, uploadId, status: 'failed' }));\n });\n};\n\n/**\n * Uploads the given entry indices one at a time through the single-file endpoint.\n *\n * For each file: dispatches \"uploading\", wires `XHR.upload.onprogress` through a\n * per-frame batcher to `setFileProgress`, awaits the XHR, then dispatches\n * \"complete\" or \"error\". Each file is wrapped in its own try/catch so one failure\n * does not stop the batch. An abort stops the loop without starting further files.\n */\nconst runUploadPool = async ({\n entries,\n indices,\n token,\n uploadId,\n abortController,\n dispatch,\n concurrency = 1,\n generateAiMetadata,\n}: {\n entries: UploadEntry[];\n indices: number[];\n token: string | null | undefined;\n uploadId: number;\n abortController: AbortController;\n dispatch: Dispatch;\n /** Parallel workers pulling from the queue. 1 (the default) = sequential. */\n concurrency?: number;\n generateAiMetadata: boolean;\n}): Promise<UploadPoolResult> => {\n const url = `${window.strapi.backendURL}/upload/files`;\n const uploaded: UploadedFile[] = [];\n\n // Shared queue: each worker shifts the next index when it frees up, so N\n // files are in flight at any moment (not N-sized waves). With concurrency 1\n // this degenerates to the original strictly sequential loop.\n const queue = [...indices];\n\n const uploadOne = async (index: number) => {\n const entry = entries[index];\n if (!entry) {\n return;\n }\n\n const fileName = entry.fileInfo?.name ?? entry.file.name;\n\n dispatch(setFileUploading({ name: fileName, index, size: entry.file.size, uploadId }));\n\n const formData = new FormData();\n formData.append('files', entry.file);\n formData.append('fileInfo', JSON.stringify(entry.fileInfo));\n\n // Coalesce high-frequency progress events into one dispatch per frame.\n const batcher = createRafBatcher<number>((bytes) => {\n dispatch(setFileProgress({ index, bytes, uploadId }));\n });\n\n try {\n const file = await uploadFileViaXHR(url, token, formData, abortController.signal, (bytes) =>\n batcher.schedule(bytes)\n );\n batcher.cancel();\n uploaded.push(file);\n dispatch(setFileComplete({ index, file, uploadId }));\n\n // Not awaited: overlaps with the next file's upload and can't fail the batch.\n maybeGenerateMetadata({\n file,\n index,\n uploadId,\n enabled: generateAiMetadata,\n dispatch,\n });\n } catch (err) {\n batcher.cancel();\n\n if (err instanceof UploadAbortedError) {\n // Batch was cancelled — the worker loop checks the signal and stops.\n // cancelUpload (dispatched from the dialog) marks the remaining rows.\n return;\n }\n\n const message = err instanceof Error ? err.message : 'Upload failed';\n dispatch(setFileError({ index, name: fileName, message, uploadId }));\n }\n };\n\n // Guard non-finite/invalid values (NaN, Infinity, <1): `Math.floor(NaN)`\n // would propagate through Math.max to `Array.from({ length: NaN })` = zero\n // workers, silently uploading nothing. Anything invalid falls back to 1.\n const requested = Number.isFinite(concurrency) ? Math.floor(concurrency) : 1;\n const workerCount = Math.min(Math.max(1, requested), queue.length);\n\n const worker = async () => {\n while (queue.length > 0) {\n if (abortController.signal.aborted) {\n break;\n }\n\n const index = queue.shift();\n if (index === undefined) {\n break;\n }\n\n // eslint-disable-next-line no-await-in-loop\n await uploadOne(index);\n }\n };\n\n await Promise.all(Array.from({ length: workerCount }, () => worker()));\n\n unregisterAbortController(uploadId);\n\n return { data: uploaded };\n};\n\n/**\n * Reuses the batch's AbortController so one Cancel stops both drops.\n * `runUploadPool` unregisters it on finish, hence the re-register below.\n *\n * Resolves with the whole batch's files, not just this leg's: the mutation\n * models one drop, and after a merge the drop is the batch. The earlier leg's\n * files come from the tail this run queued behind.\n */\nconst runMergedUploadPool = async ({\n entries,\n indices,\n token,\n uploadId,\n dispatch,\n concurrency,\n generateAiMetadata,\n}: {\n entries: UploadEntry[];\n indices: number[];\n token: string | null | undefined;\n uploadId: number;\n dispatch: Dispatch;\n concurrency: number;\n generateAiMetadata: boolean;\n}): Promise<UploadPoolResult> => {\n const abortController = abortControllers.get(uploadId) ?? new AbortController();\n\n const run = (poolTails.get(uploadId) ?? Promise.resolve(undefined)).then(\n (previous): UploadPoolResult | Promise<UploadPoolResult> => {\n // A failed earlier leg contributes no files; its error already reached the\n // store, and this leg still has files of its own to upload.\n const earlier = previous?.data ?? [];\n\n if (abortController.signal.aborted) {\n return { data: earlier };\n }\n\n registerAbortController(uploadId, abortController);\n\n return runUploadPool({\n entries,\n indices,\n token,\n uploadId,\n abortController,\n dispatch,\n concurrency,\n generateAiMetadata,\n }).then((result) => (result.error ? result : { data: [...earlier, ...(result.data ?? [])] }));\n }\n );\n\n trackPoolRun(uploadId, run);\n\n return run;\n};\n\n/* -------------------------------------------------------------------------------------------------\n * URL upload flow (SSE) — kept as-is for this iteration\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * Parses a raw SSE text chunk into event/data pairs.\n *\n * SSE format:\n * event: <eventName>\\n\n * data: <json>\\n\n * \\n\n */\nconst parseSSEEvents = (chunk: string): Array<{ event: string; data: string }> => {\n const events: Array<{ event: string; data: string }> = [];\n const blocks = chunk.split('\\n\\n').filter(Boolean);\n\n for (const block of blocks) {\n let event = '';\n let data = '';\n\n for (const line of block.split('\\n')) {\n if (line.startsWith('event: ')) {\n event = line.slice(7);\n } else if (line.startsWith('data: ')) {\n data = line.slice(6);\n }\n }\n\n if (event && data) {\n events.push({ event, data });\n }\n }\n\n return events;\n};\n\n/**\n * Makes a streaming upload-from-URLs request to the server.\n * Sends URLs as JSON body instead of FormData.\n */\nconst fetchUrlUploadStream = async ({\n token,\n urls,\n folderId,\n signal,\n}: {\n token: string | null | undefined;\n urls: string[];\n folderId: number | null;\n signal: AbortSignal;\n}): Promise<Response> => {\n const backendURL = window.strapi.backendURL;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n\n return fetch(`${backendURL}/upload/actions/upload-from-urls`, {\n method: 'POST',\n headers,\n body: JSON.stringify({ urls, folderId }),\n signal,\n });\n};\n\n/**\n * Processes an SSE stream from the URL upload endpoint.\n * Dispatches Redux actions for each file event and returns the final result.\n */\nconst processSSEStream = async ({\n response,\n dispatch,\n uploadId,\n generateAiMetadata,\n}: {\n response: Response;\n dispatch: Dispatch;\n uploadId: number;\n generateAiMetadata: boolean;\n}): Promise<CreateFilesStream.Response | null> => {\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n let streamResult: CreateFilesStream.Response | null = null;\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n\n // Process complete SSE events from the buffer\n const lastDoubleNewline = buffer.lastIndexOf('\\n\\n');\n if (lastDoubleNewline === -1) {\n // No complete events yet, keep buffering\n // eslint-disable-next-line no-continue\n continue;\n }\n\n const completePart = buffer.slice(0, lastDoubleNewline + 2);\n buffer = buffer.slice(lastDoubleNewline + 2);\n\n const events = parseSSEEvents(completePart);\n\n for (const { event, data } of events) {\n const parsed = JSON.parse(data);\n const index = parsed.index as number;\n\n switch (event) {\n case 'file:fetching': {\n // URL is being fetched server-side - mark as uploading (processing)\n dispatch(setFileUploading({ name: parsed.url as string, index, size: 0, uploadId }));\n break;\n }\n case 'file:uploading': {\n const payload = parsed as CreateFilesStreamEvents.FileUploadingEvent;\n dispatch(setFileUploading({ name: payload.name, index, size: payload.size, uploadId }));\n break;\n }\n case 'file:complete': {\n const payload = parsed as CreateFilesStreamEvents.FileCompleteEvent;\n dispatch(setFileComplete({ index, file: payload.file, uploadId }));\n\n // Same fire-and-forget semantics as the file flow.\n maybeGenerateMetadata({\n file: payload.file,\n index,\n uploadId,\n enabled: generateAiMetadata,\n dispatch,\n });\n break;\n }\n case 'file:error': {\n const payload = parsed as CreateFilesStreamEvents.FileErrorEvent;\n dispatch(setFileError({ index, name: payload.name, message: payload.message, uploadId }));\n break;\n }\n case 'stream:complete': {\n const payload = parsed as CreateFilesStreamEvents.StreamCompleteEvent;\n streamResult = {\n data: payload.data,\n errors: payload.errors,\n };\n break;\n }\n default:\n console.error(`[SSE Upload] unknown event: ${event}`, parsed);\n }\n }\n }\n\n return streamResult;\n};\n\nconst uploadApi = adminApi\n .enhanceEndpoints({\n addTagTypes: ['Asset', 'Folder'],\n })\n .injectEndpoints({\n endpoints: (builder) => ({\n /**\n * Upload files to `/upload/files`, one request per file, through a worker\n * pool of `concurrency` parallel requests (default 1 = sequential). Real\n * per-file byte progress comes from `XHR.upload.onprogress`.\n */\n uploadFiles: builder.mutation<UploadedFile[], UploadFilesArgs>({\n queryFn: async (\n { formData, totalFiles, concurrency = 1, generateAiMetadata },\n { dispatch, getState }\n ) => {\n const token = (getState() as RootState).admin_app?.token;\n\n // Extract the original files and their per-file fileInfo from the combined FormData.\n const files = formData.getAll('files') as File[];\n const fileInfoJson = formData.get('fileInfo') as string;\n const fileInfoArray = JSON.parse(fileInfoJson) as UploadFileInfo[];\n\n const entries: UploadEntry[] = files.map((file, index) => ({\n file,\n fileInfo: fileInfoArray[index] ?? {\n name: file.name,\n caption: null,\n alternativeText: null,\n folder: null,\n },\n }));\n\n const fileNames = entries.map((entry) => entry.fileInfo.name ?? entry.file.name);\n const fileSizes = entries.map((entry) => entry.file.size);\n\n // `uploadFromUrls` also leaves rows `pending`, but registers no batch —\n // so an unregistered batch is not ours to merge into, and appending would\n // land on top of its rows.\n const progress = (getState() as RootState).uploadProgress;\n const batch = getUploadEntries(progress.uploadId);\n const isMerge = batch !== undefined && isUploadInFlight(progress.files);\n\n if (isMerge) {\n const { uploadId } = progress;\n const offset = batch.entries.length;\n\n // No `totalFiles`: the reducer derives it from the rows it appends.\n dispatch(appendUploadFiles({ uploadId, fileNames, fileSizes }));\n\n const mergedEntries = [...batch.entries, ...entries];\n\n // Merged files adopt the batch's flags: a new concurrency would raise\n // the ceiling it exists to impose.\n registerUploadEntries(\n uploadId,\n mergedEntries,\n batch.generateAiMetadata,\n batch.concurrency\n );\n\n return runMergedUploadPool({\n entries: mergedEntries,\n indices: entries.map((_, index) => offset + index),\n token,\n uploadId,\n dispatch,\n concurrency: batch.concurrency,\n generateAiMetadata: batch.generateAiMetadata,\n });\n }\n\n // Open the progress dialog\n dispatch(openUploadProgress({ totalFiles, fileNames, fileSizes }));\n\n // Get the uploadId from state after dispatching\n const uploadId = (getState() as RootState).uploadProgress.uploadId;\n\n // Store original entries for retry functionality\n registerUploadEntries(uploadId, entries, generateAiMetadata, concurrency);\n\n // One AbortController per batch\n const abortController = new AbortController();\n registerAbortController(uploadId, abortController);\n\n const run = runUploadPool({\n entries,\n indices: entries.map((_, index) => index),\n token,\n uploadId,\n abortController,\n dispatch,\n concurrency,\n generateAiMetadata,\n });\n\n trackPoolRun(uploadId, run);\n\n return run;\n },\n // `Folder, LIST` refreshes the folder header count, which changes when\n // files are added to it.\n invalidatesTags: [\n { type: 'Asset', id: 'LIST' },\n { type: 'Folder', id: 'LIST' },\n ],\n }),\n\n /**\n * Upload a single, already-prepared file WITHOUT opening the global\n * upload-progress dialog. For flows that create one asset programmatically\n * (e.g. crop → \"Save as copy\"), where the bulk-upload progress UI is\n * inappropriate. Same endpoint as `uploadFiles`, minus the progress/retry\n * machinery.\n */\n uploadFileSilently: builder.mutation<UploadedFile, UploadEntry>({\n queryFn: async ({ file, fileInfo }, { getState }) => {\n const token = (getState() as RootState).admin_app?.token;\n const url = `${window.strapi.backendURL}/upload/files`;\n\n const formData = new FormData();\n formData.append('files', file);\n formData.append('fileInfo', JSON.stringify(fileInfo));\n\n try {\n const uploaded = await uploadFileViaXHR(\n url,\n token,\n formData,\n new AbortController().signal,\n () => {}\n );\n return { data: uploaded };\n } catch (err) {\n // Only pass on text the server actually sent. The XHR layer's own\n // fallbacks are hardcoded English, and callers here (crop → \"Save\n // as copy\") have a localized message of their own; an empty string\n // reads as \"nothing usable\" and lets theirs win.\n const message =\n err instanceof UploadFileError && err.isServerMessage ? err.message : '';\n return { error: { name: 'UnknownError', message } };\n }\n },\n // `Folder, LIST` refreshes the folder header count, which changes when\n // files are added to it.\n invalidatesTags: [\n { type: 'Asset', id: 'LIST' },\n { type: 'Folder', id: 'LIST' },\n ],\n }),\n\n /**\n * Retry uploading cancelled files.\n * Maps cancelled rows back to their original entries and re-runs only those\n * through the same upload pool with a fresh AbortController.\n */\n retryCancelledFiles: builder.mutation<UploadedFile[], void>({\n queryFn: async (_arg, { dispatch, getState }) => {\n const { uploadId, files: stateFiles } = (getState() as RootState).uploadProgress;\n const token = (getState() as RootState).admin_app?.token;\n\n const cancelledIndices = stateFiles\n .filter((f) => f.status === 'cancelled')\n .map((f) => f.index);\n\n if (cancelledIndices.length === 0) {\n return { error: { name: 'UnknownError', message: 'No cancelled files to retry' } };\n }\n\n const batch = getUploadEntries(uploadId);\n if (!batch) {\n return { error: { name: 'UnknownError', message: 'Original files not found' } };\n }\n\n // Reset cancelled files back to pending\n dispatch(retryCancelledFiles());\n\n // Fresh AbortController for the retry run\n const abortController = new AbortController();\n registerAbortController(uploadId, abortController);\n\n const run = runUploadPool({\n entries: batch.entries,\n indices: cancelledIndices,\n token,\n uploadId,\n abortController,\n dispatch,\n // Replay the retried rows with the flags the batch was started with.\n concurrency: batch.concurrency,\n generateAiMetadata: batch.generateAiMetadata,\n });\n\n // Retried rows are `pending` again, so a drop lands on the merge branch.\n // Untracked, that merge would find no tail to queue behind and run its\n // pool beside this one — two pools of `concurrency` each.\n trackPoolRun(uploadId, run);\n\n return run;\n },\n // `Folder, LIST` refreshes the folder header count, which changes when\n // files are added to it.\n invalidatesTags: [\n { type: 'Asset', id: 'LIST' },\n { type: 'Folder', id: 'LIST' },\n ],\n }),\n\n /**\n * Upload files from URLs.\n * Sends URLs to the server which fetches and uploads them (SSE flow, unchanged).\n */\n uploadFromUrls: builder.mutation<CreateFilesStream.Response, UploadFromUrlsArgs>({\n queryFn: async ({ urls, folderId, generateAiMetadata }, { dispatch, getState }) => {\n const token = (getState() as RootState).admin_app?.token;\n\n // Extract filenames from URLs for the progress dialog\n const fileNames = urls.map((url) => getFilenameFromUrl(url));\n\n // Open progress dialog with all URLs as pending files\n dispatch(\n openUploadProgress({\n totalFiles: urls.length,\n fileNames,\n })\n );\n\n // Get the uploadId from state after dispatching\n const uploadId = (getState() as RootState).uploadProgress.uploadId;\n\n // Create abort controller for this upload\n const abortController = new AbortController();\n registerAbortController(uploadId, abortController);\n\n try {\n // Send URLs to server for fetching and uploading\n const response = await fetchUrlUploadStream({\n token,\n urls,\n folderId,\n signal: abortController.signal,\n });\n\n if (!response.ok || !response.body) {\n unregisterAbortController(uploadId);\n\n let errorMessage = 'Upload request failed';\n try {\n const errorData = await response.json();\n if (errorData.error?.message) {\n errorMessage = errorData.error.message;\n } else if (errorData.message) {\n errorMessage = errorData.message;\n }\n } catch {\n errorMessage = `Upload failed with status ${response.status}`;\n }\n\n dispatch(setUploadFailed({ message: errorMessage }));\n\n return {\n error: {\n name: 'UnknownError' as const,\n message: errorMessage,\n status: response.status,\n },\n };\n }\n\n // Process SSE stream from server\n const streamResult = await processSSEStream({\n response,\n dispatch,\n uploadId,\n generateAiMetadata,\n });\n\n unregisterAbortController(uploadId);\n\n if (streamResult && streamResult.data.length > 0) {\n return { data: streamResult };\n }\n\n return { data: { data: [], errors: [] } };\n } catch (err) {\n unregisterAbortController(uploadId);\n\n if (err instanceof DOMException && err.name === 'AbortError') {\n return { error: { name: 'UnknownError' as const, message: 'Upload cancelled' } };\n }\n\n const errorMessage = err instanceof Error ? err.message : 'Network error occurred';\n dispatch(setUploadFailed({ message: errorMessage }));\n\n return {\n error: {\n name: 'UnknownError' as const,\n message: errorMessage,\n },\n };\n }\n },\n // `Folder, LIST` refreshes the folder header count, which changes when\n // files are added to it.\n invalidatesTags: [\n { type: 'Asset', id: 'LIST' },\n { type: 'Folder', id: 'LIST' },\n ],\n }),\n\n /**\n * Generate AI metadata (alt text + caption) for the given assets.\n * Synchronous: resolves once every file has been processed and reports the\n * outcome per file, so non-images and individual failures don't fail the\n * whole batch. Existing alt text and captions are never overwritten.\n *\n * Lives here rather than in `assets.ts` because the upload flows dispatch it\n * directly via `initiate()` after each file completes, and `assets.ts` already\n * imports from this module — defining it there would be a circular import.\n * Re-exported from `assets.ts` for the components that consume the hook.\n */\n generateAiMetadata: builder.mutation<\n GenerateAIMetadata.Response['data'],\n { fileIds: number[] }\n >({\n query: ({ fileIds }) => ({\n url: '/upload/actions/generate-ai-metadata',\n method: 'POST',\n data: { fileIds },\n }),\n transformResponse: (response: { data: GenerateAIMetadata.Response['data'] }) =>\n response.data,\n invalidatesTags: (_result, _error, { fileIds }) => [\n ...fileIds.map((id) => ({ type: 'Asset' as const, id })),\n { type: 'Asset' as const, id: 'LIST' },\n ],\n }),\n }),\n });\n\nexport const {\n useUploadFilesMutation,\n useUploadFileSilentlyMutation,\n useRetryCancelledFilesMutation,\n useUploadFromUrlsMutation,\n useGenerateAiMetadataMutation,\n} = uploadApi;\nexport { uploadApi };\n"],"names":["uploadRegistry","Map","registerUploadEntries","uploadId","entries","generateAiMetadata","concurrency","set","getUploadEntries","get","abortControllers","registerAbortController","controller","unregisterAbortController","delete","abortUpload","abort","poolTails","trackPoolRun","run","tail","catch","undefined","then","METADATA_STATUS_BY_RESULT","success","skipped","error","maybeGenerateMetadata","file","index","enabled","dispatch","id","setFileMetadataGenerating","promise","uploadApi","endpoints","initiate","fileIds","unwrap","results","result","find","r","setFileMetadataResult","status","runUploadPool","indices","token","abortController","url","window","strapi","backendURL","uploaded","queue","uploadOne","entry","fileName","fileInfo","name","setFileUploading","size","formData","FormData","append","JSON","stringify","batcher","createRafBatcher","bytes","setFileProgress","uploadFileViaXHR","signal","schedule","cancel","push","setFileComplete","err","UploadAbortedError","message","Error","setFileError","requested","Number","isFinite","Math","floor","workerCount","min","max","length","worker","aborted","shift","Promise","all","Array","from","data","runMergedUploadPool","AbortController","resolve","previous","earlier","parseSSEEvents","chunk","events","blocks","split","filter","Boolean","block","event","line","startsWith","slice","fetchUrlUploadStream","urls","folderId","headers","Authorization","fetch","method","body","processSSEStream","response","reader","getReader","decoder","TextDecoder","streamResult","buffer","done","value","read","decode","stream","lastDoubleNewline","lastIndexOf","completePart","parsed","parse","payload","errors","console","adminApi","enhanceEndpoints","addTagTypes","injectEndpoints","builder","uploadFiles","mutation","queryFn","totalFiles","getState","admin_app","files","getAll","fileInfoJson","fileInfoArray","map","caption","alternativeText","folder","fileNames","fileSizes","progress","uploadProgress","batch","isMerge","isUploadInFlight","offset","appendUploadFiles","mergedEntries","_","openUploadProgress","invalidatesTags","type","uploadFileSilently","UploadFileError","isServerMessage","retryCancelledFiles","_arg","stateFiles","cancelledIndices","f","uploadFromUrls","getFilenameFromUrl","ok","errorMessage","errorData","json","setUploadFailed","DOMException","query","transformResponse","_result","_error","useUploadFilesMutation","useUploadFileSilentlyMutation","useRetryCancelledFilesMutation","useUploadFromUrlsMutation","useGenerateAiMetadataMutation"],"mappings":"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"}
|
|
@@ -82,22 +82,16 @@ const assetsApi = api.uploadApi.injectEndpoints({
|
|
|
82
82
|
]
|
|
83
83
|
}),
|
|
84
84
|
/**
|
|
85
|
-
* Update the editable metadata of an existing asset
|
|
86
|
-
*
|
|
87
|
-
* `admin-upload.updateFileInfo`.
|
|
85
|
+
* Update the editable metadata of an existing asset, through
|
|
86
|
+
* `PUT /upload/files/<id>` (`admin-upload.updateFileInfo`).
|
|
88
87
|
*/ updateAsset: builder.mutation({
|
|
89
88
|
query: ({ id, fileInfo })=>{
|
|
90
89
|
const formData = new FormData();
|
|
91
90
|
formData.append('fileInfo', JSON.stringify(fileInfo));
|
|
92
91
|
return {
|
|
93
|
-
url:
|
|
94
|
-
method: '
|
|
95
|
-
data: formData
|
|
96
|
-
config: {
|
|
97
|
-
params: {
|
|
98
|
-
id
|
|
99
|
-
}
|
|
100
|
-
}
|
|
92
|
+
url: `/upload/files/${id}`,
|
|
93
|
+
method: 'PUT',
|
|
94
|
+
data: formData
|
|
101
95
|
};
|
|
102
96
|
},
|
|
103
97
|
invalidatesTags: (_result, _error, { id })=>[
|
|
@@ -118,11 +112,10 @@ const assetsApi = api.uploadApi.injectEndpoints({
|
|
|
118
112
|
]
|
|
119
113
|
}),
|
|
120
114
|
/**
|
|
121
|
-
* Replace the binary content of an existing asset
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
* replace one file at a time and don't need per-byte progress here.
|
|
115
|
+
* Replace the binary content of an existing asset, through
|
|
116
|
+
* `POST /upload/files/<id>/replace` (`admin-upload.replaceFile`) with a
|
|
117
|
+
* multipart body. Uses the standard axios baseQuery (no streaming) since we
|
|
118
|
+
* only ever replace one file at a time and don't need per-byte progress here.
|
|
126
119
|
*/ replaceAsset: builder.mutation({
|
|
127
120
|
query: ({ id, file, fileInfo })=>{
|
|
128
121
|
const formData = new FormData();
|
|
@@ -131,14 +124,9 @@ const assetsApi = api.uploadApi.injectEndpoints({
|
|
|
131
124
|
formData.append('fileInfo', JSON.stringify(fileInfo));
|
|
132
125
|
}
|
|
133
126
|
return {
|
|
134
|
-
url:
|
|
127
|
+
url: `/upload/files/${id}/replace`,
|
|
135
128
|
method: 'POST',
|
|
136
|
-
data: formData
|
|
137
|
-
config: {
|
|
138
|
-
params: {
|
|
139
|
-
id
|
|
140
|
-
}
|
|
141
|
-
}
|
|
129
|
+
data: formData
|
|
142
130
|
};
|
|
143
131
|
},
|
|
144
132
|
invalidatesTags: (_result, _error, { id })=>[
|