{"version":3,"file":"file.mjs","names":["magicError: UseMagicErrorReturn"],"sources":["../../src/utils/file.ts"],"sourcesContent":["import { fileTypeFromBuffer } from 'file-type'\nimport { parse } from 'pathe'\n\nimport { getFileExistsHandler } from '../endpoints/fileExistsHandler'\n\nimport { useMagicError, type UseMagicErrorReturn } from '@maas/error-handler'\nimport { MediaCloudErrors } from '../types/errors'\n\nimport type { S3Store } from '../tus/stores/s3/s3Store'\nimport type { MediaCloudPluginOptions, MimeType } from '../types'\n\nconst magicError: UseMagicErrorReturn = useMagicError({\n  prefix: 'PLUGIN-MEDIA-CLOUD',\n})\n\nconst { logError, throwError } = magicError\n\nconst MUX_SUPPORTED_VIDEO_FORMATS = new Set([\n  'application/mxf',\n  'video/3gpp',\n  'video/3gpp2',\n  'video/mp2t',\n  'video/mp4',\n  'video/mpeg',\n  'video/quicktime',\n  'video/webm',\n  'video/x-f4v',\n  'video/x-flv',\n  'video/x-matroska',\n  'video/x-ms-asf',\n  'video/x-ms-wmv',\n  'video/x-msvideo',\n  'video/x-mxf',\n])\n\n/**\n * Checks if a file is a video file supported by Mux\n * @param file - The file to check\n * @returns Promise that resolves to true if the file is a supported video format, false otherwise\n */\nexport async function isVideo(file: File): Promise<boolean> {\n  try {\n    const buffer = new Uint8Array(await file.arrayBuffer())\n    const fileType = await fileTypeFromBuffer(buffer)\n\n    return fileType?.mime\n      ? MUX_SUPPORTED_VIDEO_FORMATS.has(fileType.mime)\n      : false\n  } catch {\n    return false\n  }\n}\n\nconst allowedMimeTypes = new Set<MimeType>([\n  'application/mxf',\n  'video/3gpp',\n  'video/3gpp2',\n  'video/mp2t',\n  'video/mp4',\n  'video/mpeg',\n  'video/quicktime',\n  'video/webm',\n  'video/x-f4v',\n  'video/x-flv',\n  'video/x-matroska',\n  'video/x-ms-asf',\n  'video/x-ms-wmv',\n  'video/x-msvideo',\n  'video/x-mxf',\n  'image/apng',\n  'image/avif',\n  'image/gif',\n  'image/jpeg',\n  'image/png',\n  'image/svg+xml',\n  'image/webp',\n])\n\n/**\n * Check the mime type against allowed mime types\n * @param mimeType - The file to check\n */\nfunction validateMimeType(mimeType: string) {\n  if (!allowedMimeTypes.has(mimeType as MimeType)) {\n    throwError(MediaCloudErrors.FILE_TYPE_UNSUPPORTED_ERROR)\n  }\n}\n\n/**\n * Gets the MIME type of a file using file-type library\n * @param file - The file to check\n * @returns Promise that resolves to the MIME type of the file or undefined if it cannot be determined\n */\nexport async function getMimeType(file: File): Promise<MimeType | undefined> {\n  try {\n    const buffer = new Uint8Array(await file.arrayBuffer())\n    const fileType = await fileTypeFromBuffer(buffer)\n\n    if (!fileType?.mime) {\n      logError(MediaCloudErrors.FILE_TYPE_ERROR.message)\n      return undefined\n    }\n\n    validateMimeType(fileType.mime)\n    return fileType.mime as MimeType\n  } catch (_error) {\n    logError(MediaCloudErrors.FILE_TYPE_ERROR.message)\n    return undefined\n  }\n}\n\n/**\n * Generates a unique filename by appending a random suffix if needed\n * @param originalFilename - The original filename\n * @returns A unique filename with a random suffix appended before the extension\n */\nexport function generateUniqueFilename(originalFilename: string): string {\n  const timestamp = Date.now().toString(36)\n  // Parse name and extension\n  const { name, ext } = parse(originalFilename)\n\n  return `${name}-${timestamp}${ext}`\n}\n\n/**\n * Sanitizes a filename by removing/replacing invalid characters and handling edge cases\n * Converts all non-alphanumeric characters (except dots for extensions) to underscores\n * @param filename - The filename to sanitize\n * @returns A sanitized filename safe for all operating systems\n * @throws {TypeError} When filename is not a string\n */\nexport function sanitizeFilename(filename: string): string {\n  try {\n    const parsed = parse(filename)\n    const sanitized = parsed.name\n      .replace(/[^a-zA-Z0-9_.-]/g, '_')\n      .replace(/_{2,}/g, '_')\n      .replace(/^_|_$/g, '')\n    return `${sanitized}${parsed.ext}`\n  } catch (_error) {\n    logError(MediaCloudErrors.FILENAME_SANITIZE_ERROR.message)\n    return filename\n  }\n}\n\ninterface CreateFileEndpointsArgs {\n  getS3Store: () => S3Store\n  pluginOptions: MediaCloudPluginOptions\n}\n\nexport function createFileEndpoints(args: CreateFileEndpointsArgs) {\n  const { getS3Store, pluginOptions } = args\n\n  const collection = pluginOptions.collection\n  magicError.assert(collection, MediaCloudErrors.COLLECTION_REQUIRED)\n\n  return [\n    {\n      handler: getFileExistsHandler({ getS3Store, collection }),\n      method: 'get' as const,\n      path: '/uploads/:filename/exists',\n    },\n  ]\n}\n"],"mappings":";;;;;;;AAWA,MAAMA,aAAkC,cAAc,EACpD,QAAQ,sBACT,CAAC;AAEF,MAAM,EAAE,UAAU,eAAe;AAEjC,MAAM,8BAA8B,IAAI,IAAI;CAC1C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;;;;;AAOF,eAAsB,QAAQ,MAA8B;AAC1D,KAAI;EAEF,MAAM,WAAW,MAAM,mBADR,IAAI,WAAW,MAAM,KAAK,aAAa,CAAC,CACN;AAEjD,SAAO,UAAU,OACb,4BAA4B,IAAI,SAAS,KAAK,GAC9C;SACE;AACN,SAAO;;;AAIX,MAAM,mBAAmB,IAAI,IAAc;CACzC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;;;;;AAMF,SAAS,iBAAiB,UAAkB;AAC1C,KAAI,CAAC,iBAAiB,IAAI,SAAqB,CAC7C,YAAW,iBAAiB,4BAA4B;;;;;;;AAS5D,eAAsB,YAAY,MAA2C;AAC3E,KAAI;EAEF,MAAM,WAAW,MAAM,mBADR,IAAI,WAAW,MAAM,KAAK,aAAa,CAAC,CACN;AAEjD,MAAI,CAAC,UAAU,MAAM;AACnB,YAAS,iBAAiB,gBAAgB,QAAQ;AAClD;;AAGF,mBAAiB,SAAS,KAAK;AAC/B,SAAO,SAAS;UACT,QAAQ;AACf,WAAS,iBAAiB,gBAAgB,QAAQ;AAClD;;;;;;;;AASJ,SAAgB,uBAAuB,kBAAkC;CACvE,MAAM,YAAY,KAAK,KAAK,CAAC,SAAS,GAAG;CAEzC,MAAM,EAAE,MAAM,QAAQ,MAAM,iBAAiB;AAE7C,QAAO,GAAG,KAAK,GAAG,YAAY;;;;;;;;;AAUhC,SAAgB,iBAAiB,UAA0B;AACzD,KAAI;EACF,MAAM,SAAS,MAAM,SAAS;AAK9B,SAAO,GAJW,OAAO,KACtB,QAAQ,oBAAoB,IAAI,CAChC,QAAQ,UAAU,IAAI,CACtB,QAAQ,UAAU,GAAG,GACF,OAAO;UACtB,QAAQ;AACf,WAAS,iBAAiB,wBAAwB,QAAQ;AAC1D,SAAO;;;AASX,SAAgB,oBAAoB,MAA+B;CACjE,MAAM,EAAE,YAAY,kBAAkB;CAEtC,MAAM,aAAa,cAAc;AACjC,YAAW,OAAO,YAAY,iBAAiB,oBAAoB;AAEnE,QAAO,CACL;EACE,SAAS,qBAAqB;GAAE;GAAY;GAAY,CAAC;EACzD,QAAQ;EACR,MAAM;EACP,CACF"}