Download src/lib/api/mode.ts from asnannp/DocDoeAI: direct link, hf CLI and curl.
- Browser
- Download file 2.84 kB
-
https://huggingface.co/spaces/asnannp/DocDoeAI/resolve/main/src/lib/api/mode.ts
- Command line
-
hf download hf://spaces/asnannp/DocDoeAI/src/lib/api/mode.ts
-
curl -L -o mode.ts https://huggingface.co/spaces/asnannp/DocDoeAI/resolve/main/src/lib/api/mode.ts
2.84 kB
| import { isApiError } from "@/lib/api/client"; | |
| import { getAuthToken, isDemoPreviewSession } from "@/lib/auth/auth-client"; | |
| import { getPublicDemoMode } from "@/lib/env"; | |
| export function isLocalResourceId(id: string | null | undefined) { | |
| if (!id) return false; | |
| if (id.startsWith("doc-local-") || id.startsWith("paper-local-") || id.startsWith("job-local-") || id.startsWith("render-local-")) { | |
| return true; | |
| } | |
| return !/^(doc|paper|vjob|usr)_[a-z0-9]+$/i.test(id); | |
| } | |
| export function hasLiveSession() { | |
| return Boolean(getAuthToken()) && !isDemoPreviewSession(); | |
| } | |
| /** | |
| * Returns true when the frontend should use local mock data instead of calling the API. | |
| * | |
| * In "demo" mode: always use demo data. | |
| * In "live" mode: never use demo data. | |
| * In "auto" mode: use demo data only for local resource IDs (doc-local-xxx). | |
| */ | |
| export function shouldUseDemoData(resourceId?: string | null) { | |
| if (isDemoPreviewSession()) return true; | |
| const mode = getPublicDemoMode(); | |
| if (mode === "demo") return true; | |
| if (mode === "live") return false; | |
| // "auto" β use demo data only for local IDs (offline-created resources) | |
| if (resourceId && isLocalResourceId(resourceId)) return true; | |
| return false; | |
| } | |
| /** | |
| * Whether to silently fall back to demo data on API errors. | |
| * | |
| * Only returns true in explicit "demo" mode, or in "auto" mode when | |
| * no auth token exists (i.e., no backend connection has been established). | |
| * | |
| * When a real session exists (token present), errors must surface to the | |
| * user so they know something failed β not silently replaced with fakes. | |
| */ | |
| function shouldFallbackOnError(): boolean { | |
| if (isDemoPreviewSession()) return true; | |
| const mode = getPublicDemoMode(); | |
| if (mode === "demo") return true; | |
| if (mode === "live") return false; | |
| // "auto" β only fall back if there is no live session (no token = no backend) | |
| return !hasLiveSession(); | |
| } | |
| /** | |
| * Wraps an API call with a fallback. In production (live/auto with token), | |
| * errors are propagated to the UI so students see real error states. | |
| * Only in demo mode (or auto without a backend) are errors silently caught. | |
| */ | |
| export async function withDemoFallback<T>( | |
| request: () => Promise<T>, | |
| fallback: () => Promise<T> | T, | |
| ): Promise<T> { | |
| try { | |
| return await request(); | |
| } catch (error) { | |
| // Auth errors ALWAYS re-throw regardless of mode | |
| if (isApiError(error) && error.isAuthError) { | |
| throw error; | |
| } | |
| // In demo-only mode (no real backend), silently fall back | |
| if (shouldFallbackOnError()) { | |
| const isRecoverable = | |
| (isApiError(error) && (error.status === null || error.status >= 500)) || | |
| error instanceof TypeError; | |
| if (isRecoverable) { | |
| return fallback(); | |
| } | |
| } | |
| // In production: propagate the error so the UI shows a real error state | |
| throw error; | |
| } | |
| } | |