- Institution Browser: multi-select for types and countries - URL query param sync for shareable filter URLs - New utility: countryNames.ts with flag emoji support - New utility: imageProxy.ts for image URL handling - New component: SearchableMultiSelect dropdown - Career timeline CSS and component updates - Media gallery improvements - Lazy load error boundary component - Version check utility
65 lines
2 KiB
TypeScript
65 lines
2 KiB
TypeScript
/**
|
|
* imageProxy.ts
|
|
*
|
|
* Utility function to proxy external image URLs through the backend
|
|
* to avoid hotlinking issues and blocked images.
|
|
*
|
|
* Many institution websites and image hosts block direct embedding
|
|
* (hotlinking) of their images. This utility routes image requests
|
|
* through our backend proxy which fetches the image server-side.
|
|
*/
|
|
|
|
/**
|
|
* Convert an external image URL to use the backend image proxy.
|
|
*
|
|
* The proxy endpoint caches images for 1 hour and adds appropriate
|
|
* headers to bypass hotlink detection.
|
|
*
|
|
* @param url - The external image URL to proxy
|
|
* @returns Proxied URL via /api/geo/image-proxy, or the original URL if local
|
|
*
|
|
* @example
|
|
* // External image - will be proxied
|
|
* proxyImageUrl('https://example.com/logo.png')
|
|
* // Returns: '/api/geo/image-proxy?url=https%3A%2F%2Fexample.com%2Flogo.png'
|
|
*
|
|
* // Local image - returned as-is
|
|
* proxyImageUrl('/images/local-logo.png')
|
|
* // Returns: '/images/local-logo.png'
|
|
*
|
|
* // Data URL - returned as-is
|
|
* proxyImageUrl('data:image/png;base64,...')
|
|
* // Returns: 'data:image/png;base64,...'
|
|
*/
|
|
export function proxyImageUrl(url: string | undefined | null): string | undefined {
|
|
// Return undefined for null/undefined
|
|
if (!url) return undefined;
|
|
|
|
// Don't proxy local URLs (relative paths)
|
|
if (url.startsWith('/')) return url;
|
|
|
|
// Don't proxy data URLs (inline base64 images)
|
|
if (url.startsWith('data:')) return url;
|
|
|
|
// Don't proxy blob URLs
|
|
if (url.startsWith('blob:')) return url;
|
|
|
|
// Proxy all other (external) URLs
|
|
return `/api/geo/image-proxy?url=${encodeURIComponent(url)}`;
|
|
}
|
|
|
|
/**
|
|
* Check if a URL is an external URL that would benefit from proxying.
|
|
*
|
|
* @param url - URL to check
|
|
* @returns true if external, false if local/data/blob
|
|
*/
|
|
export function isExternalUrl(url: string | undefined | null): boolean {
|
|
if (!url) return false;
|
|
if (url.startsWith('/')) return false;
|
|
if (url.startsWith('data:')) return false;
|
|
if (url.startsWith('blob:')) return false;
|
|
return true;
|
|
}
|
|
|
|
export default proxyImageUrl;
|