UNPKG

@lobehub/chat

Version:

Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.

154 lines (140 loc) 5.99 kB
import mime from 'mime'; /** * Build a path string from a path and a hash/search object * * This function constructs a properly formatted URL path by combining a base path * with optional hash and search parameters. It uses URL constructor for proper * encoding and formatting while removing the temporary base domain. * * @param path - The base path (can be relative, absolute, or include protocol) * @param options - Optional configuration object * @param options.hash - Hash fragment to append (with or without leading #) * @param options.search - Search/query parameters to append (with or without leading ?) * @returns Formatted path string with hash and search parameters * * @example * ```typescript * pathString('/home') // '/home' * pathString('/home', { search: 'id=1&name=test' }) // '/home?id=1&name=test' * pathString('/home', { hash: 'top' }) // '/home#top' * pathString('./home') // '/home' * pathString('https://example.com/path') // 'https://example.com/path' * ``` */ export const pathString = ( path: string, { hash = '', search = '', }: { hash?: string; search?: string; } = {}, ) => { // Use a temporary base URL for proper URL parsing and formatting const tempBase = 'https://a.com'; const url = new URL(path, tempBase); // Add hash fragment if provided if (hash) url.hash = hash; // Add search parameters if provided if (search) url.search = search; // Return the formatted URL without the temporary base return url.toString().replace(tempBase, ''); }; /** * Get file extension from URL * * This function extracts the file extension from a URL's pathname and validates it against * common image formats. It properly handles URLs with query parameters, hash fragments, * relative paths, and various edge cases. Returns empty string for invalid cases. * * @param url - The URL to extract extension from (can be relative, absolute, or include query parameters and hash fragments) * @returns file extension without dot (e.g., 'jpg', 'png', 'webp'), or empty string for invalid cases * * @example * ```typescript * inferFileExtensionFromImageUrl('https://example.com/image.jpg') // 'jpg' * inferFileExtensionFromImageUrl('https://example.com/image.png?v=123') // 'png' * inferFileExtensionFromImageUrl('https://example.com/image.webp#section') // 'webp' * inferFileExtensionFromImageUrl('generations/images/photo.png') // 'png' * inferFileExtensionFromImageUrl('https://example.com/document.txt') // '' (empty string) * inferFileExtensionFromImageUrl('invalid-url') // '' (empty string) * ``` */ export const inferFileExtensionFromImageUrl = (url: string): string => { // Use a temporary base URL for proper URL parsing and formatting (handles relative paths) const tempBase = 'https://a.com'; const urlObj = new URL(url, tempBase); const pathname = urlObj.pathname; // Find the last dot in the pathname to get the file extension const lastDotIndex = pathname.lastIndexOf('.'); if (lastDotIndex === -1) return ''; // No extension found, return empty string // Extract extension after the last dot and convert to lowercase const extension = pathname.slice(Math.max(0, lastDotIndex + 1)).toLowerCase(); // Validate against common image extensions const validImageExtensions = ['webp', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'svg', 'tiff', 'tif']; if (validImageExtensions.includes(extension)) { return extension; } // Default fallback for non-image extensions return ''; }; /** * Infer content type (MIME type) from an image URL * * This function extracts the file extension from a URL and returns the corresponding MIME type. * It properly handles URLs with query parameters, hash fragments, relative paths, and various edge cases. * * @param url - The image URL to analyze (can be relative, absolute, or include query parameters and hash fragments) * @returns MIME type string (e.g., 'image/jpeg', 'image/png') * @throws {Error} When the URL doesn't contain a valid file extension * * @example * ```typescript * inferContentTypeFromImageUrl('https://example.com/image.jpg') // 'image/jpeg' * inferContentTypeFromImageUrl('https://example.com/image.png?v=123') // 'image/png' * inferContentTypeFromImageUrl('https://example.com/image.webp#section') // 'image/webp' * inferContentTypeFromImageUrl('generations/images/photo.png') // 'image/png' * ``` */ export function inferContentTypeFromImageUrl(url: string) { // Get the file extension using the dedicated function // inferFileExtensionFromImageUrl only returns valid image extensions or empty string const extension = inferFileExtensionFromImageUrl(url); // If no valid extension found, throw error if (!extension) { throw new Error(`Invalid image url: ${url}`); } // Get MIME type using the mime library // Since extension is guaranteed to be a valid image extension from the whitelist, // mime.getType() will always return a valid image MIME type const mimeType = mime.getType(extension); return mimeType!; // Non-null assertion is safe due to whitelist validation } /** * Check if a URL points to localhost (127.0.0.1) * * This function safely determines if the provided URL's hostname is '127.0.0.1'. * It handles malformed URLs gracefully by returning false instead of throwing errors. * * @param url - The URL string to check * @returns true if the URL's hostname is '127.0.0.1', false otherwise (including for malformed URLs) * * @example * ```typescript * isLocalUrl('http://127.0.0.1:8080/path') // true * isLocalUrl('https://example.com') // false * isLocalUrl('invalid-url') // false (instead of throwing) * isLocalUrl('') // false (instead of throwing) * ``` * * check: apps/desktop/src/main/core/StaticFileServerManager.ts */ export function isLocalUrl(url: string) { try { return new URL(url).hostname === '127.0.0.1'; } catch { // Return false for malformed URLs instead of throwing return false; } }