export function joinurl(...segments) { let url = segments[0]; for (const segment of segments.slice(1)) { if (url.endsWith("/") && segment.startsWith("/")) { url = url.slice(0, -1) + segment; } else if (!url.endsWith("/") && !segment.startsWith("/")) { url = url + "/" + segment; } else { url = url + segment; } } return url; } export function extname(filename) { if (!filename.includes(".")) { return ""; } return "." + filename.split(".").pop(); } export function getContentTypeForFilename(filename) { const extension = extname(filename).toLowerCase(); return getContentTypeForExtension(extension); } export function getContentTypeForExtension(extension, fallback = "text/plain") { switch (extension) { case ".html": return "text/html"; case ".css": return "text/css"; case ".js": return "application/javascript"; case ".json": return "application/json"; case ".svg": return "image/svg+xml"; case ".png": return "image/png"; case ".jpg": return "image/jpeg"; case ".gif": return "image/gif"; case ".webp": return "image/webp"; case ".ico": return "image/x-icon"; case ".txt": return "text/plain"; case ".md": return "text/markdown"; case ".xml": return "application/xml"; case ".pdf": return "application/pdf"; case ".zip": return "application/zip"; case ".7z": return "application/x-7z-compressed"; case ".tar": return "application/x-tar"; case ".gz": return "application/gzip"; case ".bz2": return "application/x-bzip2"; case ".mp3": return "audio/mpeg"; case ".mp4": return "video/mp4"; case ".webm": return "video/webm"; case ".ogg": return "audio/ogg"; case ".wav": return "audio/wav"; case ".flac": return "audio/flac"; case ".aac": return "audio/aac"; case ".m4a": return "audio/mp4"; case ".m4v": return "video/mp4"; } return fallback; } export function trimLeadingSlash(path) { if (path.startsWith("/")) { return path.slice(1); } return path; }