/** * useSiteVersion Composable * * Gets the current site version for footer badges and version displays. * Fetches the latest release version from the DCS Portal API. * * @example * ```vue * * * * ``` */ import { platformFetch } from '@duffcloudservices/cms-core' import { ref, computed, onMounted } from 'vue' import type { SiteVersionReturn } from '../types/release-notes' /** * Get environment variable value. */ function getEnvVar(key: string, defaultValue = ''): string { try { if (typeof import.meta !== 'undefined' && import.meta.env) { const value = (import.meta.env as Record)[key] if (value !== undefined) return value } } catch { // import.meta not available } return defaultValue } // Cache for site version let versionCache: { version: string; expiresAt: number } | null = null const CACHE_TTL = 10 * 60 * 1000 // 10 minutes /** * useSiteVersion composable for displaying the current site version. * * @param options - Optional configuration * @returns Site version data and computed URL */ export function useSiteVersion(options: { fetchOnMount?: boolean } = {}): SiteVersionReturn { const { fetchOnMount = true } = options const apiBaseUrl = getEnvVar('VITE_API_BASE_URL', 'https://portal.duffcloudservices.com') // @deprecated VITE_SITE_SLUG: the site is now resolved server-side from the // request Host or the dedicated Container App's DCS_SITE_SLUG. It is no longer // used for routing; retained only for source compatibility. void getEnvVar('VITE_SITE_SLUG', '') const version = ref(null) const isLoading = ref(false) const releaseNotesUrl = computed(() => { if (!version.value) return '/releaseNotes/latest' return `/releaseNotes/${version.value}` }) async function fetchVersion(): Promise { // Check cache if (versionCache && versionCache.expiresAt > Date.now()) { version.value = versionCache.version return } isLoading.value = true try { // Fetch the latest release notes to get the version const url = `${apiBaseUrl}/api/v1/release-notes/latest` // C-298 layer 2 — see useReleaseNotes: an HTML body is a misroute, not "no release // notes yet", and this composable's catch would otherwise swallow it silently. const response = await platformFetch(url, { headers: { Accept: 'application/json', }, }) if (!response.ok) { // No release notes yet - that's fine return } const data = await response.json() const latestVersion = data.version // Cache the result versionCache = { version: latestVersion, expiresAt: Date.now() + CACHE_TTL, } version.value = latestVersion } catch (e) { console.error('[@duffcloudservices/cms] Failed to fetch site version:', e) } finally { isLoading.value = false } } // Fetch on mount if enabled if (fetchOnMount && typeof window !== 'undefined') { onMounted(() => { fetchVersion() }) } return { version, isLoading, releaseNotesUrl, } }