mirror of
				https://github.com/kyantech/Palmr.git
				synced 2025-11-03 21:43:20 +00:00 
			
		
		
		
	feat: enhance content type handling in filesystem and S3 storage providers
- Updated the FilesystemController to dynamically set the Content-Type header using the getContentType utility based on the file name. - Modified the S3StorageProvider to include the ResponseContentType in the presigned URL generation, improving the handling of file types in responses.
This commit is contained in:
		@@ -4,6 +4,7 @@ import { FastifyReply, FastifyRequest } from "fastify";
 | 
			
		||||
 | 
			
		||||
import { FilesystemStorageProvider } from "../../providers/filesystem-storage.provider";
 | 
			
		||||
import { ChunkManager, ChunkMetadata } from "./chunk-manager";
 | 
			
		||||
import { getContentType } from "../../utils/mime-types";
 | 
			
		||||
 | 
			
		||||
export class FilesystemController {
 | 
			
		||||
  private chunkManager = ChunkManager.getInstance();
 | 
			
		||||
@@ -184,7 +185,7 @@ export class FilesystemController {
 | 
			
		||||
      const range = request.headers.range;
 | 
			
		||||
 | 
			
		||||
      reply.header("Content-Disposition", this.encodeFilenameForHeader(fileName));
 | 
			
		||||
      reply.header("Content-Type", "application/octet-stream");
 | 
			
		||||
      reply.header("Content-Type", getContentType(fileName));
 | 
			
		||||
      reply.header("Accept-Ranges", "bytes");
 | 
			
		||||
 | 
			
		||||
      if (range) {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
 | 
			
		||||
 | 
			
		||||
import { bucketName, s3Client } from "../config/storage.config";
 | 
			
		||||
import { StorageProvider } from "../types/storage";
 | 
			
		||||
import { getContentType } from "../utils/mime-types";
 | 
			
		||||
 | 
			
		||||
export class S3StorageProvider implements StorageProvider {
 | 
			
		||||
  constructor() {
 | 
			
		||||
@@ -91,6 +92,7 @@ export class S3StorageProvider implements StorageProvider {
 | 
			
		||||
      Bucket: bucketName,
 | 
			
		||||
      Key: objectName,
 | 
			
		||||
      ResponseContentDisposition: this.encodeFilenameForHeader(rcdFileName),
 | 
			
		||||
      ResponseContentType: getContentType(rcdFileName),
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return await getSignedUrl(s3Client, command, { expiresIn: expires });
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										378
									
								
								apps/server/src/utils/mime-types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										378
									
								
								apps/server/src/utils/mime-types.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,378 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Utility for detecting MIME types based on file extensions
 | 
			
		||||
 * Fallback to application/octet-stream if extension is unknown
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
const mimeTypeMap: Record<string, string> = {
 | 
			
		||||
  // Images
 | 
			
		||||
  ".jpg": "image/jpeg",
 | 
			
		||||
  ".jpeg": "image/jpeg",
 | 
			
		||||
  ".png": "image/png",
 | 
			
		||||
  ".gif": "image/gif",
 | 
			
		||||
  ".bmp": "image/bmp",
 | 
			
		||||
  ".webp": "image/webp",
 | 
			
		||||
  ".svg": "image/svg+xml",
 | 
			
		||||
  ".ico": "image/x-icon",
 | 
			
		||||
  ".tiff": "image/tiff",
 | 
			
		||||
  ".tif": "image/tiff",
 | 
			
		||||
  ".avif": "image/avif",
 | 
			
		||||
  ".heic": "image/heic",
 | 
			
		||||
  ".heif": "image/heif",
 | 
			
		||||
  ".jxl": "image/jxl",
 | 
			
		||||
  ".psd": "image/vnd.adobe.photoshop",
 | 
			
		||||
  ".raw": "image/x-canon-cr2",
 | 
			
		||||
  ".cr2": "image/x-canon-cr2",
 | 
			
		||||
  ".nef": "image/x-nikon-nef",
 | 
			
		||||
  ".arw": "image/x-sony-arw",
 | 
			
		||||
  ".dng": "image/x-adobe-dng",
 | 
			
		||||
  ".xcf": "image/x-xcf",
 | 
			
		||||
  ".pbm": "image/x-portable-bitmap",
 | 
			
		||||
  ".pgm": "image/x-portable-graymap",
 | 
			
		||||
  ".ppm": "image/x-portable-pixmap",
 | 
			
		||||
  ".pnm": "image/x-portable-anymap",
 | 
			
		||||
 | 
			
		||||
  // Documents
 | 
			
		||||
  ".pdf": "application/pdf",
 | 
			
		||||
  ".doc": "application/msword",
 | 
			
		||||
  ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
 | 
			
		||||
  ".docm": "application/vnd.ms-word.document.macroEnabled.12",
 | 
			
		||||
  ".dotx": "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
 | 
			
		||||
  ".dotm": "application/vnd.ms-word.template.macroEnabled.12",
 | 
			
		||||
  ".xls": "application/vnd.ms-excel",
 | 
			
		||||
  ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
 | 
			
		||||
  ".xlsm": "application/vnd.ms-excel.sheet.macroEnabled.12",
 | 
			
		||||
  ".xltx": "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
 | 
			
		||||
  ".xltm": "application/vnd.ms-excel.template.macroEnabled.12",
 | 
			
		||||
  ".xlsb": "application/vnd.ms-excel.sheet.binary.macroEnabled.12",
 | 
			
		||||
  ".ppt": "application/vnd.ms-powerpoint",
 | 
			
		||||
  ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
 | 
			
		||||
  ".pptm": "application/vnd.ms-powerpoint.presentation.macroEnabled.12",
 | 
			
		||||
  ".potx": "application/vnd.openxmlformats-officedocument.presentationml.template",
 | 
			
		||||
  ".potm": "application/vnd.ms-powerpoint.template.macroEnabled.12",
 | 
			
		||||
  ".ppsx": "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
 | 
			
		||||
  ".ppsm": "application/vnd.ms-powerpoint.slideshow.macroEnabled.12",
 | 
			
		||||
  ".odt": "application/vnd.oasis.opendocument.text",
 | 
			
		||||
  ".ods": "application/vnd.oasis.opendocument.spreadsheet",
 | 
			
		||||
  ".odp": "application/vnd.oasis.opendocument.presentation",
 | 
			
		||||
  ".odg": "application/vnd.oasis.opendocument.graphics",
 | 
			
		||||
  ".odf": "application/vnd.oasis.opendocument.formula",
 | 
			
		||||
  ".odb": "application/vnd.oasis.opendocument.database",
 | 
			
		||||
  ".odc": "application/vnd.oasis.opendocument.chart",
 | 
			
		||||
  ".odi": "application/vnd.oasis.opendocument.image",
 | 
			
		||||
 | 
			
		||||
  // Text and Code
 | 
			
		||||
  ".txt": "text/plain",
 | 
			
		||||
  ".html": "text/html",
 | 
			
		||||
  ".htm": "text/html",
 | 
			
		||||
  ".css": "text/css",
 | 
			
		||||
  ".js": "application/javascript",
 | 
			
		||||
  ".mjs": "application/javascript",
 | 
			
		||||
  ".ts": "text/typescript",
 | 
			
		||||
  ".tsx": "text/tsx",
 | 
			
		||||
  ".jsx": "text/jsx",
 | 
			
		||||
  ".json": "application/json",
 | 
			
		||||
  ".xml": "application/xml",
 | 
			
		||||
  ".csv": "text/csv",
 | 
			
		||||
  ".yaml": "text/yaml",
 | 
			
		||||
  ".yml": "text/yaml",
 | 
			
		||||
  ".toml": "text/plain",
 | 
			
		||||
  ".ini": "text/plain",
 | 
			
		||||
  ".cfg": "text/plain",
 | 
			
		||||
  ".conf": "text/plain",
 | 
			
		||||
  ".log": "text/plain",
 | 
			
		||||
  ".md": "text/markdown",
 | 
			
		||||
  ".markdown": "text/markdown",
 | 
			
		||||
  ".rst": "text/x-rst",
 | 
			
		||||
  ".tex": "text/x-tex",
 | 
			
		||||
  ".latex": "text/x-latex",
 | 
			
		||||
  ".rtf": "application/rtf",
 | 
			
		||||
  ".ps": "application/postscript",
 | 
			
		||||
  ".eps": "application/postscript",
 | 
			
		||||
 | 
			
		||||
  // Programming Languages
 | 
			
		||||
  ".c": "text/x-c",
 | 
			
		||||
  ".cc": "text/x-c",
 | 
			
		||||
  ".cpp": "text/x-c",
 | 
			
		||||
  ".cxx": "text/x-c",
 | 
			
		||||
  ".h": "text/x-c",
 | 
			
		||||
  ".hpp": "text/x-c",
 | 
			
		||||
  ".hxx": "text/x-c",
 | 
			
		||||
  ".java": "text/x-java-source",
 | 
			
		||||
  ".class": "application/java-vm",
 | 
			
		||||
  ".jar": "application/java-archive",
 | 
			
		||||
  ".war": "application/java-archive",
 | 
			
		||||
  ".py": "text/x-python",
 | 
			
		||||
  ".pyw": "text/x-python",
 | 
			
		||||
  ".rb": "text/x-ruby",
 | 
			
		||||
  ".php": "text/x-php",
 | 
			
		||||
  ".pl": "text/x-perl",
 | 
			
		||||
  ".pm": "text/x-perl",
 | 
			
		||||
  ".sh": "text/x-shellscript",
 | 
			
		||||
  ".bash": "text/x-shellscript",
 | 
			
		||||
  ".zsh": "text/x-shellscript",
 | 
			
		||||
  ".fish": "text/x-shellscript",
 | 
			
		||||
  ".bat": "text/x-msdos-batch",
 | 
			
		||||
  ".cmd": "text/x-msdos-batch",
 | 
			
		||||
  ".ps1": "text/plain",
 | 
			
		||||
  ".psm1": "text/plain",
 | 
			
		||||
  ".go": "text/x-go",
 | 
			
		||||
  ".rs": "text/x-rust",
 | 
			
		||||
  ".swift": "text/x-swift",
 | 
			
		||||
  ".kt": "text/x-kotlin",
 | 
			
		||||
  ".scala": "text/x-scala",
 | 
			
		||||
  ".clj": "text/x-clojure",
 | 
			
		||||
  ".hs": "text/x-haskell",
 | 
			
		||||
  ".elm": "text/x-elm",
 | 
			
		||||
  ".dart": "text/x-dart",
 | 
			
		||||
  ".r": "text/x-r",
 | 
			
		||||
  ".R": "text/x-r",
 | 
			
		||||
  ".sql": "text/x-sql",
 | 
			
		||||
  ".vb": "text/x-vb",
 | 
			
		||||
  ".cs": "text/x-csharp",
 | 
			
		||||
  ".fs": "text/x-fsharp",
 | 
			
		||||
  ".lua": "text/x-lua",
 | 
			
		||||
  ".m": "text/x-objc",
 | 
			
		||||
  ".mm": "text/x-objc",
 | 
			
		||||
 | 
			
		||||
  // Audio
 | 
			
		||||
  ".mp3": "audio/mpeg",
 | 
			
		||||
  ".mp2": "audio/mpeg",
 | 
			
		||||
  ".m4a": "audio/mp4",
 | 
			
		||||
  ".m4b": "audio/mp4",
 | 
			
		||||
  ".m4p": "audio/mp4",
 | 
			
		||||
  ".wav": "audio/wav",
 | 
			
		||||
  ".wave": "audio/wav",
 | 
			
		||||
  ".aiff": "audio/aiff",
 | 
			
		||||
  ".aif": "audio/aiff",
 | 
			
		||||
  ".aifc": "audio/aiff",
 | 
			
		||||
  ".flac": "audio/flac",
 | 
			
		||||
  ".ogg": "audio/ogg",
 | 
			
		||||
  ".oga": "audio/ogg",
 | 
			
		||||
  ".opus": "audio/opus",
 | 
			
		||||
  ".aac": "audio/aac",
 | 
			
		||||
  ".wma": "audio/x-ms-wma",
 | 
			
		||||
  ".ac3": "audio/ac3",
 | 
			
		||||
  ".amr": "audio/amr",
 | 
			
		||||
  ".au": "audio/basic",
 | 
			
		||||
  ".snd": "audio/basic",
 | 
			
		||||
  ".mid": "audio/midi",
 | 
			
		||||
  ".midi": "audio/midi",
 | 
			
		||||
  ".kar": "audio/midi",
 | 
			
		||||
  ".ra": "audio/x-realaudio",
 | 
			
		||||
  ".ram": "audio/x-realaudio",
 | 
			
		||||
  ".3gp": "audio/3gpp",
 | 
			
		||||
  ".3g2": "audio/3gpp2",
 | 
			
		||||
  ".spx": "audio/speex",
 | 
			
		||||
  ".wv": "audio/x-wavpack",
 | 
			
		||||
  ".ape": "audio/x-ape",
 | 
			
		||||
  ".mpc": "audio/x-musepack",
 | 
			
		||||
 | 
			
		||||
  // Video
 | 
			
		||||
  ".mp4": "video/mp4",
 | 
			
		||||
  ".m4v": "video/mp4",
 | 
			
		||||
  ".avi": "video/x-msvideo",
 | 
			
		||||
  ".mov": "video/quicktime",
 | 
			
		||||
  ".qt": "video/quicktime",
 | 
			
		||||
  ".wmv": "video/x-ms-wmv",
 | 
			
		||||
  ".asf": "video/x-ms-asf",
 | 
			
		||||
  ".flv": "video/x-flv",
 | 
			
		||||
  ".f4v": "video/x-f4v",
 | 
			
		||||
  ".webm": "video/webm",
 | 
			
		||||
  ".mkv": "video/x-matroska",
 | 
			
		||||
  ".mka": "audio/x-matroska",
 | 
			
		||||
  ".mks": "video/x-matroska",
 | 
			
		||||
  ".ogv": "video/ogg",
 | 
			
		||||
  ".ogm": "video/ogg",
 | 
			
		||||
  ".mxf": "application/mxf",
 | 
			
		||||
  ".m2ts": "video/mp2t",
 | 
			
		||||
  ".mts": "video/mp2t",
 | 
			
		||||
  ".vob": "video/dvd",
 | 
			
		||||
  ".mpg": "video/mpeg",
 | 
			
		||||
  ".mpeg": "video/mpeg",
 | 
			
		||||
  ".m1v": "video/mpeg",
 | 
			
		||||
  ".m2v": "video/mpeg",
 | 
			
		||||
  ".rm": "application/vnd.rn-realmedia",
 | 
			
		||||
  ".rmvb": "application/vnd.rn-realmedia-vbr",
 | 
			
		||||
  ".divx": "video/divx",
 | 
			
		||||
  ".xvid": "video/x-xvid",
 | 
			
		||||
 | 
			
		||||
  // Archives and Compression
 | 
			
		||||
  ".zip": "application/zip",
 | 
			
		||||
  ".rar": "application/vnd.rar",
 | 
			
		||||
  ".7z": "application/x-7z-compressed",
 | 
			
		||||
  ".tar": "application/x-tar",
 | 
			
		||||
  ".tar.gz": "application/gzip",
 | 
			
		||||
  ".tgz": "application/gzip",
 | 
			
		||||
  ".tar.bz2": "application/x-bzip2",
 | 
			
		||||
  ".tbz2": "application/x-bzip2",
 | 
			
		||||
  ".tar.xz": "application/x-xz",
 | 
			
		||||
  ".txz": "application/x-xz",
 | 
			
		||||
  ".tar.lz": "application/x-lzip",
 | 
			
		||||
  ".tar.Z": "application/x-compress",
 | 
			
		||||
  ".Z": "application/x-compress",
 | 
			
		||||
  ".gz": "application/gzip",
 | 
			
		||||
  ".bz2": "application/x-bzip2",
 | 
			
		||||
  ".xz": "application/x-xz",
 | 
			
		||||
  ".lz": "application/x-lzip",
 | 
			
		||||
  ".lzma": "application/x-lzma",
 | 
			
		||||
  ".lzo": "application/x-lzop",
 | 
			
		||||
  ".arj": "application/x-arj",
 | 
			
		||||
  ".ace": "application/x-ace-compressed",
 | 
			
		||||
  ".cab": "application/vnd.ms-cab-compressed",
 | 
			
		||||
  ".iso": "application/x-iso9660-image",
 | 
			
		||||
  ".dmg": "application/x-apple-diskimage",
 | 
			
		||||
  ".img": "application/x-img",
 | 
			
		||||
  ".bin": "application/octet-stream",
 | 
			
		||||
  ".cue": "application/x-cue",
 | 
			
		||||
  ".nrg": "application/x-nrg",
 | 
			
		||||
  ".mdf": "application/x-mdf",
 | 
			
		||||
  ".toast": "application/x-toast",
 | 
			
		||||
 | 
			
		||||
  // Executables and System
 | 
			
		||||
  ".exe": "application/vnd.microsoft.portable-executable",
 | 
			
		||||
  ".dll": "application/vnd.microsoft.portable-executable",
 | 
			
		||||
  ".msi": "application/x-msdownload",
 | 
			
		||||
  ".msp": "application/x-msdownload",
 | 
			
		||||
  ".deb": "application/vnd.debian.binary-package",
 | 
			
		||||
  ".rpm": "application/x-rpm",
 | 
			
		||||
  ".pkg": "application/x-newton-compatible-pkg",
 | 
			
		||||
  ".apk": "application/vnd.android.package-archive",
 | 
			
		||||
  ".ipa": "application/octet-stream",
 | 
			
		||||
  ".app": "application/octet-stream",
 | 
			
		||||
  ".snap": "application/x-snap",
 | 
			
		||||
  ".flatpak": "application/vnd.flatpak",
 | 
			
		||||
  ".appimage": "application/x-appimage",
 | 
			
		||||
 | 
			
		||||
  // Adobe and Design
 | 
			
		||||
  ".ai": "application/illustrator",
 | 
			
		||||
  ".indd": "application/x-indesign",
 | 
			
		||||
  ".idml": "application/vnd.adobe.indesign-idml-package",
 | 
			
		||||
  ".sketch": "application/x-sketch",
 | 
			
		||||
  ".fig": "application/x-figma",
 | 
			
		||||
  ".xd": "application/vnd.adobe.xd",
 | 
			
		||||
 | 
			
		||||
  // Fonts
 | 
			
		||||
  ".ttf": "font/ttf",
 | 
			
		||||
  ".otf": "font/otf",
 | 
			
		||||
  ".woff": "font/woff",
 | 
			
		||||
  ".woff2": "font/woff2",
 | 
			
		||||
  ".eot": "application/vnd.ms-fontobject",
 | 
			
		||||
  ".fon": "application/x-font-bdf",
 | 
			
		||||
  ".bdf": "application/x-font-bdf",
 | 
			
		||||
  ".pcf": "application/x-font-pcf",
 | 
			
		||||
  ".pfb": "application/x-font-type1",
 | 
			
		||||
  ".pfm": "application/x-font-type1",
 | 
			
		||||
  ".afm": "application/x-font-afm",
 | 
			
		||||
 | 
			
		||||
  // E-books
 | 
			
		||||
  ".epub": "application/epub+zip",
 | 
			
		||||
  ".mobi": "application/x-mobipocket-ebook",
 | 
			
		||||
  ".azw": "application/vnd.amazon.ebook",
 | 
			
		||||
  ".azw3": "application/vnd.amazon.ebook",
 | 
			
		||||
  ".fb2": "application/x-fictionbook+xml",
 | 
			
		||||
  ".lit": "application/x-ms-reader",
 | 
			
		||||
  ".pdb": "application/vnd.palm",
 | 
			
		||||
  ".prc": "application/vnd.palm",
 | 
			
		||||
  ".tcr": "application/x-psion3-s",
 | 
			
		||||
 | 
			
		||||
  // CAD and 3D
 | 
			
		||||
  ".dwg": "image/vnd.dwg",
 | 
			
		||||
  ".dxf": "image/vnd.dxf",
 | 
			
		||||
  ".step": "application/step",
 | 
			
		||||
  ".stp": "application/step",
 | 
			
		||||
  ".iges": "application/iges",
 | 
			
		||||
  ".igs": "application/iges",
 | 
			
		||||
  ".stl": "application/sla",
 | 
			
		||||
  ".obj": "application/x-tgif",
 | 
			
		||||
  ".3ds": "application/x-3ds",
 | 
			
		||||
  ".dae": "model/vnd.collada+xml",
 | 
			
		||||
  ".ply": "application/ply",
 | 
			
		||||
  ".x3d": "model/x3d+xml",
 | 
			
		||||
 | 
			
		||||
  // Database
 | 
			
		||||
  ".db": "application/x-sqlite3",
 | 
			
		||||
  ".sqlite": "application/x-sqlite3",
 | 
			
		||||
  ".sqlite3": "application/x-sqlite3",
 | 
			
		||||
  ".mdb": "application/x-msaccess",
 | 
			
		||||
  ".accdb": "application/x-msaccess",
 | 
			
		||||
 | 
			
		||||
  // Virtual Machine and Disk Images
 | 
			
		||||
  ".vmdk": "application/x-vmdk",
 | 
			
		||||
  ".vdi": "application/x-virtualbox-vdi",
 | 
			
		||||
  ".vhd": "application/x-virtualbox-vhd",
 | 
			
		||||
  ".vhdx": "application/x-virtualbox-vhdx",
 | 
			
		||||
  ".ova": "application/x-virtualbox-ova",
 | 
			
		||||
  ".ovf": "application/x-virtualbox-ovf",
 | 
			
		||||
  ".qcow2": "application/x-qemu-disk",
 | 
			
		||||
 | 
			
		||||
  // Scientific and Math
 | 
			
		||||
  ".mat": "application/x-matlab-data",
 | 
			
		||||
  ".nc": "application/x-netcdf",
 | 
			
		||||
  ".cdf": "application/x-netcdf",
 | 
			
		||||
  ".hdf": "application/x-hdf",
 | 
			
		||||
  ".h5": "application/x-hdf5",
 | 
			
		||||
 | 
			
		||||
  // Misc Application Formats
 | 
			
		||||
  ".torrent": "application/x-bittorrent",
 | 
			
		||||
  ".rss": "application/rss+xml",
 | 
			
		||||
  ".atom": "application/atom+xml",
 | 
			
		||||
  ".gpx": "application/gpx+xml",
 | 
			
		||||
  ".kml": "application/vnd.google-earth.kml+xml",
 | 
			
		||||
  ".kmz": "application/vnd.google-earth.kmz",
 | 
			
		||||
  ".ics": "text/calendar",
 | 
			
		||||
  ".vcs": "text/x-vcalendar",
 | 
			
		||||
  ".vcf": "text/x-vcard",
 | 
			
		||||
  ".p7s": "application/pkcs7-signature",
 | 
			
		||||
  ".p7m": "application/pkcs7-mime",
 | 
			
		||||
  ".p12": "application/x-pkcs12",
 | 
			
		||||
  ".pfx": "application/x-pkcs12",
 | 
			
		||||
  ".cer": "application/x-x509-ca-cert",
 | 
			
		||||
  ".crt": "application/x-x509-ca-cert",
 | 
			
		||||
  ".pem": "application/x-pem-file",
 | 
			
		||||
  ".key": "application/x-pem-file",
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get MIME type from file extension
 | 
			
		||||
 * @param filename - The filename or extension (with or without leading dot)
 | 
			
		||||
 * @returns MIME type string, defaults to 'application/octet-stream' if unknown
 | 
			
		||||
 */
 | 
			
		||||
export function getMimeType(filename: string): string {
 | 
			
		||||
  if (!filename) {
 | 
			
		||||
    return "application/octet-stream";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  let extension: string;
 | 
			
		||||
 | 
			
		||||
  if (filename.startsWith(".")) {
 | 
			
		||||
    extension = filename.toLowerCase();
 | 
			
		||||
  } else if (!filename.includes(".")) {
 | 
			
		||||
    extension = "." + filename.toLowerCase();
 | 
			
		||||
  } else {
 | 
			
		||||
    const lastDotIndex = filename.lastIndexOf(".");
 | 
			
		||||
    if (lastDotIndex === -1) {
 | 
			
		||||
      return "application/octet-stream";
 | 
			
		||||
    }
 | 
			
		||||
    extension = filename.substring(lastDotIndex).toLowerCase();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return mimeTypeMap[extension] || "application/octet-stream";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Check if a MIME type represents an image
 | 
			
		||||
 * @param mimeType - The MIME type to check
 | 
			
		||||
 * @returns true if the MIME type is an image type
 | 
			
		||||
 */
 | 
			
		||||
export function isImageMimeType(mimeType: string): boolean {
 | 
			
		||||
  return mimeType.startsWith("image/");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get appropriate Content-Type header value for a file
 | 
			
		||||
 * @param filename - The filename to detect type for
 | 
			
		||||
 * @returns Content-Type header value
 | 
			
		||||
 */
 | 
			
		||||
export function getContentType(filename: string): string {
 | 
			
		||||
  return getMimeType(filename);
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user