@maas/payload-plugin-media-cloud 0.0.18 → 0.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/mux-preview/mux-preview.d.mts +1 -1
- package/dist/components/upload-handler/upload-handler.d.mts +2 -2
- package/dist/components/upload-handler/upload-handler.mjs +3 -4
- package/dist/components/upload-handler/upload-handler.mjs.map +1 -1
- package/dist/endpoints/muxWebhookHandler.mjs +2 -2
- package/dist/endpoints/muxWebhookHandler.mjs.map +1 -1
- package/dist/endpoints/tusPostProcessorHandler.mjs +0 -2
- package/dist/endpoints/tusPostProcessorHandler.mjs.map +1 -1
- package/dist/plugin.mjs +0 -1
- package/dist/plugin.mjs.map +1 -1
- package/dist/types/errors.d.mts +4 -0
- package/dist/types/errors.mjs +4 -0
- package/dist/types/errors.mjs.map +1 -1
- package/dist/utils/tus.d.mts +5 -6
- package/dist/utils/tus.mjs +9 -12
- package/dist/utils/tus.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import * as payload2 from "payload";
|
|
2
1
|
import * as react0 from "react";
|
|
2
|
+
import * as payload1 from "payload";
|
|
3
3
|
|
|
4
4
|
//#region src/components/upload-handler/upload-handler.d.ts
|
|
5
5
|
declare const UploadHandler: ({
|
|
@@ -11,7 +11,7 @@ declare const UploadHandler: ({
|
|
|
11
11
|
serverHandlerPath
|
|
12
12
|
}: {
|
|
13
13
|
children: react0.ReactNode;
|
|
14
|
-
collectionSlug:
|
|
14
|
+
collectionSlug: payload1.UploadCollectionSlug;
|
|
15
15
|
enabled?: boolean;
|
|
16
16
|
extra: Record<string, unknown>;
|
|
17
17
|
prefix?: string;
|
|
@@ -30,7 +30,7 @@ function parseFilename(uploadUrl) {
|
|
|
30
30
|
logError(MediaCloudErrors.UPLOAD_NO_URL.message);
|
|
31
31
|
return "";
|
|
32
32
|
}
|
|
33
|
-
return
|
|
33
|
+
return new URL(uploadUrl).pathname.split("/").pop() || "";
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
36
|
* Handles Mux video upload with progress tracking
|
|
@@ -95,10 +95,9 @@ async function muxUpload(args) {
|
|
|
95
95
|
*/
|
|
96
96
|
async function tusUpload(args) {
|
|
97
97
|
const { apiRoute, serverURL, file, mimeType, updateFilename } = args;
|
|
98
|
-
const filename = file.name;
|
|
98
|
+
const filename = sanitizeFilename(file.name);
|
|
99
99
|
const filetype = file.type;
|
|
100
100
|
const filesize = file.size.toString();
|
|
101
|
-
const sanitizedFilename = sanitizeFilename(filename);
|
|
102
101
|
return new Promise((resolve) => {
|
|
103
102
|
const upload = new tus.Upload(file, {
|
|
104
103
|
endpoint: `${serverURL}${apiRoute}/uploads`,
|
|
@@ -107,7 +106,7 @@ async function tusUpload(args) {
|
|
|
107
106
|
metadata: {
|
|
108
107
|
filetype,
|
|
109
108
|
filesize,
|
|
110
|
-
filename
|
|
109
|
+
filename,
|
|
111
110
|
contentType: filetype,
|
|
112
111
|
contentDisposition: "inline",
|
|
113
112
|
contentLength: filesize
|
|
@@ -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
|
|
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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"}
|
|
@@ -2,7 +2,7 @@ import { MediaCloudErrors } from "../types/errors.mjs";
|
|
|
2
2
|
import { useErrorHandler } from "../hooks/useErrorHandler.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/endpoints/muxWebhookHandler.ts
|
|
5
|
-
const { logError } = useErrorHandler();
|
|
5
|
+
const { logError, log } = useErrorHandler();
|
|
6
6
|
function getMuxWebhookHandler(args) {
|
|
7
7
|
const { getMuxClient } = args;
|
|
8
8
|
return async (req) => {
|
|
@@ -17,7 +17,7 @@ function getMuxWebhookHandler(args) {
|
|
|
17
17
|
case "video.asset.created":
|
|
18
18
|
case "video.asset.errored":
|
|
19
19
|
case "video.asset.deleted":
|
|
20
|
-
|
|
20
|
+
log(`Received Mux webhook: ${event.type}, ${event.object.id}`);
|
|
21
21
|
break;
|
|
22
22
|
case "video.asset.ready":
|
|
23
23
|
case "video.asset.static_renditions.ready":
|
|
@@ -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 } = 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
|
|
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"}
|
|
@@ -13,14 +13,12 @@ function getTusPostProcessorHandler(args) {
|
|
|
13
13
|
const filename = routeParams?.filename;
|
|
14
14
|
if (!filename) throwError(MediaCloudErrors.FILE_MISSING_NAME);
|
|
15
15
|
const sanitizedFilename = sanitizeFilename(filename);
|
|
16
|
-
console.log("🚀 ~ sanitizedFilename:", sanitizedFilename);
|
|
17
16
|
const { docs } = await payload.find({
|
|
18
17
|
collection: "media",
|
|
19
18
|
where: { filename: { equals: sanitizedFilename } },
|
|
20
19
|
limit: 1,
|
|
21
20
|
pagination: false
|
|
22
21
|
});
|
|
23
|
-
console.log("docs", docs);
|
|
24
22
|
const media = docs?.[0];
|
|
25
23
|
if (!media) throwError(MediaCloudErrors.FILE_NOT_FOUND);
|
|
26
24
|
if (media.storage !== "s3") return Response.json({ message: "Asset not stored on S3, skipping processing" }, { status: 200 });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tusPostProcessorHandler.mjs","names":[],"sources":["../../src/endpoints/tusPostProcessorHandler.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'\nimport { imageSize } from 'image-size'\nimport { sanitizeFilename } from '../utils/file'\n\ninterface GetTusPostProcessorHandlerArgs {\n s3Store: S3Store\n}\n\nexport function getTusPostProcessorHandler(\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, payload } = req\n const filename = routeParams?.filename as string\n\n if (!filename) {\n throwError(MediaCloudErrors.FILE_MISSING_NAME)\n }\n\n const sanitizedFilename = sanitizeFilename(filename)\n
|
|
1
|
+
{"version":3,"file":"tusPostProcessorHandler.mjs","names":[],"sources":["../../src/endpoints/tusPostProcessorHandler.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'\nimport { imageSize } from 'image-size'\nimport { sanitizeFilename } from '../utils/file'\n\ninterface GetTusPostProcessorHandlerArgs {\n s3Store: S3Store\n}\n\nexport function getTusPostProcessorHandler(\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, payload } = req\n const filename = routeParams?.filename as string\n\n if (!filename) {\n throwError(MediaCloudErrors.FILE_MISSING_NAME)\n }\n\n const sanitizedFilename = sanitizeFilename(filename)\n\n const { docs } = await payload.find({\n collection: 'media',\n where: {\n filename: {\n equals: sanitizedFilename,\n },\n },\n limit: 1,\n pagination: false,\n })\n\n const media = docs?.[0]\n\n if (!media) {\n throwError(MediaCloudErrors.FILE_NOT_FOUND)\n }\n\n if (media.storage !== 's3') {\n return Response.json(\n { message: 'Asset not stored on S3, skipping processing' },\n { status: 200 }\n )\n }\n\n const matchedId = media?.id\n\n const url = s3Store.getUrl(filename)\n const response = await fetch(url)\n const arrayBuffer = await response.arrayBuffer()\n const buffer = Buffer.from(arrayBuffer)\n\n const dimensions = imageSize(buffer)\n const { width, height } = dimensions\n\n if (width && height) {\n await payload.update({\n collection: 'media',\n id: matchedId,\n data: {\n width,\n height,\n },\n })\n }\n\n return Response.json({ message: 'Asset processed' }, { status: 200 })\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":";;;;;;AAYA,SAAgB,2BACd,MACgB;CAChB,MAAM,EAAE,YAAY;CACpB,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;GAGhD,MAAM,oBAAoB,iBAAiB,SAAS;GAEpD,MAAM,EAAE,SAAS,MAAM,QAAQ,KAAK;IAClC,YAAY;IACZ,OAAO,EACL,UAAU,EACR,QAAQ,mBACT,EACF;IACD,OAAO;IACP,YAAY;IACb,CAAC;GAEF,MAAM,QAAQ,OAAO;AAErB,OAAI,CAAC,MACH,YAAW,iBAAiB,eAAe;AAG7C,OAAI,MAAM,YAAY,KACpB,QAAO,SAAS,KACd,EAAE,SAAS,+CAA+C,EAC1D,EAAE,QAAQ,KAAK,CAChB;GAGH,MAAM,YAAY,OAAO;GAEzB,MAAM,MAAM,QAAQ,OAAO,SAAS;GAEpC,MAAM,cAAc,OADH,MAAM,MAAM,IAAI,EACE,aAAa;GAIhD,MAAM,EAAE,OAAO,WADI,UAFJ,OAAO,KAAK,YAAY,CAEH;AAGpC,OAAI,SAAS,OACX,OAAM,QAAQ,OAAO;IACnB,YAAY;IACZ,IAAI;IACJ,MAAM;KACJ;KACA;KACD;IACF,CAAC;AAGJ,UAAO,SAAS,KAAK,EAAE,SAAS,mBAAmB,EAAE,EAAE,QAAQ,KAAK,CAAC;WAC9D,QAAQ;AACf,YAAS,iBAAiB,sBAAsB,QAAQ;AACxD,UAAO,SAAS,KACd,EAAE,SAAS,2BAA2B,EACtC,EAAE,QAAQ,KAAK,CAChB"}
|
package/dist/plugin.mjs
CHANGED
package/dist/plugin.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.mjs","names":["muxClient: Mux | null","mergedConfig: Config"],"sources":["../src/plugin.ts"],"sourcesContent":["import Mux from '@mux/mux-node'\nimport { cloudStoragePlugin } from '@payloadcms/plugin-cloud-storage'\nimport { initClientUploads } from '@payloadcms/plugin-cloud-storage/utilities'\n\nimport { MediaCloudErrors } from './types/errors'\nimport { getStorageAdapter } from './adapter/storageAdapter'\nimport { getMediaCollection } from './collections/mediaCollection'\nimport { useErrorHandler } from './hooks/useErrorHandler'\nimport { createS3Store } from './tus/stores/s3'\nimport {\n createMuxClient,\n createMuxEndpoints,\n validateMuxConfig,\n} from './utils/mux'\nimport { createTusEndpoints, createTusServer } from './utils/tus'\n\nimport type { Config } from 'payload'\nimport type { MediaCloudPluginOptions } from './types'\n\nconst { logError } = useErrorHandler()\n\nlet muxClient: Mux | null = null\n\n/**\n * Media Cloud Plugin for Payload CMS\n * @param pluginOptions Configuration options\n * @returns Payload config function\n */\nexport function mediaCloudPlugin(pluginOptions: MediaCloudPluginOptions) {\n return function (config: Config): Config {\n // Early returns for invalid or disabled plugin configuration\n if (!pluginOptions) {\n logError(MediaCloudErrors.PLUGIN_NOT_CONFIGURED.message)\n return config\n }\n\n if (pluginOptions.enabled === false) {\n return config\n }\n\n /**\n * Helper function to get or create Mux client instance\n * @returns Mux client instance\n */\n function getMuxClient(): Mux {\n if (muxClient) {\n return muxClient\n }\n return createMuxClient(pluginOptions.mux)\n }\n\n // Initialize Mux client if configuration is provided\n if (pluginOptions.mux) {\n validateMuxConfig(pluginOptions.mux)\n muxClient = getMuxClient()\n } else {\n logError(MediaCloudErrors.MUX_CONFIG_INCOMPLETE.message)\n muxClient = null\n }\n\n const s3Store = createS3Store(pluginOptions.s3)\n const tusServer = createTusServer({
|
|
1
|
+
{"version":3,"file":"plugin.mjs","names":["muxClient: Mux | null","mergedConfig: Config"],"sources":["../src/plugin.ts"],"sourcesContent":["import Mux from '@mux/mux-node'\nimport { cloudStoragePlugin } from '@payloadcms/plugin-cloud-storage'\nimport { initClientUploads } from '@payloadcms/plugin-cloud-storage/utilities'\n\nimport { MediaCloudErrors } from './types/errors'\nimport { getStorageAdapter } from './adapter/storageAdapter'\nimport { getMediaCollection } from './collections/mediaCollection'\nimport { useErrorHandler } from './hooks/useErrorHandler'\nimport { createS3Store } from './tus/stores/s3'\nimport {\n createMuxClient,\n createMuxEndpoints,\n validateMuxConfig,\n} from './utils/mux'\nimport { createTusEndpoints, createTusServer } from './utils/tus'\n\nimport type { Config } from 'payload'\nimport type { MediaCloudPluginOptions } from './types'\n\nconst { logError } = useErrorHandler()\n\nlet muxClient: Mux | null = null\n\n/**\n * Media Cloud Plugin for Payload CMS\n * @param pluginOptions Configuration options\n * @returns Payload config function\n */\nexport function mediaCloudPlugin(pluginOptions: MediaCloudPluginOptions) {\n return function (config: Config): Config {\n // Early returns for invalid or disabled plugin configuration\n if (!pluginOptions) {\n logError(MediaCloudErrors.PLUGIN_NOT_CONFIGURED.message)\n return config\n }\n\n if (pluginOptions.enabled === false) {\n return config\n }\n\n /**\n * Helper function to get or create Mux client instance\n * @returns Mux client instance\n */\n function getMuxClient(): Mux {\n if (muxClient) {\n return muxClient\n }\n return createMuxClient(pluginOptions.mux)\n }\n\n // Initialize Mux client if configuration is provided\n if (pluginOptions.mux) {\n validateMuxConfig(pluginOptions.mux)\n muxClient = getMuxClient()\n } else {\n logError(MediaCloudErrors.MUX_CONFIG_INCOMPLETE.message)\n muxClient = null\n }\n\n const s3Store = createS3Store(pluginOptions.s3)\n const tusServer = createTusServer({ s3Store, pluginOptions })\n\n // Handle collection extension - replace base collection if it exists\n const baseCollection = config.collections?.find(\n ({ slug }) => slug === pluginOptions.collection\n )\n\n const mediaCollection = getMediaCollection({\n s3Store,\n baseCollection,\n })\n\n if (baseCollection) {\n config = {\n ...config,\n collections:\n config.collections?.filter(\n ({ slug }) => slug !== baseCollection?.slug\n ) || [],\n }\n }\n\n initClientUploads({\n clientHandler:\n '@maas/payload-plugin-media-cloud/components#UploadHandler',\n collections: {\n media: {\n clientUploads: true,\n disableLocalStorage: true,\n },\n },\n config,\n enabled: true,\n serverHandler: () => {\n return Response.json(\n { message: 'Server handler is not implemented' },\n { status: 501 }\n )\n },\n serverHandlerPath: '/media-cloud/upload',\n })\n\n const cloudStorageConfig = {\n collections: {\n media: {\n adapter: getStorageAdapter({ getMuxClient, pluginOptions, s3Store }),\n clientUploads: true,\n disableLocalStorage: true,\n },\n },\n }\n\n const mergedConfig: Config = {\n ...config,\n admin: {\n ...config.admin,\n components: {\n ...config.admin?.components,\n providers: [\n ...(config.admin?.components?.providers ?? []),\n '@maas/payload-plugin-media-cloud/components#UploadManagerProvider',\n ],\n },\n },\n collections: [...(config.collections ?? []), mediaCollection],\n endpoints: [\n ...(config.endpoints ?? []),\n ...createTusEndpoints({ tusServer, s3Store }),\n ...createMuxEndpoints({ getMuxClient, pluginOptions }),\n ],\n }\n\n return cloudStoragePlugin(cloudStorageConfig)(mergedConfig)\n }\n}\n"],"mappings":";;;;;;;;;;;AAmBA,MAAM,EAAE,aAAa,iBAAiB;AAEtC,IAAIA,YAAwB;;;;;;AAO5B,SAAgB,iBAAiB,eAAwC;AACvE,QAAO,SAAU,QAAwB;AAEvC,MAAI,CAAC,eAAe;AAClB,YAAS,iBAAiB,sBAAsB,QAAQ;AACxD,UAAO;;AAGT,MAAI,cAAc,YAAY,MAC5B,QAAO;;;;;EAOT,SAAS,eAAoB;AAC3B,OAAI,UACF,QAAO;AAET,UAAO,gBAAgB,cAAc,IAAI;;AAI3C,MAAI,cAAc,KAAK;AACrB,qBAAkB,cAAc,IAAI;AACpC,eAAY,cAAc;SACrB;AACL,YAAS,iBAAiB,sBAAsB,QAAQ;AACxD,eAAY;;EAGd,MAAM,UAAU,cAAc,cAAc,GAAG;EAC/C,MAAM,YAAY,gBAAgB;GAAE;GAAS;GAAe,CAAC;EAG7D,MAAM,iBAAiB,OAAO,aAAa,MACxC,EAAE,WAAW,SAAS,cAAc,WACtC;EAED,MAAM,kBAAkB,mBAAmB;GACzC;GACA;GACD,CAAC;AAEF,MAAI,eACF,UAAS;GACP,GAAG;GACH,aACE,OAAO,aAAa,QACjB,EAAE,WAAW,SAAS,gBAAgB,KACxC,IAAI,EAAE;GACV;AAGH,oBAAkB;GAChB,eACE;GACF,aAAa,EACX,OAAO;IACL,eAAe;IACf,qBAAqB;IACtB,EACF;GACD;GACA,SAAS;GACT,qBAAqB;AACnB,WAAO,SAAS,KACd,EAAE,SAAS,qCAAqC,EAChD,EAAE,QAAQ,KAAK,CAChB;;GAEH,mBAAmB;GACpB,CAAC;EAEF,MAAM,qBAAqB,EACzB,aAAa,EACX,OAAO;GACL,SAAS,kBAAkB;IAAE;IAAc;IAAe;IAAS,CAAC;GACpE,eAAe;GACf,qBAAqB;GACtB,EACF,EACF;EAED,MAAMC,eAAuB;GAC3B,GAAG;GACH,OAAO;IACL,GAAG,OAAO;IACV,YAAY;KACV,GAAG,OAAO,OAAO;KACjB,WAAW,CACT,GAAI,OAAO,OAAO,YAAY,aAAa,EAAE,EAC7C,oEACD;KACF;IACF;GACD,aAAa,CAAC,GAAI,OAAO,eAAe,EAAE,EAAG,gBAAgB;GAC7D,WAAW;IACT,GAAI,OAAO,aAAa,EAAE;IAC1B,GAAG,mBAAmB;KAAE;KAAW;KAAS,CAAC;IAC7C,GAAG,mBAAmB;KAAE;KAAc;KAAe,CAAC;IACvD;GACF;AAED,SAAO,mBAAmB,mBAAmB,CAAC,aAAa"}
|
package/dist/types/errors.d.mts
CHANGED
|
@@ -44,6 +44,10 @@ declare const MediaCloudErrors: {
|
|
|
44
44
|
readonly message: "Error deleting file from S3";
|
|
45
45
|
readonly errorCode: 500;
|
|
46
46
|
};
|
|
47
|
+
readonly S3_GET_OBJECT_ERROR: {
|
|
48
|
+
readonly message: "Error getting object from S3";
|
|
49
|
+
readonly errorCode: 500;
|
|
50
|
+
};
|
|
47
51
|
readonly S3_UNIQUE_NAME_ERROR: {
|
|
48
52
|
readonly message: "Could not find a unique file name after maximum tries";
|
|
49
53
|
readonly errorCode: 500;
|
package/dist/types/errors.mjs
CHANGED
|
@@ -44,6 +44,10 @@ const MediaCloudErrors = {
|
|
|
44
44
|
message: "Error deleting file from S3",
|
|
45
45
|
errorCode: 500
|
|
46
46
|
},
|
|
47
|
+
S3_GET_OBJECT_ERROR: {
|
|
48
|
+
message: "Error getting object from S3",
|
|
49
|
+
errorCode: 500
|
|
50
|
+
},
|
|
47
51
|
S3_UNIQUE_NAME_ERROR: {
|
|
48
52
|
message: "Could not find a unique file name after maximum tries",
|
|
49
53
|
errorCode: 500
|
|
@@ -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_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,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_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"}
|
package/dist/utils/tus.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { MediaCloudPluginOptions } from "../types/index.mjs";
|
|
2
2
|
import { S3Store } from "../tus/stores/s3/s3-store.mjs";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
3
|
+
import { Server } from "@tus/server";
|
|
4
|
+
import * as payload2 from "payload";
|
|
5
|
+
import { PayloadRequest } from "payload";
|
|
6
6
|
|
|
7
7
|
//#region src/utils/tus.d.ts
|
|
8
8
|
|
|
@@ -12,8 +12,7 @@ import { DataStore, Server } from "@tus/server";
|
|
|
12
12
|
* @returns A configured TusServer instance
|
|
13
13
|
*/
|
|
14
14
|
interface CreateTusServerArgs {
|
|
15
|
-
|
|
16
|
-
s3Store: DataStore;
|
|
15
|
+
s3Store: S3Store;
|
|
17
16
|
pluginOptions: MediaCloudPluginOptions;
|
|
18
17
|
}
|
|
19
18
|
declare function createTusServer(args: CreateTusServerArgs): Server;
|
|
@@ -47,7 +46,7 @@ declare function createTusEndpoints(args: CreateTusEndpointsArgs): ({
|
|
|
47
46
|
method: "delete";
|
|
48
47
|
path: string;
|
|
49
48
|
} | {
|
|
50
|
-
handler:
|
|
49
|
+
handler: payload2.PayloadHandler;
|
|
51
50
|
method: "get";
|
|
52
51
|
path: string;
|
|
53
52
|
})[];
|
package/dist/utils/tus.mjs
CHANGED
|
@@ -2,26 +2,23 @@ import { MediaCloudErrors } from "../types/errors.mjs";
|
|
|
2
2
|
import { useErrorHandler } from "../hooks/useErrorHandler.mjs";
|
|
3
3
|
import { generateUniqueFilename } from "./file.mjs";
|
|
4
4
|
import { getTusPostProcessorHandler } from "../endpoints/tusPostProcessorHandler.mjs";
|
|
5
|
-
import { getPayload, sanitizeConfig } from "payload";
|
|
6
5
|
import { Server } from "@tus/server";
|
|
7
6
|
|
|
8
7
|
//#region src/utils/tus.ts
|
|
9
8
|
const { logError } = useErrorHandler();
|
|
10
9
|
function createTusServer(args) {
|
|
11
|
-
const {
|
|
10
|
+
const { s3Store, pluginOptions } = args;
|
|
12
11
|
return new Server({
|
|
13
12
|
datastore: s3Store,
|
|
14
|
-
namingFunction: async (
|
|
13
|
+
namingFunction: async (_req, metadata) => {
|
|
15
14
|
try {
|
|
16
|
-
const {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
default: return generateUniqueFilename("");
|
|
24
|
-
}
|
|
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;
|
|
25
22
|
} catch (_error) {
|
|
26
23
|
logError(MediaCloudErrors.NAMING_FUNCTION_ERROR.message);
|
|
27
24
|
return metadata?.filename ?? generateUniqueFilename("");
|
package/dist/utils/tus.mjs.map
CHANGED
|
@@ -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'\nimport { S3Store } from '../tus/stores/s3/s3-store'\
|
|
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"}
|