import type { AiProviderListResponse, AiProviderModelsResponse, AiProviderRequest, AiProviderResponse, AiProviderStatusRequest, AiProviderTestResponse, AiProviderUpdateRequest, AIInvocationRequest, AIInvocationResponse, ApiErrorResponse, ArtifactContentChunk, ArtifactDownloadReferenceResponse, ArtifactFilterRequest, ArtifactListResponse, AuthSessionResponse, AuditEventListResponse, ClientManagerBuildRequest, ClientManagerDistributionResponse, ClientManagerDownloadRequest, ComponentKeyResponse, ComponentKeyResetRequest, CurrentUserResponse, DependencyJobRequest, FileOperationDispatchRequest, FileOperationDispatchResponse, GamePluginListResponse, HealthResponse, JobCreateRequest, JobListResponse, JobResponse, LlmConfigSuggestionRequest, LlmConfigSuggestionResponse, LogBackfillRequest, LogStreamCursorRequest, LogStreamCursorResponse, LogStreamListResponse, LoginRequest, MarketplacePluginFilterRequest, MarketplacePluginListResponse, MarketplacePluginResponse, MarketplacePluginStateRequest, PlatformResourceUsageResponse, PluginBridgeAuthorizeRequest, PluginBridgeAuthorizeResponse, PluginBridgeExecuteRequest, PluginBridgeExecuteResponse, RegisterRequest, RunDistributionGenerateRequest, RunDistributionResponse, RunEndpointListResponse, RunUpdateJobResponse, RunUpdateRequest, ServerConfigResponse, ServerConfigDiffPreviewRequest, ServerConfigDiffPreviewResponse, ServerLifecycleCommandRequest, ServerLifecycleCreateRequest, ServerLifecycleResponse, ServerConfigWriteApprovalRequest, ServerConfigWriteDispatchResponse, ServerInstanceListResponse, ServerInstanceUpdateRequest, ServerInstanceResponse, ServerMemberListResponse, ServerMemberRequest, ServerMetricsListResponse, ServerRuntimeActionsResponse, UserCreateRequest, UserListResponse, UserProfileUpdateRequest, UserResponse, UserThemePreferenceRequest, UserThemePreferenceResponse, UserUpdateRequest } from "./types"; import { readWebRuntimeEnv } from "../schemas/env"; let platformApiSessionToken: string | null = null; export function setPlatformApiSessionToken(token: string | null) { platformApiSessionToken = token; } export class PlatformApiClient { constructor(private readonly baseUrl = "/api/v1", private readonly sessionTokenProvider: () => string | null = () => platformApiSessionToken) {} async health(): Promise { return this.request("/healthz", { absolute: true }); } async listGamePlugins(): Promise { return this.request("/game-plugins"); } async listMarketplacePlugins(filter: MarketplacePluginFilterRequest = {}): Promise { return this.request(`/plugin-marketplace/plugins${marketplaceQuery(filter)}`); } async getMarketplacePlugin(id: string): Promise { return this.request(`/plugin-marketplace/plugins/${encodeURIComponent(id)}`); } async setMarketplacePluginState(id: string, request: MarketplacePluginStateRequest): Promise { return this.request(`/plugin-marketplace/plugins/${encodeURIComponent(id)}/state`, { method: "POST", body: request }); } async listServerInstances(): Promise { return this.request("/server-instances"); } async createServerWorkflow(request: ServerLifecycleCreateRequest): Promise { return this.request("/server-instances/workflows/create", { method: "POST", body: request }); } async startServerInstance(id: string, request: ServerLifecycleCommandRequest): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/start`, { method: "POST", body: request }); } async stopServerInstance(id: string, request: ServerLifecycleCommandRequest): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/stop`, { method: "POST", body: request }); } async listServerAdministratorCandidates(id: string): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/administrators/candidates`); } async addServerAdministrator(id: string, request: ServerMemberRequest): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/administrators`, { method: "POST", body: request }); } async removeServerAdministrator(id: string, userId: string): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/administrators/${encodeURIComponent(userId)}`, { method: "DELETE" }); } async listRunEndpoints(): Promise { return this.request("/run/endpoints"); } async listJobs(serverInstanceId?: string): Promise { const params = serverInstanceId ? `?serverInstanceId=${encodeURIComponent(serverInstanceId)}` : ""; return this.request(`/jobs${params}`); } async listArtifacts(filter: ArtifactFilterRequest = {}): Promise { return this.request(`/artifacts${artifactQuery(filter)}`); } async openArtifactDownload(id: string): Promise { return this.request(`/artifacts/${encodeURIComponent(id)}/download`, { method: "POST", body: {} }); } async readArtifactContent(id: string, offset = 0, limit?: number): Promise { const params = new URLSearchParams({ offset: String(offset) }); if (limit !== undefined) { params.set("limit", String(limit)); } const headers = new Headers(); const sessionToken = this.sessionTokenProvider(); if (sessionToken) { headers.set("Authorization", `Bearer ${sessionToken}`); } const response = await fetch(`${this.baseUrl}/artifacts/${encodeURIComponent(id)}/content?${params.toString()}`, { headers }); if (!response.ok) { const apiError = await safeReadError(response); throw new Error(apiError?.message ?? `request failed: ${response.status}`); } const payload = await response.arrayBuffer(); return { artifactId: response.headers.get("X-Artifact-Id") ?? undefined, payload, contentType: response.headers.get("Content-Type") ?? "application/octet-stream", contentLength: Number(response.headers.get("Content-Length") ?? payload.byteLength), contentRange: response.headers.get("Content-Range") ?? undefined, checksum: response.headers.get("X-Artifact-Checksum") ?? undefined, contentChecksum: response.headers.get("X-Artifact-Content-Checksum") ?? undefined, storageBehavior: response.headers.get("X-Artifact-Storage") ?? undefined }; } async getJob(id: string): Promise { return this.request(`/jobs/${encodeURIComponent(id)}`); } async getServerRuntimeActions(id: string): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/runtime/actions`); } async generateRunDistribution(id: string, request: RunDistributionGenerateRequest): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/run/generate`, { method: "POST", body: request }); } async downloadLatestRunDistribution(id: string): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/run/download`, { method: "POST", body: {} }); } async resetRunKey(id: string): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/run/key/reset`, { method: "POST", body: {} }); } async pushRunUpdate(id: string, request: RunUpdateRequest): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/run/update`, { method: "POST", body: request }); } async generateClientManager(id: string, request: ClientManagerBuildRequest): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/client-managers/generate`, { method: "POST", body: request }); } async downloadLatestClientManager(id: string, request: ClientManagerDownloadRequest = {}): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/client-managers/download`, { method: "POST", body: request }); } async resetClientManagerKey(id: string, request: ComponentKeyResetRequest): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/client-managers/key/reset`, { method: "POST", body: request }); } async checkDependencies(id: string, request: DependencyJobRequest): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/dependencies/check`, { method: "POST", body: request }); } async installDependencies(id: string, request: DependencyJobRequest): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/dependencies/install`, { method: "POST", body: request }); } async listServerLiveLogs(id: string): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/logs/live`); } async requestLogBackfill(id: string, request: LogBackfillRequest): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/logs/backfill`, { method: "POST", body: request }); } async createJob(request: JobCreateRequest): Promise { return this.request("/jobs", { method: "POST", body: request }); } async register(request: RegisterRequest): Promise { return this.request("/auth/register", { method: "POST", body: request }); } async login(request: LoginRequest): Promise { return this.request("/auth/login", { method: "POST", body: request }); } async logout(): Promise { await this.request("/auth/logout", { method: "POST", parseJson: false }); } async getCurrentUser(): Promise { return this.request("/users/current"); } async listUsers(): Promise { return this.request("/users"); } async createUser(request: UserCreateRequest): Promise { return this.request("/users", { method: "POST", body: request }); } async updateUser(id: string, request: UserUpdateRequest): Promise { return this.request(`/users/${encodeURIComponent(id)}`, { method: "PUT", body: request }); } async updateCurrentUserProfile(request: UserProfileUpdateRequest): Promise { return this.request("/users/current/profile", { method: "PUT", body: request }); } async updateCurrentUserTheme(request: UserThemePreferenceRequest): Promise { return this.request("/users/current/theme", { method: "PUT", body: request }); } async getServerInstance(id: string): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}`); } async updateServerInstance(id: string, request: ServerInstanceUpdateRequest): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}`, { method: "PUT", body: request }); } async archiveServerInstance(id: string): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}`, { method: "DELETE", parseJson: false }); } async getPlatformResourceUsage(): Promise { return this.request("/metrics/platform"); } async listServerMetrics(): Promise { return this.request("/metrics/server-instances"); } async getServerConfig(id: string): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/config`); } async previewServerConfigDiff(id: string, request: ServerConfigDiffPreviewRequest): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/config/diff`, { method: "POST", body: request }); } async approveServerConfigWrite(id: string, request: ServerConfigWriteApprovalRequest): Promise { return this.request(`/server-instances/${encodeURIComponent(id)}/config/approve`, { method: "POST", body: request }); } async dispatchFileOperation(request: FileOperationDispatchRequest): Promise { return this.request("/file-operations/dispatch", { method: "POST", body: request }); } async listLogStreams(): Promise { return this.request("/log-streams"); } async queryLogStream(request: LogStreamCursorRequest): Promise { return this.request("/log-streams/query", { method: "POST", body: request }); } async listAuditEvents(): Promise { return this.request("/audit-events"); } async suggestServerConfig(request: LlmConfigSuggestionRequest): Promise { return this.request("/ai/config-suggestions", { method: "POST", body: request }); } async invokeAI(request: AIInvocationRequest): Promise { return this.request("/ai/invocations", { method: "POST", body: request }); } async authorizePluginBridge(request: PluginBridgeAuthorizeRequest): Promise { return this.request("/plugin-bridge/authorize", { method: "POST", body: request }); } async executePluginBridge(request: PluginBridgeExecuteRequest): Promise { return this.request("/plugin-bridge/execute", { method: "POST", body: request }); } async listAiProviders(): Promise { return this.request("/ai-providers"); } async createAiProvider(request: AiProviderRequest): Promise { return this.request("/ai-providers", { method: "POST", body: request }); } async updateAiProvider(id: string, request: AiProviderUpdateRequest): Promise { return this.request(`/ai-providers/${encodeURIComponent(id)}`, { method: "PUT", body: request }); } async setAiProviderStatus(id: string, request: AiProviderStatusRequest): Promise { return this.request(`/ai-providers/${encodeURIComponent(id)}/status`, { method: "POST", body: request }); } async testAiProvider(id: string): Promise { return this.request(`/ai-providers/${encodeURIComponent(id)}/test`, { method: "POST" }); } async listAiProviderModels(id: string): Promise { return this.request(`/ai-providers/${encodeURIComponent(id)}/models`); } private async request(path: string, options: ApiRequestOptions = {}): Promise { const headers = new Headers(options.init?.headers); if (options.body !== undefined) { headers.set("Content-Type", "application/json"); } const sessionToken = this.sessionTokenProvider(); if (sessionToken && !headers.has("Authorization")) { headers.set("Authorization", `Bearer ${sessionToken}`); } const response = await fetch(options.absolute ? path : `${this.baseUrl}${path}`, { ...options.init, method: options.method ?? options.init?.method ?? "GET", headers, body: options.body === undefined ? options.init?.body : JSON.stringify(options.body) }); if (!response.ok) { const apiError = await safeReadError(response); throw new Error(apiError?.message ?? `request failed: ${response.status}`); } if (options.parseJson === false || response.status === 204) { return undefined as T; } return response.json() as Promise; } } interface ApiRequestOptions { absolute?: boolean; method?: string; body?: unknown; init?: RequestInit; parseJson?: boolean; } async function safeReadError(response: Response): Promise { try { return (await response.json()) as ApiErrorResponse; } catch { return null; } } function marketplaceQuery(filter: MarketplacePluginFilterRequest): string { const params = new URLSearchParams(); if (filter.status && filter.status !== "all") { params.set("status", filter.status); } if (filter.serverType) { params.set("serverType", filter.serverType); } if (filter.capability) { params.set("capability", filter.capability); } if (filter.keyword) { params.set("keyword", filter.keyword); } const query = params.toString(); return query ? `?${query}` : ""; } function artifactQuery(filter: ArtifactFilterRequest): string { const params = new URLSearchParams(); if (filter.ownerKind) { params.set("ownerKind", filter.ownerKind); } if (filter.ownerId) { params.set("ownerId", filter.ownerId); } if (filter.state) { params.set("state", filter.state); } const query = params.toString(); return query ? `?${query}` : ""; } export const platformApiClient = new PlatformApiClient(readWebRuntimeEnv().platformApiBaseUrl);