From b5dbf55c71bb4e8461aa0da832e3e9fb5a9a7343 Mon Sep 17 00:00:00 2001 From: Babayaga Date: Sat, 11 Apr 2026 21:06:22 +0200 Subject: [PATCH] deploy --- packages/ui/src/App.tsx | 12 +++++++----- packages/ui/src/bundles/ecommerce.tsx | 3 ++- .../ui/src/components/CreationWizardPopup.tsx | 1 - packages/ui/src/components/GlobalDragDrop.tsx | 18 ++++++------------ .../ui/src/components/MarkdownRenderer.tsx | 3 ++- packages/ui/src/components/UserAvatarBlock.tsx | 3 +-- packages/ui/src/components/VideoCard.tsx | 8 ++++---- .../ui/src/components/admin/BansManager.tsx | 5 +++-- .../ui/src/components/admin/UserPicker.tsx | 5 +++-- .../ui/src/components/admin/VideoManager.tsx | 3 ++- .../src/components/admin/ViolationsMonitor.tsx | 3 ++- .../src/components/lazy-editors/LinkPlugin.tsx | 2 +- .../ui/src/components/widgets/HomeWidget.tsx | 3 ++- .../components/widgets/VideoBannerWidget.tsx | 3 ++- packages/ui/src/contexts/ProfilesContext.tsx | 3 ++- packages/ui/src/contexts/StreamContext.tsx | 10 +++------- packages/ui/src/contexts/WS_Socket.tsx | 12 ++++++++---- packages/ui/src/hooks/useResponsiveImage.ts | 8 ++++---- packages/ui/src/hooks/useSystemInfo.ts | 12 +++--------- packages/ui/src/lib/openai.ts | 10 ++++------ packages/ui/src/lib/video-router.ts | 2 +- packages/ui/src/modules/ai/searchTools.ts | 5 ++--- packages/ui/src/modules/ai/types.ts | 6 +++--- packages/ui/src/modules/ai/useChatEngine.ts | 8 ++++---- .../src/modules/campaigns/client-campaigns.ts | 4 +++- .../ui/src/modules/contacts/client-contacts.ts | 4 ++-- .../src/modules/contacts/client-mailboxes.ts | 6 ++++-- packages/ui/src/modules/pages/PageActions.tsx | 3 ++- .../modules/pages/editor/EmailPreviewPanel.tsx | 2 +- .../pages/editor/hooks/useEmailActions.ts | 3 +-- .../pages/editor/ribbons/PageRibbonBar.tsx | 5 ++--- packages/ui/src/modules/places/InfoPanel.tsx | 7 +++---- .../places/components/MapPosterOverlay.tsx | 4 ++-- packages/ui/src/modules/posts/NewPost.tsx | 3 +-- .../ui/src/modules/posts/client-pictures.ts | 3 +-- packages/ui/src/modules/posts/client-videos.ts | 4 ++-- .../posts/views/components/ExportDropdown.tsx | 4 ++-- .../posts/views/renderers/ArticleRenderer.tsx | 4 ++-- .../ui/src/modules/search/client-search.ts | 4 ++-- packages/ui/src/modules/user/client-user.ts | 4 ++-- packages/ui/src/pages/AdminPage.tsx | 5 +++-- .../ui/src/pages/PlaygroundImageEditor.tsx | 6 ++---- .../src/pages/VideoPlayerPlaygroundIntern.tsx | 6 +----- packages/ui/src/playground/auth.tsx | 3 ++- packages/ui/src/utils/uploadUtils.ts | 3 +-- 45 files changed, 112 insertions(+), 123 deletions(-) diff --git a/packages/ui/src/App.tsx b/packages/ui/src/App.tsx index 11f68463..3db435c6 100644 --- a/packages/ui/src/App.tsx +++ b/packages/ui/src/App.tsx @@ -19,6 +19,7 @@ import TopNavigation from "@/components/TopNavigation"; import Footer from "@/components/Footer"; import { DragDropProvider } from "@/contexts/DragDropContext"; import { useAppStore } from "@/store/appStore"; +import { serverUrl } from "@/lib/db"; const GlobalDragDrop = React.lazy(() => import("@/components/GlobalDragDrop")); // Register all widgets on app boot @@ -66,6 +67,7 @@ let SupportChat: any; GridSearch = React.lazy(() => import("./modules/places/gridsearch/GridSearch")); LocationDetail = React.lazy(() => import("./modules/places/LocationDetail")); TypesPlayground = React.lazy(() => import("@/modules/types/TypesPlayground")); +PlaygroundAuth = React.lazy(() => import("./playground/auth")); if (enablePlaygrounds) { PlaygroundEditor = React.lazy(() => import("./pages/PlaygroundEditor")); @@ -77,8 +79,7 @@ if (enablePlaygrounds) { VariablePlayground = React.lazy(() => import("./components/variables/VariablesEditor").then(module => ({ default: module.VariablesEditor }))); I18nPlayground = React.lazy(() => import("./components/playground/I18nPlayground")); PlaygroundChat = React.lazy(() => import("./pages/PlaygroundChat")); - PlaygroundVfs = React.lazy(() => import("./pages/PlaygroundVfs")); - PlaygroundAuth = React.lazy(() => import("./playground/auth")); + PlaygroundVfs = React.lazy(() => import("./pages/PlaygroundVfs")); SupportChat = React.lazy(() => import("./pages/SupportChat")); } @@ -203,12 +204,13 @@ const AppWrapper = () => { Loading...}>} /> Loading...}>} /> Loading...}>} /> - Loading...}>} /> )} {enablePlaygrounds && Loading...}>} />} + Loading...}>} /> + {/* Logs */} Loading...}>} /> @@ -284,8 +286,8 @@ const App = () => { - - + + diff --git a/packages/ui/src/bundles/ecommerce.tsx b/packages/ui/src/bundles/ecommerce.tsx index f7b26f51..336dfa60 100644 --- a/packages/ui/src/bundles/ecommerce.tsx +++ b/packages/ui/src/bundles/ecommerce.tsx @@ -3,6 +3,7 @@ import { useNavigate } from "react-router-dom"; import { useAuth } from "@/hooks/useAuth"; import { getCurrentLang, translate } from "@/i18n"; +import { serverUrl } from "@/lib/db"; const EcommerceBundle = React.lazy(() => import("@polymech/ecommerce").then(m => ({ default: m.EcommerceBundle }))); @@ -68,7 +69,7 @@ export const EcommerceBundleWrapper = () => { siteName: "PolyMech", contactEmail: "sales@plastic-hub.com", stripePublishableKey: import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY, - apiBaseUrl: import.meta.env.VITE_SERVER_IMAGE_API_URL || "", + apiBaseUrl: serverUrl, getAuthToken: async () => session?.access_token ?? null, locale, t: translate, diff --git a/packages/ui/src/components/CreationWizardPopup.tsx b/packages/ui/src/components/CreationWizardPopup.tsx index 2d43bd4f..c8c3c4f9 100644 --- a/packages/ui/src/components/CreationWizardPopup.tsx +++ b/packages/ui/src/components/CreationWizardPopup.tsx @@ -351,7 +351,6 @@ export const CreationWizardPopup: React.FC = ({ const videoToken = await getAuthToken(); return new Promise((resolve, reject) => { - const serverUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL; const formData = new FormData(); formData.append('file', file); diff --git a/packages/ui/src/components/GlobalDragDrop.tsx b/packages/ui/src/components/GlobalDragDrop.tsx index d645f312..1a10d5e3 100644 --- a/packages/ui/src/components/GlobalDragDrop.tsx +++ b/packages/ui/src/components/GlobalDragDrop.tsx @@ -4,7 +4,7 @@ import { set } from 'idb-keyval'; import { toast } from 'sonner'; import { Upload } from 'lucide-react'; import { T, translate } from '@/i18n'; -import { getAuthToken } from '@/lib/db'; +import { apiClient } from '@/lib/db'; import { useDragDrop } from '@/contexts/DragDropContext'; const GlobalDragDrop = () => { @@ -50,19 +50,13 @@ const GlobalDragDrop = () => { } else if (isUrl) { // URL workflow toast.info(translate('Processing link...')); - const serverUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL; - - const token = await getAuthToken(); - const headers: Record = {}; - if (token) headers['Authorization'] = `Bearer ${token}`; try { - const response = await fetch(`${serverUrl}/api/serving/site-info?url=${encodeURIComponent(url)}`, { - headers - }); - if (!response.ok) throw new Error('Failed to fetch site info'); - - const siteInfo = await response.json(); + const siteInfo = await apiClient<{ + page?: { image?: string; title?: string; description?: string }; + title?: string; + description?: string; + }>(`/api/serving/site-info?url=${encodeURIComponent(url)}`); const virtualItem = { id: crypto.randomUUID(), diff --git a/packages/ui/src/components/MarkdownRenderer.tsx b/packages/ui/src/components/MarkdownRenderer.tsx index 99f07766..3502af35 100644 --- a/packages/ui/src/components/MarkdownRenderer.tsx +++ b/packages/ui/src/components/MarkdownRenderer.tsx @@ -77,6 +77,7 @@ const getPlainText = (children: React.ReactNode): string => { }; import { substitute } from '@/lib/variables'; +import { serverUrl } from '@/lib/db'; // Helper to strip YAML frontmatter const stripFrontmatter = (text: string) => { @@ -98,7 +99,7 @@ const MarkdownRenderer = React.memo(({ content, className = "", variables, baseU // If baseUrl is relative, make it absolute using the API origin so the server can fetch it let absoluteBase = baseUrl; if (baseUrl.startsWith('/')) { - const apiOrigin = import.meta.env.VITE_SERVER_IMAGE_API_URL || window.location.origin; + const apiOrigin = serverUrl || window.location.origin; // if API url is absolute (http://...), use it as the base. // fallback to window.location.origin for relative API configs. const originToUse = apiOrigin.startsWith('http') ? apiOrigin : window.location.origin; diff --git a/packages/ui/src/components/UserAvatarBlock.tsx b/packages/ui/src/components/UserAvatarBlock.tsx index bd42e2cc..3e470be6 100644 --- a/packages/ui/src/components/UserAvatarBlock.tsx +++ b/packages/ui/src/components/UserAvatarBlock.tsx @@ -3,6 +3,7 @@ import { User as UserIcon } from "lucide-react"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { useNavigate } from "react-router-dom"; import { useProfiles } from "@/contexts/ProfilesContext"; +import { serverUrl } from "@/lib/db"; interface UserAvatarBlockProps { userId: string; @@ -44,9 +45,7 @@ const UserAvatarBlock: React.FC = ({ // Construct optimized URL // We use the render endpoint: /api/images/render?url=...&width=128&format=webp - const serverUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL; if (!serverUrl) return url; - try { const optimized = new URL(`${serverUrl}/api/images/render`); optimized.searchParams.set('url', url); diff --git a/packages/ui/src/components/VideoCard.tsx b/packages/ui/src/components/VideoCard.tsx index ca0572d9..d065662e 100644 --- a/packages/ui/src/components/VideoCard.tsx +++ b/packages/ui/src/components/VideoCard.tsx @@ -18,6 +18,7 @@ import { formatDate, isLikelyFilename } from "@/utils/textUtils"; // MediaPlayer, MediaProvider, type MediaPlayerInstance // } from '@vidstack/react'; import type { MediaPlayerInstance } from '@vidstack/react'; +import { serverUrl } from "@/lib/db"; // Import Vidstack styles // import '@vidstack/react/player/styles/default/theme.css'; @@ -120,7 +121,7 @@ const VideoCard = ({ // Extracts the /api/ path and prepends the configured server base. const rewriteUrl = (url: string): string => { if (!url) return url; - const serverBase = import.meta.env.VITE_SERVER_IMAGE_API_URL; + const serverBase = serverUrl; if (!serverBase) return url; const apiIdx = url.indexOf('/api/'); if (apiIdx !== -1) return `${serverBase}${url.slice(apiIdx)}`; @@ -198,7 +199,7 @@ const VideoCard = ({ if (!match) return; const jobId = match[1]; - const baseUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL || ''; + const baseUrl = serverUrl || ''; let eventSource: EventSource | null = null; let isMounted = true; @@ -278,8 +279,7 @@ const VideoCard = ({ if (!match) return; const jobId = match[1]; - const baseUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL || ''; - + const baseUrl = serverUrl || ''; try { await fetch(`${baseUrl}/api/videos/jobs/${jobId}`, { method: 'DELETE' diff --git a/packages/ui/src/components/admin/BansManager.tsx b/packages/ui/src/components/admin/BansManager.tsx index 863e9374..35c46774 100644 --- a/packages/ui/src/components/admin/BansManager.tsx +++ b/packages/ui/src/components/admin/BansManager.tsx @@ -23,6 +23,7 @@ import { AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; +import { serverUrl } from "@/lib/db"; interface BanList { bannedIPs: string[]; @@ -42,7 +43,7 @@ export const BansManager = ({ session }: { session: any }) => { const fetchBanList = async () => { try { setLoading(true); - const res = await fetch(`${import.meta.env.VITE_SERVER_IMAGE_API_URL}/api/admin/bans`, { + const res = await fetch(`${serverUrl}/api/admin/bans`, { headers: { 'Authorization': `Bearer ${session?.access_token || ''}` } @@ -75,7 +76,7 @@ export const BansManager = ({ session }: { session: any }) => { ? { ip: unbanTarget.value } : { userId: unbanTarget.value }; - const res = await fetch(`${import.meta.env.VITE_SERVER_IMAGE_API_URL}${endpoint}`, { + const res = await fetch(`${serverUrl}${endpoint}`, { method: 'POST', headers: { 'Authorization': `Bearer ${session?.access_token || ''}`, diff --git a/packages/ui/src/components/admin/UserPicker.tsx b/packages/ui/src/components/admin/UserPicker.tsx index 44b71922..02be5b1c 100644 --- a/packages/ui/src/components/admin/UserPicker.tsx +++ b/packages/ui/src/components/admin/UserPicker.tsx @@ -17,6 +17,7 @@ import { } from "@/components/ui/popover"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { useAuth } from "@/hooks/useAuth"; +import { serverUrl } from "@/lib/db"; interface UserPickerProps { value?: string; @@ -48,8 +49,8 @@ export function UserPicker({ value, onSelect, disabled }: UserPickerProps) { try { setLoading(true); const url = q - ? `${import.meta.env.VITE_SERVER_IMAGE_API_URL}/api/profiles?q=${encodeURIComponent(q)}` - : `${import.meta.env.VITE_SERVER_IMAGE_API_URL}/api/profiles`; + ? `${serverUrl}/api/profiles?q=${encodeURIComponent(q)}` + : `${serverUrl}/api/profiles`; // Remove early return to allow fetching defaults // if (!q) { ... } diff --git a/packages/ui/src/components/admin/VideoManager.tsx b/packages/ui/src/components/admin/VideoManager.tsx index c686d030..21ff8b0e 100644 --- a/packages/ui/src/components/admin/VideoManager.tsx +++ b/packages/ui/src/components/admin/VideoManager.tsx @@ -9,11 +9,12 @@ import { fetchVideos, deleteVideos, scanVideoDisk, deleteVideoFolders, type VideoEntry, type DiskVideoFolder } from '@/modules/posts/client-videos'; +import { serverUrl } from '@/lib/db'; /** Normalize URLs: DB may store relative paths or old localhost URLs. */ const rewriteUrl = (url: string): string => { if (!url) return url; - const serverBase = import.meta.env.VITE_SERVER_IMAGE_API_URL; + const serverBase = serverUrl; if (!serverBase) return url; const apiIdx = url.indexOf('/api/'); if (apiIdx !== -1) return `${serverBase}${url.slice(apiIdx)}`; diff --git a/packages/ui/src/components/admin/ViolationsMonitor.tsx b/packages/ui/src/components/admin/ViolationsMonitor.tsx index e593d64c..9d41808a 100644 --- a/packages/ui/src/components/admin/ViolationsMonitor.tsx +++ b/packages/ui/src/components/admin/ViolationsMonitor.tsx @@ -5,6 +5,7 @@ import { Badge } from "@/components/ui/badge"; import { toast } from "sonner"; import { AlertTriangle, RefreshCw } from "lucide-react"; import { T, translate } from "@/i18n"; +import { serverUrl } from "@/lib/db"; import { Table, TableBody, @@ -36,7 +37,7 @@ export const ViolationsMonitor = ({ session }: { session: any }) => { const fetchViolationStats = async () => { try { setLoading(true); - const res = await fetch(`${import.meta.env.VITE_SERVER_IMAGE_API_URL}/api/admin/bans/violations`, { + const res = await fetch(`${serverUrl}/api/admin/bans/violations`, { headers: { 'Authorization': `Bearer ${session?.access_token || ''}` } diff --git a/packages/ui/src/components/lazy-editors/LinkPlugin.tsx b/packages/ui/src/components/lazy-editors/LinkPlugin.tsx index 29b57e10..5a042e3e 100644 --- a/packages/ui/src/components/lazy-editors/LinkPlugin.tsx +++ b/packages/ui/src/components/lazy-editors/LinkPlugin.tsx @@ -20,6 +20,7 @@ import { FileBrowserWidget } from '@/modules/storage/FileBrowserWidget'; import { vfsUrl } from '@/modules/storage/helpers'; import type { INode } from '@/modules/storage/types'; import { useAuth } from '@/hooks/useAuth'; +import { serverUrl } from '@/lib/db'; export const OPEN_LINK_EDITOR_COMMAND: LexicalCommand = createCommand('OPEN_LINK_EDITOR_COMMAND'); @@ -222,7 +223,6 @@ function LinkEditorComponent() { }, []); const handleImageSelectPicture = useCallback((picture: { id: string; title: string; image_url: string }) => { - const serverUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL || ''; const linkUrl = serverUrl ? `${serverUrl}/api/images/render?url=${encodeURIComponent(picture.image_url)}` : picture.image_url; diff --git a/packages/ui/src/components/widgets/HomeWidget.tsx b/packages/ui/src/components/widgets/HomeWidget.tsx index a6db225d..a252b76c 100644 --- a/packages/ui/src/components/widgets/HomeWidget.tsx +++ b/packages/ui/src/components/widgets/HomeWidget.tsx @@ -45,6 +45,7 @@ import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription } from ' import { LayoutGrid, GalleryVerticalEnd, TrendingUp, Clock, List, FolderTree, FileText, Image as ImageIcon, EyeOff, Lock, SlidersHorizontal, Layers, Camera, MapPin } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { cn } from '@/lib/utils'; +import { serverUrl } from '@/lib/db'; const SIDEBAR_KEY = 'categorySidebarSize'; const DEFAULT_SIDEBAR = 15; @@ -299,7 +300,7 @@ const HomeWidget: React.FC = ({ if (pictures.length === 0) { return
No pictures yet
; } - const SERVER_URL = import.meta.env.VITE_SERVER_IMAGE_API_URL || ''; + const SERVER_URL = serverUrl || ''; const isAuto = columns === 'auto'; const gridColsClass = isAuto ? 'grid-cols-[repeat(auto-fit,minmax(250px,350px))] justify-center' : Number(columns) === 1 ? 'grid-cols-1' : diff --git a/packages/ui/src/components/widgets/VideoBannerWidget.tsx b/packages/ui/src/components/widgets/VideoBannerWidget.tsx index 1976c7fe..0f1688cf 100644 --- a/packages/ui/src/components/widgets/VideoBannerWidget.tsx +++ b/packages/ui/src/components/widgets/VideoBannerWidget.tsx @@ -7,6 +7,7 @@ import { Plus, Trash2, Video, Image as ImageIcon, FileText } from 'lucide-react' import { Button } from '@/components/ui/button'; import { cn } from '@/lib/utils'; import ResponsiveImage from '@/components/ResponsiveImage'; +import { serverUrl } from '@/lib/db'; export interface ButtonConfig { id: string; @@ -203,7 +204,7 @@ const VideoBannerWidget: React.FC = ({ // Supabase bucket URLs are proxied through the server's image render API. const rewriteUrl = (url: string): string => { if (!url) return url; - const serverBase = import.meta.env.VITE_SERVER_IMAGE_API_URL; + const serverBase = serverUrl; if (!serverBase) return url; const apiIdx = url.indexOf('/api/'); if (apiIdx !== -1) return `${serverBase}${url.slice(apiIdx)}`; diff --git a/packages/ui/src/contexts/ProfilesContext.tsx b/packages/ui/src/contexts/ProfilesContext.tsx index 4b1e7f6c..a013f51b 100644 --- a/packages/ui/src/contexts/ProfilesContext.tsx +++ b/packages/ui/src/contexts/ProfilesContext.tsx @@ -1,5 +1,6 @@ import React, { createContext, useContext, useState, useEffect, useCallback } from 'react'; import { UserProfile } from "@/modules/posts/views/types"; +import { serverUrl } from '@/lib/db'; interface ProfilesContextType { profiles: Record; @@ -31,7 +32,7 @@ export const ProfilesProvider: React.FC<{ children: React.ReactNode }> = ({ chil setIsLoading(true); try { // Use the new batch API endpoint - const SERVER_URL = import.meta.env.VITE_SERVER_IMAGE_API_URL; + const SERVER_URL = serverUrl; const res = await fetch(`${SERVER_URL}/api/profiles?ids=${uniqueMissingIds.join(',')}`); if (!res.ok) { console.error('Error fetching profiles context:', res.statusText); diff --git a/packages/ui/src/contexts/StreamContext.tsx b/packages/ui/src/contexts/StreamContext.tsx index dd58de0d..2ea1c880 100644 --- a/packages/ui/src/contexts/StreamContext.tsx +++ b/packages/ui/src/contexts/StreamContext.tsx @@ -1,6 +1,7 @@ import React, { createContext, useContext, useEffect, useState, ReactNode } from 'react'; import { AppEvent } from '../types-server'; import logger from '@/Logger'; +import { serverUrl } from '@/lib/db'; type StreamStatus = 'DISCONNECTED' | 'CONNECTING' | 'CONNECTED' | 'ERROR'; @@ -41,18 +42,13 @@ export const StreamProvider: React.FC = ({ children, url }) }, []); useEffect(() => { - if (!url) return; - let eventSource: EventSource | null = null; let reconnectTimer: NodeJS.Timeout | null = null; const connect = () => { setStatus('CONNECTING'); - const SERVER_URL = import.meta.env.VITE_SERVER_IMAGE_API_URL || ''; - const streamUrl = SERVER_URL - ? `${SERVER_URL}/api/stream` - : `/api/stream`; + const streamUrl = `${serverUrl}/api/stream`; try { eventSource = new EventSource(streamUrl); @@ -117,7 +113,7 @@ export const StreamProvider: React.FC = ({ children, url }) eventSource?.close(); if (reconnectTimer) clearTimeout(reconnectTimer); }; - }, [url]); + }, []); return ( diff --git a/packages/ui/src/contexts/WS_Socket.tsx b/packages/ui/src/contexts/WS_Socket.tsx index bbcfc8eb..aef4b7cf 100644 --- a/packages/ui/src/contexts/WS_Socket.tsx +++ b/packages/ui/src/contexts/WS_Socket.tsx @@ -121,7 +121,9 @@ export const WebSocketProvider: React.FC = ({ children, }, [disconnectWebSocket]); const connectToServer = useCallback(async (urlToUse?: string): Promise => { - const targetUrl = urlToUse || apiUrl; + const raw = urlToUse ?? apiUrl; + const targetUrl = + raw || (typeof window !== 'undefined' ? window.location.origin : ''); if (urlToUse && urlToUse !== apiUrl) { setApiUrl(targetUrl); @@ -162,10 +164,12 @@ export const WebSocketProvider: React.FC = ({ children, disconnectWebSocket(true); }, [disconnectWebSocket]); - // Initial connection effect + // Initial connection effect (same-origin when initialUrl is empty) useEffect(() => { - if (initialUrl && !isConnected && !isConnecting && !connectionAborted) { - connectToServer(initialUrl); + const base = + initialUrl || (typeof window !== 'undefined' ? window.location.origin : ''); + if (base && !isConnected && !isConnecting && !connectionAborted) { + connectToServer(base); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [initialUrl]); diff --git a/packages/ui/src/hooks/useResponsiveImage.ts b/packages/ui/src/hooks/useResponsiveImage.ts index e5606910..75501591 100644 --- a/packages/ui/src/hooks/useResponsiveImage.ts +++ b/packages/ui/src/hooks/useResponsiveImage.ts @@ -1,6 +1,7 @@ import { useState, useEffect, useMemo } from 'react'; import { ResponsiveData } from '@/components/ResponsiveImage'; +import { serverUrl } from '@/lib/db'; interface UseResponsiveImageProps { src: string | File | null; @@ -22,7 +23,7 @@ export const useResponsiveImage = ({ responsiveSizes = DEFAULT_SIZES, formats = DEFAULT_FORMATS, enabled = true, - apiUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL, + apiUrl = serverUrl, }: UseResponsiveImageProps) => { const [data, setData] = useState(null); const [loading, setLoading] = useState(false); @@ -78,7 +79,7 @@ export const useResponsiveImage = ({ if (!requestCache.has(cacheKey)) { const requestPromise = (async () => { - const serverUrl = apiUrl || import.meta.env.VITE_SERVER_IMAGE_API_URL; + const serverBase = apiUrl; // Resolve relative URLs to absolute so the server-side API can fetch them let resolvedSrc = src; if (src.startsWith('/')) { @@ -96,7 +97,7 @@ export const useResponsiveImage = ({ formats: JSON.stringify(formats), }); - const response = await fetch(`${serverUrl}/api/images/responsive?${params.toString()}`); + const response = await fetch(`${serverBase}/api/images/responsive?${params.toString()}`); if (!response.ok) { const txt = await response.text(); @@ -122,7 +123,6 @@ export const useResponsiveImage = ({ formData.append('sizes', JSON.stringify(responsiveSizes)); formData.append('formats', JSON.stringify(formats)); - const serverUrl = apiUrl || import.meta.env.VITE_SERVER_IMAGE_API_URL || ''; const response = await fetch(`${serverUrl}/api/images/responsive`, { method: 'POST', body: formData, diff --git a/packages/ui/src/hooks/useSystemInfo.ts b/packages/ui/src/hooks/useSystemInfo.ts index 88aed017..6820d55e 100644 --- a/packages/ui/src/hooks/useSystemInfo.ts +++ b/packages/ui/src/hooks/useSystemInfo.ts @@ -1,22 +1,16 @@ import { useQuery } from '@tanstack/react-query'; import type { AppConfig } from '../../shared/src/config/config'; +import { apiClient, serverUrl } from '@/lib/db.js'; interface SystemInfo { env: Record & { appConfig?: AppConfig }; } export const useSystemInfo = () => { + console.log(`useSystemInfo : ${serverUrl}`); return useQuery({ queryKey: ['system-info'], - queryFn: async () => { - const SERVER_URL = import.meta.env.VITE_SERVER_IMAGE_API_URL || ''; - const fetchUrl = SERVER_URL - ? `${SERVER_URL}/api/system-info` - : '/api/system-info'; - const res = await fetch(fetchUrl); - if (!res.ok) throw new Error('Failed to fetch system info'); - return res.json(); - }, + queryFn: () => apiClient('/api/system-info'), staleTime: Infinity, gcTime: Infinity, }); diff --git a/packages/ui/src/lib/openai.ts b/packages/ui/src/lib/openai.ts index 5dc4c52d..b1aae378 100644 --- a/packages/ui/src/lib/openai.ts +++ b/packages/ui/src/lib/openai.ts @@ -10,7 +10,7 @@ * See PRESET_TOOLS mapping below for tool combinations. */ import OpenAI from 'openai'; -import { getAuthToken as getZitadelToken } from "@/lib/db"; +import { getAuthToken as getZitadelToken, serverUrl } from "@/lib/db"; import { z } from 'zod'; import { zodToJsonSchema } from 'zod-to-json-schema'; import { RunnableToolFunctionWithParse } from 'openai/lib/RunnableFunction'; @@ -114,7 +114,7 @@ export const createOpenAIClient = async (apiKey?: string): Promise void; const defaultLog: LogFunction = (level, message, data) => console.log(`[${level}] ${message}`, data); /** Production server base URL for constructing public links */ -const SERVER_BASE = (import.meta.env.VITE_SERVER_IMAGE_API_URL - || import.meta.env.VITE_SERVER_IMAGE_API_URL - || '').replace(/\/$/, ''); +const SERVER_BASE = serverUrl; /** Extract the best image URL from a FeedPost-shaped search result */ const extractImageUrl = (item: any): string | null => { diff --git a/packages/ui/src/modules/ai/types.ts b/packages/ui/src/modules/ai/types.ts index 09342925..5e146e70 100644 --- a/packages/ui/src/modules/ai/types.ts +++ b/packages/ui/src/modules/ai/types.ts @@ -2,6 +2,8 @@ * Chat Playground — shared types & helpers */ +import { serverUrl } from "@/lib/db"; + export interface ImageAttachment { id: string; url: string; // data URL for local files, or remote URL from picker @@ -41,9 +43,7 @@ export const fileToDataUrl = (file: File): Promise => /** Convert a remote image URL to a resized proxy URL via the production server. * Local images (data URLs, blobs) pass through unchanged. */ -const RENDER_API_BASE = import.meta.env.VITE_SERVER_IMAGE_API_URL_R - || import.meta.env.VITE_SERVER_IMAGE_API_URL - || ''; +const RENDER_API_BASE = serverUrl; export const getResizedImageUrl = (img: ImageAttachment, maxWidth = 1000): string => { if (img.isLocal || img.url.startsWith('data:') || img.url.startsWith('blob:')) { diff --git a/packages/ui/src/modules/ai/useChatEngine.ts b/packages/ui/src/modules/ai/useChatEngine.ts index 7feacf17..fd90e05e 100644 --- a/packages/ui/src/modules/ai/useChatEngine.ts +++ b/packages/ui/src/modules/ai/useChatEngine.ts @@ -12,6 +12,7 @@ import { useAuth } from '@/hooks/useAuth'; import { usePromptHistory } from '@/hooks/usePromptHistory'; import { useDragDrop } from '@/contexts/DragDropContext'; import { getProviderConfig } from '@/modules/user/client-user'; +import { serverUrl } from '@/lib/db'; import { createOpenAIClient } from '@/lib/openai'; import { createSearchToolPreset, createWebSearchToolPreset } from '@/modules/ai/searchTools'; import { createPageTool } from '@/lib/pageTools'; @@ -177,8 +178,7 @@ export function useChatEngine(namespace = 'chat') { const token = await getAuthToken(); if (token) headers['Authorization'] = `Bearer ${token}`; } catch { } - const apiBase = import.meta.env.VITE_SERVER_IMAGE_API_URL || ''; - const res = await fetch(`${apiBase}/api/vfs/read/${mount}/${clean}`, { headers }); + const res = await fetch(`${serverUrl}/api/vfs/read/${mount}/${clean}`, { headers }); if (!res.ok) { const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` })); addChatLog('error', `Failed to read file: ${err.error || res.status}`); @@ -262,14 +262,14 @@ export function useChatEngine(namespace = 'chat') { return new OpenAI({ apiKey: token, // This is sent as Bearer token to our proxy - baseURL: `${import.meta.env.VITE_SERVER_IMAGE_API_URL}/api/openrouter/v1`, + baseURL: `${serverUrl}/api/openrouter/v1`, dangerouslyAllowBrowser: true }); } if (provider === 'support') { return new OpenAI({ apiKey: 'support-token-placeholder', // Ignored by proxy, but required by OpenAI SDK - baseURL: `${import.meta.env.VITE_SERVER_IMAGE_API_URL}/api/support/v1`, + baseURL: `${serverUrl}/api/support/v1`, dangerouslyAllowBrowser: true }); } diff --git a/packages/ui/src/modules/campaigns/client-campaigns.ts b/packages/ui/src/modules/campaigns/client-campaigns.ts index 67a9556b..5ec79a56 100644 --- a/packages/ui/src/modules/campaigns/client-campaigns.ts +++ b/packages/ui/src/modules/campaigns/client-campaigns.ts @@ -1,5 +1,7 @@ // ─── Types ──────────────────────────────────────────────────────────────────── +import { serverUrl } from '@/lib/db'; + export interface Campaign { id: string; owner_id: string; @@ -32,7 +34,7 @@ async function authHeaders(contentType?: string): Promise { return h; } -const SERVER_URL = import.meta.env.VITE_SERVER_IMAGE_API_URL || ''; +const SERVER_URL = serverUrl; async function apiFetch(path: string, init?: RequestInit) { const url = SERVER_URL ? `${SERVER_URL}${path}` : path; diff --git a/packages/ui/src/modules/contacts/client-contacts.ts b/packages/ui/src/modules/contacts/client-contacts.ts index f798c2b4..678ee3e3 100644 --- a/packages/ui/src/modules/contacts/client-contacts.ts +++ b/packages/ui/src/modules/contacts/client-contacts.ts @@ -1,4 +1,4 @@ -import { fetchWithDeduplication } from "@/lib/db"; +import { fetchWithDeduplication, serverUrl } from "@/lib/db"; // ─── Types ──────────────────────────────────────────────────────────────────── @@ -60,7 +60,7 @@ async function authHeaders(contentType?: string): Promise { return h; } -const SERVER_URL = import.meta.env.VITE_SERVER_IMAGE_API_URL || ''; +const SERVER_URL = serverUrl; async function apiFetch(path: string, init?: RequestInit) { const url = SERVER_URL ? `${SERVER_URL}${path}` : path; diff --git a/packages/ui/src/modules/contacts/client-mailboxes.ts b/packages/ui/src/modules/contacts/client-mailboxes.ts index 9c040ca4..187fa295 100644 --- a/packages/ui/src/modules/contacts/client-mailboxes.ts +++ b/packages/ui/src/modules/contacts/client-mailboxes.ts @@ -3,8 +3,10 @@ * Calls server routes at /api/contacts/mailboxes */ -const SERVER_URL = import.meta.env.VITE_SERVER_IMAGE_API_URL || ''; -const API_BASE = '/api/contacts/mailboxes'; +import { serverUrl } from '@/lib/db'; + +const SERVER_URL = serverUrl; +const API_BASE = `${serverUrl}/api/contacts/mailboxes`; async function authHeaders(contentType?: string): Promise { const { getAuthToken } = await import('@/lib/db'); diff --git a/packages/ui/src/modules/pages/PageActions.tsx b/packages/ui/src/modules/pages/PageActions.tsx index f695d50c..5906ef03 100644 --- a/packages/ui/src/modules/pages/PageActions.tsx +++ b/packages/ui/src/modules/pages/PageActions.tsx @@ -17,6 +17,7 @@ import { } from "@/components/ui/dropdown-menu"; import { Button } from "@/components/ui/button"; import { updatePage, updatePageMeta, deletePage } from "./client-pages"; +import { serverUrl } from "@/lib/db"; const CategoryManager = React.lazy(() => import("@/components/widgets/CategoryManager").then(module => ({ default: module.CategoryManager }))); const VersionManager = React.lazy(() => import("./VersionManager").then(module => ({ default: module.VersionManager }))); @@ -59,7 +60,7 @@ export const PageActions = ({ const addItem = useCartStore((s) => s.addItem); const navigate = useNavigate(); - const baseUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL || window.location.origin; + const baseUrl = serverUrl; // Extract product price from typeValues (first entry with a numeric price > 0) const productPrice = (() => { diff --git a/packages/ui/src/modules/pages/editor/EmailPreviewPanel.tsx b/packages/ui/src/modules/pages/editor/EmailPreviewPanel.tsx index 81a30172..65761999 100644 --- a/packages/ui/src/modules/pages/editor/EmailPreviewPanel.tsx +++ b/packages/ui/src/modules/pages/editor/EmailPreviewPanel.tsx @@ -3,6 +3,7 @@ import { Button } from "@/components/ui/button"; import { ArrowLeft, Monitor, Smartphone } from "lucide-react"; import { Page } from "../types"; import { getCurrentLang } from "@/i18n"; +import { serverUrl } from "@/lib/db"; interface EmailPreviewPanelProps { page: Page; @@ -21,7 +22,6 @@ export const EmailPreviewPanel = ({ iframeRef, authToken, }: EmailPreviewPanelProps) => { - const serverUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL; const previewPath = orgSlug ? `/org/${orgSlug}/user/${page.owner}/pages/${page.slug}/email-preview` : `/user/${page.owner}/pages/${page.slug}/email-preview`; diff --git a/packages/ui/src/modules/pages/editor/hooks/useEmailActions.ts b/packages/ui/src/modules/pages/editor/hooks/useEmailActions.ts index 41fd9e7e..f0a69b68 100644 --- a/packages/ui/src/modules/pages/editor/hooks/useEmailActions.ts +++ b/packages/ui/src/modules/pages/editor/hooks/useEmailActions.ts @@ -1,5 +1,5 @@ import { useState, useEffect, useRef } from "react"; -import { getAuthToken } from "@/lib/db"; +import { getAuthToken, serverUrl } from "@/lib/db"; import { toast } from "sonner"; import { translate, getCurrentLang } from "@/i18n"; @@ -33,7 +33,6 @@ export function useEmailActions({ page, orgSlug }: UseEmailActionsParams) { setIsSendingEmail(true); try { - const serverUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL; const lang = getCurrentLang(); const endpoint = orgSlug ? `${serverUrl}/org/${orgSlug}/user/${page.owner}/pages/${page.slug}/email-send?lang=${lang}` diff --git a/packages/ui/src/modules/pages/editor/ribbons/PageRibbonBar.tsx b/packages/ui/src/modules/pages/editor/ribbons/PageRibbonBar.tsx index c651911b..33b572da 100644 --- a/packages/ui/src/modules/pages/editor/ribbons/PageRibbonBar.tsx +++ b/packages/ui/src/modules/pages/editor/ribbons/PageRibbonBar.tsx @@ -2,8 +2,7 @@ import React, { useState, useRef, useEffect } from 'react'; import { useDraggable } from '@dnd-kit/core'; import { useNavigate, useParams } from 'react-router-dom'; import { cn } from "@/lib/utils"; -import { Button } from "@/components/ui/button"; -import { getAuthToken } from "@/lib/db"; +import { getAuthToken, serverUrl } from "@/lib/db"; import { toast } from "sonner"; import { LayoutTemplate, @@ -439,7 +438,7 @@ export const PageRibbonBar = ({ const { updateAction, getActionsByGroup } = useActions(); // Logic duplicated from PageActions - const baseUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL || window.location.origin; + const baseUrl = serverUrl; useEffect(() => { if (activeTab === 'advanced') { diff --git a/packages/ui/src/modules/places/InfoPanel.tsx b/packages/ui/src/modules/places/InfoPanel.tsx index 5056309c..198a19f8 100644 --- a/packages/ui/src/modules/places/InfoPanel.tsx +++ b/packages/ui/src/modules/places/InfoPanel.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useState } from 'react'; import { ExternalLink, BookOpen, X, Info, Globe } from 'lucide-react'; import CollapsibleSection from '../../components/CollapsibleSection'; +import { serverUrl } from '@/lib/db'; interface WikiResult { pageid: number; @@ -44,8 +45,7 @@ export const InfoPanel = React.memo(({ isOpen, onClose, lat, lng, locationName } setLoadingWiki(true); setErrorWiki(null); try { - const apiUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL || ''; - const res = await fetch(`${apiUrl}/api/locations/wiki?lat=${stableLat}&lon=${stableLng}&limit=20`); + const res = await fetch(`${serverUrl}/api/locations/wiki?lat=${stableLat}&lon=${stableLng}&limit=20`); if (res.ok) { const json = await res.json(); setArticles(json.data || []); @@ -72,8 +72,7 @@ export const InfoPanel = React.memo(({ isOpen, onClose, lat, lng, locationName } setLoadingLlm(true); setLlmInfo(null); try { - const apiUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL || ''; - const res = await fetch(`${apiUrl}/api/locations/llm-info?location=${encodeURIComponent(locationName)}`); + const res = await fetch(`${serverUrl}/api/locations/llm-info?location=${encodeURIComponent(locationName)}`); if (res.ok) { const json = await res.json(); setLlmInfo(json.data); diff --git a/packages/ui/src/modules/places/components/MapPosterOverlay.tsx b/packages/ui/src/modules/places/components/MapPosterOverlay.tsx index 3318638a..9468acd9 100644 --- a/packages/ui/src/modules/places/components/MapPosterOverlay.tsx +++ b/packages/ui/src/modules/places/components/MapPosterOverlay.tsx @@ -1,6 +1,7 @@ import React, { useEffect, useState } from 'react'; import maplibregl from 'maplibre-gl'; import { POSTER_THEMES, applyPosterTheme } from '../utils/poster-themes'; +import { serverUrl } from '@/lib/db'; // Fallback feather icons if lucide-react unavailable, or just raw SVG const XIcon = ({ className }: { className?: string }) => ( @@ -40,8 +41,7 @@ export function MapPosterOverlay({ map, pickerRegions, pickerPolygons, posterThe const fetchGeo = async () => { const c = map.getCenter(); try { - const apiUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL || ''; - const res = await fetch(`${apiUrl}/api/regions/reverse?lat=${c.lat}&lon=${c.lng}`); + const res = await fetch(`${serverUrl}/api/regions/reverse?lat=${c.lat}&lon=${c.lng}`); if (res.ok) { const json = await res.json(); if (json.data) { diff --git a/packages/ui/src/modules/posts/NewPost.tsx b/packages/ui/src/modules/posts/NewPost.tsx index 4c5e4e68..b566010d 100644 --- a/packages/ui/src/modules/posts/NewPost.tsx +++ b/packages/ui/src/modules/posts/NewPost.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { getAuthToken } from "@/lib/db"; +import { getAuthToken, serverUrl } from "@/lib/db"; import { useAuth } from "@/hooks/useAuth"; import { useNavigate, Navigate } from "react-router-dom"; import { CreationWizardPopup } from "@/components/CreationWizardPopup"; @@ -28,7 +28,6 @@ const NewPost = () => { try { // Use relative path for API calls to support mobile/PWA proxying // Fallback to localhost only if strictly needed in dev without proxy, but empty string is safer for Vite proxy - const serverUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL || ''; addLog(`Fetching site info from: ${serverUrl || '/api'}/serving/site-info`); const token = await getAuthToken(); diff --git a/packages/ui/src/modules/posts/client-pictures.ts b/packages/ui/src/modules/posts/client-pictures.ts index 51915dad..04fba159 100644 --- a/packages/ui/src/modules/posts/client-pictures.ts +++ b/packages/ui/src/modules/posts/client-pictures.ts @@ -1,6 +1,6 @@ import { PostMediaItem } from "@/modules/posts/views/types"; import { MediaItem } from "@/types"; -import { fetchWithDeduplication, apiClient, getAuthHeaders } from "@/lib/db"; +import { fetchWithDeduplication, apiClient, getAuthHeaders, serverUrl } from "@/lib/db"; import { uploadImage } from "@/lib/uploadUtils"; import { FetchMediaOptions } from "@/utils/mediaUtils"; @@ -260,7 +260,6 @@ export const transformImage = async (file: File | Blob, operations: any[]): Prom formData.append('file', file); formData.append('operations', JSON.stringify(operations)); - const serverUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL || window.location.origin; const response = await fetch(`${serverUrl}/api/images/transform`, { method: 'POST', headers, diff --git a/packages/ui/src/modules/posts/client-videos.ts b/packages/ui/src/modules/posts/client-videos.ts index 5d9811f8..48b0ac94 100644 --- a/packages/ui/src/modules/posts/client-videos.ts +++ b/packages/ui/src/modules/posts/client-videos.ts @@ -1,6 +1,6 @@ -import { getAuthToken } from "@/lib/db"; +import { getAuthToken, serverUrl } from "@/lib/db"; -const API_BASE = import.meta.env.VITE_SERVER_IMAGE_API_URL || ''; +const API_BASE = serverUrl || ''; export interface VideoEntry { id: string; diff --git a/packages/ui/src/modules/posts/views/components/ExportDropdown.tsx b/packages/ui/src/modules/posts/views/components/ExportDropdown.tsx index c83e0d80..852124b5 100644 --- a/packages/ui/src/modules/posts/views/components/ExportDropdown.tsx +++ b/packages/ui/src/modules/posts/views/components/ExportDropdown.tsx @@ -12,10 +12,10 @@ import { import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog"; import { toast } from "sonner"; import { generateOfflineZip } from "@/utils/zipGenerator"; -import { T } from "@/i18n"; import { PostItem, UserProfile } from "../types"; import { Picture } from "@/types-server"; +import { serverUrl } from "../db"; interface ExportDropdownProps { post: PostItem | null; @@ -37,7 +37,7 @@ export const ExportDropdown: React.FC = ({ const [isEmailDialogOpen, setIsEmailDialogOpen] = useState(false); const [emailHtml, setEmailHtml] = useState(''); - const baseUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL || window.location.origin; + const baseUrl = serverUrl; const embedUrl = `${baseUrl}/embed/${post?.id}`; const embedCode = ``; diff --git a/packages/ui/src/modules/posts/views/renderers/ArticleRenderer.tsx b/packages/ui/src/modules/posts/views/renderers/ArticleRenderer.tsx index 466d2375..a32fe345 100644 --- a/packages/ui/src/modules/posts/views/renderers/ArticleRenderer.tsx +++ b/packages/ui/src/modules/posts/views/renderers/ArticleRenderer.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import { apiClient } from "@/lib/db"; +import { apiClient, serverUrl } from "@/lib/db"; import { Link, useNavigate } from "react-router-dom"; import { User as UserIcon, LayoutGrid, StretchHorizontal, FileText, Save, X, Edit3, MoreVertical, Trash2, ArrowUp, ArrowDown, Heart, MessageCircle, Maximize, ImageIcon, Youtube, Music, Wand2, Map, Brush, Mail, Archive } from 'lucide-react'; import { useOrganization } from "@/contexts/OrganizationContext"; @@ -75,7 +75,7 @@ export const ArticleRenderer: React.FC = (props) => { const navigate = useNavigate(); const { orgSlug } = useOrganization(); - const baseUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL || window.location.origin; + const baseUrl = serverUrl || window.location.origin; const embedUrl = `${baseUrl}/embed/${post?.id || mediaItem.id}`; const embedCode = ``; const [emailHtml, setEmailHtml] = useState(''); diff --git a/packages/ui/src/modules/search/client-search.ts b/packages/ui/src/modules/search/client-search.ts index 30bd339c..92449f60 100644 --- a/packages/ui/src/modules/search/client-search.ts +++ b/packages/ui/src/modules/search/client-search.ts @@ -1,4 +1,4 @@ -const SERVER_API_URL = import.meta.env.VITE_SERVER_IMAGE_API_URL || ''; +import { serverUrl } from "@/lib/db"; export interface SearchOptions { q: string; @@ -23,7 +23,7 @@ export const searchContent = async (options: SearchOptions): Promise => { if (options.formats) params.append('formats', options.formats); if (options.visibilityFilter) params.append('visibilityFilter', options.visibilityFilter); - const url = `${SERVER_API_URL}/api/search?${params.toString()}`; + const url = `${serverUrl}/api/search?${params.toString()}`; const headers: Record = {}; if (options.token) headers['Authorization'] = `Bearer ${options.token}`; const res = await fetch(url, { headers }); diff --git a/packages/ui/src/modules/user/client-user.ts b/packages/ui/src/modules/user/client-user.ts index c903048b..6ff94ada 100644 --- a/packages/ui/src/modules/user/client-user.ts +++ b/packages/ui/src/modules/user/client-user.ts @@ -1,8 +1,8 @@ import { UserProfile } from "@/modules/posts/views/types"; -import { fetchWithDeduplication, apiClient, getAuthToken as getZitadelToken } from "@/lib/db"; +import { fetchWithDeduplication, apiClient, getAuthToken as getZitadelToken, serverUrl as serverBaseUrl } from "@/lib/db"; const serverUrl = (path: string) => { - const baseUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL || window.location.origin; + const baseUrl = serverBaseUrl || window.location.origin; return `${baseUrl}${path}`; }; diff --git a/packages/ui/src/pages/AdminPage.tsx b/packages/ui/src/pages/AdminPage.tsx index deb40910..732a45df 100644 --- a/packages/ui/src/pages/AdminPage.tsx +++ b/packages/ui/src/pages/AdminPage.tsx @@ -15,6 +15,7 @@ import { BansManager } from "@/components/admin/BansManager"; import { ViolationsMonitor } from "@/components/admin/ViolationsMonitor"; import React, { Suspense } from "react"; import { Routes, Route, Navigate } from "react-router-dom"; +import { serverUrl } from "@/lib/db"; // Lazy load AnalyticsDashboard const AnalyticsDashboard = React.lazy(() => import("@/modules/analytics").then(module => ({ default: module.AnalyticsDashboard }))); @@ -108,7 +109,7 @@ const ServerSection = ({ session }: { session: any }) => { const handleFlushCache = async () => { try { setLoading(true); - const res = await fetch(`${import.meta.env.VITE_SERVER_IMAGE_API_URL}/api/flush-cache`, { + const res = await fetch(`${serverUrl}/api/flush-cache`, { method: 'POST', headers: { 'Authorization': `Bearer ${session?.access_token || ''}` @@ -138,7 +139,7 @@ const ServerSection = ({ session }: { session: any }) => { } try { - const res = await fetch(`${import.meta.env.VITE_SERVER_IMAGE_API_URL}/api/admin/system/restart`, { + const res = await fetch(`${serverUrl}/api/admin/system/restart`, { method: 'POST', headers: { 'Authorization': `Bearer ${session?.access_token || ''}` diff --git a/packages/ui/src/pages/PlaygroundImageEditor.tsx b/packages/ui/src/pages/PlaygroundImageEditor.tsx index 1e2c9d93..9bccf6fd 100644 --- a/packages/ui/src/pages/PlaygroundImageEditor.tsx +++ b/packages/ui/src/pages/PlaygroundImageEditor.tsx @@ -1,15 +1,14 @@ import React, { useState, useRef, useEffect } from 'react'; import { Button } from '@/components/ui/button'; -import { Card } from '@/components/ui/card'; import { ImagePickerDialog } from '@/components/widgets/ImagePickerDialog'; import { RotateCw, RotateCcw, Crop as CropIcon, Download, Sliders, Image as ImageIcon, X, Check, Save } from 'lucide-react'; import { fetchPictureById, updatePicture } from '@/modules/posts/client-pictures'; import { useAuth } from '@/hooks/useAuth'; import { useToast } from '@/components/ui/use-toast'; -import { cn } from '@/lib/utils'; -import { Slider } from '@/components/ui/slider'; + import { uploadImage } from '@/lib/uploadUtils'; +import { serverUrl } from '@/lib/db'; const PlaygroundImageEditor = () => { const [pickerOpen, setPickerOpen] = useState(false); @@ -82,7 +81,6 @@ const PlaygroundImageEditor = () => { formData.append('file', file); formData.append('operations', JSON.stringify(ops)); - const serverUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL; const res = await fetch(`${serverUrl}/api/images/transform`, { method: 'POST', body: formData diff --git a/packages/ui/src/pages/VideoPlayerPlaygroundIntern.tsx b/packages/ui/src/pages/VideoPlayerPlaygroundIntern.tsx index 1ea842f5..6efb106c 100644 --- a/packages/ui/src/pages/VideoPlayerPlaygroundIntern.tsx +++ b/packages/ui/src/pages/VideoPlayerPlaygroundIntern.tsx @@ -8,6 +8,7 @@ import VideoCard from "@/components/VideoCard"; import { toast } from "sonner"; import { useAuth } from "@/hooks/useAuth"; import { Loader2, AlertCircle, CheckCircle2 } from "lucide-react"; +import { serverUrl } from "@/lib/db"; type UploadStatus = 'idle' | 'uploading' | 'processing' | 'ready' | 'error'; @@ -47,9 +48,7 @@ const VideoPlayerPlaygroundIntern = () => { }; const trackProgress = (id: string) => { - const serverUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL; const eventSource = new EventSource(`${serverUrl}/api/videos/jobs/${id}/progress`); - eventSource.onmessage = (event) => { try { const data = JSON.parse(event.data); @@ -77,7 +76,6 @@ const VideoPlayerPlaygroundIntern = () => { }; const pollJob = async (id: string) => { - const serverUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL; let attempts = 0; const maxAttempts = 60; // 2 minutes @@ -132,8 +130,6 @@ const VideoPlayerPlaygroundIntern = () => { const formData = new FormData(); formData.append('file', file); - const serverUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL; - try { const xhr = new XMLHttpRequest(); xhr.open('POST', `${serverUrl}/api/videos/upload?userId=${user.id}&title=${encodeURIComponent(title)}&preset=original`); diff --git a/packages/ui/src/playground/auth.tsx b/packages/ui/src/playground/auth.tsx index 1900003e..e7f2f3c3 100644 --- a/packages/ui/src/playground/auth.tsx +++ b/packages/ui/src/playground/auth.tsx @@ -6,6 +6,7 @@ import { Badge } from '@/components/ui/badge'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Separator } from '@/components/ui/separator'; import { Shield, RefreshCw, ExternalLink, Copy, Check } from 'lucide-react'; +import { serverUrl } from '@/lib/db'; type AuthzDebugResponse = { verified: boolean; @@ -108,7 +109,7 @@ function Row({ */ export default function PlaygroundAuth() { const auth = useAuth(); - const base = import.meta.env.VITE_SERVER_IMAGE_API_URL || ''; + const base = serverUrl || ''; const [loading, setLoading] = useState(false); const [last, setLast] = useState(null); const [fetchError, setFetchError] = useState(null); diff --git a/packages/ui/src/utils/uploadUtils.ts b/packages/ui/src/utils/uploadUtils.ts index 8d8ecf38..ef4c3931 100644 --- a/packages/ui/src/utils/uploadUtils.ts +++ b/packages/ui/src/utils/uploadUtils.ts @@ -2,7 +2,7 @@ * Upload Utility Functions */ -import { getAuthToken } from '@/lib/db'; +import { getAuthToken, serverUrl } from '@/lib/db'; // Helper to upload internal video export const uploadInternalVideo = async ( @@ -13,7 +13,6 @@ export const uploadInternalVideo = async ( const token = await getAuthToken(); return new Promise((resolve, reject) => { - const serverUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL; const formData = new FormData(); formData.append('file', file); const title = file.name.replace(/\.[^/.]+$/, '');