deploy
This commit is contained in:
parent
138068a3d9
commit
b5dbf55c71
@ -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 = () => {
|
||||
<Route path="/playground/i18n" element={<React.Suspense fallback={<div>Loading...</div>}><I18nPlayground /></React.Suspense>} />
|
||||
<Route path="/playground/chat" element={<React.Suspense fallback={<div>Loading...</div>}><PlaygroundChat /></React.Suspense>} />
|
||||
<Route path="/playground/vfs" element={<React.Suspense fallback={<div>Loading...</div>}><PlaygroundVfs /></React.Suspense>} />
|
||||
<Route path="/playground/auth" element={<React.Suspense fallback={<div>Loading...</div>}><PlaygroundAuth /></React.Suspense>} />
|
||||
</>
|
||||
)}
|
||||
|
||||
{enablePlaygrounds && <Route path="/support-chat" element={<React.Suspense fallback={<div>Loading...</div>}><SupportChat /></React.Suspense>} />}
|
||||
|
||||
<Route path="/playground/auth" element={<React.Suspense fallback={<div>Loading...</div>}><PlaygroundAuth /></React.Suspense>} />
|
||||
|
||||
{/* Logs */}
|
||||
<Route path="/logs" element={<React.Suspense fallback={<div>Loading...</div>}><LogsPage /></React.Suspense>} />
|
||||
|
||||
@ -284,8 +286,8 @@ const App = () => {
|
||||
<BrowserRouter future={{ v7_relativeSplatPath: true }}>
|
||||
<DragDropProvider>
|
||||
<ProfilesProvider>
|
||||
<WebSocketProvider url={import.meta.env.VITE_SERVER_IMAGE_API_URL}>
|
||||
<StreamProvider url={import.meta.env.VITE_SERVER_IMAGE_API_URL}>
|
||||
<WebSocketProvider url={serverUrl}>
|
||||
<StreamProvider>
|
||||
<StreamInvalidator />
|
||||
<FeedCacheProvider>
|
||||
<AppWrapper />
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -351,7 +351,6 @@ export const CreationWizardPopup: React.FC<CreationWizardPopupProps> = ({
|
||||
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);
|
||||
|
||||
|
||||
@ -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<string, string> = {};
|
||||
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(),
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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<UserAvatarBlockProps> = ({
|
||||
|
||||
// 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);
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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 || ''}`,
|
||||
|
||||
@ -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) { ... }
|
||||
|
||||
@ -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)}`;
|
||||
|
||||
@ -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 || ''}`
|
||||
}
|
||||
|
||||
@ -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<void> = 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;
|
||||
|
||||
@ -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<HomeWidgetProps> = ({
|
||||
if (pictures.length === 0) {
|
||||
return <div className="py-8 text-center text-muted-foreground"><T>No pictures yet</T></div>;
|
||||
}
|
||||
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' :
|
||||
|
||||
@ -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<VideoBannerWidgetProps> = ({
|
||||
// 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)}`;
|
||||
|
||||
@ -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<string, UserProfile>;
|
||||
@ -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);
|
||||
|
||||
@ -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<StreamProviderProps> = ({ 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<StreamProviderProps> = ({ children, url })
|
||||
eventSource?.close();
|
||||
if (reconnectTimer) clearTimeout(reconnectTimer);
|
||||
};
|
||||
}, [url]);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<StreamContext.Provider value={{ status, lastEvent, isConnected: status === 'CONNECTED', subscribe }}>
|
||||
|
||||
@ -121,7 +121,9 @@ export const WebSocketProvider: React.FC<WebSocketProviderProps> = ({ children,
|
||||
}, [disconnectWebSocket]);
|
||||
|
||||
const connectToServer = useCallback(async (urlToUse?: string): Promise<boolean> => {
|
||||
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<WebSocketProviderProps> = ({ 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]);
|
||||
|
||||
@ -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<ResponsiveData | null>(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,
|
||||
|
||||
@ -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<string, string> & { appConfig?: AppConfig };
|
||||
}
|
||||
|
||||
export const useSystemInfo = () => {
|
||||
console.log(`useSystemInfo : ${serverUrl}`);
|
||||
return useQuery<SystemInfo>({
|
||||
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<SystemInfo>('/api/system-info'),
|
||||
staleTime: Infinity,
|
||||
gcTime: Infinity,
|
||||
});
|
||||
|
||||
@ -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<OpenAI | null
|
||||
console.log('[createOpenAIClient] resolved token:', token ? token.substring(0, 10) + '...' : 'null');
|
||||
return new OpenAI({
|
||||
apiKey: token, // This is sent as Bearer token to our proxy
|
||||
baseURL: `${import.meta.env.VITE_SERVER_IMAGE_API_URL}/api/openai/v1`,
|
||||
baseURL: `${serverUrl}/api/openai/v1`,
|
||||
dangerouslyAllowBrowser: true // Required for client-side usage
|
||||
});
|
||||
} catch (error) {
|
||||
@ -522,10 +522,8 @@ export const transcribeAudio = async (
|
||||
// Convert audio file to base64
|
||||
const base64Audio = await encodeWav(audioFile);
|
||||
|
||||
const baseUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL || '';
|
||||
|
||||
// Use the OpenRouter proxy endpoint
|
||||
const response = await fetch(`${baseUrl}/api/openrouter/v1/chat/completions`, {
|
||||
const response = await fetch(`${serverUrl}/api/openrouter/v1/chat/completions`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Authorization": `Bearer ${token}`,
|
||||
@ -1291,7 +1289,7 @@ export const runTools = async (options: RunToolsOptions): Promise<RunToolsResult
|
||||
}
|
||||
client = new OpenAI({
|
||||
apiKey: token,
|
||||
baseURL: `${import.meta.env.VITE_SERVER_IMAGE_API_URL}/api/openrouter/v1`,
|
||||
baseURL: `${serverUrl}/api/openrouter/v1`,
|
||||
dangerouslyAllowBrowser: true,
|
||||
});
|
||||
} else {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { GoogleGenAI } from "@google/genai";
|
||||
import { getGoogleApiKey } from "@/image-api";
|
||||
import { serverUrl } from "./db";
|
||||
|
||||
export interface VideoGenerationResult {
|
||||
videoUrl: string;
|
||||
@ -203,7 +204,6 @@ export const generateVideo = async (
|
||||
const targetUrl = `${videoFile.uri}${separator}key=${apiKey}`;
|
||||
|
||||
// Use the proxy endpoint to fetch the video, as direct access might be blocked by CORS or require specific headers.
|
||||
const serverUrl = import.meta.env.VITE_SERVER_IMAGE_API_URL || '';
|
||||
const proxyUrl = `${serverUrl}/api/videos/proxy?url=${encodeURIComponent(targetUrl)}`;
|
||||
|
||||
return { videoUrl: proxyUrl, metadata: operation.response };
|
||||
|
||||
@ -11,14 +11,13 @@
|
||||
import { z } from 'zod';
|
||||
import { searchContent, type SearchOptions } from '@/modules/search/client-search';
|
||||
import type { RunnableToolFunctionWithParse } from 'openai/lib/RunnableFunction';
|
||||
import { serverUrl } from '@/lib/db';
|
||||
|
||||
type LogFunction = (level: string, message: string, data?: any) => 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 => {
|
||||
|
||||
@ -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<string> =>
|
||||
|
||||
/** 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:')) {
|
||||
|
||||
@ -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
|
||||
});
|
||||
}
|
||||
|
||||
@ -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<HeadersInit> {
|
||||
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;
|
||||
|
||||
@ -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<HeadersInit> {
|
||||
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;
|
||||
|
||||
@ -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<HeadersInit> {
|
||||
const { getAuthToken } = await import('@/lib/db');
|
||||
|
||||
@ -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 = (() => {
|
||||
|
||||
@ -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`;
|
||||
|
||||
@ -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}`
|
||||
|
||||
@ -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') {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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<ExportDropdownProps> = ({
|
||||
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 = `<iframe src="${embedUrl}" width="100%" height="600" frameborder="0"></iframe>`;
|
||||
|
||||
|
||||
@ -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<PostRendererProps> = (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 = `<iframe src="${embedUrl}" width="100%" height="600" frameborder="0"></iframe>`;
|
||||
const [emailHtml, setEmailHtml] = useState('');
|
||||
|
||||
@ -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<any[]> => {
|
||||
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<string, string> = {};
|
||||
if (options.token) headers['Authorization'] = `Bearer ${options.token}`;
|
||||
const res = await fetch(url, { headers });
|
||||
|
||||
@ -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}`;
|
||||
};
|
||||
|
||||
|
||||
@ -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 || ''}`
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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`);
|
||||
|
||||
@ -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<AuthzDebugResponse | null>(null);
|
||||
const [fetchError, setFetchError] = useState<string | null>(null);
|
||||
|
||||
@ -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(/\.[^/.]+$/, '');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user