@maas/payload-plugin-media-cloud 0.0.19 → 0.0.21

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.
@@ -1,8 +1,8 @@
1
1
  'use client';
2
2
 
3
- import { MediaCloudErrors } from "../../types/errors.mjs";
3
+ import { MediaCloudErrors, MediaCloudLogs } from "../../types/errors.mjs";
4
4
  import { useErrorHandler } from "../../hooks/useErrorHandler.mjs";
5
- import { getFileType, isVideo, sanitizeFilename } from "../../utils/file.mjs";
5
+ import { generateUniqueFilename, getFileType, isVideo } from "../../utils/file.mjs";
6
6
  import { useMediaCloudEmitter } from "../../hooks/useMediaCloudEmitter.mjs";
7
7
  import * as upchunk from "@mux/upchunk";
8
8
  import * as tus from "tus-js-client";
@@ -21,26 +21,13 @@ const TUS_RETRY_DELAYS = [
21
21
  5e3
22
22
  ];
23
23
  /**
24
- * Utility function to parse upload ID from URL
25
- * @param uploadUrl - The upload URL to parse
26
- * @returns The extracted upload ID or empty string if parsing fails
27
- */
28
- function parseFilename(uploadUrl) {
29
- if (!uploadUrl) {
30
- logError(MediaCloudErrors.UPLOAD_NO_URL.message);
31
- return "";
32
- }
33
- return new URL(uploadUrl).pathname.split("/").pop() || "";
34
- }
35
- /**
36
24
  * Handles Mux video upload with progress tracking
37
25
  * @param args - The upload arguments including file, server URL, and callbacks
38
26
  * @returns Promise that resolves to upload result or null if upload fails
39
27
  */
40
28
  async function muxUpload(args) {
41
- const { file, serverURL, apiRoute, mimeType, updateFilename } = args;
42
- const filename = sanitizeFilename(file.name);
43
- updateFilename(filename);
29
+ const { file, serverURL, apiRoute, mimeType } = args;
30
+ const filename = file.name;
44
31
  try {
45
32
  const { url, uploadId } = await (await fetch(`${serverURL}${apiRoute}/mux/upload`, {
46
33
  body: JSON.stringify({
@@ -94,12 +81,12 @@ async function muxUpload(args) {
94
81
  * @returns Promise that resolves to upload result or null if upload fails
95
82
  */
96
83
  async function tusUpload(args) {
97
- const { apiRoute, serverURL, file, mimeType, updateFilename } = args;
98
- const filename = sanitizeFilename(file.name);
84
+ const { apiRoute, serverURL, file, mimeType } = args;
85
+ const filename = file.name;
99
86
  const filetype = file.type;
100
87
  const filesize = file.size.toString();
101
88
  return new Promise((resolve) => {
102
- const upload = new tus.Upload(file, {
89
+ new tus.Upload(file, {
103
90
  endpoint: `${serverURL}${apiRoute}/uploads`,
104
91
  retryDelays: TUS_RETRY_DELAYS,
105
92
  chunkSize: TUS_CHUNK_SIZE,
@@ -118,33 +105,30 @@ async function tusUpload(args) {
118
105
  },
119
106
  onProgress: function(bytesUploaded, bytesTotal) {
120
107
  const percentage = Math.round(bytesUploaded / bytesTotal * 100);
121
- const filename$1 = parseFilename(upload?.url);
122
108
  emitter.emit("updateUpload", {
123
- filename: filename$1,
109
+ filename,
124
110
  progress: percentage
125
111
  });
126
112
  },
127
113
  onSuccess: function() {
128
- const filename$1 = parseFilename(upload?.url);
129
- emitter.emit("uploadComplete", { filename: filename$1 });
130
- fetch(`${serverURL}${apiRoute}/uploads/${filename$1}/process`);
114
+ emitter.emit("uploadComplete", { filename });
115
+ fetch(`${serverURL}${apiRoute}/uploads/${filename}/process`);
131
116
  },
132
- onUploadUrlAvailable: function() {
133
- const filename$1 = parseFilename(upload?.url);
134
- updateFilename(filename$1);
135
- emitter.emit("addUpload", { filename: filename$1 });
117
+ onUploadUrlAvailable: async function() {
118
+ emitter.emit("addUpload", { filename });
136
119
  resolve({
137
- filename: filename$1,
120
+ filename,
138
121
  mimeType,
139
122
  storage: "s3"
140
123
  });
141
124
  }
142
- });
143
- upload.start();
125
+ }).start();
144
126
  });
145
127
  }
128
+ const { log } = useErrorHandler();
146
129
  const UploadHandler = createClientUploadHandler({ handler: async function(args) {
147
130
  const { serverURL, apiRoute, file, updateFilename } = args;
131
+ console.log("upload handler called", file);
148
132
  try {
149
133
  const mimeType = await getFileType(file) || file.type || "application/octet-stream";
150
134
  if (!mimeType) {
@@ -152,12 +136,22 @@ const UploadHandler = createClientUploadHandler({ handler: async function(args)
152
136
  return null;
153
137
  }
154
138
  const isVideoFile = await isVideo(file);
139
+ let mappedFile = file;
140
+ if (!isVideoFile) try {
141
+ if ((await fetch(`${serverURL}${apiRoute}/uploads/${file.name}/exists`)).status === 200) {
142
+ log(MediaCloudLogs.S3_STORE_FILE_FOUND);
143
+ const newFilename = generateUniqueFilename(file.name);
144
+ mappedFile = new File([file], newFilename, { type: file.type });
145
+ await updateFilename(newFilename);
146
+ }
147
+ } catch (_error) {
148
+ logError(MediaCloudErrors.NAMING_FUNCTION_ERROR.message);
149
+ }
155
150
  const uploadArgs = {
156
- file,
151
+ file: mappedFile,
157
152
  serverURL,
158
153
  apiRoute,
159
- mimeType,
160
- updateFilename
154
+ mimeType
161
155
  };
162
156
  if (isVideoFile) return await muxUpload(uploadArgs);
163
157
  else return await tusUpload(uploadArgs);
@@ -1 +1 @@
1
- {"version":3,"file":"upload-handler.mjs","names":["filename","uploadArgs: UploadArgs"],"sources":["../../../src/components/upload-handler/upload-handler.tsx"],"sourcesContent":["'use client'\n\nimport * as upchunk from '@mux/upchunk'\nimport * as tus from 'tus-js-client'\n\nimport { toast } from '@payloadcms/ui'\nimport { createClientUploadHandler } from '@payloadcms/plugin-cloud-storage/client'\n\nimport { MediaCloudErrors } from '../../types/errors'\nimport { useMediaCloudEmitter } from '../../hooks/useMediaCloudEmitter'\nimport { useErrorHandler } from '../../hooks/useErrorHandler'\nimport { isVideo, getFileType, sanitizeFilename } from '../../utils/file'\n\ninterface UploadArgs {\n serverURL: string\n apiRoute: string\n file: File\n mimeType: string\n updateFilename: (filename: string) => void\n}\n\ninterface UploadResult {\n filename: string\n uploadId?: string\n mimeType: string\n storage: 'mux' | 's3'\n}\n\ninterface MuxCreateUploadResponse {\n url: string\n uploadId: string\n filename: string\n}\n\nconst { logError, throwError } = useErrorHandler()\nconst emitter = useMediaCloudEmitter()\n\nconst MUX_CHUNK_SIZE = 30720\nconst TUS_CHUNK_SIZE = 1024 * 1024\nconst TUS_RETRY_DELAYS = [0, 1000, 2000, 5000]\n\n/**\n * Utility function to parse upload ID from URL\n * @param uploadUrl - The upload URL to parse\n * @returns The extracted upload ID or empty string if parsing fails\n */\nfunction parseFilename(uploadUrl?: string | null): string {\n if (!uploadUrl) {\n logError(MediaCloudErrors.UPLOAD_NO_URL.message)\n return ''\n }\n const url = new URL(uploadUrl)\n return url.pathname.split('/').pop() || ''\n}\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, updateFilename } = args\n\n const filename = sanitizeFilename(file.name)\n updateFilename(filename)\n\n try {\n // Request upload URL from Mux\n const response = await fetch(`${serverURL}${apiRoute}/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: `${serverURL}${apiRoute}/mux/asset`,\n })\n\n // Set up event handlers\n uploader.on('error', function () {\n logError(MediaCloudErrors.MUX_UPLOAD_ERROR.message)\n toast.error('Video upload failed')\n emitter.emit('removeUpload', { uploadId })\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 (_error) {\n logError(MediaCloudErrors.MUX_DIRECT_UPLOAD_ERROR.message)\n toast.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, mimeType, updateFilename } = args\n\n const filename = sanitizeFilename(file.name)\n const filetype = file.type\n const filesize = file.size.toString()\n\n return new Promise((resolve) => {\n const upload = new tus.Upload(file, {\n endpoint: `${serverURL}${apiRoute}/uploads`,\n retryDelays: TUS_RETRY_DELAYS,\n chunkSize: TUS_CHUNK_SIZE,\n metadata: {\n filetype,\n filesize,\n filename,\n contentType: filetype,\n contentDisposition: 'inline',\n contentLength: filesize,\n },\n onError: function () {\n logError(MediaCloudErrors.TUS_UPLOAD_ERROR.message)\n toast.error('File upload failed')\n resolve(null)\n },\n onProgress: function (bytesUploaded, bytesTotal) {\n const percentage = Math.round((bytesUploaded / bytesTotal) * 100)\n const filename = parseFilename(upload?.url)\n emitter.emit('updateUpload', {\n filename,\n progress: percentage,\n })\n },\n onSuccess: function () {\n const filename = parseFilename(upload?.url)\n emitter.emit('uploadComplete', { filename })\n\n // Trigger post upload processing\n fetch(`${serverURL}${apiRoute}/uploads/${filename}/process`)\n },\n onUploadUrlAvailable: function () {\n const filename = parseFilename(upload?.url)\n updateFilename(filename)\n\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\nexport const UploadHandler = createClientUploadHandler({\n handler: async function (args) {\n const { serverURL, apiRoute, file, updateFilename } = args\n\n try {\n const mimeType =\n (await getFileType(file)) || file.type || 'application/octet-stream'\n\n if (!mimeType) {\n throwError(MediaCloudErrors.FILE_TYPE_UNKNOWN)\n return null\n }\n\n const isVideoFile = await isVideo(file)\n const uploadArgs: UploadArgs = {\n file,\n serverURL,\n apiRoute,\n mimeType,\n updateFilename,\n }\n\n if (isVideoFile) {\n return await muxUpload(uploadArgs)\n } else {\n return await tusUpload(uploadArgs)\n }\n } catch (error) {\n console.error(\n '[PLUGIN-MEDIA-CLOUD] Upload handler detailed error:',\n error\n )\n logError(MediaCloudErrors.UPLOAD_HANDLER_ERROR.message)\n toast.error(\n `Upload failed: ${error instanceof Error ? error.message : 'Unknown error'}`\n )\n return null\n }\n },\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"upload-handler.mjs","names":["uploadArgs: UploadArgs"],"sources":["../../../src/components/upload-handler/upload-handler.tsx"],"sourcesContent":["'use client'\n\nimport * as upchunk from '@mux/upchunk'\nimport * as tus from 'tus-js-client'\n\nimport { toast } from '@payloadcms/ui'\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 { isVideo, getFileType, generateUniqueFilename } from '../../utils/file'\n\ninterface UploadArgs {\n serverURL: string\n apiRoute: string\n file: File\n mimeType: string\n}\n\ninterface UploadResult {\n filename: string\n uploadId?: string\n mimeType: string\n storage: 'mux' | 's3'\n}\n\ninterface MuxCreateUploadResponse {\n url: string\n uploadId: string\n filename: string\n}\n\nconst { logError, throwError } = useErrorHandler()\nconst emitter = useMediaCloudEmitter()\n\nconst MUX_CHUNK_SIZE = 30720\nconst TUS_CHUNK_SIZE = 1024 * 1024\nconst TUS_RETRY_DELAYS = [0, 1000, 2000, 5000]\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 filename = file.name\n try {\n // Request upload URL from Mux\n const response = await fetch(`${serverURL}${apiRoute}/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: `${serverURL}${apiRoute}/mux/asset`,\n })\n\n // Set up event handlers\n uploader.on('error', function () {\n logError(MediaCloudErrors.MUX_UPLOAD_ERROR.message)\n toast.error('Video upload failed')\n emitter.emit('removeUpload', { uploadId })\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 (_error) {\n logError(MediaCloudErrors.MUX_DIRECT_UPLOAD_ERROR.message)\n toast.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, mimeType } = args\n\n const filename = file.name\n const filetype = file.type\n const filesize = file.size.toString()\n\n return new Promise((resolve) => {\n const upload = new tus.Upload(file, {\n endpoint: `${serverURL}${apiRoute}/uploads`,\n retryDelays: TUS_RETRY_DELAYS,\n chunkSize: TUS_CHUNK_SIZE,\n metadata: {\n filetype,\n filesize,\n filename,\n contentType: filetype,\n contentDisposition: 'inline',\n contentLength: filesize,\n },\n onError: function () {\n logError(MediaCloudErrors.TUS_UPLOAD_ERROR.message)\n toast.error('File upload failed')\n resolve(null)\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 onSuccess: function () {\n emitter.emit('uploadComplete', { filename })\n\n // Trigger post upload processing\n fetch(`${serverURL}${apiRoute}/uploads/${filename}/process`)\n },\n onUploadUrlAvailable: async function () {\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\nexport const UploadHandler = createClientUploadHandler({\n handler: async function (args) {\n const { serverURL, apiRoute, file, updateFilename } = args\n console.log('upload handler called', file)\n try {\n const mimeType =\n (await getFileType(file)) || file.type || 'application/octet-stream'\n if (!mimeType) {\n throwError(MediaCloudErrors.FILE_TYPE_UNKNOWN)\n return null\n }\n\n const isVideoFile = await isVideo(file)\n\n // Clone file\n let mappedFile = file\n\n if (!isVideoFile) {\n try {\n // Check if file with same name exists\n const response = await fetch(\n `${serverURL}${apiRoute}/uploads/${file.name}/exists`\n )\n\n // If file exists, generate a cloned file with a unique filename\n if (response.status === 200) {\n log(MediaCloudLogs.S3_STORE_FILE_FOUND)\n\n const newFilename = generateUniqueFilename(file.name)\n mappedFile = new File([file], newFilename, { type: file.type })\n await updateFilename(newFilename)\n }\n } catch (_error) {\n logError(MediaCloudErrors.NAMING_FUNCTION_ERROR.message)\n }\n }\n\n const uploadArgs: UploadArgs = {\n file: mappedFile,\n serverURL,\n apiRoute,\n mimeType,\n }\n\n if (isVideoFile) {\n return await muxUpload(uploadArgs)\n } else {\n return await tusUpload(uploadArgs)\n }\n } catch (error) {\n console.error(\n '[PLUGIN-MEDIA-CLOUD] Upload handler detailed error:',\n error\n )\n logError(MediaCloudErrors.UPLOAD_HANDLER_ERROR.message)\n toast.error(\n `Upload failed: ${error instanceof Error ? error.message : 'Unknown error'}`\n )\n return null\n }\n },\n})\n"],"mappings":"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"}
@@ -21,7 +21,7 @@ function getMuxAssetHandler(args) {
21
21
  pagination: false
22
22
  });
23
23
  if (docs.length > 0) {
24
- const { id, filename } = docs[0];
24
+ const { id } = docs[0];
25
25
  const width = Array.from(asset.tracks ?? []).reduce((max, track) => track.type === "video" && track.max_width ? Math.max(max, track.max_width) : max, 0);
26
26
  const height = Array.from(asset.tracks ?? []).reduce((max, track) => track.type === "video" && track.max_height ? Math.max(max, track.max_height) : max, 0);
27
27
  await payload.update({
@@ -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}\n\nexport function getMuxAssetHandler(\n args: GetMuxAssetHandlerArgs\n): PayloadHandler {\n const { getMuxClient } = 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: 'media',\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, filename } = 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: 'media',\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":";AAQA,SAAgB,mBACd,MACgB;CAChB,MAAM,EAAE,iBAAiB;AAEzB,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,YAAY;KACZ,OAAO,EACL,gBAAgB,EACd,QAAQ,UACT,EACF;KACD,OAAO;KACP,YAAY;KACb,CAAC;AAEF,QAAI,KAAK,SAAS,GAAG;KACnB,MAAM,EAAE,IAAI,aAAa,KAAK;KAE9B,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,YAAY;MACZ;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}\n\nexport function getMuxAssetHandler(\n args: GetMuxAssetHandlerArgs\n): PayloadHandler {\n const { getMuxClient } = 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: 'media',\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: 'media',\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":";AAQA,SAAgB,mBACd,MACgB;CAChB,MAAM,EAAE,iBAAiB;AAEzB,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,YAAY;KACZ,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,YAAY;MACZ;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"}
@@ -44,7 +44,7 @@ async function updateMuxAsset(args) {
44
44
  pagination: false
45
45
  });
46
46
  if (docs.length > 0) {
47
- const { id, filename } = docs[0];
47
+ const { id } = docs[0];
48
48
  const width = Array.from(asset.tracks ?? []).reduce((max, track) => track.type === "video" && track.max_width ? Math.max(max, track.max_width) : max, 0);
49
49
  const height = Array.from(asset.tracks ?? []).reduce((max, track) => track.type === "video" && track.max_height ? Math.max(max, track.max_height) : max, 0);
50
50
  await payload.update({
@@ -1 +1 @@
1
- {"version":3,"file":"muxWebhookHandler.mjs","names":[],"sources":["../../src/endpoints/muxWebhookHandler.ts"],"sourcesContent":["import { useErrorHandler } from '../hooks/useErrorHandler'\nimport { MediaCloudErrors } from '../types/errors'\n\nimport type { Mux } from '@mux/mux-node'\nimport type { BasePayload, PayloadHandler } from 'payload'\nimport type { StaticRenditions } from '../types'\n\ninterface GetMuxWebhookHandlerArgs {\n getMuxClient: () => Mux\n}\n\nconst { logError, log } = useErrorHandler()\n\nexport function getMuxWebhookHandler(\n args: GetMuxWebhookHandlerArgs\n): PayloadHandler {\n const { getMuxClient } = args\n\n return async (req) => {\n const mux = getMuxClient()\n\n try {\n const body = req.text ? await req.text() : ''\n const headers = req.headers\n\n if (!body) {\n logError(MediaCloudErrors.MUX_WEBHOOK_BODY_INVALID.message)\n }\n\n // Verify the webhook signature\n mux.webhooks.verifySignature(body, headers)\n\n // Parse the request body\n const event = JSON.parse(body)\n\n // Handle the event\n switch (event.type) {\n case 'video.asset.created':\n case 'video.asset.errored':\n case 'video.asset.deleted':\n log(`Received Mux webhook: ${event.type}, ${event.object.id}`)\n break\n case 'video.asset.ready':\n case 'video.asset.static_renditions.ready':\n case 'video.asset.static_renditions.deleted':\n await updateMuxAsset({ asset: event.object, payload: req.payload })\n break\n }\n\n return Response.json({ message: 'Webhook received' }, { status: 200 })\n } catch (error) {\n return Response.json(\n { message: error instanceof Error ? error.message : String(error) },\n { status: 500 }\n )\n }\n }\n}\n\ninterface UpdateMuxAssetArgs {\n asset: Mux.Video.Asset\n payload: BasePayload\n}\n\nasync function updateMuxAsset(args: UpdateMuxAssetArgs): Promise<void> {\n const { asset, payload } = args\n\n if (asset.status === 'ready') {\n const { docs } = await payload.find({\n collection: 'media',\n where: {\n 'mux.assetId': {\n equals: asset.id,\n },\n },\n limit: 1,\n pagination: false,\n })\n\n if (docs.length > 0) {\n const { id, filename } = 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: 'media',\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}\n"],"mappings":";;;;AAWA,MAAM,EAAE,UAAU,QAAQ,iBAAiB;AAE3C,SAAgB,qBACd,MACgB;CAChB,MAAM,EAAE,iBAAiB;AAEzB,QAAO,OAAO,QAAQ;EACpB,MAAM,MAAM,cAAc;AAE1B,MAAI;GACF,MAAM,OAAO,IAAI,OAAO,MAAM,IAAI,MAAM,GAAG;GAC3C,MAAM,UAAU,IAAI;AAEpB,OAAI,CAAC,KACH,UAAS,iBAAiB,yBAAyB,QAAQ;AAI7D,OAAI,SAAS,gBAAgB,MAAM,QAAQ;GAG3C,MAAM,QAAQ,KAAK,MAAM,KAAK;AAG9B,WAAQ,MAAM,MAAd;IACE,KAAK;IACL,KAAK;IACL,KAAK;AACH,SAAI,yBAAyB,MAAM,KAAK,IAAI,MAAM,OAAO,KAAK;AAC9D;IACF,KAAK;IACL,KAAK;IACL,KAAK;AACH,WAAM,eAAe;MAAE,OAAO,MAAM;MAAQ,SAAS,IAAI;MAAS,CAAC;AACnE;;AAGJ,UAAO,SAAS,KAAK,EAAE,SAAS,oBAAoB,EAAE,EAAE,QAAQ,KAAK,CAAC;WAC/D,OAAO;AACd,UAAO,SAAS,KACd,EAAE,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAAE,EACnE,EAAE,QAAQ,KAAK,CAChB;;;;AAUP,eAAe,eAAe,MAAyC;CACrE,MAAM,EAAE,OAAO,YAAY;AAE3B,KAAI,MAAM,WAAW,SAAS;EAC5B,MAAM,EAAE,SAAS,MAAM,QAAQ,KAAK;GAClC,YAAY;GACZ,OAAO,EACL,eAAe,EACb,QAAQ,MAAM,IACf,EACF;GACD,OAAO;GACP,YAAY;GACb,CAAC;AAEF,MAAI,KAAK,SAAS,GAAG;GACnB,MAAM,EAAE,IAAI,aAAa,KAAK;GAE9B,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;GAED,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,SAAM,QAAQ,OAAO;IACnB,YAAY;IACZ;IACA,MAAM;KACJ,KAAK;MACH,QAAQ,MAAM;MACd,SAAS,MAAM;MACf,YAAY,MAAM,eAAe,IAAI;MACrC,aAAa,MAAM;MACnB,UAAU,MAAM;MAChB,QAAQ,MAAM;MACd,mBAAmB,MAAM;MACzB,cAAc,MAAM;MACpB,kBAAkB,MAAM;MACzB;KACD;KACA;KACD;IACF,CAAC"}
1
+ {"version":3,"file":"muxWebhookHandler.mjs","names":[],"sources":["../../src/endpoints/muxWebhookHandler.ts"],"sourcesContent":["import { useErrorHandler } from '../hooks/useErrorHandler'\nimport { MediaCloudErrors } from '../types/errors'\n\nimport type { Mux } from '@mux/mux-node'\nimport type { BasePayload, PayloadHandler } from 'payload'\nimport type { StaticRenditions } from '../types'\n\ninterface GetMuxWebhookHandlerArgs {\n getMuxClient: () => Mux\n}\n\nconst { logError, log } = useErrorHandler()\n\nexport function getMuxWebhookHandler(\n args: GetMuxWebhookHandlerArgs\n): PayloadHandler {\n const { getMuxClient } = args\n\n return async (req) => {\n const mux = getMuxClient()\n\n try {\n const body = req.text ? await req.text() : ''\n const headers = req.headers\n\n if (!body) {\n logError(MediaCloudErrors.MUX_WEBHOOK_BODY_INVALID.message)\n }\n\n // Verify the webhook signature\n mux.webhooks.verifySignature(body, headers)\n\n // Parse the request body\n const event = JSON.parse(body)\n\n // Handle the event\n switch (event.type) {\n case 'video.asset.created':\n case 'video.asset.errored':\n case 'video.asset.deleted':\n log(`Received Mux webhook: ${event.type}, ${event.object.id}`)\n break\n case 'video.asset.ready':\n case 'video.asset.static_renditions.ready':\n case 'video.asset.static_renditions.deleted':\n await updateMuxAsset({ asset: event.object, payload: req.payload })\n break\n }\n\n return Response.json({ message: 'Webhook received' }, { status: 200 })\n } catch (error) {\n return Response.json(\n { message: error instanceof Error ? error.message : String(error) },\n { status: 500 }\n )\n }\n }\n}\n\ninterface UpdateMuxAssetArgs {\n asset: Mux.Video.Asset\n payload: BasePayload\n}\n\nasync function updateMuxAsset(args: UpdateMuxAssetArgs): Promise<void> {\n const { asset, payload } = args\n\n if (asset.status === 'ready') {\n const { docs } = await payload.find({\n collection: 'media',\n where: {\n 'mux.assetId': {\n equals: asset.id,\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: 'media',\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}\n"],"mappings":";;;;AAWA,MAAM,EAAE,UAAU,QAAQ,iBAAiB;AAE3C,SAAgB,qBACd,MACgB;CAChB,MAAM,EAAE,iBAAiB;AAEzB,QAAO,OAAO,QAAQ;EACpB,MAAM,MAAM,cAAc;AAE1B,MAAI;GACF,MAAM,OAAO,IAAI,OAAO,MAAM,IAAI,MAAM,GAAG;GAC3C,MAAM,UAAU,IAAI;AAEpB,OAAI,CAAC,KACH,UAAS,iBAAiB,yBAAyB,QAAQ;AAI7D,OAAI,SAAS,gBAAgB,MAAM,QAAQ;GAG3C,MAAM,QAAQ,KAAK,MAAM,KAAK;AAG9B,WAAQ,MAAM,MAAd;IACE,KAAK;IACL,KAAK;IACL,KAAK;AACH,SAAI,yBAAyB,MAAM,KAAK,IAAI,MAAM,OAAO,KAAK;AAC9D;IACF,KAAK;IACL,KAAK;IACL,KAAK;AACH,WAAM,eAAe;MAAE,OAAO,MAAM;MAAQ,SAAS,IAAI;MAAS,CAAC;AACnE;;AAGJ,UAAO,SAAS,KAAK,EAAE,SAAS,oBAAoB,EAAE,EAAE,QAAQ,KAAK,CAAC;WAC/D,OAAO;AACd,UAAO,SAAS,KACd,EAAE,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAAE,EACnE,EAAE,QAAQ,KAAK,CAChB;;;;AAUP,eAAe,eAAe,MAAyC;CACrE,MAAM,EAAE,OAAO,YAAY;AAE3B,KAAI,MAAM,WAAW,SAAS;EAC5B,MAAM,EAAE,SAAS,MAAM,QAAQ,KAAK;GAClC,YAAY;GACZ,OAAO,EACL,eAAe,EACb,QAAQ,MAAM,IACf,EACF;GACD,OAAO;GACP,YAAY;GACb,CAAC;AAEF,MAAI,KAAK,SAAS,GAAG;GACnB,MAAM,EAAE,OAAO,KAAK;GAEpB,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;GAED,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,SAAM,QAAQ,OAAO;IACnB,YAAY;IACZ;IACA,MAAM;KACJ,KAAK;MACH,QAAQ,MAAM;MACd,SAAS,MAAM;MACf,YAAY,MAAM,eAAe,IAAI;MACrC,aAAa,MAAM;MACnB,UAAU,MAAM;MAChB,QAAQ,MAAM;MACd,mBAAmB,MAAM;MACzB,cAAc,MAAM;MACpB,kBAAkB,MAAM;MACzB;KACD;KACA;KACD;IACF,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { S3Store } from "../tus/stores/s3/s3-store.mjs";
2
+ import { PayloadHandler } from "payload";
3
+
4
+ //#region src/endpoints/tusFileExistsHandler.d.ts
5
+ interface GetTusPostProcessorHandlerArgs {
6
+ s3Store: S3Store;
7
+ }
8
+ declare function getTusFileExistsHandler(args: GetTusPostProcessorHandlerArgs): PayloadHandler;
9
+ //#endregion
10
+ export { getTusFileExistsHandler };
11
+ //# sourceMappingURL=tusFileExistsHandler.d.mts.map
@@ -0,0 +1,25 @@
1
+ import { MediaCloudErrors } from "../types/errors.mjs";
2
+ import { useErrorHandler } from "../hooks/useErrorHandler.mjs";
3
+
4
+ //#region src/endpoints/tusFileExistsHandler.ts
5
+ function getTusFileExistsHandler(args) {
6
+ const { s3Store } = args;
7
+ const { throwError, logError } = useErrorHandler();
8
+ return async function(req) {
9
+ try {
10
+ const { routeParams } = req;
11
+ const filename = routeParams?.filename;
12
+ if (!filename) throwError(MediaCloudErrors.FILE_MISSING_NAME);
13
+ const url = s3Store.getUrl(filename);
14
+ if ((await fetch(url)).status === 200) return Response.json({ message: "File found" }, { status: 200 });
15
+ return Response.json({ message: "File not found" }, { status: 404 });
16
+ } catch (_error) {
17
+ logError(MediaCloudErrors.FILE_DIMENSIONS_ERROR.message);
18
+ return Response.json({ message: "Failed to process asset" }, { status: 500 });
19
+ }
20
+ };
21
+ }
22
+
23
+ //#endregion
24
+ export { getTusFileExistsHandler };
25
+ //# sourceMappingURL=tusFileExistsHandler.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tusFileExistsHandler.mjs","names":[],"sources":["../../src/endpoints/tusFileExistsHandler.ts"],"sourcesContent":["import type { PayloadHandler } from 'payload'\nimport { useErrorHandler } from '../hooks/useErrorHandler'\nimport { MediaCloudErrors } from '../types/errors'\n\nimport { S3Store } from '../tus/stores/s3/s3-store'\n\ninterface GetTusPostProcessorHandlerArgs {\n s3Store: S3Store\n}\n\nexport function getTusFileExistsHandler(\n args: GetTusPostProcessorHandlerArgs\n): PayloadHandler {\n const { s3Store } = args\n const { throwError, logError } = useErrorHandler()\n\n return async function (req) {\n try {\n const { routeParams } = req\n const filename = routeParams?.filename as string\n\n if (!filename) {\n throwError(MediaCloudErrors.FILE_MISSING_NAME)\n }\n\n const url = s3Store.getUrl(filename)\n const response = await fetch(url)\n\n if (response.status === 200) {\n return Response.json({ message: 'File found' }, { 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":";;;;AAUA,SAAgB,wBACd,MACgB;CAChB,MAAM,EAAE,YAAY;CACpB,MAAM,EAAE,YAAY,aAAa,iBAAiB;AAElD,QAAO,eAAgB,KAAK;AAC1B,MAAI;GACF,MAAM,EAAE,gBAAgB;GACxB,MAAM,WAAW,aAAa;AAE9B,OAAI,CAAC,SACH,YAAW,iBAAiB,kBAAkB;GAGhD,MAAM,MAAM,QAAQ,OAAO,SAAS;AAGpC,QAFiB,MAAM,MAAM,IAAI,EAEpB,WAAW,IACtB,QAAO,SAAS,KAAK,EAAE,SAAS,cAAc,EAAE,EAAE,QAAQ,KAAK,CAAC;AAGlE,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"}
@@ -114,6 +114,7 @@ declare enum MediaCloudLogs {
114
114
  S3_STORE_READ_RETRY = "Failed to read file, trying again",
115
115
  S3_STORE_READ_FAILED = "Failed to read file",
116
116
  S3_STORE_FILE_NOT_FOUND = "No file found",
117
+ S3_STORE_FILE_FOUND = "File found",
117
118
  S3_STORE_RETRIEVE_PARTS_ERROR = "Error retrieving parts",
118
119
  S3_STORE_METADATA_SAVING = "Saving metadata",
119
120
  S3_STORE_METADATA_SAVED = "Metadata file saved",
@@ -114,6 +114,7 @@ let MediaCloudLogs = /* @__PURE__ */ function(MediaCloudLogs$1) {
114
114
  MediaCloudLogs$1["S3_STORE_READ_RETRY"] = "Failed to read file, trying again";
115
115
  MediaCloudLogs$1["S3_STORE_READ_FAILED"] = "Failed to read file";
116
116
  MediaCloudLogs$1["S3_STORE_FILE_NOT_FOUND"] = "No file found";
117
+ MediaCloudLogs$1["S3_STORE_FILE_FOUND"] = "File found";
117
118
  MediaCloudLogs$1["S3_STORE_RETRIEVE_PARTS_ERROR"] = "Error retrieving parts";
118
119
  MediaCloudLogs$1["S3_STORE_METADATA_SAVING"] = "Saving metadata";
119
120
  MediaCloudLogs$1["S3_STORE_METADATA_SAVED"] = "Metadata file saved";
@@ -1 +1 @@
1
- {"version":3,"file":"errors.mjs","names":[],"sources":["../../src/types/errors.ts"],"sourcesContent":["export const MediaCloudErrors = {\n // Mux Errors\n MUX_CONFIG_MISSING: {\n message:\n 'Mux configuration (tokenId and tokenSecret) must be provided in pluginOptions to use Mux',\n errorCode: 400,\n },\n MUX_CONFIG_INCOMPLETE: {\n message: 'Mux configuration is missing. Mux features will not be available',\n errorCode: 400,\n },\n MUX_UPLOAD_ID_MISSING: {\n message: 'No upload-id found for upload',\n errorCode: 400,\n },\n MUX_ASSET_DELETE_ERROR: {\n message: 'Error deleting Mux asset',\n errorCode: 500,\n },\n MUX_UPLOAD_ERROR: {\n message: 'Mux video upload failed',\n errorCode: 500,\n },\n MUX_DIRECT_UPLOAD_ERROR: {\n message: 'Mux direct upload failed',\n errorCode: 500,\n },\n MUX_CREATE_UPLOAD_ERROR: {\n message: 'Error in Mux create upload handler',\n errorCode: 500,\n },\n MUX_REQUEST_NO_JSON: {\n message: 'Request does not support json() method',\n errorCode: 400,\n },\n MUX_WEBHOOK_BODY_INVALID: {\n message: 'Invalid Mux webhook body',\n errorCode: 400,\n },\n\n // S3 Errors\n S3_CONFIG_MISSING: {\n message:\n 'S3 configuration (bucket, region, accessKeyId, secretAccessKey) must be provided in pluginOptions',\n errorCode: 400,\n },\n S3_DELETE_ERROR: {\n message: 'Error deleting file from S3',\n errorCode: 500,\n },\n S3_GET_OBJECT_ERROR: {\n message: 'Error getting object from S3',\n errorCode: 500,\n },\n S3_UNIQUE_NAME_ERROR: {\n message: 'Could not find a unique file name after maximum tries',\n errorCode: 500,\n },\n\n // TUS Errors\n TUS_UPLOAD_ERROR: {\n message: 'TUS file upload error occurred',\n errorCode: 500,\n },\n\n // General Errors\n UNKNOWN_STORAGE_TYPE: {\n message: 'Unknown storage type for media',\n errorCode: 500,\n },\n\n // File Errors\n FILE_TYPE_UNKNOWN: {\n message: 'Unable to determine file type',\n errorCode: 400,\n },\n FILE_TYPE_ERROR: {\n message: 'Error determining file type',\n errorCode: 500,\n },\n FILENAME_SANITIZE_ERROR: {\n message: 'Error sanitizing filename',\n errorCode: 500,\n },\n FILE_MISSING_NAME: {\n message: 'Filename is missing, cannot parse file',\n errorCode: 500,\n },\n FILE_NOT_FOUND: {\n message: 'File not found',\n errorCode: 404,\n },\n FILE_DIMENSIONS_ERROR: {\n message: 'Error setting media dimensions',\n errorCode: 500,\n },\n\n // Upload Errors\n UPLOAD_NO_URL: {\n message: 'No upload URL provided, cannot parse upload ID',\n errorCode: 400,\n },\n UPLOAD_HANDLER_ERROR: {\n message: 'Upload handler error occurred',\n errorCode: 500,\n },\n UPLOAD_POLLING_ERROR: {\n message: 'Polling error for upload',\n errorCode: 500,\n },\n\n // Plugin Errors\n PLUGIN_NOT_CONFIGURED: {\n message: 'Payload Media Cloud plugin is not configured',\n errorCode: 500,\n },\n NAMING_FUNCTION_ERROR: {\n message: 'Error in namingFunction',\n errorCode: 500,\n },\n} as const\n\nexport enum MediaCloudLogs {\n S3_STORE_MULTIPART_INIT = 'Initializing multipart upload',\n S3_STORE_MULTIPART_CREATED = 'Multipart upload created',\n S3_STORE_UPLOAD_FAILED = 'Failed to finish upload',\n S3_STORE_READ_ATTEMPT = 'Attempting to read file from S3',\n S3_STORE_READ_SUCCESS = 'Successfully read file from S3',\n S3_STORE_READ_RETRY = 'Failed to read file, trying again',\n S3_STORE_READ_FAILED = 'Failed to read file',\n S3_STORE_FILE_NOT_FOUND = 'No file found',\n S3_STORE_RETRIEVE_PARTS_ERROR = 'Error retrieving parts',\n S3_STORE_METADATA_SAVING = 'Saving metadata',\n S3_STORE_METADATA_SAVED = 'Metadata file saved',\n S3_STORE_METADATA_CACHE_CLEARED = 'Removing cached data',\n S3_STORE_INCOMPLETE_PART_UPLOADED = 'Finished uploading incomplete part',\n S3_STORE_CHUNK_REMOVAL_FAILED = 'Failed to remove chunk',\n}\n"],"mappings":";AAAA,MAAa,mBAAmB;CAE9B,oBAAoB;EAClB,SACE;EACF,WAAW;EACZ;CACD,uBAAuB;EACrB,SAAS;EACT,WAAW;EACZ;CACD,uBAAuB;EACrB,SAAS;EACT,WAAW;EACZ;CACD,wBAAwB;EACtB,SAAS;EACT,WAAW;EACZ;CACD,kBAAkB;EAChB,SAAS;EACT,WAAW;EACZ;CACD,yBAAyB;EACvB,SAAS;EACT,WAAW;EACZ;CACD,yBAAyB;EACvB,SAAS;EACT,WAAW;EACZ;CACD,qBAAqB;EACnB,SAAS;EACT,WAAW;EACZ;CACD,0BAA0B;EACxB,SAAS;EACT,WAAW;EACZ;CAGD,mBAAmB;EACjB,SACE;EACF,WAAW;EACZ;CACD,iBAAiB;EACf,SAAS;EACT,WAAW;EACZ;CACD,qBAAqB;EACnB,SAAS;EACT,WAAW;EACZ;CACD,sBAAsB;EACpB,SAAS;EACT,WAAW;EACZ;CAGD,kBAAkB;EAChB,SAAS;EACT,WAAW;EACZ;CAGD,sBAAsB;EACpB,SAAS;EACT,WAAW;EACZ;CAGD,mBAAmB;EACjB,SAAS;EACT,WAAW;EACZ;CACD,iBAAiB;EACf,SAAS;EACT,WAAW;EACZ;CACD,yBAAyB;EACvB,SAAS;EACT,WAAW;EACZ;CACD,mBAAmB;EACjB,SAAS;EACT,WAAW;EACZ;CACD,gBAAgB;EACd,SAAS;EACT,WAAW;EACZ;CACD,uBAAuB;EACrB,SAAS;EACT,WAAW;EACZ;CAGD,eAAe;EACb,SAAS;EACT,WAAW;EACZ;CACD,sBAAsB;EACpB,SAAS;EACT,WAAW;EACZ;CACD,sBAAsB;EACpB,SAAS;EACT,WAAW;EACZ;CAGD,uBAAuB;EACrB,SAAS;EACT,WAAW;EACZ;CACD,uBAAuB;EACrB,SAAS;EACT,WAAW;EACZ;CACF;AAED,IAAY,4DAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
1
+ {"version":3,"file":"errors.mjs","names":[],"sources":["../../src/types/errors.ts"],"sourcesContent":["export const MediaCloudErrors = {\n // Mux Errors\n MUX_CONFIG_MISSING: {\n message:\n 'Mux configuration (tokenId and tokenSecret) must be provided in pluginOptions to use Mux',\n errorCode: 400,\n },\n MUX_CONFIG_INCOMPLETE: {\n message: 'Mux configuration is missing. Mux features will not be available',\n errorCode: 400,\n },\n MUX_UPLOAD_ID_MISSING: {\n message: 'No upload-id found for upload',\n errorCode: 400,\n },\n MUX_ASSET_DELETE_ERROR: {\n message: 'Error deleting Mux asset',\n errorCode: 500,\n },\n MUX_UPLOAD_ERROR: {\n message: 'Mux video upload failed',\n errorCode: 500,\n },\n MUX_DIRECT_UPLOAD_ERROR: {\n message: 'Mux direct upload failed',\n errorCode: 500,\n },\n MUX_CREATE_UPLOAD_ERROR: {\n message: 'Error in Mux create upload handler',\n errorCode: 500,\n },\n MUX_REQUEST_NO_JSON: {\n message: 'Request does not support json() method',\n errorCode: 400,\n },\n MUX_WEBHOOK_BODY_INVALID: {\n message: 'Invalid Mux webhook body',\n errorCode: 400,\n },\n\n // S3 Errors\n S3_CONFIG_MISSING: {\n message:\n 'S3 configuration (bucket, region, accessKeyId, secretAccessKey) must be provided in pluginOptions',\n errorCode: 400,\n },\n S3_DELETE_ERROR: {\n message: 'Error deleting file from S3',\n errorCode: 500,\n },\n S3_GET_OBJECT_ERROR: {\n message: 'Error getting object from S3',\n errorCode: 500,\n },\n S3_UNIQUE_NAME_ERROR: {\n message: 'Could not find a unique file name after maximum tries',\n errorCode: 500,\n },\n\n // TUS Errors\n TUS_UPLOAD_ERROR: {\n message: 'TUS file upload error occurred',\n errorCode: 500,\n },\n\n // General Errors\n UNKNOWN_STORAGE_TYPE: {\n message: 'Unknown storage type for media',\n errorCode: 500,\n },\n\n // File Errors\n FILE_TYPE_UNKNOWN: {\n message: 'Unable to determine file type',\n errorCode: 400,\n },\n FILE_TYPE_ERROR: {\n message: 'Error determining file type',\n errorCode: 500,\n },\n FILENAME_SANITIZE_ERROR: {\n message: 'Error sanitizing filename',\n errorCode: 500,\n },\n FILE_MISSING_NAME: {\n message: 'Filename is missing, cannot parse file',\n errorCode: 500,\n },\n FILE_NOT_FOUND: {\n message: 'File not found',\n errorCode: 404,\n },\n FILE_DIMENSIONS_ERROR: {\n message: 'Error setting media dimensions',\n errorCode: 500,\n },\n\n // Upload Errors\n UPLOAD_NO_URL: {\n message: 'No upload URL provided, cannot parse upload ID',\n errorCode: 400,\n },\n UPLOAD_HANDLER_ERROR: {\n message: 'Upload handler error occurred',\n errorCode: 500,\n },\n UPLOAD_POLLING_ERROR: {\n message: 'Polling error for upload',\n errorCode: 500,\n },\n\n // Plugin Errors\n PLUGIN_NOT_CONFIGURED: {\n message: 'Payload Media Cloud plugin is not configured',\n errorCode: 500,\n },\n NAMING_FUNCTION_ERROR: {\n message: 'Error in namingFunction',\n errorCode: 500,\n },\n} as const\n\nexport enum MediaCloudLogs {\n S3_STORE_MULTIPART_INIT = 'Initializing multipart upload',\n S3_STORE_MULTIPART_CREATED = 'Multipart upload created',\n S3_STORE_UPLOAD_FAILED = 'Failed to finish upload',\n S3_STORE_READ_ATTEMPT = 'Attempting to read file from S3',\n S3_STORE_READ_SUCCESS = 'Successfully read file from S3',\n S3_STORE_READ_RETRY = 'Failed to read file, trying again',\n S3_STORE_READ_FAILED = 'Failed to read file',\n S3_STORE_FILE_NOT_FOUND = 'No file found',\n S3_STORE_FILE_FOUND = 'File found',\n S3_STORE_RETRIEVE_PARTS_ERROR = 'Error retrieving parts',\n S3_STORE_METADATA_SAVING = 'Saving metadata',\n S3_STORE_METADATA_SAVED = 'Metadata file saved',\n S3_STORE_METADATA_CACHE_CLEARED = 'Removing cached data',\n S3_STORE_INCOMPLETE_PART_UPLOADED = 'Finished uploading incomplete part',\n S3_STORE_CHUNK_REMOVAL_FAILED = 'Failed to remove chunk',\n}\n"],"mappings":";AAAA,MAAa,mBAAmB;CAE9B,oBAAoB;EAClB,SACE;EACF,WAAW;EACZ;CACD,uBAAuB;EACrB,SAAS;EACT,WAAW;EACZ;CACD,uBAAuB;EACrB,SAAS;EACT,WAAW;EACZ;CACD,wBAAwB;EACtB,SAAS;EACT,WAAW;EACZ;CACD,kBAAkB;EAChB,SAAS;EACT,WAAW;EACZ;CACD,yBAAyB;EACvB,SAAS;EACT,WAAW;EACZ;CACD,yBAAyB;EACvB,SAAS;EACT,WAAW;EACZ;CACD,qBAAqB;EACnB,SAAS;EACT,WAAW;EACZ;CACD,0BAA0B;EACxB,SAAS;EACT,WAAW;EACZ;CAGD,mBAAmB;EACjB,SACE;EACF,WAAW;EACZ;CACD,iBAAiB;EACf,SAAS;EACT,WAAW;EACZ;CACD,qBAAqB;EACnB,SAAS;EACT,WAAW;EACZ;CACD,sBAAsB;EACpB,SAAS;EACT,WAAW;EACZ;CAGD,kBAAkB;EAChB,SAAS;EACT,WAAW;EACZ;CAGD,sBAAsB;EACpB,SAAS;EACT,WAAW;EACZ;CAGD,mBAAmB;EACjB,SAAS;EACT,WAAW;EACZ;CACD,iBAAiB;EACf,SAAS;EACT,WAAW;EACZ;CACD,yBAAyB;EACvB,SAAS;EACT,WAAW;EACZ;CACD,mBAAmB;EACjB,SAAS;EACT,WAAW;EACZ;CACD,gBAAgB;EACd,SAAS;EACT,WAAW;EACZ;CACD,uBAAuB;EACrB,SAAS;EACT,WAAW;EACZ;CAGD,eAAe;EACb,SAAS;EACT,WAAW;EACZ;CACD,sBAAsB;EACpB,SAAS;EACT,WAAW;EACZ;CACD,sBAAsB;EACpB,SAAS;EACT,WAAW;EACZ;CAGD,uBAAuB;EACrB,SAAS;EACT,WAAW;EACZ;CACD,uBAAuB;EACrB,SAAS;EACT,WAAW;EACZ;CACF;AAED,IAAY,4DAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA"}
@@ -1,28 +1,15 @@
1
- import { MediaCloudErrors } from "../types/errors.mjs";
2
- import { useErrorHandler } from "../hooks/useErrorHandler.mjs";
3
1
  import { generateUniqueFilename } from "./file.mjs";
4
2
  import { getTusPostProcessorHandler } from "../endpoints/tusPostProcessorHandler.mjs";
3
+ import { getTusFileExistsHandler } from "../endpoints/tusFileExistsHandler.mjs";
5
4
  import { Server } from "@tus/server";
6
5
 
7
6
  //#region src/utils/tus.ts
8
- const { logError } = useErrorHandler();
9
7
  function createTusServer(args) {
10
8
  const { s3Store, pluginOptions } = args;
11
9
  return new Server({
12
10
  datastore: s3Store,
13
11
  namingFunction: async (_req, metadata) => {
14
- try {
15
- const { client, bucket } = s3Store;
16
- if (!metadata?.filename) return generateUniqueFilename("");
17
- if (await client.getObject({
18
- Key: metadata?.filename ?? "",
19
- Bucket: bucket
20
- }).catch(() => logError(MediaCloudErrors.S3_GET_OBJECT_ERROR.message))) return generateUniqueFilename(metadata?.filename ?? "");
21
- else return metadata.filename;
22
- } catch (_error) {
23
- logError(MediaCloudErrors.NAMING_FUNCTION_ERROR.message);
24
- return metadata?.filename ?? generateUniqueFilename("");
25
- }
12
+ return metadata?.filename ?? generateUniqueFilename("");
26
13
  },
27
14
  path: "/api/uploads",
28
15
  respectForwardedHeaders: pluginOptions.s3.respectForwardedHeaders ?? true
@@ -69,6 +56,11 @@ function createTusEndpoints(args) {
69
56
  method: "delete",
70
57
  path: "/uploads/:id"
71
58
  },
59
+ {
60
+ handler: getTusFileExistsHandler({ s3Store }),
61
+ method: "get",
62
+ path: "/uploads/:filename/exists"
63
+ },
72
64
  {
73
65
  handler: getTusPostProcessorHandler({ s3Store }),
74
66
  method: "get",
@@ -1 +1 @@
1
- {"version":3,"file":"tus.mjs","names":["TusServer"],"sources":["../../src/utils/tus.ts"],"sourcesContent":["import { getPayload, sanitizeConfig } from 'payload'\nimport { Server as TusServer, type DataStore } from '@tus/server'\n\nimport { MediaCloudErrors } from '../types/errors'\nimport { generateUniqueFilename } from '../utils/file'\nimport { useErrorHandler } from '../hooks/useErrorHandler'\n\nimport { getTusPostProcessorHandler } from '../endpoints/tusPostProcessorHandler'\n\nimport type { S3Store } from '../tus/stores/s3/s3-store'\nimport type { Config, PayloadRequest } from 'payload'\nimport type { MediaCloudPluginOptions } from '../types'\n\nconst { logError } = useErrorHandler()\n\n/**\n * Creates a TUS server instance with S3 storage\n * @param args - The arguments for creating the TUS server\n * @returns A configured TusServer instance\n */\ninterface CreateTusServerArgs {\n s3Store: S3Store\n pluginOptions: MediaCloudPluginOptions\n}\n\nexport function createTusServer(args: CreateTusServerArgs): TusServer {\n const { s3Store, pluginOptions } = args\n\n return new TusServer({\n datastore: s3Store,\n namingFunction: async (_req, metadata) => {\n try {\n const { client, bucket } = s3Store\n if (!metadata?.filename) {\n return generateUniqueFilename('')\n }\n\n // Check if a file with the same name already exists\n const file = await client\n .getObject({\n Key: metadata?.filename ?? '',\n Bucket: bucket,\n })\n .catch(() => logError(MediaCloudErrors.S3_GET_OBJECT_ERROR.message))\n\n if (file) {\n return generateUniqueFilename(metadata?.filename ?? '')\n } else {\n return metadata.filename\n }\n } catch (_error) {\n logError(MediaCloudErrors.NAMING_FUNCTION_ERROR.message)\n return metadata?.filename ?? generateUniqueFilename('')\n }\n },\n path: '/api/uploads',\n respectForwardedHeaders: pluginOptions.s3.respectForwardedHeaders ?? true,\n })\n}\n\n/**\n * Creates TUS upload endpoints for file handling\n * @param tusServer - The TUS server instance\n * @returns An array of endpoint configurations\n */\ninterface CreateTusEndpointsArgs {\n tusServer: TusServer\n s3Store: S3Store\n}\n\nexport function createTusEndpoints(args: CreateTusEndpointsArgs) {\n const { tusServer, s3Store } = args\n\n /**\n * Handles TUS requests through the server\n * @param req - The payload request object\n * @returns The server response\n */\n function tusHandler(req: PayloadRequest) {\n return tusServer.handleWeb(req as Request)\n }\n\n return [\n { handler: tusHandler, method: 'options' as const, path: '/uploads' },\n { handler: tusHandler, method: 'post' as const, path: '/uploads' },\n { handler: tusHandler, method: 'get' as const, path: '/uploads/:id' },\n { handler: tusHandler, method: 'put' as const, path: '/uploads/:id' },\n { handler: tusHandler, method: 'patch' as const, path: '/uploads/:id' },\n { handler: tusHandler, method: 'delete' as const, path: '/uploads/:id' },\n {\n handler: getTusPostProcessorHandler({ s3Store }),\n method: 'get' as const,\n path: '/uploads/:filename/process',\n },\n ]\n}\n"],"mappings":";;;;;;;AAaA,MAAM,EAAE,aAAa,iBAAiB;AAYtC,SAAgB,gBAAgB,MAAsC;CACpE,MAAM,EAAE,SAAS,kBAAkB;AAEnC,QAAO,IAAIA,OAAU;EACnB,WAAW;EACX,gBAAgB,OAAO,MAAM,aAAa;AACxC,OAAI;IACF,MAAM,EAAE,QAAQ,WAAW;AAC3B,QAAI,CAAC,UAAU,SACb,QAAO,uBAAuB,GAAG;AAWnC,QAPa,MAAM,OAChB,UAAU;KACT,KAAK,UAAU,YAAY;KAC3B,QAAQ;KACT,CAAC,CACD,YAAY,SAAS,iBAAiB,oBAAoB,QAAQ,CAAC,CAGpE,QAAO,uBAAuB,UAAU,YAAY,GAAG;QAEvD,QAAO,SAAS;YAEX,QAAQ;AACf,aAAS,iBAAiB,sBAAsB,QAAQ;AACxD,WAAO,UAAU,YAAY,uBAAuB,GAAG;;;EAG3D,MAAM;EACN,yBAAyB,cAAc,GAAG,2BAA2B;EACtE,CAAC;;AAaJ,SAAgB,mBAAmB,MAA8B;CAC/D,MAAM,EAAE,WAAW,YAAY;;;;;;CAO/B,SAAS,WAAW,KAAqB;AACvC,SAAO,UAAU,UAAU,IAAe;;AAG5C,QAAO;EACL;GAAE,SAAS;GAAY,QAAQ;GAAoB,MAAM;GAAY;EACrE;GAAE,SAAS;GAAY,QAAQ;GAAiB,MAAM;GAAY;EAClE;GAAE,SAAS;GAAY,QAAQ;GAAgB,MAAM;GAAgB;EACrE;GAAE,SAAS;GAAY,QAAQ;GAAgB,MAAM;GAAgB;EACrE;GAAE,SAAS;GAAY,QAAQ;GAAkB,MAAM;GAAgB;EACvE;GAAE,SAAS;GAAY,QAAQ;GAAmB,MAAM;GAAgB;EACxE;GACE,SAAS,2BAA2B,EAAE,SAAS,CAAC;GAChD,QAAQ;GACR,MAAM;GACP;EACF"}
1
+ {"version":3,"file":"tus.mjs","names":["TusServer"],"sources":["../../src/utils/tus.ts"],"sourcesContent":["import { Server as TusServer } from '@tus/server'\n\nimport { getTusPostProcessorHandler } from '../endpoints/tusPostProcessorHandler'\nimport { getTusFileExistsHandler } from '../endpoints/tusFileExistsHandler'\n\nimport { generateUniqueFilename } from './file'\n\nimport type { S3Store } from '../tus/stores/s3/s3-store'\nimport type { PayloadRequest } from 'payload'\nimport type { MediaCloudPluginOptions } from '../types'\n\n/**\n * Creates a TUS server instance with S3 storage\n * @param args - The arguments for creating the TUS server\n * @returns A configured TusServer instance\n */\ninterface CreateTusServerArgs {\n s3Store: S3Store\n pluginOptions: MediaCloudPluginOptions\n}\n\nexport function createTusServer(args: CreateTusServerArgs): TusServer {\n const { s3Store, pluginOptions } = args\n\n return new TusServer({\n datastore: s3Store,\n namingFunction: async (_req, metadata) => {\n return metadata?.filename ?? generateUniqueFilename('')\n },\n path: '/api/uploads',\n respectForwardedHeaders: pluginOptions.s3.respectForwardedHeaders ?? true,\n })\n}\n\n/**\n * Creates TUS upload endpoints for file handling\n * @param tusServer - The TUS server instance\n * @returns An array of endpoint configurations\n */\ninterface CreateTusEndpointsArgs {\n tusServer: TusServer\n s3Store: S3Store\n}\n\nexport function createTusEndpoints(args: CreateTusEndpointsArgs) {\n const { tusServer, s3Store } = args\n\n /**\n * Handles TUS requests through the server\n * @param req - The payload request object\n * @returns The server response\n */\n function tusHandler(req: PayloadRequest) {\n return tusServer.handleWeb(req as Request)\n }\n\n return [\n { handler: tusHandler, method: 'options' as const, path: '/uploads' },\n { handler: tusHandler, method: 'post' as const, path: '/uploads' },\n { handler: tusHandler, method: 'get' as const, path: '/uploads/:id' },\n { handler: tusHandler, method: 'put' as const, path: '/uploads/:id' },\n { handler: tusHandler, method: 'patch' as const, path: '/uploads/:id' },\n { handler: tusHandler, method: 'delete' as const, path: '/uploads/:id' },\n {\n handler: getTusFileExistsHandler({ s3Store }),\n method: 'get' as const,\n path: '/uploads/:filename/exists',\n },\n {\n handler: getTusPostProcessorHandler({ s3Store }),\n method: 'get' as const,\n path: '/uploads/:filename/process',\n },\n ]\n}\n"],"mappings":";;;;;;AAqBA,SAAgB,gBAAgB,MAAsC;CACpE,MAAM,EAAE,SAAS,kBAAkB;AAEnC,QAAO,IAAIA,OAAU;EACnB,WAAW;EACX,gBAAgB,OAAO,MAAM,aAAa;AACxC,UAAO,UAAU,YAAY,uBAAuB,GAAG;;EAEzD,MAAM;EACN,yBAAyB,cAAc,GAAG,2BAA2B;EACtE,CAAC;;AAaJ,SAAgB,mBAAmB,MAA8B;CAC/D,MAAM,EAAE,WAAW,YAAY;;;;;;CAO/B,SAAS,WAAW,KAAqB;AACvC,SAAO,UAAU,UAAU,IAAe;;AAG5C,QAAO;EACL;GAAE,SAAS;GAAY,QAAQ;GAAoB,MAAM;GAAY;EACrE;GAAE,SAAS;GAAY,QAAQ;GAAiB,MAAM;GAAY;EAClE;GAAE,SAAS;GAAY,QAAQ;GAAgB,MAAM;GAAgB;EACrE;GAAE,SAAS;GAAY,QAAQ;GAAgB,MAAM;GAAgB;EACrE;GAAE,SAAS;GAAY,QAAQ;GAAkB,MAAM;GAAgB;EACvE;GAAE,SAAS;GAAY,QAAQ;GAAmB,MAAM;GAAgB;EACxE;GACE,SAAS,wBAAwB,EAAE,SAAS,CAAC;GAC7C,QAAQ;GACR,MAAM;GACP;EACD;GACE,SAAS,2BAA2B,EAAE,SAAS,CAAC;GAChD,QAAQ;GACR,MAAM;GACP;EACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maas/payload-plugin-media-cloud",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
4
4
  "type": "module",
5
5
  "contributors": [
6
6
  {