@maas/payload-plugin-media-cloud 0.0.38 → 0.0.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/adapter/handleUpload.mjs +9 -9
  2. package/dist/adapter/handleUpload.mjs.map +1 -1
  3. package/dist/adapter/staticHandler.mjs +5 -2
  4. package/dist/adapter/staticHandler.mjs.map +1 -1
  5. package/dist/adapter/storageAdapter.mjs +1 -1
  6. package/dist/collectionHooks/afterChange.mjs +14 -3
  7. package/dist/collectionHooks/afterChange.mjs.map +1 -1
  8. package/dist/collections/mediaCollection.mjs +2 -3
  9. package/dist/collections/mediaCollection.mjs.map +1 -1
  10. package/dist/components/gridContext/gridContext.d.mts +1 -1
  11. package/dist/components/gridView/gridView.css +11 -1
  12. package/dist/components/gridView/gridView.d.mts +1 -1
  13. package/dist/components/gridView/gridView.mjs +3 -2
  14. package/dist/components/gridView/gridView.mjs.map +1 -1
  15. package/dist/components/muxPreview/muxPreview.d.mts +1 -1
  16. package/dist/components/selectMany/selectMany.d.mts +10 -0
  17. package/dist/components/selectMany/selectMany.mjs +49 -0
  18. package/dist/components/selectMany/selectMany.mjs.map +1 -0
  19. package/dist/components/uploadHandler/uploadHandler.d.mts +1 -1
  20. package/dist/components/uploadHandler/uploadHandler.mjs +117 -99
  21. package/dist/components/uploadHandler/uploadHandler.mjs.map +1 -1
  22. package/dist/components/uploadManager/uploadManager.mjs +2 -2
  23. package/dist/components/uploadManager/uploadManager.mjs.map +1 -1
  24. package/dist/endpoints/fileExistsHandler.mjs +3 -3
  25. package/dist/endpoints/fileExistsHandler.mjs.map +1 -1
  26. package/dist/endpoints/muxAssetHandler.d.mts +1 -1
  27. package/dist/endpoints/muxAssetHandler.mjs +2 -2
  28. package/dist/endpoints/muxAssetHandler.mjs.map +1 -1
  29. package/dist/endpoints/muxCreateUploadHandler.d.mts +1 -1
  30. package/dist/endpoints/muxCreateUploadHandler.mjs +2 -2
  31. package/dist/endpoints/muxCreateUploadHandler.mjs.map +1 -1
  32. package/dist/endpoints/muxWebhookHandler.d.mts +1 -1
  33. package/dist/endpoints/tusPostProcessorHandler.mjs +13 -3
  34. package/dist/endpoints/tusPostProcessorHandler.mjs.map +1 -1
  35. package/dist/fields/mux.mjs +0 -3
  36. package/dist/fields/mux.mjs.map +1 -1
  37. package/dist/tus/stores/s3/partsManager.mjs +4 -10
  38. package/dist/tus/stores/s3/partsManager.mjs.map +1 -1
  39. package/dist/tus/stores/s3/s3Store.mjs +4 -1
  40. package/dist/tus/stores/s3/s3Store.mjs.map +1 -1
  41. package/dist/types/errors.d.mts +8 -0
  42. package/dist/types/errors.mjs +8 -0
  43. package/dist/types/errors.mjs.map +1 -1
  44. package/dist/types/index.d.mts +5 -1
  45. package/dist/utils/defaultOptions.mjs +5 -1
  46. package/dist/utils/defaultOptions.mjs.map +1 -1
  47. package/dist/utils/file.d.mts +2 -2
  48. package/dist/utils/file.mjs +1 -1
  49. package/dist/utils/file.mjs.map +1 -1
  50. package/dist/utils/mux.d.mts +3 -3
  51. package/dist/utils/tus.d.mts +4 -4
  52. package/package.json +6 -5
@@ -2,14 +2,15 @@
2
2
 
3
3
  import { MediaCloudErrors, MediaCloudLogs } from "../../types/errors.mjs";
4
4
  import { useMagicError } from "../../error-handler/dist/index.mjs";
5
- import { useErrorHandler } from "../../hooks/useErrorHandler.mjs";
6
5
  import { generateUniqueFilename, getMimeType, isVideo, sanitizeFilename } from "../../utils/file.mjs";
7
6
  import { useMediaCloudEmitter } from "../../hooks/useMediaCloudEmitter.mjs";
7
+ import PQueue from "p-queue";
8
8
  import * as upchunk from "@mux/upchunk";
9
9
  import * as tus from "tus-js-client";
10
10
  import { createClientUploadHandler } from "@payloadcms/plugin-cloud-storage/client";
11
11
 
12
12
  //#region src/components/uploadHandler/uploadHandler.tsx
13
+ let queue;
13
14
  const MUX_CHUNK_SIZE = 30720;
14
15
  const TUS_CHUNK_SIZE = 1024 * 1024;
15
16
  const TUS_RETRY_DELAYS = [
@@ -19,7 +20,7 @@ const TUS_RETRY_DELAYS = [
19
20
  5e3
20
21
  ];
21
22
  const magicError = useMagicError({ prefix: "PLUGIN-MEDIA-CLOUD" });
22
- const { throwError } = magicError;
23
+ const { throwError, log } = magicError;
23
24
  const emitter = useMediaCloudEmitter();
24
25
  /**
25
26
  * Handles Mux video upload with progress tracking
@@ -27,7 +28,7 @@ const emitter = useMediaCloudEmitter();
27
28
  * @returns Promise that resolves to upload result or null if upload fails
28
29
  */
29
30
  async function muxUpload(args) {
30
- const { file, serverURL, apiRoute, mimeType } = args;
31
+ const { file, serverURL, apiRoute, mimeType, onResolve } = args;
31
32
  const endpoint = `${serverURL}${apiRoute}`;
32
33
  const filename = file.name;
33
34
  try {
@@ -51,32 +52,38 @@ async function muxUpload(args) {
51
52
  polling: false,
52
53
  pollingUrl: `${endpoint}/mux/asset`
53
54
  });
54
- uploader.on("error", function() {
55
- emitter.emit("removeUpload", { uploadId });
56
- throwError(MediaCloudErrors.MUX_UPLOAD_ERROR);
55
+ await onResolve({
56
+ storage: "mux",
57
+ filename,
58
+ uploadId,
59
+ mimeType
57
60
  });
58
- uploader.on("progress", function(progress) {
59
- emitter.emit("updateUpload", {
60
- filename,
61
- progress: progress.detail
61
+ return new Promise((resolve, reject) => {
62
+ uploader.on("error", function(error) {
63
+ emitter.emit("removeUpload", { uploadId });
64
+ throwError({
65
+ ...MediaCloudErrors.MUX_UPLOAD_ERROR,
66
+ cause: error
67
+ });
68
+ reject(error);
69
+ });
70
+ uploader.on("progress", function(progress) {
71
+ emitter.emit("updateUpload", {
72
+ filename,
73
+ progress: progress.detail
74
+ });
75
+ });
76
+ uploader.on("success", function() {
77
+ emitter.emit("uploadComplete", { filename });
78
+ resolve();
62
79
  });
63
80
  });
64
- uploader.on("success", function() {
65
- emitter.emit("uploadComplete", { filename });
66
- });
67
- return {
68
- filename,
69
- uploadId,
70
- mimeType,
71
- storage: "mux"
72
- };
73
81
  } catch {
74
82
  throwError(MediaCloudErrors.MUX_DIRECT_UPLOAD_ERROR);
75
83
  emitter.emit("uploadError", {
76
84
  filename,
77
85
  error: "Video upload failed"
78
86
  });
79
- return null;
80
87
  }
81
88
  }
82
89
  /**
@@ -85,23 +92,13 @@ async function muxUpload(args) {
85
92
  * @returns Promise that resolves to upload result or null if upload fails
86
93
  */
87
94
  async function tusUpload(args) {
88
- const { apiRoute, serverURL, file, prefix = "", mimeType } = args;
95
+ const { apiRoute, serverURL, file, prefix = "", mimeType, onResolve } = args;
89
96
  const filename = file.name;
90
97
  const filetype = file.type;
91
98
  const filesize = file.size.toString();
92
99
  const endpoint = `${serverURL}${apiRoute}/uploads`;
93
- Object.keys(localStorage).filter((key) => key.startsWith("tus::")).forEach((key) => localStorage.removeItem(key));
94
100
  let uploadUrlAvailable = false;
95
- let eventListenerAdded = false;
96
- function onBeforeUnload(e) {
97
- window.removeEventListener("beforeunload", onBeforeUnload);
98
- e.preventDefault();
99
- }
100
- function onPageUnload() {
101
- window.removeEventListener("unload", onPageUnload);
102
- navigator.sendBeacon(`${endpoint}/cleanup`, JSON.stringify({ filename }));
103
- }
104
- return new Promise((resolve) => {
101
+ return new Promise((resolve, reject) => {
105
102
  new tus.Upload(file, {
106
103
  endpoint,
107
104
  retryDelays: TUS_RETRY_DELAYS,
@@ -127,14 +124,7 @@ async function tusUpload(args) {
127
124
  ...MediaCloudErrors.TUS_UPLOAD_ERROR,
128
125
  cause: error
129
126
  });
130
- resolve(null);
131
- },
132
- onBeforeRequest() {
133
- if (!eventListenerAdded) {
134
- window.addEventListener("beforeunload", onBeforeUnload);
135
- window.addEventListener("unload", onPageUnload);
136
- eventListenerAdded = true;
137
- }
127
+ reject(error);
138
128
  },
139
129
  onProgress: function(bytesUploaded, bytesTotal) {
140
130
  const percentage = Math.round(bytesUploaded / bytesTotal * 100);
@@ -144,77 +134,105 @@ async function tusUpload(args) {
144
134
  });
145
135
  },
146
136
  async onSuccess() {
147
- window.removeEventListener("beforeunload", onBeforeUnload);
148
- window.removeEventListener("unload", onPageUnload);
149
- emitter.emit("uploadComplete", { filename });
150
- await fetch(`${endpoint}/${filename}/process`);
151
- await fetch(`${endpoint}/${filename}/folder`);
137
+ try {
138
+ emitter.emit("uploadComplete", { filename });
139
+ await fetch(`${endpoint}/${filename}/process`);
140
+ await fetch(`${endpoint}/${filename}/folder`);
141
+ } catch (error) {
142
+ console.error(error);
143
+ } finally {
144
+ resolve();
145
+ }
152
146
  },
153
147
  onUploadUrlAvailable: async function() {
154
- if (uploadUrlAvailable) return;
155
- uploadUrlAvailable = true;
156
- emitter.emit("addUpload", { filename });
157
- resolve({
158
- filename,
159
- mimeType,
160
- storage: "s3"
161
- });
148
+ try {
149
+ if (uploadUrlAvailable) return;
150
+ uploadUrlAvailable = true;
151
+ emitter.emit("addUpload", { filename });
152
+ onResolve({
153
+ filename,
154
+ mimeType,
155
+ storage: "s3"
156
+ });
157
+ } catch (error) {
158
+ console.error(error);
159
+ }
162
160
  }
163
161
  }).start();
164
162
  });
165
163
  }
166
- const { log } = useErrorHandler();
167
164
  function UploadHandler(props) {
168
165
  return createClientUploadHandler({ handler: async function(args) {
169
166
  const { serverURL, apiRoute, file, prefix, updateFilename, extra } = args;
170
167
  const { pluginOptions } = extra;
171
- const mimeType = await getMimeType(file);
172
- magicError.assert(mimeType, MediaCloudErrors.FILE_TYPE_UNKNOWN);
173
- if (!(pluginOptions.limits?.mimeTypes ?? []).some((allowed) => allowed.endsWith("/*") ? mimeType?.startsWith(allowed.replace("/*", "/")) : mimeType === allowed)) {
174
- throwError(MediaCloudErrors.FILE_TYPE_NOT_ALLOWED);
175
- return null;
176
- }
177
- if (file.size > (pluginOptions.limits?.fileSize ?? Infinity)) {
178
- throwError(MediaCloudErrors.FILE_SIZE_EXCEEDED);
179
- return null;
180
- }
181
- let mappedFile = file;
182
- try {
183
- const endpoint = `${serverURL}${apiRoute}/uploads`;
184
- const response = await fetch(`${endpoint}/${file.name}/exists`);
185
- if (response?.status === 200) log(MediaCloudLogs.S3_STORE_FILE_FOUND);
186
- const newFilename = response?.status === 200 ? generateUniqueFilename(file.name) : sanitizeFilename(file.name);
187
- mappedFile = new File([file], newFilename, { type: file.type });
188
- await updateFilename(newFilename);
189
- } catch (error) {
190
- throwError({
191
- ...MediaCloudErrors.NAMING_FUNCTION_ERROR,
192
- cause: error
193
- });
194
- return null;
195
- }
196
- try {
197
- const uploadArgs = {
198
- file: mappedFile,
199
- serverURL,
200
- apiRoute,
201
- mimeType,
202
- prefix
203
- };
204
- const storageForMimeType = pluginOptions.storage && Object.prototype.hasOwnProperty.call(pluginOptions.storage, mimeType) ? pluginOptions.storage[mimeType] : void 0;
205
- const isVideoFile = await isVideo(file);
206
- const storeOnMux = pluginOptions.storage?.["video/*"] === "mux" || storageForMimeType === "mux";
207
- switch (true) {
208
- case storeOnMux && isVideoFile: return await muxUpload(uploadArgs);
209
- default: return await tusUpload(uploadArgs);
168
+ if (!queue) queue = new PQueue({ concurrency: pluginOptions.limits.concurrency });
169
+ if (queue && queue.concurrency !== pluginOptions.limits.concurrency) queue.concurrency = pluginOptions.limits.concurrency;
170
+ async function upload(onResolve) {
171
+ const mimeType = await getMimeType(file);
172
+ const allowedMimeTypes = pluginOptions.limits?.mimeTypes ?? [];
173
+ magicError.assert(mimeType, MediaCloudErrors.FILE_TYPE_UNKNOWN);
174
+ if (!allowedMimeTypes.some((allowed) => allowed.endsWith("/*") ? mimeType?.startsWith(allowed.replace("/*", "/")) : mimeType === allowed)) {
175
+ throwError(MediaCloudErrors.FILE_TYPE_NOT_ALLOWED);
176
+ onResolve(null);
177
+ return;
178
+ }
179
+ if (file.size > pluginOptions.limits.fileSize) {
180
+ throwError(MediaCloudErrors.FILE_SIZE_EXCEEDED);
181
+ onResolve(null);
182
+ return;
183
+ }
184
+ let mappedFile = file;
185
+ try {
186
+ const sanitizedFilename = sanitizeFilename(file.name);
187
+ const endpoint = `${serverURL}${apiRoute}/uploads`;
188
+ const response = await fetch(`${endpoint}/${sanitizedFilename}/exists`);
189
+ switch (response?.status) {
190
+ case 200:
191
+ log(MediaCloudLogs.S3_STORE_FILE_FOUND);
192
+ break;
193
+ case 204:
194
+ log(MediaCloudLogs.S3_STORE_FILE_NOT_FOUND);
195
+ break;
196
+ }
197
+ const newFilename = response?.status === 200 ? generateUniqueFilename(sanitizedFilename) : sanitizedFilename;
198
+ mappedFile = new File([file], newFilename, { type: file.type });
199
+ await updateFilename(newFilename);
200
+ } catch (error) {
201
+ throwError({
202
+ ...MediaCloudErrors.NAMING_FUNCTION_ERROR,
203
+ cause: error
204
+ });
205
+ onResolve(null);
206
+ return;
207
+ }
208
+ try {
209
+ const uploadArgs = {
210
+ file: mappedFile,
211
+ serverURL,
212
+ apiRoute,
213
+ mimeType,
214
+ prefix,
215
+ onResolve
216
+ };
217
+ const storageForMimeType = pluginOptions.storage && Object.prototype.hasOwnProperty.call(pluginOptions.storage, mimeType) ? pluginOptions.storage[mimeType] : void 0;
218
+ const isVideoFile = await isVideo(file);
219
+ const storeOnMux = pluginOptions.storage?.["video/*"] === "mux" || storageForMimeType === "mux";
220
+ switch (true) {
221
+ case storeOnMux && isVideoFile: return await muxUpload(uploadArgs);
222
+ default: return await tusUpload(uploadArgs);
223
+ }
224
+ } catch (error) {
225
+ throwError({
226
+ ...MediaCloudErrors.UPLOAD_HANDLER_ERROR,
227
+ cause: error
228
+ });
229
+ onResolve(null);
210
230
  }
211
- } catch (error) {
212
- throwError({
213
- ...MediaCloudErrors.UPLOAD_HANDLER_ERROR,
214
- cause: error
215
- });
216
- return null;
217
231
  }
232
+ return new Promise((resolve) => {
233
+ magicError.assert(queue, MediaCloudErrors.UPLOAD_QUEUE_NOT_INITIALIZED);
234
+ queue.add(() => upload(resolve));
235
+ });
218
236
  } })(props);
219
237
  }
220
238
 
@@ -1 +1 @@
1
- {"version":3,"file":"uploadHandler.mjs","names":["upchunk","tus","createClientUploadHandler","MediaCloudErrors","MediaCloudLogs","useMediaCloudEmitter","useErrorHandler","isVideo","getMimeType","generateUniqueFilename","sanitizeFilename","useMagicError","MUX_CHUNK_SIZE","TUS_CHUNK_SIZE","TUS_RETRY_DELAYS","magicError","prefix","throwError","emitter","muxUpload","args","file","serverURL","apiRoute","mimeType","endpoint","filename","name","response","fetch","body","JSON","stringify","credentials","method","headers","url","uploadId","json","uploader","createUpload","chunkSize","emit","polling","pollingUrl","on","MUX_UPLOAD_ERROR","progress","detail","storage","MUX_DIRECT_UPLOAD_ERROR","error","tusUpload","filetype","type","filesize","size","toString","Object","keys","localStorage","filter","key","startsWith","forEach","removeItem","uploadUrlAvailable","eventListenerAdded","onBeforeUnload","e","window","removeEventListener","preventDefault","onPageUnload","navigator","sendBeacon","Promise","resolve","upload","Upload","retryDelays","storeFingerprintForResuming","metadata","contentType","contentLength","contentDisposition","onError","message","TUS_UPLOAD_ERROR","cause","onBeforeRequest","addEventListener","onProgress","bytesUploaded","bytesTotal","percentage","Math","round","onSuccess","onUploadUrlAvailable","start","log","UploadHandler","props","handler","updateFilename","extra","pluginOptions","assert","FILE_TYPE_UNKNOWN","allowedMimeTypes","limits","mimeTypes","mimeTypeMatches","some","allowed","endsWith","replace","FILE_TYPE_NOT_ALLOWED","fileSize","Infinity","FILE_SIZE_EXCEEDED","mappedFile","status","S3_STORE_FILE_FOUND","newFilename","File","NAMING_FUNCTION_ERROR","uploadArgs","storageForMimeType","prototype","hasOwnProperty","call","undefined","isVideoFile","storeOnMux","UPLOAD_HANDLER_ERROR"],"sources":["../../../src/components/uploadHandler/uploadHandler.tsx"],"sourcesContent":["'use client'\n\nimport * as upchunk from '@mux/upchunk'\nimport * as tus from 'tus-js-client'\n\nimport { createClientUploadHandler } from '@payloadcms/plugin-cloud-storage/client'\n\nimport { MediaCloudErrors, MediaCloudLogs } from '../../types/errors'\nimport { useMediaCloudEmitter } from '../../hooks/useMediaCloudEmitter'\nimport { useErrorHandler } from '../../hooks/useErrorHandler'\nimport {\n isVideo,\n getMimeType,\n generateUniqueFilename,\n sanitizeFilename,\n} from '../../utils/file'\n\nimport type {\n MediaCloudPluginOptions,\n Storage,\n MimeType,\n} from '../../types/index'\nimport type { ReactNode } from 'react'\nimport type { UploadCollectionSlug } from 'payload'\nimport { useMagicError, UseMagicErrorReturn } from '@maas/error-handler'\n\ninterface UploadArgs {\n serverURL: string\n apiRoute: string\n file: File\n mimeType: MimeType\n prefix?: string\n}\n\ninterface UploadResult {\n storage: Storage\n mimeType: MimeType\n filename: string\n uploadId?: string\n}\n\ninterface MuxCreateUploadResponse {\n url: string\n uploadId: string\n filename: string\n}\n\nconst MUX_CHUNK_SIZE = 30720\nconst TUS_CHUNK_SIZE = 1024 * 1024\nconst TUS_RETRY_DELAYS = [0, 1000, 2000, 5000]\n\nconst magicError: UseMagicErrorReturn = useMagicError({\n prefix: 'PLUGIN-MEDIA-CLOUD',\n})\n\nconst { throwError } = magicError\nconst emitter = useMediaCloudEmitter()\n\n/**\n * Handles Mux video upload with progress tracking\n * @param args - The upload arguments including file, server URL, and callbacks\n * @returns Promise that resolves to upload result or null if upload fails\n */\nasync function muxUpload(args: UploadArgs): Promise<UploadResult | null> {\n const { file, serverURL, apiRoute, mimeType } = args\n\n const endpoint = `${serverURL}${apiRoute}`\n const filename = file.name\n\n try {\n // Request upload URL from Mux\n const response = await fetch(`${endpoint}/mux/upload`, {\n body: JSON.stringify({ filename, mimeType }),\n credentials: 'include',\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n })\n\n const { url, uploadId } = (await response.json()) as MuxCreateUploadResponse\n\n // Create upchunk uploader\n const uploader = await upchunk.createUpload({\n endpoint: url,\n file,\n chunkSize: MUX_CHUNK_SIZE,\n })\n\n // Add upload to tracker\n emitter.emit('addUpload', {\n filename,\n uploadId,\n polling: false,\n pollingUrl: `${endpoint}/mux/asset`,\n })\n\n // Set up event handlers\n uploader.on('error', function () {\n emitter.emit('removeUpload', { uploadId })\n throwError(MediaCloudErrors.MUX_UPLOAD_ERROR)\n })\n\n uploader.on('progress', function (progress) {\n emitter.emit('updateUpload', {\n filename,\n progress: progress.detail,\n })\n })\n\n uploader.on('success', function () {\n emitter.emit('uploadComplete', { filename })\n })\n\n // Update collection entry\n // with filename, uploadId, mimeType, and storage\n return {\n filename,\n uploadId,\n mimeType,\n storage: 'mux',\n }\n } catch {\n throwError(MediaCloudErrors.MUX_DIRECT_UPLOAD_ERROR)\n emitter.emit('uploadError', { filename, error: 'Video upload failed' })\n return null\n }\n}\n\n/**\n * Handles TUS file upload with resumable capabilities\n * @param args - The upload arguments including file, server URL, and callbacks\n * @returns Promise that resolves to upload result or null if upload fails\n */\nasync function tusUpload(args: UploadArgs): Promise<UploadResult | null> {\n const { apiRoute, serverURL, file, prefix = '', mimeType } = args\n\n const filename = file.name\n const filetype = file.type\n const filesize = file.size.toString()\n\n const endpoint = `${serverURL}${apiRoute}/uploads`\n\n // Clear any stale TUS uploads from localStorage\n Object.keys(localStorage)\n .filter((key) => key.startsWith('tus::'))\n .forEach((key) => localStorage.removeItem(key))\n\n // Flag to prevent multiple onUploadUrlAvailable calls\n let uploadUrlAvailable = false\n let eventListenerAdded = false\n\n function onBeforeUnload(e: BeforeUnloadEvent) {\n window.removeEventListener('beforeunload', onBeforeUnload)\n e.preventDefault()\n }\n\n function onPageUnload() {\n window.removeEventListener('unload', onPageUnload)\n navigator.sendBeacon(`${endpoint}/cleanup`, JSON.stringify({ filename }))\n }\n\n return new Promise((resolve) => {\n const upload = new tus.Upload(file, {\n endpoint,\n retryDelays: TUS_RETRY_DELAYS,\n chunkSize: TUS_CHUNK_SIZE,\n storeFingerprintForResuming: false,\n metadata: {\n filetype,\n filesize,\n filename,\n prefix,\n contentType: filetype,\n contentLength: filesize,\n contentDisposition: 'inline',\n },\n onError(error) {\n // Clean up\n navigator.sendBeacon(\n `${endpoint}/cleanup`,\n JSON.stringify({ filename })\n )\n\n // Inform user\n emitter.emit('uploadError', { filename, error: error.message })\n emitter.emit('removeUpload', { filename })\n throwError({ ...MediaCloudErrors.TUS_UPLOAD_ERROR, cause: error })\n resolve(null)\n },\n onBeforeRequest() {\n if (!eventListenerAdded) {\n window.addEventListener('beforeunload', onBeforeUnload)\n window.addEventListener('unload', onPageUnload)\n eventListenerAdded = true\n }\n },\n onProgress: function (bytesUploaded, bytesTotal) {\n const percentage = Math.round((bytesUploaded / bytesTotal) * 100)\n emitter.emit('updateUpload', {\n filename,\n progress: percentage,\n })\n },\n async onSuccess() {\n // Clean up beforeunload listener\n window.removeEventListener('beforeunload', onBeforeUnload)\n window.removeEventListener('unload', onPageUnload)\n\n // Mark upload as complete in UI\n emitter.emit('uploadComplete', { filename })\n\n // Trigger post upload processing\n await fetch(`${endpoint}/${filename}/process`)\n\n // Move file to correct folder\n await fetch(`${endpoint}/${filename}/folder`)\n },\n onUploadUrlAvailable: async function () {\n // Prevent multiple callbacks\n if (uploadUrlAvailable) {\n return\n }\n\n // Update flag\n uploadUrlAvailable = true\n\n // Add upload to UI\n emitter.emit('addUpload', { filename })\n\n // Update collection entry\n // with filename, mimeType, and storage\n resolve({\n filename,\n mimeType,\n storage: 's3',\n })\n },\n })\n\n upload.start()\n })\n}\n\nconst { log } = useErrorHandler()\n\ninterface Extra {\n pluginOptions: MediaCloudPluginOptions\n}\n\ntype ClientUploadHandlerProps<T extends Record<string, unknown>> = {\n children: ReactNode\n collectionSlug: UploadCollectionSlug\n enabled?: boolean\n extra: T\n prefix?: string\n serverHandlerPath: `/${string}`\n}\n\nexport function UploadHandler(\n props: ClientUploadHandlerProps<{ pluginOptions: MediaCloudPluginOptions }>\n) {\n return createClientUploadHandler({\n handler: async function (args) {\n const { serverURL, apiRoute, file, prefix, updateFilename, extra } = args\n const { pluginOptions } = extra as unknown as Extra\n\n // Check mime type\n const mimeType = await getMimeType(file)\n\n magicError.assert(mimeType, MediaCloudErrors.FILE_TYPE_UNKNOWN)\n\n const allowedMimeTypes = pluginOptions.limits?.mimeTypes ?? []\n\n const mimeTypeMatches = allowedMimeTypes.some((allowed) =>\n allowed.endsWith('/*')\n ? mimeType?.startsWith(allowed.replace('/*', '/'))\n : mimeType === allowed\n )\n\n if (!mimeTypeMatches) {\n throwError(MediaCloudErrors.FILE_TYPE_NOT_ALLOWED)\n return null\n }\n\n // Check file size limit\n if (file.size > (pluginOptions.limits?.fileSize ?? Infinity)) {\n throwError(MediaCloudErrors.FILE_SIZE_EXCEEDED)\n return null\n }\n\n // Clone file\n let mappedFile = file\n\n try {\n // Check if file with same name exists\n const endpoint = `${serverURL}${apiRoute}/uploads`\n const response = await fetch(`${endpoint}/${file.name}/exists`)\n\n if (response?.status === 200) {\n log(MediaCloudLogs.S3_STORE_FILE_FOUND)\n }\n\n // If file exists, generate a cloned file with a unique filename\n // If not, generate a cloned file with a sanitized filename\n const newFilename =\n response?.status === 200\n ? generateUniqueFilename(file.name)\n : sanitizeFilename(file.name)\n\n mappedFile = new File([file], newFilename, {\n type: file.type,\n })\n\n await updateFilename(newFilename)\n } catch (error) {\n throwError({\n ...MediaCloudErrors.NAMING_FUNCTION_ERROR,\n cause: error,\n })\n return null\n }\n\n try {\n const uploadArgs: UploadArgs = {\n file: mappedFile,\n serverURL,\n apiRoute,\n mimeType,\n prefix,\n }\n\n // Check storage mapping for mime type\n type StorageMap = NonNullable<typeof pluginOptions.storage>\n\n const storageForMimeType =\n pluginOptions.storage &&\n Object.prototype.hasOwnProperty.call(pluginOptions.storage, mimeType)\n ? pluginOptions.storage[mimeType as keyof StorageMap]\n : undefined\n\n const isVideoFile = await isVideo(file)\n const storeOnMux =\n pluginOptions.storage?.['video/*'] === 'mux' ||\n storageForMimeType === 'mux'\n\n switch (true) {\n case storeOnMux && isVideoFile:\n return await muxUpload(uploadArgs)\n default:\n return await tusUpload(uploadArgs)\n }\n } catch (error) {\n throwError({ ...MediaCloudErrors.UPLOAD_HANDLER_ERROR, cause: error })\n return null\n }\n },\n })(props)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"uploadHandler.mjs","names":["PQueue","upchunk","tus","createClientUploadHandler","MediaCloudErrors","MediaCloudLogs","useMediaCloudEmitter","isVideo","getMimeType","generateUniqueFilename","sanitizeFilename","useMagicError","queue","MUX_CHUNK_SIZE","TUS_CHUNK_SIZE","TUS_RETRY_DELAYS","magicError","prefix","throwError","log","emitter","muxUpload","args","file","serverURL","apiRoute","mimeType","onResolve","endpoint","filename","name","response","fetch","body","JSON","stringify","credentials","method","headers","url","uploadId","json","uploader","createUpload","chunkSize","emit","polling","pollingUrl","storage","Promise","resolve","reject","on","error","MUX_UPLOAD_ERROR","cause","progress","detail","MUX_DIRECT_UPLOAD_ERROR","tusUpload","filetype","type","filesize","size","toString","uploadUrlAvailable","upload","Upload","retryDelays","storeFingerprintForResuming","metadata","contentType","contentLength","contentDisposition","onError","navigator","sendBeacon","message","TUS_UPLOAD_ERROR","onProgress","bytesUploaded","bytesTotal","percentage","Math","round","onSuccess","console","onUploadUrlAvailable","start","UploadHandler","props","handler","updateFilename","extra","pluginOptions","concurrency","limits","allowedMimeTypes","mimeTypes","assert","FILE_TYPE_UNKNOWN","mimeTypeMatches","some","allowed","endsWith","startsWith","replace","FILE_TYPE_NOT_ALLOWED","fileSize","FILE_SIZE_EXCEEDED","mappedFile","sanitizedFilename","status","S3_STORE_FILE_FOUND","S3_STORE_FILE_NOT_FOUND","newFilename","File","NAMING_FUNCTION_ERROR","uploadArgs","storageForMimeType","Object","prototype","hasOwnProperty","call","undefined","isVideoFile","storeOnMux","UPLOAD_HANDLER_ERROR","UPLOAD_QUEUE_NOT_INITIALIZED","add"],"sources":["../../../src/components/uploadHandler/uploadHandler.tsx"],"sourcesContent":["'use client'\n\nimport PQueue from 'p-queue'\n\nimport * as upchunk from '@mux/upchunk'\nimport * as tus from 'tus-js-client'\n\nimport { createClientUploadHandler } from '@payloadcms/plugin-cloud-storage/client'\n\nimport { MediaCloudErrors, MediaCloudLogs } from '../../types/errors'\nimport { useMediaCloudEmitter } from '../../hooks/useMediaCloudEmitter'\nimport {\n isVideo,\n getMimeType,\n generateUniqueFilename,\n sanitizeFilename,\n} from '../../utils/file'\n\nimport type {\n MediaCloudPluginOptions,\n Storage,\n MimeType,\n RequireAllNested,\n} from '../../types/index'\nimport type { ReactNode } from 'react'\nimport type { UploadCollectionSlug } from 'payload'\nimport { useMagicError, UseMagicErrorReturn } from '@maas/error-handler'\n\ninterface UploadResult {\n storage: Storage\n mimeType: MimeType\n filename: string\n uploadId?: string\n}\n\ninterface UploadArgs {\n serverURL: string\n apiRoute: string\n file: File\n mimeType: MimeType\n prefix?: string\n onResolve: (result: UploadResult | null) => void\n}\n\ninterface MuxCreateUploadResponse {\n url: string\n uploadId: string\n filename: string\n}\n\nlet queue: PQueue | undefined\n\nconst MUX_CHUNK_SIZE = 30720\nconst TUS_CHUNK_SIZE = 1024 * 1024\nconst TUS_RETRY_DELAYS = [0, 1000, 2000, 5000]\n\nconst magicError: UseMagicErrorReturn = useMagicError({\n prefix: 'PLUGIN-MEDIA-CLOUD',\n})\n\nconst { throwError, log } = magicError\nconst emitter = useMediaCloudEmitter()\n\n/**\n * Handles Mux video upload with progress tracking\n * @param args - The upload arguments including file, server URL, and callbacks\n * @returns Promise that resolves to upload result or null if upload fails\n */\nasync function muxUpload(args: UploadArgs): Promise<void> {\n const { file, serverURL, apiRoute, mimeType, onResolve } = args\n\n const endpoint = `${serverURL}${apiRoute}`\n const filename = file.name\n\n try {\n // Request upload URL from Mux\n const response = await fetch(`${endpoint}/mux/upload`, {\n body: JSON.stringify({ filename, mimeType }),\n credentials: 'include',\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n })\n\n const { url, uploadId } = (await response.json()) as MuxCreateUploadResponse\n\n // Create upchunk uploader\n const uploader = await upchunk.createUpload({\n endpoint: url,\n file,\n chunkSize: MUX_CHUNK_SIZE,\n })\n\n // Add upload to tracker\n emitter.emit('addUpload', {\n filename,\n uploadId,\n polling: false,\n pollingUrl: `${endpoint}/mux/asset`,\n })\n\n // Update collection entry\n await onResolve({\n storage: 'mux',\n filename,\n uploadId,\n mimeType,\n })\n\n return new Promise((resolve, reject) => {\n // Set up event handlers\n uploader.on('error', function (error) {\n emitter.emit('removeUpload', { uploadId })\n throwError({ ...MediaCloudErrors.MUX_UPLOAD_ERROR, cause: error })\n reject(error)\n })\n\n uploader.on('progress', function (progress) {\n emitter.emit('updateUpload', {\n filename,\n progress: progress.detail,\n })\n })\n\n uploader.on('success', function () {\n emitter.emit('uploadComplete', { filename })\n resolve()\n })\n })\n } catch {\n throwError(MediaCloudErrors.MUX_DIRECT_UPLOAD_ERROR)\n emitter.emit('uploadError', { filename, error: 'Video upload failed' })\n }\n}\n\n/**\n * Handles TUS file upload with resumable capabilities\n * @param args - The upload arguments including file, server URL, and callbacks\n * @returns Promise that resolves to upload result or null if upload fails\n */\nasync function tusUpload(args: UploadArgs): Promise<void> {\n const { apiRoute, serverURL, file, prefix = '', mimeType, onResolve } = args\n\n const filename = file.name\n const filetype = file.type\n const filesize = file.size.toString()\n\n const endpoint = `${serverURL}${apiRoute}/uploads`\n\n // Flag to prevent multiple onUploadUrlAvailable calls\n let uploadUrlAvailable = false\n\n return new Promise((resolve, reject) => {\n const upload = new tus.Upload(file, {\n endpoint,\n retryDelays: TUS_RETRY_DELAYS,\n chunkSize: TUS_CHUNK_SIZE,\n storeFingerprintForResuming: false,\n metadata: {\n filetype,\n filesize,\n filename,\n prefix,\n contentType: filetype,\n contentLength: filesize,\n contentDisposition: 'inline',\n },\n onError(error) {\n // Clean up\n navigator.sendBeacon(\n `${endpoint}/cleanup`,\n JSON.stringify({ filename })\n )\n\n // Inform user\n emitter.emit('uploadError', { filename, error: error.message })\n emitter.emit('removeUpload', { filename })\n throwError({ ...MediaCloudErrors.TUS_UPLOAD_ERROR, cause: error })\n reject(error)\n },\n onProgress: function (bytesUploaded, bytesTotal) {\n const percentage = Math.round((bytesUploaded / bytesTotal) * 100)\n emitter.emit('updateUpload', {\n filename,\n progress: percentage,\n })\n },\n async onSuccess() {\n try {\n // Mark upload as complete in UI\n emitter.emit('uploadComplete', { filename })\n\n // Trigger post upload processing\n await fetch(`${endpoint}/${filename}/process`)\n\n // Move file to correct folder\n await fetch(`${endpoint}/${filename}/folder`)\n } catch (error) {\n console.error(error)\n } finally {\n resolve()\n }\n },\n onUploadUrlAvailable: async function () {\n try {\n // Prevent multiple callbacks\n if (uploadUrlAvailable) {\n return\n }\n\n // Update flag\n uploadUrlAvailable = true\n\n // Add upload to UI\n emitter.emit('addUpload', { filename })\n\n // Update collection entry\n onResolve({\n filename,\n mimeType,\n storage: 's3',\n })\n } catch (error) {\n // Handled elsewhere\n console.error(error)\n }\n },\n })\n\n upload.start()\n })\n}\n\ninterface Extra {\n pluginOptions: RequireAllNested<MediaCloudPluginOptions>\n}\n\ntype ClientUploadHandlerProps<T extends Record<string, unknown>> = {\n children: ReactNode\n collectionSlug: UploadCollectionSlug\n enabled?: boolean\n extra: T\n prefix?: string\n serverHandlerPath: `/${string}`\n}\n\nexport function UploadHandler(\n props: ClientUploadHandlerProps<{ pluginOptions: MediaCloudPluginOptions }>\n) {\n return createClientUploadHandler({\n handler: async function (args) {\n const { serverURL, apiRoute, file, prefix, updateFilename, extra } = args\n const { pluginOptions } = extra as unknown as Extra\n\n // Initialize upload queue\n if (!queue) {\n queue = new PQueue({\n concurrency: pluginOptions.limits.concurrency,\n })\n }\n\n // Update concurrency\n if (queue && queue.concurrency !== pluginOptions.limits.concurrency) {\n queue.concurrency = pluginOptions.limits.concurrency\n }\n\n async function upload(onResolve: UploadArgs['onResolve']) {\n // Check mime type\n const mimeType = await getMimeType(file)\n const allowedMimeTypes = pluginOptions.limits?.mimeTypes ?? []\n\n magicError.assert(mimeType, MediaCloudErrors.FILE_TYPE_UNKNOWN)\n\n const mimeTypeMatches = allowedMimeTypes.some((allowed) =>\n allowed.endsWith('/*')\n ? mimeType?.startsWith(allowed.replace('/*', '/'))\n : mimeType === allowed\n )\n\n if (!mimeTypeMatches) {\n throwError(MediaCloudErrors.FILE_TYPE_NOT_ALLOWED)\n onResolve(null)\n return\n }\n\n // Check file size limit\n if (file.size > pluginOptions.limits.fileSize) {\n throwError(MediaCloudErrors.FILE_SIZE_EXCEEDED)\n onResolve(null)\n return\n }\n\n // Clone file\n let mappedFile = file\n\n try {\n // Check if file with same name exists\n const sanitizedFilename = sanitizeFilename(file.name)\n const endpoint = `${serverURL}${apiRoute}/uploads`\n const response = await fetch(\n `${endpoint}/${sanitizedFilename}/exists`\n )\n\n switch (response?.status) {\n case 200:\n log(MediaCloudLogs.S3_STORE_FILE_FOUND)\n break\n case 204:\n log(MediaCloudLogs.S3_STORE_FILE_NOT_FOUND)\n break\n }\n\n // If file exists, generate a cloned file with a unique filename\n // If not, generate a cloned file with a sanitized filename\n const newFilename =\n response?.status === 200\n ? generateUniqueFilename(sanitizedFilename)\n : sanitizedFilename\n\n mappedFile = new File([file], newFilename, {\n type: file.type,\n })\n\n await updateFilename(newFilename)\n } catch (error) {\n throwError({\n ...MediaCloudErrors.NAMING_FUNCTION_ERROR,\n cause: error,\n })\n onResolve(null)\n return\n }\n\n try {\n const uploadArgs: UploadArgs = {\n file: mappedFile,\n serverURL,\n apiRoute,\n mimeType,\n prefix,\n onResolve,\n }\n\n // Check storage mapping for mime type\n type StorageMap = NonNullable<typeof pluginOptions.storage>\n\n const storageForMimeType =\n pluginOptions.storage &&\n Object.prototype.hasOwnProperty.call(\n pluginOptions.storage,\n mimeType\n )\n ? pluginOptions.storage[mimeType as keyof StorageMap]\n : undefined\n\n const isVideoFile = await isVideo(file)\n const storeOnMux =\n pluginOptions.storage?.['video/*'] === 'mux' ||\n storageForMimeType === 'mux'\n\n switch (true) {\n case storeOnMux && isVideoFile:\n return await muxUpload(uploadArgs)\n default:\n return await tusUpload(uploadArgs)\n }\n } catch (error) {\n throwError({\n ...MediaCloudErrors.UPLOAD_HANDLER_ERROR,\n cause: error,\n })\n\n onResolve(null)\n }\n }\n\n return new Promise((resolve) => {\n magicError.assert(queue, MediaCloudErrors.UPLOAD_QUEUE_NOT_INITIALIZED)\n queue.add(() => upload(resolve))\n })\n },\n })(props)\n}\n"],"mappings":"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"}
@@ -409,7 +409,7 @@ function _temp0() {
409
409
  function _temp9(upload_18) {
410
410
  return upload_18.polling;
411
411
  }
412
- function _temp8(upload_17) {
412
+ function _temp8(upload_17, index) {
413
413
  return /* @__PURE__ */ jsxs("li", {
414
414
  "data-status": upload_17.status,
415
415
  children: [/* @__PURE__ */ jsxs("div", {
@@ -429,7 +429,7 @@ function _temp8(upload_17) {
429
429
  className: "upload-progress"
430
430
  })
431
431
  })]
432
- }, upload_17.filename);
432
+ }, `${upload_17.filename}-${index}`);
433
433
  }
434
434
  function _temp7(upload_16) {
435
435
  return upload_16.status === "completed";
@@ -1 +1 @@
1
- {"version":3,"file":"uploadManager.mjs","names":["c","_c","createContext","use","useState","useCallback","useEffect","useRef","Button","useMediaCloudEmitter","useErrorHandler","MediaCloudErrors","jsx","_jsx","jsxs","_jsxs","UploadManagerContext","showUploadManager","activeUploads","addUpload","updateUpload","UploadManagerProvider","args","$","children","setShowUploadManager","t0","Symbol","for","setActiveUploads","activeTab","setActiveTab","emitter","activeTabRef","activeUploadsRef","logError","t1","t2","current","t3","t4","t5","uploads","hasActiveUploads","some","_temp","hasProcessingUploads","_temp2","hasCompletedUploads","_temp3","checkAutoSwitchToCompleted","t6","t7","pollingUploads","filter","_temp4","length","pollAssets","pollingUpload","response","fetch","pollingUrl","uploadId","method","credentials","ok","data","json","ready","prev","updatedUploads","map","upload_3","upload","polling","progress","status","setTimeout","t8","UPLOAD_POLLING_ERROR","message","intervalId","setInterval","clearInterval","event","filename","error","TUS_UPLOAD_ERROR","prev_0","upload_4","onUploadError","t9","event_0","upload_5","prev_1","onAddUpload","t10","event_1","filename_0","prev_2","upload_6","undefined","onUpdateUpload","t11","event_2","prev_3","upload_7","onRemoveUpload","t12","event_3","upload_9","find","upload_8","prev_4","upload_10","prev_5","updatedUploads_0","upload_11","onUploadComplete","t13","t14","on","off","t15","args_0","filename_1","t16","polling_0","upload_12","prev_6","args_1","filename_2","progress_0","polling_1","prev_7","upload_13","T0","t17","t18","uploadingFiles","_temp5","processingFiles","_temp6","completedFiles","_temp7","t19","renderUploadList","args_2","uploads_0","_temp8","t20","closeUploadManager","hasPollingUploads","_temp9","t21","value","Provider","className","buttonStyle","icon","margin","onClick","size","_temp0","window","location","reload","upload_18","upload_17","Math","ceil","style","upload_16","upload_15","upload_14","upload_2","upload_1","upload_0","useUploadManagerContext"],"sources":["../../../src/components/uploadManager/uploadManager.tsx"],"sourcesContent":["'use client'\n\nimport {\n createContext,\n use,\n useState,\n useCallback,\n useEffect,\n useRef,\n} from 'react'\nimport { Button } from '@payloadcms/ui'\n\nimport { useMediaCloudEmitter } from '../../hooks/useMediaCloudEmitter'\nimport { useErrorHandler } from '../../hooks/useErrorHandler'\nimport { MediaCloudErrors } from '../../types/errors'\n\nimport type { MediaCloudEmitterEvents } from '../../types'\nimport type React from 'react'\n\nimport './uploadManager.css'\n\ninterface Upload {\n filename: string\n progress: number\n uploadId?: string\n error?: string\n polling?: boolean\n pollingUrl?: string\n status?: 'uploading' | 'processing' | 'completed'\n}\n\ninterface UploadManagerContextType {\n showUploadManager?: boolean\n activeUploads: Upload[]\n addUpload: (args: MediaCloudEmitterEvents['addUpload']) => void\n updateUpload: (args: MediaCloudEmitterEvents['updateUpload']) => void\n}\n\ninterface UploadManagerProviderArgs {\n children: React.ReactNode\n}\n\ninterface RenderUploadListArgs {\n uploads: Upload[]\n}\n\nconst UploadManagerContext = createContext<UploadManagerContextType>({\n showUploadManager: false,\n activeUploads: [],\n addUpload: () => {},\n updateUpload: () => {},\n})\n\n/**\n * Provider component for upload management context\n * @param args - Arguments including children to wrap\n * @returns JSX element providing upload management context\n */\nexport function UploadManagerProvider(args: UploadManagerProviderArgs) {\n const { children } = args\n const [showUploadManager, setShowUploadManager] = useState(false)\n const [activeUploads, setActiveUploads] = useState<Upload[]>([])\n const [activeTab, setActiveTab] = useState<\n 'uploading' | 'processing' | 'completed'\n >('uploading')\n\n const emitter = useMediaCloudEmitter()\n const activeTabRef = useRef(activeTab)\n const activeUploadsRef = useRef(activeUploads)\n\n const { logError } = useErrorHandler()\n\n // Keep refs in sync with state\n useEffect(() => {\n activeTabRef.current = activeTab\n }, [activeTab])\n\n useEffect(() => {\n activeUploadsRef.current = activeUploads\n }, [activeUploads])\n\n // Helper function to check if we should auto-switch to completed tab\n const checkAutoSwitchToCompleted = useCallback((uploads: Upload[]) => {\n const hasActiveUploads = uploads.some(\n (upload) => upload.status === 'uploading'\n )\n const hasProcessingUploads = uploads.some(\n (upload) => upload.status === 'processing'\n )\n const hasCompletedUploads = uploads.some(\n (upload) => upload.status === 'completed'\n )\n\n // Auto-switch to completed tab if no uploading/processing uploads remain\n if (\n !hasActiveUploads &&\n !hasProcessingUploads &&\n hasCompletedUploads &&\n activeTabRef.current !== 'completed'\n ) {\n setActiveTab('completed')\n }\n }, [])\n\n // Polling logic\n useEffect(() => {\n const pollingUploads = activeUploads.filter(\n (upload) => upload.polling && upload.pollingUrl\n )\n\n if (pollingUploads.length === 0) {\n return\n }\n\n const pollAssets = async () => {\n for (const pollingUpload of pollingUploads) {\n try {\n const response = await fetch(\n `${pollingUpload.pollingUrl}?upload_id=${pollingUpload.uploadId}`,\n {\n method: 'GET',\n credentials: 'include',\n }\n )\n\n if (response.ok) {\n const data = await response.json()\n\n if (data.ready) {\n // Asset is ready, stop polling for this upload\n setActiveUploads((prev) => {\n const updatedUploads = prev.map((upload) =>\n upload.uploadId === pollingUpload.uploadId\n ? {\n ...upload,\n polling: false,\n progress: 100,\n status: 'completed' as const,\n }\n : upload\n )\n\n // Check if we should auto-switch to completed tab\n setTimeout(() => checkAutoSwitchToCompleted(updatedUploads), 0)\n\n return updatedUploads\n })\n }\n }\n } catch (_error) {\n logError(MediaCloudErrors.UPLOAD_POLLING_ERROR.message)\n }\n }\n }\n\n const intervalId = setInterval(pollAssets, 2000) // Poll every 2 seconds\n\n return () => clearInterval(intervalId)\n }, [activeUploads, checkAutoSwitchToCompleted, logError])\n\n /**\n * Handles the 'uploadError' event\n * @param event - The upload error event\n */\n const onUploadError = useCallback(\n (event: MediaCloudEmitterEvents['uploadError']) => {\n const { filename, error } = event\n\n logError(MediaCloudErrors.TUS_UPLOAD_ERROR.message)\n\n setActiveUploads((prev) =>\n prev.map((upload) =>\n upload.filename === filename\n ? { ...upload, error: error, status: 'completed' }\n : upload\n )\n )\n },\n [logError]\n )\n\n /**\n * Handles the 'addUpload' event\n * @param event - The add upload event\n */\n const onAddUpload = useCallback(\n (event: MediaCloudEmitterEvents['addUpload']) => {\n const upload: Upload = {\n filename: event.filename,\n uploadId: event.uploadId,\n progress: 0,\n polling: event.polling,\n pollingUrl: event.pollingUrl,\n status: 'uploading',\n }\n\n setActiveUploads((prev) => [...prev, upload])\n\n // Show the upload manager when new upload starts\n setShowUploadManager(true)\n\n // Auto-switch to uploading tab when new upload starts\n if (activeTabRef.current !== 'uploading') {\n setActiveTab('uploading')\n }\n },\n []\n )\n\n /**\n * Handles the 'updateUpload' event\n * @param event - The update upload event\n */\n const onUpdateUpload = useCallback(\n (event: MediaCloudEmitterEvents['updateUpload']) => {\n const { filename, progress, polling } = event\n setActiveUploads((prev) =>\n prev.map((upload) =>\n upload.filename === filename\n ? {\n ...upload,\n progress,\n ...(polling !== undefined && { polling }),\n status: polling\n ? 'processing'\n : progress >= 100\n ? 'completed'\n : 'uploading',\n }\n : upload\n )\n )\n },\n []\n )\n\n /**\n * Handles the 'removeUpload' event\n * @param event - The remove upload event\n */\n const onRemoveUpload = useCallback(\n (event: MediaCloudEmitterEvents['removeUpload']) => {\n setActiveUploads((prev) =>\n prev.filter((upload) => upload.filename !== event.filename)\n )\n },\n []\n )\n\n /**\n * Handles the 'uploadComplete' event\n * @param event - The upload completed event\n */\n const onUploadComplete = useCallback(\n (event: MediaCloudEmitterEvents['uploadComplete']) => {\n // Check if this upload has a polling URL (Mux upload)\n const upload = activeUploadsRef.current.find(\n (upload) => upload.filename === event.filename\n )\n if (upload?.pollingUrl) {\n setActiveUploads((prev) =>\n prev.map((upload) =>\n upload.filename === event.filename\n ? {\n ...upload,\n polling: true,\n progress: 100,\n status: 'processing' as const,\n }\n : upload\n )\n )\n } else {\n // Regular upload completion\n setActiveUploads((prev) => {\n const updatedUploads = prev.map((upload) =>\n upload.filename === event.filename\n ? { ...upload, progress: 100, status: 'completed' as const }\n : upload\n )\n\n // Check if we should auto-switch to completed tab\n setTimeout(() => checkAutoSwitchToCompleted(updatedUploads), 0)\n\n return updatedUploads\n })\n }\n },\n [checkAutoSwitchToCompleted]\n )\n\n useEffect(() => {\n emitter.on('addUpload', onAddUpload)\n emitter.on('updateUpload', onUpdateUpload)\n emitter.on('removeUpload', onRemoveUpload)\n emitter.on('uploadError', onUploadError)\n emitter.on('uploadComplete', onUploadComplete)\n\n return () => {\n emitter.off('addUpload', onAddUpload)\n emitter.off('updateUpload', onUpdateUpload)\n emitter.off('removeUpload', onRemoveUpload)\n emitter.off('uploadError', onUploadError)\n emitter.off('uploadComplete', onUploadComplete)\n }\n }, [\n emitter,\n onAddUpload,\n onUpdateUpload,\n onRemoveUpload,\n onUploadError,\n onUploadComplete,\n ])\n\n /**\n * Adds a new upload to the manager\n * @param args - The upload arguments\n */\n const addUpload = useCallback(\n (args: MediaCloudEmitterEvents['addUpload']) => {\n const { filename, polling = false, pollingUrl } = args\n const upload: Upload = {\n filename,\n progress: 0,\n polling,\n pollingUrl,\n status: 'uploading',\n }\n\n setActiveUploads((prev) => [...prev, upload])\n },\n []\n )\n\n /**\n * Updates an existing upload in the manager\n * @param args - The update arguments\n */\n const updateUpload = useCallback(\n (args: MediaCloudEmitterEvents['updateUpload']) => {\n const { filename, progress, polling } = args\n setActiveUploads((prev) =>\n prev.map((upload) =>\n upload.filename === filename\n ? {\n ...upload,\n progress,\n ...(polling !== undefined && { polling }),\n status: polling\n ? 'processing'\n : progress >= 100\n ? 'completed'\n : 'uploading',\n }\n : upload\n )\n )\n },\n []\n )\n\n // Filter uploads by status\n const uploadingFiles = activeUploads.filter(\n (upload) => upload.status === 'uploading'\n )\n const processingFiles = activeUploads.filter(\n (upload) => upload.status === 'processing'\n )\n const completedFiles = activeUploads.filter(\n (upload) => upload.status === 'completed'\n )\n\n /**\n * Renders the upload list\n * @param args - The render arguments\n * @returns JSX element representing the upload list\n */\n function renderUploadList(args: RenderUploadListArgs) {\n const { uploads } = args\n return (\n <ul>\n {uploads.map((upload) => (\n <li key={upload.filename} data-status={upload.status}>\n <div className=\"upload-info\">\n <span className=\"upload-filename\">{upload.filename}</span>\n <span className=\"upload-meta\">\n {upload.status === 'processing'\n ? 'Processing...'\n : upload.progress < 100\n ? `${Math.ceil(upload.progress)}%`\n : 'Completed'}\n </span>\n </div>\n <div\n className=\"upload-progress-bar\"\n style={\n {\n ['--progress']:\n upload.status === 'processing'\n ? '1'\n : `${upload.progress / 100}`,\n } as React.CSSProperties\n }\n >\n <div\n data-active={upload.status === 'processing'}\n className=\"upload-progress\"\n />\n </div>\n </li>\n ))}\n </ul>\n )\n }\n\n /**\n * Closes the upload manager\n */\n function closeUploadManager() {\n // Only allow closing if no uploads are actively polling\n const hasPollingUploads = activeUploads.some((upload) => upload.polling)\n if (!hasPollingUploads) {\n setActiveUploads([])\n setShowUploadManager(false)\n }\n }\n\n const value: UploadManagerContextType = {\n activeUploads,\n addUpload,\n updateUpload,\n }\n\n return (\n <UploadManagerContext.Provider value={value}>\n {showUploadManager && (\n <div className=\"upload-manager\">\n <div className=\"upload-manager__header\">\n <h4>Uploads</h4>\n <Button\n buttonStyle=\"icon-label\"\n icon=\"x\"\n margin={false}\n onClick={closeUploadManager}\n />\n </div>\n\n <div className=\"upload-manager__tabs\">\n <button\n data-active={activeTab === 'uploading'}\n className=\"upload-tab\"\n onClick={() => setActiveTab('uploading')}\n >\n Uploading ({uploadingFiles.length})\n </button>\n <button\n data-active={activeTab === 'processing'}\n className=\"upload-tab\"\n onClick={() => setActiveTab('processing')}\n >\n Processing ({processingFiles.length})\n </button>\n <button\n data-active={activeTab === 'completed'}\n className=\"upload-tab\"\n onClick={() => setActiveTab('completed')}\n >\n Completed ({completedFiles.length})\n </button>\n </div>\n\n <div className=\"upload-manager__content\">\n {activeTab === 'uploading' && uploadingFiles.length > 0 && (\n <div>{renderUploadList({ uploads: uploadingFiles })}</div>\n )}\n {activeTab === 'processing' && processingFiles.length > 0 && (\n <div>{renderUploadList({ uploads: processingFiles })}</div>\n )}\n {activeTab === 'completed' && completedFiles.length > 0 && (\n <div>\n {renderUploadList({ uploads: completedFiles })}\n <div className=\"upload-manager__footer\">\n <Button\n buttonStyle=\"subtle\"\n size=\"small\"\n margin={false}\n onClick={() => window?.location?.reload()}\n >\n Refresh\n </Button>\n </div>\n </div>\n )}\n {((activeTab === 'uploading' && uploadingFiles.length === 0) ||\n (activeTab === 'processing' && processingFiles.length === 0) ||\n (activeTab === 'completed' && completedFiles.length === 0)) && (\n <p className=\"upload-empty-state\">No {activeTab} files</p>\n )}\n </div>\n </div>\n )}\n {children}\n </UploadManagerContext.Provider>\n )\n}\n\nexport const useUploadManagerContext = () => use(UploadManagerContext)\n"],"mappings":"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"}
1
+ {"version":3,"file":"uploadManager.mjs","names":["c","_c","createContext","use","useState","useCallback","useEffect","useRef","Button","useMediaCloudEmitter","useErrorHandler","MediaCloudErrors","jsx","_jsx","jsxs","_jsxs","UploadManagerContext","showUploadManager","activeUploads","addUpload","updateUpload","UploadManagerProvider","args","$","children","setShowUploadManager","t0","Symbol","for","setActiveUploads","activeTab","setActiveTab","emitter","activeTabRef","activeUploadsRef","logError","t1","t2","current","t3","t4","t5","uploads","hasActiveUploads","some","_temp","hasProcessingUploads","_temp2","hasCompletedUploads","_temp3","checkAutoSwitchToCompleted","t6","t7","pollingUploads","filter","_temp4","length","pollAssets","pollingUpload","response","fetch","pollingUrl","uploadId","method","credentials","ok","data","json","ready","prev","updatedUploads","map","upload_3","upload","polling","progress","status","setTimeout","t8","UPLOAD_POLLING_ERROR","message","intervalId","setInterval","clearInterval","event","filename","error","TUS_UPLOAD_ERROR","prev_0","upload_4","onUploadError","t9","event_0","upload_5","prev_1","onAddUpload","t10","event_1","filename_0","prev_2","upload_6","undefined","onUpdateUpload","t11","event_2","prev_3","upload_7","onRemoveUpload","t12","event_3","upload_9","find","upload_8","prev_4","upload_10","prev_5","updatedUploads_0","upload_11","onUploadComplete","t13","t14","on","off","t15","args_0","filename_1","t16","polling_0","upload_12","prev_6","args_1","filename_2","progress_0","polling_1","prev_7","upload_13","T0","t17","t18","uploadingFiles","_temp5","processingFiles","_temp6","completedFiles","_temp7","t19","renderUploadList","args_2","uploads_0","_temp8","t20","closeUploadManager","hasPollingUploads","_temp9","t21","value","Provider","className","buttonStyle","icon","margin","onClick","size","_temp0","window","location","reload","upload_18","upload_17","index","Math","ceil","style","upload_16","upload_15","upload_14","upload_2","upload_1","upload_0","useUploadManagerContext"],"sources":["../../../src/components/uploadManager/uploadManager.tsx"],"sourcesContent":["'use client'\n\nimport {\n createContext,\n use,\n useState,\n useCallback,\n useEffect,\n useRef,\n} from 'react'\nimport { Button } from '@payloadcms/ui'\n\nimport { useMediaCloudEmitter } from '../../hooks/useMediaCloudEmitter'\nimport { useErrorHandler } from '../../hooks/useErrorHandler'\nimport { MediaCloudErrors } from '../../types/errors'\n\nimport type { MediaCloudEmitterEvents } from '../../types'\nimport type React from 'react'\n\nimport './uploadManager.css'\n\ninterface Upload {\n filename: string\n progress: number\n uploadId?: string\n error?: string\n polling?: boolean\n pollingUrl?: string\n status?: 'uploading' | 'processing' | 'completed'\n}\n\ninterface UploadManagerContextType {\n showUploadManager?: boolean\n activeUploads: Upload[]\n addUpload: (args: MediaCloudEmitterEvents['addUpload']) => void\n updateUpload: (args: MediaCloudEmitterEvents['updateUpload']) => void\n}\n\ninterface UploadManagerProviderArgs {\n children: React.ReactNode\n}\n\ninterface RenderUploadListArgs {\n uploads: Upload[]\n}\n\nconst UploadManagerContext = createContext<UploadManagerContextType>({\n showUploadManager: false,\n activeUploads: [],\n addUpload: () => {},\n updateUpload: () => {},\n})\n\n/**\n * Provider component for upload management context\n * @param args - Arguments including children to wrap\n * @returns JSX element providing upload management context\n */\nexport function UploadManagerProvider(args: UploadManagerProviderArgs) {\n const { children } = args\n const [showUploadManager, setShowUploadManager] = useState(false)\n const [activeUploads, setActiveUploads] = useState<Upload[]>([])\n const [activeTab, setActiveTab] = useState<\n 'uploading' | 'processing' | 'completed'\n >('uploading')\n\n const emitter = useMediaCloudEmitter()\n const activeTabRef = useRef(activeTab)\n const activeUploadsRef = useRef(activeUploads)\n\n const { logError } = useErrorHandler()\n\n // Keep refs in sync with state\n useEffect(() => {\n activeTabRef.current = activeTab\n }, [activeTab])\n\n useEffect(() => {\n activeUploadsRef.current = activeUploads\n }, [activeUploads])\n\n // Helper function to check if we should auto-switch to completed tab\n const checkAutoSwitchToCompleted = useCallback((uploads: Upload[]) => {\n const hasActiveUploads = uploads.some(\n (upload) => upload.status === 'uploading'\n )\n const hasProcessingUploads = uploads.some(\n (upload) => upload.status === 'processing'\n )\n const hasCompletedUploads = uploads.some(\n (upload) => upload.status === 'completed'\n )\n\n // Auto-switch to completed tab if no uploading/processing uploads remain\n if (\n !hasActiveUploads &&\n !hasProcessingUploads &&\n hasCompletedUploads &&\n activeTabRef.current !== 'completed'\n ) {\n setActiveTab('completed')\n }\n }, [])\n\n // Polling logic\n useEffect(() => {\n const pollingUploads = activeUploads.filter(\n (upload) => upload.polling && upload.pollingUrl\n )\n\n if (pollingUploads.length === 0) {\n return\n }\n\n const pollAssets = async () => {\n for (const pollingUpload of pollingUploads) {\n try {\n const response = await fetch(\n `${pollingUpload.pollingUrl}?upload_id=${pollingUpload.uploadId}`,\n {\n method: 'GET',\n credentials: 'include',\n }\n )\n\n if (response.ok) {\n const data = await response.json()\n\n if (data.ready) {\n // Asset is ready, stop polling for this upload\n setActiveUploads((prev) => {\n const updatedUploads = prev.map((upload) =>\n upload.uploadId === pollingUpload.uploadId\n ? {\n ...upload,\n polling: false,\n progress: 100,\n status: 'completed' as const,\n }\n : upload\n )\n\n // Check if we should auto-switch to completed tab\n setTimeout(() => checkAutoSwitchToCompleted(updatedUploads), 0)\n\n return updatedUploads\n })\n }\n }\n } catch (_error) {\n logError(MediaCloudErrors.UPLOAD_POLLING_ERROR.message)\n }\n }\n }\n\n const intervalId = setInterval(pollAssets, 2000) // Poll every 2 seconds\n\n return () => clearInterval(intervalId)\n }, [activeUploads, checkAutoSwitchToCompleted, logError])\n\n /**\n * Handles the 'uploadError' event\n * @param event - The upload error event\n */\n const onUploadError = useCallback(\n (event: MediaCloudEmitterEvents['uploadError']) => {\n const { filename, error } = event\n\n logError(MediaCloudErrors.TUS_UPLOAD_ERROR.message)\n\n setActiveUploads((prev) =>\n prev.map((upload) =>\n upload.filename === filename\n ? { ...upload, error: error, status: 'completed' }\n : upload\n )\n )\n },\n [logError]\n )\n\n /**\n * Handles the 'addUpload' event\n * @param event - The add upload event\n */\n const onAddUpload = useCallback(\n (event: MediaCloudEmitterEvents['addUpload']) => {\n const upload: Upload = {\n filename: event.filename,\n uploadId: event.uploadId,\n progress: 0,\n polling: event.polling,\n pollingUrl: event.pollingUrl,\n status: 'uploading',\n }\n\n setActiveUploads((prev) => [...prev, upload])\n\n // Show the upload manager when new upload starts\n setShowUploadManager(true)\n\n // Auto-switch to uploading tab when new upload starts\n if (activeTabRef.current !== 'uploading') {\n setActiveTab('uploading')\n }\n },\n []\n )\n\n /**\n * Handles the 'updateUpload' event\n * @param event - The update upload event\n */\n const onUpdateUpload = useCallback(\n (event: MediaCloudEmitterEvents['updateUpload']) => {\n const { filename, progress, polling } = event\n setActiveUploads((prev) =>\n prev.map((upload) =>\n upload.filename === filename\n ? {\n ...upload,\n progress,\n ...(polling !== undefined && { polling }),\n status: polling\n ? 'processing'\n : progress >= 100\n ? 'completed'\n : 'uploading',\n }\n : upload\n )\n )\n },\n []\n )\n\n /**\n * Handles the 'removeUpload' event\n * @param event - The remove upload event\n */\n const onRemoveUpload = useCallback(\n (event: MediaCloudEmitterEvents['removeUpload']) => {\n setActiveUploads((prev) =>\n prev.filter((upload) => upload.filename !== event.filename)\n )\n },\n []\n )\n\n /**\n * Handles the 'uploadComplete' event\n * @param event - The upload completed event\n */\n const onUploadComplete = useCallback(\n (event: MediaCloudEmitterEvents['uploadComplete']) => {\n // Check if this upload has a polling URL (Mux upload)\n const upload = activeUploadsRef.current.find(\n (upload) => upload.filename === event.filename\n )\n if (upload?.pollingUrl) {\n setActiveUploads((prev) =>\n prev.map((upload) =>\n upload.filename === event.filename\n ? {\n ...upload,\n polling: true,\n progress: 100,\n status: 'processing' as const,\n }\n : upload\n )\n )\n } else {\n // Regular upload completion\n setActiveUploads((prev) => {\n const updatedUploads = prev.map((upload) =>\n upload.filename === event.filename\n ? { ...upload, progress: 100, status: 'completed' as const }\n : upload\n )\n\n // Check if we should auto-switch to completed tab\n setTimeout(() => checkAutoSwitchToCompleted(updatedUploads), 0)\n\n return updatedUploads\n })\n }\n },\n [checkAutoSwitchToCompleted]\n )\n\n useEffect(() => {\n emitter.on('addUpload', onAddUpload)\n emitter.on('updateUpload', onUpdateUpload)\n emitter.on('removeUpload', onRemoveUpload)\n emitter.on('uploadError', onUploadError)\n emitter.on('uploadComplete', onUploadComplete)\n\n return () => {\n emitter.off('addUpload', onAddUpload)\n emitter.off('updateUpload', onUpdateUpload)\n emitter.off('removeUpload', onRemoveUpload)\n emitter.off('uploadError', onUploadError)\n emitter.off('uploadComplete', onUploadComplete)\n }\n }, [\n emitter,\n onAddUpload,\n onUpdateUpload,\n onRemoveUpload,\n onUploadError,\n onUploadComplete,\n ])\n\n /**\n * Adds a new upload to the manager\n * @param args - The upload arguments\n */\n const addUpload = useCallback(\n (args: MediaCloudEmitterEvents['addUpload']) => {\n const { filename, polling = false, pollingUrl } = args\n const upload: Upload = {\n filename,\n progress: 0,\n polling,\n pollingUrl,\n status: 'uploading',\n }\n\n setActiveUploads((prev) => [...prev, upload])\n },\n []\n )\n\n /**\n * Updates an existing upload in the manager\n * @param args - The update arguments\n */\n const updateUpload = useCallback(\n (args: MediaCloudEmitterEvents['updateUpload']) => {\n const { filename, progress, polling } = args\n setActiveUploads((prev) =>\n prev.map((upload) =>\n upload.filename === filename\n ? {\n ...upload,\n progress,\n ...(polling !== undefined && { polling }),\n status: polling\n ? 'processing'\n : progress >= 100\n ? 'completed'\n : 'uploading',\n }\n : upload\n )\n )\n },\n []\n )\n\n // Filter uploads by status\n const uploadingFiles = activeUploads.filter(\n (upload) => upload.status === 'uploading'\n )\n const processingFiles = activeUploads.filter(\n (upload) => upload.status === 'processing'\n )\n const completedFiles = activeUploads.filter(\n (upload) => upload.status === 'completed'\n )\n\n /**\n * Renders the upload list\n * @param args - The render arguments\n * @returns JSX element representing the upload list\n */\n function renderUploadList(args: RenderUploadListArgs) {\n const { uploads } = args\n return (\n <ul>\n {uploads.map((upload, index) => (\n <li key={`${upload.filename}-${index}`} data-status={upload.status}>\n <div className=\"upload-info\">\n <span className=\"upload-filename\">{upload.filename}</span>\n <span className=\"upload-meta\">\n {upload.status === 'processing'\n ? 'Processing...'\n : upload.progress < 100\n ? `${Math.ceil(upload.progress)}%`\n : 'Completed'}\n </span>\n </div>\n <div\n className=\"upload-progress-bar\"\n style={\n {\n ['--progress']:\n upload.status === 'processing'\n ? '1'\n : `${upload.progress / 100}`,\n } as React.CSSProperties\n }\n >\n <div\n data-active={upload.status === 'processing'}\n className=\"upload-progress\"\n />\n </div>\n </li>\n ))}\n </ul>\n )\n }\n\n /**\n * Closes the upload manager\n */\n function closeUploadManager() {\n // Only allow closing if no uploads are actively polling\n const hasPollingUploads = activeUploads.some((upload) => upload.polling)\n if (!hasPollingUploads) {\n setActiveUploads([])\n setShowUploadManager(false)\n }\n }\n\n const value: UploadManagerContextType = {\n activeUploads,\n addUpload,\n updateUpload,\n }\n\n return (\n <UploadManagerContext.Provider value={value}>\n {showUploadManager && (\n <div className=\"upload-manager\">\n <div className=\"upload-manager__header\">\n <h4>Uploads</h4>\n <Button\n buttonStyle=\"icon-label\"\n icon=\"x\"\n margin={false}\n onClick={closeUploadManager}\n />\n </div>\n\n <div className=\"upload-manager__tabs\">\n <button\n data-active={activeTab === 'uploading'}\n className=\"upload-tab\"\n onClick={() => setActiveTab('uploading')}\n >\n Uploading ({uploadingFiles.length})\n </button>\n <button\n data-active={activeTab === 'processing'}\n className=\"upload-tab\"\n onClick={() => setActiveTab('processing')}\n >\n Processing ({processingFiles.length})\n </button>\n <button\n data-active={activeTab === 'completed'}\n className=\"upload-tab\"\n onClick={() => setActiveTab('completed')}\n >\n Completed ({completedFiles.length})\n </button>\n </div>\n\n <div className=\"upload-manager__content\">\n {activeTab === 'uploading' && uploadingFiles.length > 0 && (\n <div>{renderUploadList({ uploads: uploadingFiles })}</div>\n )}\n {activeTab === 'processing' && processingFiles.length > 0 && (\n <div>{renderUploadList({ uploads: processingFiles })}</div>\n )}\n {activeTab === 'completed' && completedFiles.length > 0 && (\n <div>\n {renderUploadList({ uploads: completedFiles })}\n <div className=\"upload-manager__footer\">\n <Button\n buttonStyle=\"subtle\"\n size=\"small\"\n margin={false}\n onClick={() => window?.location?.reload()}\n >\n Refresh\n </Button>\n </div>\n </div>\n )}\n {((activeTab === 'uploading' && uploadingFiles.length === 0) ||\n (activeTab === 'processing' && processingFiles.length === 0) ||\n (activeTab === 'completed' && completedFiles.length === 0)) && (\n <p className=\"upload-empty-state\">No {activeTab} files</p>\n )}\n </div>\n </div>\n )}\n {children}\n </UploadManagerContext.Provider>\n )\n}\n\nexport const useUploadManagerContext = () => use(UploadManagerContext)\n"],"mappings":";;;;;;;;;;;;AA8CA,MAAMgB,uBAAuBd,8BAAwC;CACnEe,mBAAmB;CACnBC,eAAe,EAAE;CACjBC,iBAAiB;CACjBC,oBAAoB;CACrB,CAAC;;;;;;AAOF,SAAOC,sBAAAC,MAAA;CAAA,MAAAC,IAAAtB,EAAA,GAAA;CACL,MAAA,EAAAuB,aAAqBF;CACrB,MAAA,CAAAL,mBAAAQ,wBAAkDrB,SAAS,MAAM;CAAA,IAAAsB;AAAA,KAAAH,EAAA,OAAAI,OAAAC,IAAA,4BAAA,EAAA;AACJF,OAAA,EAAE;AAAAH,IAAA,KAAAG;OAAAA,MAAAH,EAAA;CAA/D,MAAA,CAAAL,eAAAW,oBAA0CzB,SAAmBsB,GAAG;CAChE,MAAA,CAAAI,WAAAC,gBAAkC3B,SAEhC,YAAY;CAEd,MAAA4B,UAAgBvB,sBAAsB;CACtC,MAAAwB,eAAqB1B,OAAOuB,UAAU;CACtC,MAAAI,mBAAyB3B,OAAOW,cAAc;CAE9C,MAAA,EAAAiB,aAAqBzB,iBAAiB;CAAA,IAAA0B;CAAA,IAAAC;AAAA,KAAAd,EAAA,OAAAO,WAAA;AAG5BM,aAAA;AACRH,gBAAYK,UAAWR;;AACtBO,OAAA,CAACP,UAAU;AAAAP,IAAA,KAAAO;AAAAP,IAAA,KAAAa;AAAAb,IAAA,KAAAc;QAAA;AAAAD,OAAAb,EAAA;AAAAc,OAAAd,EAAA;;AAFdjB,WAAU8B,IAEPC,GAAY;CAAA,IAAAE;CAAA,IAAAC;AAAA,KAAAjB,EAAA,OAAAL,eAAA;AAELqB,aAAA;AACRL,oBAAgBI,UAAWpB;;AAC1BsB,OAAA,CAACtB,cAAc;AAAAK,IAAA,KAAAL;AAAAK,IAAA,KAAAgB;AAAAhB,IAAA,KAAAiB;QAAA;AAAAD,OAAAhB,EAAA;AAAAiB,OAAAjB,EAAA;;AAFlBjB,WAAUiC,IAEPC,GAAgB;CAAA,IAAAC;AAAA,KAAAlB,EAAA,OAAAI,OAAAC,IAAA,4BAAA,EAAA;AAG4Ba,QAAAC,YAAA;GAC7C,MAAAC,mBAAyBD,QAAOE,KAC9BC,MACD;GACD,MAAAC,uBAA6BJ,QAAOE,KAClCG,OACD;GACD,MAAAC,sBAA4BN,QAAOE,KACjCK,OACD;AAGD,OACE,CAACN,oBAAD,CACCG,wBADDE,uBAGAf,aAAYK,YAAa,YAEzBP,cAAa,YAAY;;AAE5BR,IAAA,KAAAkB;OAAAA,MAAAlB,EAAA;CApBD,MAAA2B,6BAAmCT;CAoB7B,IAAAU;CAAA,IAAAC;AAAA,KAAA7B,EAAA,OAAAL,iBAAAK,EAAA,OAAAY,UAAA;AAGIgB,aAAA;GACR,MAAAE,iBAAuBnC,cAAaoC,OAClCC,OACD;AAED,OAAIF,eAAcG,WAAY,EAAC;GAI/B,MAAAC,aAAmB,YAAA;AACjB,SAAK,MAAAC,iBAAuBL,eAC1B,KAAA;KACE,MAAAM,WAAiB,MAAMC,MACrB,GAAGF,cAAaG,WAAW,aAAcH,cAAaI,YACtD;MAAAC,QACU;MAAKC,aACA;MAEjB,CAAC;AAED,SAAIL,SAAQM,IAGV;WAFa,MAAMN,SAAQQ,MAAO,EAE1BC,MAENvC,mBAAiBwC,SAAA;OACf,MAAAC,iBAAuBD,KAAIE,KAAKC,aAC9BC,SAAMX,aAAcJ,cAAaI,WAAjC;QAAA,GAESW;QAAMC,SACA;QAAKC,UACJ;QAAGC,QACL;QAEJ,GAPVJ,SAQD;AAGDK,wBAAiB3B,2BAA2BoB,eAAe,EAAE,EAAE;AAAA,cAExDA;QACP;;aAELQ,MAAA;AAED3C,cAASxB,iBAAgBoE,qBAAqBC,QAAS;;;GAK7D,MAAAC,aAAmBC,YAAYzB,YAAY,IAAK;AAAA,gBAEnC0B,cAAcF,WAAW;;AACrC7B,OAAA;GAAClC;GAAegC;GAA4Bf;GAAS;AAAAZ,IAAA,KAAAL;AAAAK,IAAA,KAAAY;AAAAZ,IAAA,MAAA4B;AAAA5B,IAAA,MAAA6B;QAAA;AAAAD,OAAA5B,EAAA;AAAA6B,OAAA7B,EAAA;;AArDxDjB,WAAU6C,IAqDPC,GAAsD;CAAA,IAAA0B;AAAA,KAAAvD,EAAA,QAAAY,UAAA;AAOvD2C,QAAAM,UAAA;GACE,MAAA,EAAAC,UAAAC,UAA4BF;AAE5BjD,YAASxB,iBAAgB4E,iBAAiBP,QAAS;AAEnDnD,qBAAiB2D,WACfnB,OAAIE,KAAKkB,aACPhB,SAAMY,aAAcA,WAApB;IAAA,GACSZ;IAAMa;IAAAV,QAAwB;IAC7B,GAFVa,SAIJ,CAAC;;AACFlE,IAAA,MAAAY;AAAAZ,IAAA,MAAAuD;OAAAA,MAAAvD,EAAA;CAbH,MAAAmE,gBAAsBZ;CAerB,IAAAa;AAAA,KAAApE,EAAA,QAAAI,OAAAC,IAAA,4BAAA,EAAA;AAOC+D,QAAAC,YAAA;GACE,MAAAC,WAAuB;IAAAR,UACXD,QAAKC;IAASvB,UACdsB,QAAKtB;IAASa,UACd;IAACD,SACFU,QAAKV;IAAQb,YACVuB,QAAKvB;IAAWe,QACpB;IACT;AAED/C,qBAAiBiE,WAAU,CAAA,GAAIzB,QAAMI,SAAO,CAAC;AAG7ChD,wBAAqB,KAAK;AAG1B,OAAIQ,aAAYK,YAAa,YAC3BP,cAAa,YAAY;;AAE5BR,IAAA,MAAAoE;OAAAA,MAAApE,EAAA;CApBH,MAAAwE,cAAoBJ;CAsBnB,IAAAK;AAAA,KAAAzE,EAAA,QAAAI,OAAAC,IAAA,4BAAA,EAAA;AAOCoE,SAAAC,YAAA;GACE,MAAA,EAAAZ,UAAAa,YAAAvB,UAAAD,YAAwCU;AACxCvD,qBAAiBsE,WACf9B,OAAIE,KAAK6B,aACP3B,SAAMY,aAAcA,aAApB;IAAA,GAESZ;IAAME;IAAA,GAELD,YAAY2B,UAAZ,EAAA3B,SAAoC;IAAAE,QAChCF,UAAA,eAEJC,YAAY,MAAZ,cAAA;IAIA,GAXVyB,SAaJ,CAAC;;AACF7E,IAAA,MAAAyE;OAAAA,OAAAzE,EAAA;CAnBH,MAAA+E,iBAAuBN;CAqBtB,IAAAO;AAAA,KAAAhF,EAAA,QAAAI,OAAAC,IAAA,4BAAA,EAAA;AAOC2E,SAAAC,YAAA;AACE3E,qBAAiB4E,WACfpC,OAAIf,QAAQoD,aAAYjC,SAAMY,aAAcD,QAAKC,SACnD,CAAC;;AACF9D,IAAA,MAAAgF;OAAAA,OAAAhF,EAAA;CALH,MAAAoF,iBAAuBJ;CAOtB,IAAAK;AAAA,KAAArF,EAAA,QAAAI,OAAAC,IAAA,4BAAA,EAAA;AAOCgF,SAAAC,YAAA;AAKE,OAHe3E,iBAAgBI,QAAQyE,MACrCC,aAAYvC,SAAMY,aAAcD,QAAKC,SACtC,EACSxB,WACRhC,mBAAiBoF,WACf5C,OAAIE,KAAK2C,cACPzC,UAAMY,aAAcD,QAAKC,WAAzB;IAAA,GAESZ;IAAMC,SACA;IAAIC,UACH;IAAGC,QACL;IAEJ,GAPVsC,UASJ,CAAC;OAGDrF,mBAAiBsF,WAAA;IACf,MAAAC,mBAAuB/C,OAAIE,KAAK8C,cAC9B5C,UAAMY,aAAcD,QAAKC,WAAzB;KAAA,GACSZ;KAAME,UAAY;KAAGC,QAAU;KAC9B,GAFVyC,UAGD;AAGDxC,qBAAiB3B,2BAA2BoB,iBAAe,EAAE,EAAE;AAAA,WAExDA;KACP;;AAEL/C,IAAA,MAAAqF;OAAAA,OAAArF,EAAA;CAlCH,MAAA+F,mBAAyBV;CAoCxB,IAAAW;CAAA,IAAAC;AAAA,KAAAjG,EAAA,QAAAS,WAAAT,EAAA,QAAAmE,eAAA;AAES6B,cAAA;AACRvF,WAAOyF,GAAI,aAAa1B,YAAY;AACpC/D,WAAOyF,GAAI,gBAAgBnB,eAAe;AAC1CtE,WAAOyF,GAAI,gBAAgBd,eAAe;AAC1C3E,WAAOyF,GAAI,eAAe/B,cAAc;AACxC1D,WAAOyF,GAAI,kBAAkBH,iBAAiB;AAAA,gBAEvC;AACLtF,YAAO0F,IAAK,aAAa3B,YAAY;AACrC/D,YAAO0F,IAAK,gBAAgBpB,eAAe;AAC3CtE,YAAO0F,IAAK,gBAAgBf,eAAe;AAC3C3E,YAAO0F,IAAK,eAAehC,cAAc;AACzC1D,YAAO0F,IAAK,kBAAkBJ,iBAAiB;;;AAEhDE,QAAA;GACDxF;GACA+D;GACAO;GACAK;GACAjB;GACA4B;GACD;AAAA/F,IAAA,MAAAS;AAAAT,IAAA,MAAAmE;AAAAnE,IAAA,MAAAgG;AAAAhG,IAAA,MAAAiG;QAAA;AAAAD,QAAAhG,EAAA;AAAAiG,QAAAjG,EAAA;;AArBDjB,WAAUiH,KAcPC,IAOD;CAAA,IAAAG;AAAA,KAAApG,EAAA,QAAAI,OAAAC,IAAA,4BAAA,EAAA;AAOA+F,SAAAC,WAAA;GACE,MAAA,EAAAvC,UAAAwC,YAAAnD,SAAAoD,OAAAjE,eAAkDvC;GAClD,MAAA0G,YAAuB;IAAA3C,UACrBA;IAAQV,UACE;IAACD,SAHKoD,UAAAzB,SAAA,QAAAyB;IAITjE;IAAAe,QAEC;IACT;AAED/C,qBAAiBoG,WAAU,CAAA,GAAI5D,QAAMI,UAAO,CAAC;;AAC9ClD,IAAA,MAAAoG;OAAAA,OAAApG,EAAA;CAZH,MAAAJ,YAAkBwG;CAcjB,IAAAG;AAAA,KAAAvG,EAAA,QAAAI,OAAAC,IAAA,4BAAA,EAAA;AAOCkG,SAAAI,WAAA;GACE,MAAA,EAAA7C,UAAA8C,YAAAxD,UAAAyD,YAAA1D,SAAA2D,cAAwC/G;AACxCO,qBAAiByG,WACfjE,OAAIE,KAAKgE,cACP9D,UAAMY,aAAcA,aAApB;IAAA,GAESZ;IAAME,UACTA;IAAQ,GACJD,cAAY2B,UAAZ,EAAA3B,SAA2BA,WAAS;IAAAE,QAChCF,YAAA,eAEJC,cAAY,MAAZ,cAAA;IAIA,GAXV4D,UAaJ,CAAC;;AACFhH,IAAA,MAAAuG;OAAAA,OAAAvG,EAAA;CAnBH,MAAAH,eAAqB0G;CAqBpB,IAAAU;CAAA,IAAAC;CAAA,IAAAC;AAAA,KAAAnH,EAAA,QAAAO,aAAAP,EAAA,QAAAL,iBAAAK,EAAA,QAAAN,mBAAA;EAGD,MAAA0H,iBAAuBzH,cAAaoC,OAClCsF,OACD;EACD,MAAAC,kBAAwB3H,cAAaoC,OACnCwF,OACD;EACD,MAAAC,iBAAuB7H,cAAaoC,OAClC0F,OACD;EAAA,IAAAC;AAAA,MAAA1H,EAAA,QAAAI,OAAAC,IAAA,4BAAA,EAAA;AAODqH,WAAA,SAAAC,mBAAAC,QAAA;IACE,MAAA,EAAAzG,SAAA0G,cAAoB9H;AAAI,WAEtBT,oBAAA,MAAA,EAAAW,UACGkB,UAAO6B,IAAK8E,OA6BZ,EACC,CAAC;;AAER9H,KAAA,MAAA0H;QAAAA,SAAA1H,EAAA;EApCD,MAAA2H,mBAAAD;EAoCC,IAAAK;AAAA,MAAA/H,EAAA,QAAAL,eAAA;AAKDoI,SAAA,SAAAC,uBAAA;AAGE,QAAI,CADsBrI,cAAa0B,KAAM6G,OAA2B,EAClD;AACpB5H,sBAAiB,EAAE,CAAC;AACpBJ,0BAAqB,MAAM;;;AAE9BF,KAAA,MAAAL;AAAAK,KAAA,MAAA+H;QAAAA,OAAA/H,EAAA;EAPD,MAAAgI,qBAAAD;EAOC,IAAAI;AAAA,MAAAnI,EAAA,QAAAL,eAAA;AAEuCwI,SAAA;IAAAxI;IAAAC;IAAAC;IAIvC;AAAAG,KAAA,MAAAL;AAAAK,KAAA,MAAAmI;QAAAA,OAAAnI,EAAA;EAJD,MAAAoI,QAAwCD;AAOrClB,OAAAxH,qBAAoB4I;AAAiBD,QAAAA;AACnCjB,QAAAzH,qBAAAF,qBAAA,OAAA;GACgB8I,WAAA;GAAgBrI,UAAA;IAC7BT,qBAAA,OAAA;KAAe8I,WAAA;KAAwBrI,UAAA,CACrCX,oBAAA,MAAA,EAAAW,UAAI,WAAW,CAAC,EAChBX,oBAACL,QAAM;MACOsJ,aAAA;MACPC,MAAA;MACGC,QAAA;MACCT,SAAAA;MACV,CAAC,CAAA;KACC,CAAC;IAENxI,qBAAA,OAAA;KAAe8I,WAAA;KAAsBrI,UAAA;MACnCT,qBAAA,UAAA;OACe,eAAAe,cAAc;OACjB+H,WAAA;OACDI,eAAMlI,aAAa,YAAY;OAAAP,UAAA;QACzC;QACamH,eAAcnF;QAAQ;QACpC;OAAQ,CAAC;MACTzC,qBAAA,UAAA;OACe,eAAAe,cAAc;OACjB+H,WAAA;OACDI,eAAMlI,aAAa,aAAa;OAAAP,UAAA;QAC1C;QACcqH,gBAAerF;QAAQ;QACtC;OAAQ,CAAC;MACTzC,qBAAA,UAAA;OACe,eAAAe,cAAc;OACjB+H,WAAA;OACDI,eAAMlI,aAAa,YAAY;OAAAP,UAAA;QACzC;QACauH,eAAcvF;QAAQ;QACpC;OAAQ,CAAC;MAAA;KACN,CAAC;IAENzC,qBAAA,OAAA;KAAe8I,WAAA;KAAyBrI,UAAA;MACrCM,cAAc,eAAe6G,eAAcnF,SAAU,KAArD3C,oBAAA,OAAA,EAAAW,UACO0H,iBAAiB,EAAAxG,SAAWiG,gBAAgB,CAAA,EACpD,CAAC;MACA7G,cAAc,gBAAgB+G,gBAAerF,SAAU,KAAvD3C,oBAAA,OAAA,EAAAW,UACO0H,iBAAiB,EAAAxG,SAAWmG,iBAAiB,CAAA,EACrD,CAAC;MACA/G,cAAc,eAAeiH,eAAcvF,SAAU,KAArDzC,qBAAA,OAAA,EAAAS,UAAA,CAEI0H,iBAAiB,EAAAxG,SAAWqG,gBAAgB,CAAC,EAC9ClI,oBAAA,OAAA;OAAegJ,WAAA;OAAwBrI,UACrCX,oBAACL,QAAM;QACOsJ,aAAA;QACPI,MAAA;QACGF,QAAA;QACCC,SAAAE;QAAgC3I,UAC1C;QAEO,CAAA;OACL,CAAC,CAAA,EAEV,CAAC;OACEM,cAAc,eAAe6G,eAAcnF,WAAY,KACvD1B,cAAc,gBAAgB+G,gBAAerF,WAAY,KACzD1B,cAAc,eAAeiH,eAAcvF,WAAY,MAFzDzC,qBAAA,KAAA;OAGc8I,WAAA;OAAoBrI,UAAA;QAAC;QAAIM;QAAU;QAAM;OACxD,CAAC;MAAA;KACE,CAAC;IAAA;GAEV,CAAC;AAAAP,IAAA,MAAAO;AAAAP,IAAA,MAAAL;AAAAK,IAAA,MAAAN;AAAAM,IAAA,MAAAiH;AAAAjH,IAAA,MAAAkH;AAAAlH,IAAA,MAAAmH;QAAA;AAAAF,OAAAjH,EAAA;AAAAkH,QAAAlH,EAAA;AAAAmH,QAAAnH,EAAA;;CAAA,IAAA0H;AAAA,KAAA1H,EAAA,QAAAiH,MAAAjH,EAAA,QAAAC,YAAAD,EAAA,QAAAkH,OAAAlH,EAAA,QAAAmH,KAAA;AAlEHO,QAAAlI,qBAACyH,IAA6B;GAAQmB,OAAAA;GAAKnI,UAAA,CACxCkH,KAkEAlH,SAAQ;GACoB,CAAC;AAAAD,IAAA,MAAAiH;AAAAjH,IAAA,MAAAC;AAAAD,IAAA,MAAAkH;AAAAlH,IAAA,MAAAmH;AAAAnH,IAAA,MAAA0H;OAAAA,OAAA1H,EAAA;AAAA,QApEhC0H;;AAxXG,SAAAkB,SAAA;AAAA,QA4a4BC,QAAMC,UAAkBC,QAAE;;AA5atD,SAAAb,OAAAc,WAAA;AAAA,QA0WsD9F,UAAMC;;AA1W5D,SAAA2E,OAAAmB,WAAAC,OAAA;AAAA,QAoUG1J,qBAAA,MAAA;EAAqD,eAAA0D,UAAMG;EAAOpD,UAAA,CAChET,qBAAA,OAAA;GAAe8I,WAAA;GAAarI,UAAA,CAC1BX,oBAAA,QAAA;IAAgBgJ,WAAA;IAAiBrI,UAAEiD,UAAMY;IAAgB,CAAC,EAC1DxE,oBAAA,QAAA;IAAgBgJ,WAAA;IAAarI,UAC1BiD,UAAMG,WAAY,eAAlB,kBAEGH,UAAME,WAAY,MAAlB,GACK+F,KAAIC,KAAMlG,UAAME,SAAU,CAAA,KAD/B;IAGA,CAAC,CAAA;GACJ,CAAC,EACN9D,oBAAA,OAAA;GACYgJ,WAAA;GAERe,OAAA,EAAA,cAEInG,UAAMG,WAAY,eAAlB,MAAA,GAEOH,UAAME,WAAY,OACL;GAAAnD,UAG1BX,oBAAA,OAAA;IACe,eAAA4D,UAAMG,WAAY;IACrBiF,WAAA;IACX,CAAA;GACE,CAAC,CAAA;EAAA,EA1BC,GAAGpF,UAAMY,SAAS,GAAIoF,QA2B1B;;AA/VR,SAAAzB,OAAA6B,WAAA;AAAA,QAuTSpG,UAAMG,WAAY;;AAvT3B,SAAAkE,OAAAgC,WAAA;AAAA,QAoTSrG,UAAMG,WAAY;;AApT3B,SAAAgE,OAAAmC,WAAA;AAAA,QAiTStG,UAAMG,WAAY;;AAjT3B,SAAArB,OAAAyH,UAAA;AAAA,QAiDWvG,SAAMC,WAAYD,SAAMZ;;AAjDnC,SAAAZ,OAAAgI,UAAA;AAAA,QAgCWxG,SAAMG,WAAY;;AAhC7B,SAAA7B,OAAAmI,UAAA;AAAA,QA6BWzG,SAAMG,WAAY;;AA7B7B,SAAA/B,MAAA4B,QAAA;AAAA,QA0BWA,OAAMG,WAAY;;AAsapC,MAAauG,gCAAgChL,IAAIa,qBAAqB"}
@@ -16,11 +16,11 @@ function getFileExistsHandler(args) {
16
16
  limit: 1,
17
17
  pagination: false
18
18
  });
19
- if (docs.length > 0) return Response.json({ message: "File found [payload]" }, { status: 200 });
19
+ if (docs.length > 0) return Response.json({ message: "File found [Payload]" }, { status: 200 });
20
20
  const url = getS3Store().getUrl(filename);
21
21
  if ((await fetch(url, { method: "HEAD" })).status === 200) return Response.json({ message: "File found [S3]" }, { status: 200 });
22
- return Response.json({ message: "File not found" }, { status: 404 });
23
- } catch (_error) {
22
+ return new Response(null, { status: 204 });
23
+ } catch (error) {
24
24
  logError(MediaCloudErrors.FILE_DIMENSIONS_ERROR.message);
25
25
  return Response.json({ message: "Failed to process asset" }, { status: 500 });
26
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"fileExistsHandler.mjs","names":[],"sources":["../../src/endpoints/fileExistsHandler.ts"],"sourcesContent":["import type { PayloadHandler } from 'payload'\nimport { useErrorHandler } from '../hooks/useErrorHandler'\nimport { MediaCloudErrors } from '../types/errors'\n\nimport { S3Store } from '../tus/stores/s3/s3Store'\n\ninterface GetFileExistsHandlerArgs {\n getS3Store: () => S3Store\n collection: string\n}\n\nexport function getFileExistsHandler(\n args: GetFileExistsHandlerArgs\n): PayloadHandler {\n const { getS3Store, collection } = args\n const { throwError, logError } = useErrorHandler()\n\n return async function (req) {\n try {\n const { routeParams, payload } = req\n const filename = routeParams?.filename as string\n\n if (!filename) {\n throwError(MediaCloudErrors.FILE_MISSING_NAME)\n }\n\n // Check if file exists in Payload database\n const { docs } = await payload.find({\n collection,\n where: {\n filename: {\n equals: filename,\n },\n },\n limit: 1,\n pagination: false,\n })\n\n if (docs.length > 0) {\n return Response.json(\n { message: 'File found [payload]' },\n { status: 200 }\n )\n }\n\n // Check if completed file exists in S3\n const url = getS3Store().getUrl(filename)\n const s3Response = await fetch(url, { method: 'HEAD' })\n\n if (s3Response.status === 200) {\n return Response.json({ message: 'File found [S3]' }, { status: 200 })\n }\n\n return Response.json({ message: 'File not found' }, { status: 404 })\n } catch (_error) {\n logError(MediaCloudErrors.FILE_DIMENSIONS_ERROR.message)\n return Response.json(\n { message: 'Failed to process asset' },\n { status: 500 }\n )\n }\n }\n}\n"],"mappings":";;;;AAWA,SAAgB,qBACd,MACgB;CAChB,MAAM,EAAE,YAAY,eAAe;CACnC,MAAM,EAAE,YAAY,aAAa,iBAAiB;AAElD,QAAO,eAAgB,KAAK;AAC1B,MAAI;GACF,MAAM,EAAE,aAAa,YAAY;GACjC,MAAM,WAAW,aAAa;AAE9B,OAAI,CAAC,SACH,YAAW,iBAAiB,kBAAkB;GAIhD,MAAM,EAAE,SAAS,MAAM,QAAQ,KAAK;IAClC;IACA,OAAO,EACL,UAAU,EACR,QAAQ,UACT,EACF;IACD,OAAO;IACP,YAAY;IACb,CAAC;AAEF,OAAI,KAAK,SAAS,EAChB,QAAO,SAAS,KACd,EAAE,SAAS,wBAAwB,EACnC,EAAE,QAAQ,KAAK,CAChB;GAIH,MAAM,MAAM,YAAY,CAAC,OAAO,SAAS;AAGzC,QAFmB,MAAM,MAAM,KAAK,EAAE,QAAQ,QAAQ,CAAC,EAExC,WAAW,IACxB,QAAO,SAAS,KAAK,EAAE,SAAS,mBAAmB,EAAE,EAAE,QAAQ,KAAK,CAAC;AAGvE,UAAO,SAAS,KAAK,EAAE,SAAS,kBAAkB,EAAE,EAAE,QAAQ,KAAK,CAAC;WAC7D,QAAQ;AACf,YAAS,iBAAiB,sBAAsB,QAAQ;AACxD,UAAO,SAAS,KACd,EAAE,SAAS,2BAA2B,EACtC,EAAE,QAAQ,KAAK,CAChB"}
1
+ {"version":3,"file":"fileExistsHandler.mjs","names":[],"sources":["../../src/endpoints/fileExistsHandler.ts"],"sourcesContent":["import type { PayloadHandler } from 'payload'\nimport { useErrorHandler } from '../hooks/useErrorHandler'\nimport { MediaCloudErrors } from '../types/errors'\n\nimport { S3Store } from '../tus/stores/s3/s3Store'\n\ninterface GetFileExistsHandlerArgs {\n getS3Store: () => S3Store\n collection: string\n}\n\nexport function getFileExistsHandler(\n args: GetFileExistsHandlerArgs\n): PayloadHandler {\n const { getS3Store, collection } = args\n const { throwError, logError } = useErrorHandler()\n\n return async function (req) {\n try {\n const { routeParams, payload } = req\n const filename = routeParams?.filename as string\n\n if (!filename) {\n throwError(MediaCloudErrors.FILE_MISSING_NAME)\n }\n\n // Check if file exists in Payload database\n const { docs } = await payload.find({\n collection,\n where: {\n filename: {\n equals: filename,\n },\n },\n limit: 1,\n pagination: false,\n })\n\n if (docs.length > 0) {\n return Response.json(\n { message: 'File found [Payload]' },\n { status: 200 }\n )\n }\n\n // Check if completed file exists in S3\n const url = getS3Store().getUrl(filename)\n const s3Response = await fetch(url, { method: 'HEAD' })\n\n if (s3Response.status === 200) {\n return Response.json({ message: 'File found [S3]' }, { status: 200 })\n }\n\n return new Response(null, {\n status: 204,\n })\n } catch (error) {\n logError(MediaCloudErrors.FILE_DIMENSIONS_ERROR.message)\n return Response.json(\n { message: 'Failed to process asset' },\n { status: 500 }\n )\n }\n }\n}\n"],"mappings":";;;;AAWA,SAAgB,qBACd,MACgB;CAChB,MAAM,EAAE,YAAY,eAAe;CACnC,MAAM,EAAE,YAAY,aAAa,iBAAiB;AAElD,QAAO,eAAgB,KAAK;AAC1B,MAAI;GACF,MAAM,EAAE,aAAa,YAAY;GACjC,MAAM,WAAW,aAAa;AAE9B,OAAI,CAAC,SACH,YAAW,iBAAiB,kBAAkB;GAIhD,MAAM,EAAE,SAAS,MAAM,QAAQ,KAAK;IAClC;IACA,OAAO,EACL,UAAU,EACR,QAAQ,UACT,EACF;IACD,OAAO;IACP,YAAY;IACb,CAAC;AAEF,OAAI,KAAK,SAAS,EAChB,QAAO,SAAS,KACd,EAAE,SAAS,wBAAwB,EACnC,EAAE,QAAQ,KAAK,CAChB;GAIH,MAAM,MAAM,YAAY,CAAC,OAAO,SAAS;AAGzC,QAFmB,MAAM,MAAM,KAAK,EAAE,QAAQ,QAAQ,CAAC,EAExC,WAAW,IACxB,QAAO,SAAS,KAAK,EAAE,SAAS,mBAAmB,EAAE,EAAE,QAAQ,KAAK,CAAC;AAGvE,UAAO,IAAI,SAAS,MAAM,EACxB,QAAQ,KACT,CAAC;WACK,OAAO;AACd,YAAS,iBAAiB,sBAAsB,QAAQ;AACxD,UAAO,SAAS,KACd,EAAE,SAAS,2BAA2B,EACtC,EAAE,QAAQ,KAAK,CAChB"}
@@ -1,5 +1,5 @@
1
- import { Mux as Mux$1 } from "@mux/mux-node";
2
1
  import { PayloadHandler } from "payload";
2
+ import { Mux as Mux$1 } from "@mux/mux-node";
3
3
 
4
4
  //#region src/endpoints/muxAssetHandler.d.ts
5
5
  interface GetMuxAssetHandlerArgs {
@@ -3,11 +3,11 @@ function getMuxAssetHandler(args) {
3
3
  const { getMuxClient, collection } = args;
4
4
  return async (req) => {
5
5
  try {
6
- const mux = getMuxClient();
6
+ const muxClient = getMuxClient();
7
7
  const { query } = req;
8
8
  const uploadId = query.upload_id;
9
9
  if (!uploadId) return Response.json({ message: "Upload ID is required" }, { status: 400 });
10
- const asset = (await mux.video.assets.list({
10
+ const asset = (await muxClient.video.assets.list({
11
11
  limit: 1,
12
12
  upload_id: uploadId
13
13
  }))?.data[0];
@@ -1 +1 @@
1
- {"version":3,"file":"muxAssetHandler.mjs","names":[],"sources":["../../src/endpoints/muxAssetHandler.ts"],"sourcesContent":["import type { Mux } from '@mux/mux-node'\nimport type { PayloadHandler } from 'payload'\nimport type { StaticRenditions } from '../types'\n\ninterface GetMuxAssetHandlerArgs {\n getMuxClient: () => Mux\n collection: string\n}\n\nexport function getMuxAssetHandler(\n args: GetMuxAssetHandlerArgs\n): PayloadHandler {\n const { getMuxClient, collection } = args\n\n return async (req) => {\n try {\n const mux = getMuxClient()\n const { query } = req\n\n const uploadId = query.upload_id as string\n\n if (!uploadId) {\n return Response.json(\n { message: 'Upload ID is required' },\n { status: 400 }\n )\n }\n\n const assets = await mux.video.assets.list({\n limit: 1,\n upload_id: uploadId,\n })\n\n const asset = assets?.data[0]\n\n if (!asset) {\n return Response.json(\n { message: 'No asset found for the given upload ID' },\n { status: 404 }\n )\n }\n\n if (asset.status === 'ready') {\n const { payload } = req\n\n const { docs } = await payload.find({\n collection,\n where: {\n 'mux.uploadId': {\n equals: uploadId,\n },\n },\n limit: 1,\n pagination: false,\n })\n\n if (docs.length > 0) {\n const { id } = docs[0]\n\n const width = Array.from(asset.tracks ?? []).reduce(\n (max, track) =>\n track.type === 'video' && track.max_width\n ? Math.max(max, track.max_width)\n : max,\n 0\n )\n\n const height = Array.from(asset.tracks ?? []).reduce(\n (max, track) =>\n track.type === 'video' && track.max_height\n ? Math.max(max, track.max_height)\n : max,\n 0\n )\n\n await payload.update({\n collection,\n id,\n data: {\n mux: {\n status: asset.status,\n assetId: asset.id,\n playbackId: asset.playback_ids?.[0]?.id,\n aspectRatio: asset.aspect_ratio,\n duration: asset.duration,\n tracks: asset.tracks,\n maxResolutionTier: asset.max_resolution_tier,\n videoQuality: asset.video_quality,\n staticRenditions: asset.static_renditions as StaticRenditions,\n },\n width,\n height,\n },\n })\n }\n\n return Response.json(\n {\n ready: asset.status === 'ready',\n asset,\n },\n { status: 200 }\n )\n } else {\n return Response.json(\n {\n ready: false,\n asset,\n },\n { status: 200 }\n )\n }\n } catch (_error) {\n return Response.json(\n { message: 'Failed to fetch Mux asset' },\n { status: 500 }\n )\n }\n }\n}\n"],"mappings":";AASA,SAAgB,mBACd,MACgB;CAChB,MAAM,EAAE,cAAc,eAAe;AAErC,QAAO,OAAO,QAAQ;AACpB,MAAI;GACF,MAAM,MAAM,cAAc;GAC1B,MAAM,EAAE,UAAU;GAElB,MAAM,WAAW,MAAM;AAEvB,OAAI,CAAC,SACH,QAAO,SAAS,KACd,EAAE,SAAS,yBAAyB,EACpC,EAAE,QAAQ,KAAK,CAChB;GAQH,MAAM,SALS,MAAM,IAAI,MAAM,OAAO,KAAK;IACzC,OAAO;IACP,WAAW;IACZ,CAAC,GAEoB,KAAK;AAE3B,OAAI,CAAC,MACH,QAAO,SAAS,KACd,EAAE,SAAS,0CAA0C,EACrD,EAAE,QAAQ,KAAK,CAChB;AAGH,OAAI,MAAM,WAAW,SAAS;IAC5B,MAAM,EAAE,YAAY;IAEpB,MAAM,EAAE,SAAS,MAAM,QAAQ,KAAK;KAClC;KACA,OAAO,EACL,gBAAgB,EACd,QAAQ,UACT,EACF;KACD,OAAO;KACP,YAAY;KACb,CAAC;AAEF,QAAI,KAAK,SAAS,GAAG;KACnB,MAAM,EAAE,OAAO,KAAK;KAEpB,MAAM,QAAQ,MAAM,KAAK,MAAM,UAAU,EAAE,CAAC,CAAC,QAC1C,KAAK,UACJ,MAAM,SAAS,WAAW,MAAM,YAC5B,KAAK,IAAI,KAAK,MAAM,UAAU,GAC9B,KACN,EACD;KAED,MAAM,SAAS,MAAM,KAAK,MAAM,UAAU,EAAE,CAAC,CAAC,QAC3C,KAAK,UACJ,MAAM,SAAS,WAAW,MAAM,aAC5B,KAAK,IAAI,KAAK,MAAM,WAAW,GAC/B,KACN,EACD;AAED,WAAM,QAAQ,OAAO;MACnB;MACA;MACA,MAAM;OACJ,KAAK;QACH,QAAQ,MAAM;QACd,SAAS,MAAM;QACf,YAAY,MAAM,eAAe,IAAI;QACrC,aAAa,MAAM;QACnB,UAAU,MAAM;QAChB,QAAQ,MAAM;QACd,mBAAmB,MAAM;QACzB,cAAc,MAAM;QACpB,kBAAkB,MAAM;QACzB;OACD;OACA;OACD;MACF,CAAC;;AAGJ,WAAO,SAAS,KACd;KACE,OAAO,MAAM,WAAW;KACxB;KACD,EACD,EAAE,QAAQ,KAAK,CAChB;SAED,QAAO,SAAS,KACd;IACE,OAAO;IACP;IACD,EACD,EAAE,QAAQ,KAAK,CAChB;WAEI,QAAQ;AACf,UAAO,SAAS,KACd,EAAE,SAAS,6BAA6B,EACxC,EAAE,QAAQ,KAAK,CAChB"}
1
+ {"version":3,"file":"muxAssetHandler.mjs","names":[],"sources":["../../src/endpoints/muxAssetHandler.ts"],"sourcesContent":["import type { Mux } from '@mux/mux-node'\nimport type { PayloadHandler } from 'payload'\nimport type { StaticRenditions } from '../types'\n\ninterface GetMuxAssetHandlerArgs {\n getMuxClient: () => Mux\n collection: string\n}\n\nexport function getMuxAssetHandler(\n args: GetMuxAssetHandlerArgs\n): PayloadHandler {\n const { getMuxClient, collection } = args\n\n return async (req) => {\n try {\n const muxClient = getMuxClient()\n const { query } = req\n\n const uploadId = query.upload_id as string\n\n if (!uploadId) {\n return Response.json(\n { message: 'Upload ID is required' },\n { status: 400 }\n )\n }\n\n const assets = await muxClient.video.assets.list({\n limit: 1,\n upload_id: uploadId,\n })\n\n const asset = assets?.data[0]\n\n if (!asset) {\n return Response.json(\n { message: 'No asset found for the given upload ID' },\n { status: 404 }\n )\n }\n\n if (asset.status === 'ready') {\n const { payload } = req\n\n const { docs } = await payload.find({\n collection,\n where: {\n 'mux.uploadId': {\n equals: uploadId,\n },\n },\n limit: 1,\n pagination: false,\n })\n\n if (docs.length > 0) {\n const { id } = docs[0]\n\n const width = Array.from(asset.tracks ?? []).reduce(\n (max, track) =>\n track.type === 'video' && track.max_width\n ? Math.max(max, track.max_width)\n : max,\n 0\n )\n\n const height = Array.from(asset.tracks ?? []).reduce(\n (max, track) =>\n track.type === 'video' && track.max_height\n ? Math.max(max, track.max_height)\n : max,\n 0\n )\n\n await payload.update({\n collection,\n id,\n data: {\n mux: {\n status: asset.status,\n assetId: asset.id,\n playbackId: asset.playback_ids?.[0]?.id,\n aspectRatio: asset.aspect_ratio,\n duration: asset.duration,\n tracks: asset.tracks,\n maxResolutionTier: asset.max_resolution_tier,\n videoQuality: asset.video_quality,\n staticRenditions: asset.static_renditions as StaticRenditions,\n },\n width,\n height,\n },\n })\n }\n\n return Response.json(\n {\n ready: asset.status === 'ready',\n asset,\n },\n { status: 200 }\n )\n } else {\n return Response.json(\n {\n ready: false,\n asset,\n },\n { status: 200 }\n )\n }\n } catch (_error) {\n return Response.json(\n { message: 'Failed to fetch Mux asset' },\n { status: 500 }\n )\n }\n }\n}\n"],"mappings":";AASA,SAAgB,mBACd,MACgB;CAChB,MAAM,EAAE,cAAc,eAAe;AAErC,QAAO,OAAO,QAAQ;AACpB,MAAI;GACF,MAAM,YAAY,cAAc;GAChC,MAAM,EAAE,UAAU;GAElB,MAAM,WAAW,MAAM;AAEvB,OAAI,CAAC,SACH,QAAO,SAAS,KACd,EAAE,SAAS,yBAAyB,EACpC,EAAE,QAAQ,KAAK,CAChB;GAQH,MAAM,SALS,MAAM,UAAU,MAAM,OAAO,KAAK;IAC/C,OAAO;IACP,WAAW;IACZ,CAAC,GAEoB,KAAK;AAE3B,OAAI,CAAC,MACH,QAAO,SAAS,KACd,EAAE,SAAS,0CAA0C,EACrD,EAAE,QAAQ,KAAK,CAChB;AAGH,OAAI,MAAM,WAAW,SAAS;IAC5B,MAAM,EAAE,YAAY;IAEpB,MAAM,EAAE,SAAS,MAAM,QAAQ,KAAK;KAClC;KACA,OAAO,EACL,gBAAgB,EACd,QAAQ,UACT,EACF;KACD,OAAO;KACP,YAAY;KACb,CAAC;AAEF,QAAI,KAAK,SAAS,GAAG;KACnB,MAAM,EAAE,OAAO,KAAK;KAEpB,MAAM,QAAQ,MAAM,KAAK,MAAM,UAAU,EAAE,CAAC,CAAC,QAC1C,KAAK,UACJ,MAAM,SAAS,WAAW,MAAM,YAC5B,KAAK,IAAI,KAAK,MAAM,UAAU,GAC9B,KACN,EACD;KAED,MAAM,SAAS,MAAM,KAAK,MAAM,UAAU,EAAE,CAAC,CAAC,QAC3C,KAAK,UACJ,MAAM,SAAS,WAAW,MAAM,aAC5B,KAAK,IAAI,KAAK,MAAM,WAAW,GAC/B,KACN,EACD;AAED,WAAM,QAAQ,OAAO;MACnB;MACA;MACA,MAAM;OACJ,KAAK;QACH,QAAQ,MAAM;QACd,SAAS,MAAM;QACf,YAAY,MAAM,eAAe,IAAI;QACrC,aAAa,MAAM;QACnB,UAAU,MAAM;QAChB,QAAQ,MAAM;QACd,mBAAmB,MAAM;QACzB,cAAc,MAAM;QACpB,kBAAkB,MAAM;QACzB;OACD;OACA;OACD;MACF,CAAC;;AAGJ,WAAO,SAAS,KACd;KACE,OAAO,MAAM,WAAW;KACxB;KACD,EACD,EAAE,QAAQ,KAAK,CAChB;SAED,QAAO,SAAS,KACd;IACE,OAAO;IACP;IACD,EACD,EAAE,QAAQ,KAAK,CAChB;WAEI,QAAQ;AACf,UAAO,SAAS,KACd,EAAE,SAAS,6BAA6B,EACxC,EAAE,QAAQ,KAAK,CAChB"}