import type { AuthResponse, BaseModelCatalogItem, BaseModelUpsertRequest, CatalogProvider, CatalogProviderUpsertRequest, CreatedGatewayApiKey, GatewayAccessRuleBatchRequest, GatewayAccessRule, GatewayAccessRuleUpsertRequest, GatewayApiKey, GatewayTenant, GatewayTenantUpsertRequest, GatewayTask, GatewayUser, GatewayUserUpsertRequest, IntegrationPlatform, ListResponse, ModelCatalogResponse, PlatformModel, PlayableGatewayApiKey, PricingRule, PricingRuleSet, PricingRuleSetUpsertRequest, RateLimitWindow, RuntimePolicySet, RuntimePolicySetUpsertRequest, UserGroup, UserGroupUpsertRequest, } from '@easyai-ai-gateway/contracts'; import type { PlatformCreateInput, PlatformModelBindingInput, WorkspaceTaskQuery } from './types'; const API_BASE = import.meta.env.VITE_GATEWAY_API_BASE_URL ?? 'http://localhost:8088'; export interface HealthResponse { ok: boolean; service: string; env: string; identityMode?: string; } export async function getHealth(): Promise { return request('/healthz', { auth: false }); } export async function registerLocalAccount(input: { username: string; email?: string; password: string; displayName?: string; invitationCode?: string; }): Promise { return request('/api/v1/auth/register', { auth: false, body: input, method: 'POST', }); } export async function loginLocalAccount(input: { account: string; password: string }): Promise { return request('/api/v1/auth/login', { auth: false, body: input, method: 'POST', }); } export async function listPlatforms(token: string): Promise> { return request>('/api/admin/platforms', { token }); } export async function listModels(token: string): Promise> { return request>('/api/admin/models', { token }); } export async function listPlayableModels(token: string): Promise> { return request>('/api/v1/models', { token }); } export async function listModelCatalog(token: string): Promise { return request('/api/v1/model-catalog', { token }); } export async function listPublicCatalogProviders(): Promise> { return request>('/api/v1/public/catalog/providers', { auth: false }); } export async function listCatalogProviders(token: string): Promise> { return request>('/api/admin/catalog/providers', { token }); } export async function createCatalogProvider( token: string, input: CatalogProviderUpsertRequest, ): Promise { return request('/api/admin/catalog/providers', { body: input, method: 'POST', token, }); } export async function updateCatalogProvider( token: string, providerId: string, input: CatalogProviderUpsertRequest, ): Promise { return request(`/api/admin/catalog/providers/${providerId}`, { body: input, method: 'PATCH', token, }); } export async function deleteCatalogProvider(token: string, providerId: string): Promise { await request(`/api/admin/catalog/providers/${providerId}`, { method: 'DELETE', token, }); } export async function listPublicBaseModels(): Promise> { return request>('/api/v1/public/catalog/base-models', { auth: false }); } export async function listBaseModels(token: string): Promise> { return request>('/api/admin/catalog/base-models', { token }); } export async function createBaseModel(token: string, input: BaseModelUpsertRequest): Promise { return request('/api/admin/catalog/base-models', { body: input, method: 'POST', token, }); } export async function updateBaseModel( token: string, baseModelId: string, input: BaseModelUpsertRequest, ): Promise { return request(`/api/admin/catalog/base-models/${baseModelId}`, { body: input, method: 'PATCH', token, }); } export async function resetBaseModel(token: string, baseModelId: string): Promise { return request(`/api/admin/catalog/base-models/${baseModelId}/reset`, { method: 'POST', token, }); } export async function resetAllBaseModels(token: string): Promise> { return request>('/api/admin/catalog/base-models/reset-all', { method: 'POST', token, }); } export async function deleteBaseModel(token: string, baseModelId: string): Promise { await request(`/api/admin/catalog/base-models/${baseModelId}`, { method: 'DELETE', token, }); } export async function listPricingRules(token: string): Promise> { return request>('/api/admin/pricing/rules', { token }); } export async function listPricingRuleSets(token: string): Promise> { return request>('/api/admin/pricing/rule-sets', { token }); } export async function createPricingRuleSet( token: string, input: PricingRuleSetUpsertRequest, ): Promise { return request('/api/admin/pricing/rule-sets', { body: input, method: 'POST', token, }); } export async function updatePricingRuleSet( token: string, ruleSetId: string, input: PricingRuleSetUpsertRequest, ): Promise { return request(`/api/admin/pricing/rule-sets/${ruleSetId}`, { body: input, method: 'PATCH', token, }); } export async function deletePricingRuleSet(token: string, ruleSetId: string): Promise { await request(`/api/admin/pricing/rule-sets/${ruleSetId}`, { method: 'DELETE', token, }); } export async function listRuntimePolicySets(token: string): Promise> { return request>('/api/admin/runtime/policy-sets', { token }); } export async function createRuntimePolicySet( token: string, input: RuntimePolicySetUpsertRequest, ): Promise { return request('/api/admin/runtime/policy-sets', { body: input, method: 'POST', token, }); } export async function updateRuntimePolicySet( token: string, policySetId: string, input: RuntimePolicySetUpsertRequest, ): Promise { return request(`/api/admin/runtime/policy-sets/${policySetId}`, { body: input, method: 'PATCH', token, }); } export async function deleteRuntimePolicySet(token: string, policySetId: string): Promise { await request(`/api/admin/runtime/policy-sets/${policySetId}`, { method: 'DELETE', token, }); } export async function listTenants(token: string): Promise> { return request>('/api/admin/tenants', { token }); } export async function createTenant(token: string, input: GatewayTenantUpsertRequest): Promise { return request('/api/admin/tenants', { body: input, method: 'POST', token, }); } export async function updateTenant(token: string, tenantId: string, input: GatewayTenantUpsertRequest): Promise { return request(`/api/admin/tenants/${tenantId}`, { body: input, method: 'PATCH', token, }); } export async function deleteTenant(token: string, tenantId: string): Promise { await request(`/api/admin/tenants/${tenantId}`, { method: 'DELETE', token, }); } export async function listUsers(token: string): Promise> { return request>('/api/admin/users', { token }); } export async function createGatewayUser(token: string, input: GatewayUserUpsertRequest): Promise { return request('/api/admin/users', { body: input, method: 'POST', token, }); } export async function updateGatewayUser(token: string, userId: string, input: GatewayUserUpsertRequest): Promise { return request(`/api/admin/users/${userId}`, { body: input, method: 'PATCH', token, }); } export async function deleteGatewayUser(token: string, userId: string): Promise { await request(`/api/admin/users/${userId}`, { method: 'DELETE', token, }); } export async function listUserGroups(token: string): Promise> { return request>('/api/admin/user-groups', { token }); } export async function createUserGroup(token: string, input: UserGroupUpsertRequest): Promise { return request('/api/admin/user-groups', { body: input, method: 'POST', token, }); } export async function updateUserGroup(token: string, groupId: string, input: UserGroupUpsertRequest): Promise { return request(`/api/admin/user-groups/${groupId}`, { body: input, method: 'PATCH', token, }); } export async function deleteUserGroup(token: string, groupId: string): Promise { await request(`/api/admin/user-groups/${groupId}`, { method: 'DELETE', token, }); } export async function listAccessRules(token: string): Promise> { return request>('/api/admin/access-rules', { token }); } export async function listApiKeyAccessRules(token: string): Promise> { return request>('/api/v1/api-keys/access-rules', { token }); } export async function createAccessRule(token: string, input: GatewayAccessRuleUpsertRequest): Promise { return request('/api/admin/access-rules', { body: input, method: 'POST', token, }); } export async function batchAccessRules(token: string, input: GatewayAccessRuleBatchRequest): Promise> { return request>('/api/admin/access-rules/batch', { body: input, method: 'POST', token, }); } export async function batchApiKeyAccessRules(token: string, input: GatewayAccessRuleBatchRequest): Promise> { return request>('/api/v1/api-keys/access-rules/batch', { body: input, method: 'POST', token, }); } export async function updateAccessRule( token: string, ruleId: string, input: GatewayAccessRuleUpsertRequest, ): Promise { return request(`/api/admin/access-rules/${ruleId}`, { body: input, method: 'PATCH', token, }); } export async function deleteAccessRule(token: string, ruleId: string): Promise { await request(`/api/admin/access-rules/${ruleId}`, { method: 'DELETE', token, }); } export async function listApiKeys(token: string): Promise> { return request>('/api/v1/api-keys', { token }); } export async function listPlayableApiKeys(token: string): Promise> { return request>('/api/playground/api-keys', { token }); } export async function createApiKey( token: string, input: { name: string; scopes?: string[]; expiresAt?: string }, ): Promise { return request('/api/v1/api-keys', { body: input, method: 'POST', token, }); } export async function deleteApiKey(token: string, apiKeyId: string): Promise { await request(`/api/v1/api-keys/${apiKeyId}`, { method: 'DELETE', token, }); } export async function createPlatform(token: string, input: PlatformCreateInput): Promise { return request('/api/admin/platforms', { body: input, method: 'POST', token, }); } export async function updatePlatform(token: string, platformId: string, input: PlatformCreateInput): Promise { return request(`/api/admin/platforms/${platformId}`, { body: input, method: 'PATCH', token, }); } export async function deletePlatform(token: string, platformId: string): Promise { await request(`/api/admin/platforms/${platformId}`, { method: 'DELETE', token, }); } export async function createPlatformModel( token: string, platformId: string, input: PlatformModelBindingInput, ): Promise { return request(`/api/admin/platforms/${platformId}/models`, { body: input, method: 'POST', token, }); } export async function replacePlatformModels( token: string, platformId: string, models: PlatformModelBindingInput[], ): Promise> { return request>(`/api/admin/platforms/${platformId}/models`, { body: { models }, method: 'PUT', token, }); } export async function deletePlatformModel(token: string, modelId: string): Promise { await request(`/api/admin/platform-models/${modelId}`, { method: 'DELETE', token, }); } export async function createChatTask( token: string, input: { model: string; messages: Array>; runMode?: string; simulation?: boolean }, ): Promise<{ task: GatewayTask; next: Record }> { return request<{ task: GatewayTask; next: Record }>('/api/v1/chat/completions', { body: input, method: 'POST', token, }); } export async function streamChatCompletions( token: string, input: { model: string; messages: Array>; simulation?: boolean }, onDelta: (delta: string) => void, ): Promise { for await (const delta of streamChatCompletionText(token, input)) { onDelta(delta); } } export async function* streamChatCompletionText( token: string, input: { model: string; messages: Array>; simulation?: boolean }, signal?: AbortSignal, ): AsyncGenerator { const response = await fetch(`${API_BASE}/v1/chat/completions`, { body: JSON.stringify({ ...input, stream: true }), headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', }, method: 'POST', signal, }); if (!response.ok) { const body = await response.text(); throw new Error(parseErrorMessage(body) || `Request failed: ${response.status}`); } if (!response.body) { return; } const reader = response.body.getReader(); const decoder = new TextDecoder(); let buffer = ''; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const events = buffer.split(/\n\n/); buffer = events.pop() ?? ''; for (const eventBlock of events) { const delta = parseSSEBlockDelta(eventBlock); if (delta) yield delta; } } if (buffer.trim()) { const delta = parseSSEBlockDelta(buffer); if (delta) yield delta; } } export async function createImageGenerationTask( token: string, input: { model: string; prompt: string; aspect_ratio?: string; count?: number; height?: number; n?: number; quality?: string; resolution?: string; runMode?: string; simulation?: boolean; size?: string; width?: number; }, ): Promise<{ task: GatewayTask; next: Record }> { return request<{ task: GatewayTask; next: Record }>('/api/v1/images/generations', { body: input, method: 'POST', token, }); } export async function createImageEditTask( token: string, input: { model: string; prompt: string; image?: string; mask?: string; runMode?: string; simulation?: boolean }, ): Promise<{ task: GatewayTask; next: Record }> { return request<{ task: GatewayTask; next: Record }>('/api/v1/images/edits', { body: input, method: 'POST', token, }); } export async function createVideoGenerationTask( token: string, input: { model: string; prompt: string; aspect_ratio?: string; count?: number; height?: number; n?: number; resolution?: string; runMode?: string; simulation?: boolean; size?: string; width?: number; }, ): Promise<{ task: GatewayTask; next: Record }> { return request<{ task: GatewayTask; next: Record }>('/api/v1/videos/generations', { body: input, method: 'POST', token, }); } export async function estimatePricing( token: string, input: Record, ): Promise<{ items: unknown[]; resolver: string }> { return request<{ items: unknown[]; resolver: string }>('/api/v1/pricing/estimate', { body: input, method: 'POST', token, }); } export async function getTask(token: string, taskId: string): Promise { return request(`/api/v1/tasks/${taskId}`, { token }); } export async function listTasks(token: string, query: WorkspaceTaskQuery): Promise> { const search = new URLSearchParams({ page: String(query.page), pageSize: String(query.pageSize), }); if (query.query) search.set('q', query.query); if (query.modelType) search.set('modelType', query.modelType); if (query.createdFrom) search.set('createdFrom', query.createdFrom); if (query.createdTo) search.set('createdTo', query.createdTo); return request>(`/api/v1/tasks?${search.toString()}`, { token }); } export function resolveApiAssetUrl(src: string) { if (/^(https?:|data:|blob:)/i.test(src)) return src; return `${API_BASE}${src.startsWith('/') ? src : `/${src}`}`; } export async function listRateLimitWindows(token: string): Promise> { return request>('/api/admin/runtime/rate-limit-windows', { token }); } async function request( path: string, options: { token?: string; auth?: boolean; method?: string; body?: unknown } = {}, ): Promise { const headers: Record = {}; if (options.auth !== false && options.token) { headers.Authorization = `Bearer ${options.token}`; } if (options.body !== undefined) { headers['Content-Type'] = 'application/json'; } const response = await fetch(`${API_BASE}${path}`, { method: options.method ?? 'GET', headers, body: options.body === undefined ? undefined : JSON.stringify(options.body), }); if (!response.ok) { const body = await response.text(); throw new Error(parseErrorMessage(body) || `Request failed: ${response.status}`); } if (response.status === 204) { return undefined as T; } return response.json() as Promise; } function parseErrorMessage(body: string) { if (!body) { return ''; } try { const parsed = JSON.parse(body) as { error?: { message?: string } }; return parsed.error?.message ?? body; } catch { return body; } } function parseSSEBlockDelta(block: string) { const data = block .split(/\n/) .filter((line) => line.startsWith('data:')) .map((line) => line.replace(/^data:\s?/, '')) .join('\n') .trim(); if (!data || data === '[DONE]') return ''; try { const parsed = JSON.parse(data) as { choices?: Array<{ delta?: { content?: string }; message?: { content?: string } }>; delta?: string; output_text?: string; }; return parsed.choices?.[0]?.delta?.content ?? parsed.delta ?? parsed.output_text ?? ''; } catch { return data; } }