/** * Asset URL Resolution Utilities * Provides helpers for constructing full asset URLs from item IDs or relative paths. * Works for both local development and production environments. */ import { env } from "./env"; /** * Get the base URL for assets. * In production, this should be the public dashboard URL. * In development, it defaults to localhost with the configured port. */ function getAssetsBaseUrl(): string { // Check for explicitly configured asset URL first if (process.env.ASSETS_BASE_URL) { return process.env.ASSETS_BASE_URL.replace(/\/$/, ""); // Remove trailing slash } // In production, construct from HOST/PORT or use a default if (process.env.NODE_ENV === "production") { // If WEB_URL is set, use it (future-proofing) if (process.env.WEB_URL) { return process.env.WEB_URL.replace(/\/$/, ""); } // Fallback: use the configured host and port const host = env.HOST === "0.0.0.0" ? "localhost" : env.HOST; return `http://${host}:${env.PORT}`; } // Development: use localhost with the configured port return `http://localhost:${env.PORT}`; } /** * Get the full URL for an item's icon image. * @param itemId - The item's database ID * @returns Full URL to the item's icon image * * @example * getItemIconUrl(42) // => "http://localhost:3000/assets/items/42.png" */ export function getItemIconUrl(itemId: number): string { return `${getAssetsBaseUrl()}/assets/items/${itemId}.png`; } /** * Get the full URL for any asset given its relative path. * @param relativePath - Path relative to the assets root (e.g., "items/42.png") * @returns Full URL to the asset * * @example * getAssetUrl("items/42.png") // => "http://localhost:3000/assets/items/42.png" */ export function getAssetUrl(relativePath: string): string { const cleanPath = relativePath.replace(/^\/+/, ""); // Remove leading slashes return `${getAssetsBaseUrl()}/assets/${cleanPath}`; } /** * Check if a URL is a local asset URL (relative path starting with /assets/). * @param url - The URL to check * @returns True if it's a local asset reference */ export function isLocalAssetUrl(url: string | null | undefined): boolean { if (!url) return false; return url.startsWith("/assets/") || url.startsWith("assets/"); } /** * Convert a relative asset path to a full URL. * If the URL is already absolute (http/https), returns it unchanged. * If it's a relative asset path, constructs the full URL. * * @param url - The URL to resolve (relative or absolute) * @returns The resolved full URL, or null if input was null/undefined */ export function resolveAssetUrl(url: string | null | undefined): string | null { if (!url) return null; // Already absolute if (url.startsWith("http://") || url.startsWith("https://")) { return url; } // Relative asset path if (isLocalAssetUrl(url)) { const cleanPath = url.replace(/^\/+assets\//, "").replace(/^assets\//, ""); return getAssetUrl(cleanPath); } // Unknown format, return as-is return url; } /** * Get the placeholder image URL for items without an uploaded image. * @returns Full URL to the placeholder image */ export function getPlaceholderIconUrl(): string { return `${getAssetsBaseUrl()}/assets/items/placeholder.png`; }