Spaces:
Sleeping
Sleeping
File size: 5,072 Bytes
f871fed |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
/**
* Runtime configuration for the frontend.
* This allows the same Docker image to work in different environments.
*/
import { AppConfig, BackendConfigResponse } from '@/lib/types/config'
// Build timestamp for debugging - set at build time
const BUILD_TIME = new Date().toISOString()
let config: AppConfig | null = null
let configPromise: Promise<AppConfig> | null = null
/**
* Get the API URL to use for requests.
*
* Priority:
* 1. Runtime config from API server (/api/config endpoint)
* 2. Environment variable (NEXT_PUBLIC_API_URL)
* 3. Default fallback (http://localhost:5055)
*/
export async function getApiUrl(): Promise<string> {
// If we already have config, return it
if (config) {
return config.apiUrl
}
// If we're already fetching, wait for that
if (configPromise) {
const cfg = await configPromise
return cfg.apiUrl
}
// Start fetching config
configPromise = fetchConfig()
const cfg = await configPromise
return cfg.apiUrl
}
/**
* Get the full configuration.
*/
export async function getConfig(): Promise<AppConfig> {
if (config) {
return config
}
if (configPromise) {
return await configPromise
}
configPromise = fetchConfig()
return await configPromise
}
/**
* Fetch configuration from the API or use defaults.
*/
async function fetchConfig(): Promise<AppConfig> {
console.log('π§ [Config] Starting configuration detection...')
console.log('π§ [Config] Build time:', BUILD_TIME)
// STEP 1: Try to get runtime config from Next.js server-side endpoint
// This allows API_URL to be set at runtime (not baked into build)
// Note: Endpoint is at /config (not /api/config) to avoid reverse proxy conflicts
let runtimeApiUrl: string | null = null
try {
console.log('π§ [Config] Attempting to fetch runtime config from /config endpoint...')
const runtimeResponse = await fetch('/config', {
cache: 'no-store',
})
if (runtimeResponse.ok) {
const runtimeData = await runtimeResponse.json()
runtimeApiUrl = runtimeData.apiUrl
console.log('β
[Config] Runtime API URL from server:', runtimeApiUrl)
} else {
console.log('β οΈ [Config] Runtime config endpoint returned status:', runtimeResponse.status)
}
} catch (error) {
console.log('β οΈ [Config] Could not fetch runtime config:', error)
}
// STEP 2: Fallback to build-time environment variable
const envApiUrl = process.env.NEXT_PUBLIC_API_URL
console.log('π§ [Config] NEXT_PUBLIC_API_URL from build:', envApiUrl || '(not set)')
// STEP 3: Smart default - use Hugging Face Space URL as fallback
// Priority: Runtime config > Build-time env var > Hugging Face Space URL > localhost
let defaultApiUrl = process.env.NEXT_PUBLIC_API_URL || 'https://baveshraam-open-notebook.hf.space'
if (typeof window !== 'undefined') {
const hostname = window.location.hostname
const protocol = window.location.protocol
console.log('π§ [Config] Current frontend URL:', `${protocol}//${hostname}${window.location.port ? ':' + window.location.port : ''}`)
// If not localhost, use the same hostname with port 5055
if (hostname !== 'localhost' && hostname !== '127.0.0.1') {
defaultApiUrl = `${protocol}//${hostname}:5055`
console.log('π§ [Config] Detected remote hostname, using:', defaultApiUrl)
} else {
console.log('π§ [Config] Detected localhost, using:', defaultApiUrl)
}
}
// Priority: Runtime config > Build-time env var > Smart default
const baseUrl = runtimeApiUrl || envApiUrl || defaultApiUrl
console.log('π§ [Config] Final base URL to try:', baseUrl)
console.log('π§ [Config] Selection priority: runtime=' + (runtimeApiUrl ? 'β
' : 'β') +
', build-time=' + (envApiUrl ? 'β
' : 'β') +
', smart-default=' + (!runtimeApiUrl && !envApiUrl ? 'β
' : 'β'))
try {
console.log('π§ [Config] Fetching backend config from:', `${baseUrl}/api/config`)
// Try to fetch runtime config from backend API
const response = await fetch(`${baseUrl}/api/config`, {
cache: 'no-store',
})
if (response.ok) {
const data: BackendConfigResponse = await response.json()
config = {
apiUrl: baseUrl, // Use baseUrl from runtime-config (Python no longer returns this)
version: data.version || 'unknown',
buildTime: BUILD_TIME,
latestVersion: data.latestVersion || null,
hasUpdate: data.hasUpdate || false,
dbStatus: data.dbStatus, // Can be undefined for old backends
}
console.log('β
[Config] Successfully loaded API config:', config)
return config
} else {
// Don't log error here - ConnectionGuard will display it
throw new Error(`API config endpoint returned status ${response.status}`)
}
} catch (error) {
// Don't log error here - ConnectionGuard will display it with proper UI
throw error
}
}
/**
* Reset the configuration cache (useful for testing).
*/
export function resetConfig(): void {
config = null
configPromise = null
}
|