Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# API Keys
GEMINI_API_KEY=your_api_key_here

# API Configuration
API_BASE_URL=http://localhost:3000
ENVIRONMENT=development
52 changes: 14 additions & 38 deletions client/src/lib/queryClient.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,33 @@
import { QueryClient, QueryFunction } from "@tanstack/react-query";
import { QueryClient } from '@tanstack/react-query';

async function throwIfResNotOk(res: Response) {
if (!res.ok) {
const text = (await res.text()) || res.statusText;
throw new Error(`${res.status}: ${text}`);
}
}

export async function apiRequest(
export async function apiRequest<T>(
method: string,
url: string,
data?: unknown | undefined,
): Promise<Response> {
): Promise<T> {
const res = await fetch(url, {
method,
headers: data ? { "Content-Type": "application/json" } : {},
headers: data ? {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.GEMINI_API_KEY}`
} : {},
body: data ? JSON.stringify(data) : undefined,
credentials: "include",
credentials: 'include',
});

await throwIfResNotOk(res);
return res;
}

type UnauthorizedBehavior = "returnNull" | "throw";
export const getQueryFn: <T>(options: {
on401: UnauthorizedBehavior;
}) => QueryFunction<T> =
({ on401: unauthorizedBehavior }) =>
async ({ queryKey }) => {
const res = await fetch(queryKey.join("/") as string, {
credentials: "include",
});

if (unauthorizedBehavior === "returnNull" && res.status === 401) {
return null;
}
if (!res.ok) {
const text = await res.text();
throw new Error(`API Error ${res.status}: ${text || res.statusText}`);
}

await throwIfResNotOk(res);
return await res.json();
};
return res.json();
}

export const queryClient = new QueryClient({
defaultOptions: {
queries: {
queryFn: getQueryFn({ on401: "throw" }),
refetchInterval: false,
refetchOnWindowFocus: false,
staleTime: Infinity,
retry: false,
},
mutations: {
retry: false,
},
},
});
9 changes: 9 additions & 0 deletions server/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const CONFIG = {
API_KEYS: {
GEMINI_API_KEY: process.env.GEMINI_API_KEY,
},
API_ENDPOINTS: {
TEXT_API: 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-09-2025:generateContent',
IMAGE_API: 'https://generativelanguage.googleapis.com/v1beta/models/imagen-3.0-generate-002:predict'
}
};
Loading