import React, { useState, useCallback, useEffect, createContext, useContext, ReactNode } from 'react'; import ReactDOM from 'react-dom/client'; // --- TYPES --- interface UserProfile { id: string; username: string; is_admin: boolean; subscription: UserSubscription; } interface UserSubscription { id: string; user_id: string; plan_id: string; remaining_generations: number; token_balance: number; expires_at: string; is_active: boolean; } interface ApiKey { id: string; name: string; user_id: string; key_preview: string; created_at: string; last_used_at: string | null; } interface Job { id: string; user_id: string; api_key_id: string; job_id: string; status: 'PENDING' | 'COMPLETED' | 'FAILED'; prompt: string; request_body: string; cost: number; created_at: string; } interface GenerationParams { prompt: string; negativePrompt?: string; width?: number; height?: number; step?: number; seed?: number; count?: number; hires?: boolean; hiresUpscale?: number; adetailer?: boolean; } interface CostCalculation { totalTokenCost: number; generationDiscount: number; finalTokenCost: number; canUseGeneration: boolean; remainingGenerations: number; remainingTokens: number; hasSufficientCredits: boolean; } interface GenerationResponse { jobId: string; status: string; message: string; } interface Plan { id: string; name: string; price: number; monthlyGenerations: number; monthlyTokens: number; allowedParams: string[]; fixedParams: Record; rateLimits: { requestsPerMinute: number; requestsPerHour: number; requestsPerDay: number; }; } // --- API SERVICE --- const BASE_URL = 'https://jitome-api.herobrine0991.workers.dev'; class ApiService { private async request(endpoint: string, options: RequestInit = {}): Promise { const url = `${BASE_URL}${endpoint}`; const response = await fetch(url, options); if (!response.ok) { const errorData = await response.json().catch(() => ({ message: 'An unknown error occurred' })); throw new Error(errorData.message || `HTTP error! status: ${response.status}`); } return response.json() as Promise; } // Auth async login(username: string, password: string): Promise<{ token: string }> { return this.request('/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }), }); } // Profile async getProfile(jwt: string): Promise { return this.request('/auth/profile', { headers: { 'Authorization': `Bearer ${jwt}` } }); } // API Keys async getApiKeys(jwt: string): Promise { return this.request('/auth/api-keys', { headers: { 'Authorization': `Bearer ${jwt}` } }); } async createApiKey(jwt: string, name: string): Promise<{ key: string, keyData: any }> { return this.request('/auth/api-keys', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${jwt}` }, body: JSON.stringify({ name }), }); } async deleteApiKey(jwt: string, keyId: string) { return this.request(`/auth/api-keys/${keyId}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${jwt}` } }); } // Jobs async getJobs(jwt: string): Promise { return this.request('/auth/jobs', { headers: { 'Authorization': `Bearer ${jwt}` } }); } // Generation async calculateCost(apiKey: string, params: GenerationParams): Promise { return this.request('/calculate-cost', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` }, body: JSON.stringify(params), }); } async generateImage(apiKey: string, params: GenerationParams): Promise { return this.request('/generate', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` }, body: JSON.stringify(params), }); } // Admin async getPlans(adminJwt: string): Promise { return this.request('/admin/plans', { headers: { 'Authorization': `Bearer ${adminJwt}` } }); } async createPlan(adminJwt: string, plan: Omit & { rateLimits: any}) { return this.request('/admin/plans', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${adminJwt}` }, body: JSON.stringify(plan), }); } async updatePlan(adminJwt: string, planId: string, plan: Partial) { return this.request(`/admin/plans/${planId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${adminJwt}` }, body: JSON.stringify(plan), }); } async deletePlan(adminJwt: string, planId: string) { return this.request(`/admin/plans/${planId}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${adminJwt}` } }); } } const apiService = new ApiService(); // --- AUTH CONTEXT --- interface AuthContextType { jwt: string | null; setJwt: (token: string | null) => void; user: UserProfile | null; setUser: (user: UserProfile | null) => void; } const AuthContext = createContext(undefined); const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) => { const [jwt, setJwt] = useState(null); const [user, setUser] = useState(null); return ( {children} ); }; const useAuth = (): AuthContextType => { const context = useContext(AuthContext); if (!context) { throw new Error('useAuth must be used within an AuthProvider'); } return context; }; // --- COMPONENTS --- // components/auth/LoginPage.tsx const LoginPage: React.FC = () => { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(''); const [isLoading, setIsLoading] = useState(false); const { setJwt } = useAuth(); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setError(''); setIsLoading(true); try { const data = await apiService.login(username, password); setJwt(data.token); } catch (err) { setError(err instanceof Error ? err.message : 'Login failed'); } finally { setIsLoading(false); } }; return (

Jitome API Login

setUsername(e.target.value)} className="w-full px-3 py-2 text-gray-200 bg-gray-700 border border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" required />
setPassword(e.target.value)} className="w-full px-3 py-2 text-gray-200 bg-gray-700 border border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" required />
{error &&

{error}

}
); }; // components/user/ImageGenerator.tsx const ImageGenerator: React.FC = () => { const { jwt } = useAuth(); const [apiKeys, setApiKeys] = useState([]); const [selectedApiKey, setSelectedApiKey] = useState(''); const [params, setParams] = useState({ prompt: '', negativePrompt: '', width: 512, height: 768, step: 25, seed: -1, count: 1, hires: false, hiresUpscale: 1.5, adetailer: false, }); const [cost, setCost] = useState(null); const [generationResult, setGenerationResult] = useState(null); const [error, setError] = useState(''); const [isLoading, setIsLoading] = useState(false); useEffect(() => { const fetchKeys = async () => { if (jwt) { try { const keys = await apiService.getApiKeys(jwt); setApiKeys(keys); if (keys.length > 0) { // We don't get the full key, so we can't set it here. // User needs to provide it. } } catch (err) { setError(err instanceof Error ? err.message : 'Failed to fetch API keys'); } } }; fetchKeys(); }, [jwt]); const handleParamChange = (e: React.ChangeEvent) => { const { name, value, type } = e.target; let processedValue: string | number | boolean = value; if (type === 'number') { processedValue = value ? parseFloat(value) : 0; } else if (type === 'checkbox') { processedValue = (e.target as HTMLInputElement).checked; } setParams(prev => ({ ...prev, [name]: processedValue })); }; const handleAction = async (action: 'cost' | 'generate') => { if (!selectedApiKey) { setError('Please enter your API Key to proceed.'); return; } setError(''); setCost(null); setGenerationResult(null); setIsLoading(true); try { if (action === 'cost') { const result = await apiService.calculateCost(selectedApiKey, params); setCost(result); } else { const result = await apiService.generateImage(selectedApiKey, params); setGenerationResult(result); } } catch (err) { setError(err instanceof Error ? err.message : `Failed to ${action}`); } finally { setIsLoading(false); } }; return (

Generation Parameters

setSelectedApiKey(e.target.value)} className="w-full px-3 py-2 text-gray-200 bg-gray-700 border border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500" />

We only show key previews. Please paste your full key here.