mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-07-03 05:38:26 +00:00
## Summary Let the running ComfyUI server decide which backend the web UI talks to (and which Firebase project it signs you into), so launching with `--comfy-api-base` just works with the regular bundled frontend. ## Changes - **What**: At startup the frontend reads `/api/features` on every build (not just cloud) and treats the server's `comfy_api_base_url` / `comfy_platform_base_url` as authoritative, falling back to the build-time defaults. When that api base is a staging-tier host (staging, or a `*.testenvs.comfy.org` preview env) and the server hasn't supplied its own Firebase config, the frontend picks the dev Firebase project, derived from the api base. Production is left exactly as it is today. - `main.ts`: load remote config first thing, before Firebase initializes, so every module sees the right values from the first render - `config/comfyApi.ts`: the api/platform getters now read the server's values on all distributions - `config/firebase.ts`: `getFirebaseConfig()` resolves in order: a server-provided config first (cloud), then the dev project for a staging-tier api base, then the build-time default - `platform/remoteConfig/refreshRemoteConfig.ts`: the startup fetch now has a 5s timeout, so a slow or wedged `/features` can never keep the app from mounting; on failure we fall back to the build-time defaults - **Breaking**: None. With no `/features` overrides (production and ordinary self-hosting), behavior is unchanged ## Review Focus - The precedence in `getFirebaseConfig()` (`config/firebase.ts`): server config first, then the staging-tier dev project, then the build-time default. The staging-tier check matches `stagingapi.comfy.org` and any `*.testenvs.comfy.org` host, and falls back to build-time for anything it can't parse. - Running `refreshRemoteConfig()` unconditionally and first in `main.ts`, with the new fetch timeout as the safety net. ## Testing I tested every case by hand, locally, on top of the automated checks. Tested both with `pnpm run build` and `USE_PROD_CONFIG=true pnpm build` and running Comfy from that folder. Pointed a local ComfyUI at each backend with `--comfy-api-base` and signed in with Google each time: - **Production** (default / `https://api.comfy.org`): stays on production and signs into the production Firebase project, identical to today. - **Staging** (`https://stagingapi.comfy.org`): follows it and signs into the dev project. - **Ephemeral preview env** (`https://pr-<n>.testenvs.comfy.org`): the friendly host is accepted as-is, the frontend follows it, lands in the dev project, and Google sign-in completes. The only exception where fronted does not respect the `--comfy-api-base` is when Comfy runs against `prod` and frontend runs with the `pnpm run dev` - due to overridden config(this is expected behavior). Supersedes: https://github.com/Comfy-Org/ComfyUI_frontend/pull/12560 Companion Core PR: https://github.com/Comfy-Org/ComfyUI/pull/14569 ## Screenshots (if applicable) <!-- Add screenshots or video recording to help explain your changes -->
80 lines
2.4 KiB
TypeScript
80 lines
2.4 KiB
TypeScript
import {
|
|
cachedTeamWorkspacesEnabled,
|
|
remoteConfig,
|
|
remoteConfigState
|
|
} from './remoteConfig'
|
|
|
|
// Cap the bootstrap fetch so a wedged /features endpoint can never block app.mount indefinitely.
|
|
// A same-origin GET against the local comfyui server should resolve in well under a second;
|
|
// on timeout the catch below clears remoteConfig and consumers fall back to build-time defaults.
|
|
const FEATURES_FETCH_TIMEOUT_MS = 5_000
|
|
|
|
interface RefreshRemoteConfigOptions {
|
|
/**
|
|
* Whether to use authenticated API (default: true).
|
|
* Set to false during bootstrap before auth is initialized.
|
|
*/
|
|
useAuth?: boolean
|
|
}
|
|
|
|
async function fetchRemoteConfig(
|
|
useAuth: boolean,
|
|
signal?: AbortSignal
|
|
): Promise<Response> {
|
|
const { api } = await import('@/scripts/api')
|
|
if (!useAuth) {
|
|
return fetch(api.apiURL('/features'), { cache: 'no-store', signal })
|
|
}
|
|
return api.fetchApi('/features', { cache: 'no-store' })
|
|
}
|
|
|
|
/**
|
|
* Loads remote configuration from the backend /features endpoint
|
|
* and updates the reactive remoteConfig ref.
|
|
*
|
|
* Sets remoteConfigState to:
|
|
* - 'anonymous' when loaded without auth
|
|
* - 'authenticated' when loaded with auth
|
|
* - 'error' when load fails
|
|
*/
|
|
export async function refreshRemoteConfig(
|
|
options: RefreshRemoteConfigOptions = {}
|
|
): Promise<void> {
|
|
const { useAuth = true } = options
|
|
|
|
const controller = useAuth ? null : new AbortController()
|
|
const timeoutId = controller
|
|
? setTimeout(() => controller.abort(), FEATURES_FETCH_TIMEOUT_MS)
|
|
: null
|
|
|
|
try {
|
|
const response = await fetchRemoteConfig(useAuth, controller?.signal)
|
|
|
|
if (response.ok) {
|
|
const config = await response.json()
|
|
window.__CONFIG__ = config
|
|
remoteConfig.value = config
|
|
remoteConfigState.value = useAuth ? 'authenticated' : 'anonymous'
|
|
if (useAuth)
|
|
cachedTeamWorkspacesEnabled.value = Boolean(
|
|
config.team_workspaces_enabled
|
|
)
|
|
return
|
|
}
|
|
|
|
console.warn('Failed to load remote config:', response.statusText)
|
|
if (response.status === 401 || response.status === 403) {
|
|
window.__CONFIG__ = {}
|
|
remoteConfig.value = {}
|
|
remoteConfigState.value = 'error'
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to fetch remote config:', error)
|
|
window.__CONFIG__ = {}
|
|
remoteConfig.value = {}
|
|
remoteConfigState.value = 'error'
|
|
} finally {
|
|
if (timeoutId !== null) clearTimeout(timeoutId)
|
|
}
|
|
}
|