first commit
This commit is contained in:
@@ -0,0 +1,414 @@
|
||||
import type {
|
||||
AiProviderListResponse,
|
||||
AiProviderModelsResponse,
|
||||
AiProviderRequest,
|
||||
AiProviderResponse,
|
||||
AiProviderStatusRequest,
|
||||
AiProviderTestResponse,
|
||||
AiProviderUpdateRequest,
|
||||
AIInvocationRequest,
|
||||
AIInvocationResponse,
|
||||
ApiErrorResponse,
|
||||
ArtifactContentChunk,
|
||||
ArtifactDownloadReferenceResponse,
|
||||
ArtifactFilterRequest,
|
||||
ArtifactListResponse,
|
||||
AuthSessionResponse,
|
||||
AuditEventListResponse,
|
||||
CurrentUserResponse,
|
||||
FileOperationDispatchRequest,
|
||||
FileOperationDispatchResponse,
|
||||
GamePluginListResponse,
|
||||
HealthResponse,
|
||||
JobCreateRequest,
|
||||
JobListResponse,
|
||||
JobResponse,
|
||||
LlmConfigSuggestionRequest,
|
||||
LlmConfigSuggestionResponse,
|
||||
LogStreamCursorRequest,
|
||||
LogStreamCursorResponse,
|
||||
LogStreamListResponse,
|
||||
LoginRequest,
|
||||
MarketplacePluginFilterRequest,
|
||||
MarketplacePluginListResponse,
|
||||
MarketplacePluginResponse,
|
||||
MarketplacePluginStateRequest,
|
||||
PlatformResourceUsageResponse,
|
||||
PluginBridgeAuthorizeRequest,
|
||||
PluginBridgeAuthorizeResponse,
|
||||
PluginBridgeExecuteRequest,
|
||||
PluginBridgeExecuteResponse,
|
||||
RegisterRequest,
|
||||
RunEndpointListResponse,
|
||||
ServerConfigResponse,
|
||||
ServerConfigDiffPreviewRequest,
|
||||
ServerConfigDiffPreviewResponse,
|
||||
ServerLifecycleCommandRequest,
|
||||
ServerLifecycleCreateRequest,
|
||||
ServerLifecycleResponse,
|
||||
ServerConfigWriteApprovalRequest,
|
||||
ServerConfigWriteDispatchResponse,
|
||||
ServerInstanceListResponse,
|
||||
ServerInstanceResponse,
|
||||
ServerMemberListResponse,
|
||||
ServerMemberRequest,
|
||||
ServerMetricsListResponse,
|
||||
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<HealthResponse> {
|
||||
return this.request<HealthResponse>("/healthz", { absolute: true });
|
||||
}
|
||||
|
||||
async listGamePlugins(): Promise<GamePluginListResponse> {
|
||||
return this.request<GamePluginListResponse>("/game-plugins");
|
||||
}
|
||||
|
||||
async listMarketplacePlugins(filter: MarketplacePluginFilterRequest = {}): Promise<MarketplacePluginListResponse> {
|
||||
return this.request<MarketplacePluginListResponse>(`/plugin-marketplace/plugins${marketplaceQuery(filter)}`);
|
||||
}
|
||||
|
||||
async getMarketplacePlugin(id: string): Promise<MarketplacePluginResponse> {
|
||||
return this.request<MarketplacePluginResponse>(`/plugin-marketplace/plugins/${encodeURIComponent(id)}`);
|
||||
}
|
||||
|
||||
async setMarketplacePluginState(id: string, request: MarketplacePluginStateRequest): Promise<MarketplacePluginResponse> {
|
||||
return this.request<MarketplacePluginResponse>(`/plugin-marketplace/plugins/${encodeURIComponent(id)}/state`, {
|
||||
method: "POST",
|
||||
body: request
|
||||
});
|
||||
}
|
||||
|
||||
async listServerInstances(): Promise<ServerInstanceListResponse> {
|
||||
return this.request<ServerInstanceListResponse>("/server-instances");
|
||||
}
|
||||
|
||||
async createServerWorkflow(request: ServerLifecycleCreateRequest): Promise<ServerLifecycleResponse> {
|
||||
return this.request<ServerLifecycleResponse>("/server-instances/workflows/create", {
|
||||
method: "POST",
|
||||
body: request
|
||||
});
|
||||
}
|
||||
|
||||
async startServerInstance(id: string, request: ServerLifecycleCommandRequest): Promise<ServerLifecycleResponse> {
|
||||
return this.request<ServerLifecycleResponse>(`/server-instances/${encodeURIComponent(id)}/start`, {
|
||||
method: "POST",
|
||||
body: request
|
||||
});
|
||||
}
|
||||
|
||||
async stopServerInstance(id: string, request: ServerLifecycleCommandRequest): Promise<ServerLifecycleResponse> {
|
||||
return this.request<ServerLifecycleResponse>(`/server-instances/${encodeURIComponent(id)}/stop`, {
|
||||
method: "POST",
|
||||
body: request
|
||||
});
|
||||
}
|
||||
|
||||
async listServerAdministratorCandidates(id: string): Promise<ServerMemberListResponse> {
|
||||
return this.request<ServerMemberListResponse>(`/server-instances/${encodeURIComponent(id)}/administrators/candidates`);
|
||||
}
|
||||
|
||||
async addServerAdministrator(id: string, request: ServerMemberRequest): Promise<ServerInstanceResponse> {
|
||||
return this.request<ServerInstanceResponse>(`/server-instances/${encodeURIComponent(id)}/administrators`, {
|
||||
method: "POST",
|
||||
body: request
|
||||
});
|
||||
}
|
||||
|
||||
async removeServerAdministrator(id: string, userId: string): Promise<ServerInstanceResponse> {
|
||||
return this.request<ServerInstanceResponse>(`/server-instances/${encodeURIComponent(id)}/administrators/${encodeURIComponent(userId)}`, {
|
||||
method: "DELETE"
|
||||
});
|
||||
}
|
||||
|
||||
async listRunEndpoints(): Promise<RunEndpointListResponse> {
|
||||
return this.request<RunEndpointListResponse>("/run/endpoints");
|
||||
}
|
||||
|
||||
async listJobs(serverInstanceId?: string): Promise<JobListResponse> {
|
||||
const params = serverInstanceId ? `?serverInstanceId=${encodeURIComponent(serverInstanceId)}` : "";
|
||||
return this.request<JobListResponse>(`/jobs${params}`);
|
||||
}
|
||||
|
||||
async listArtifacts(filter: ArtifactFilterRequest = {}): Promise<ArtifactListResponse> {
|
||||
return this.request<ArtifactListResponse>(`/artifacts${artifactQuery(filter)}`);
|
||||
}
|
||||
|
||||
async openArtifactDownload(id: string): Promise<ArtifactDownloadReferenceResponse> {
|
||||
return this.request<ArtifactDownloadReferenceResponse>(`/artifacts/${encodeURIComponent(id)}/download`, { method: "POST", body: {} });
|
||||
}
|
||||
|
||||
async readArtifactContent(id: string, offset = 0, limit?: number): Promise<ArtifactContentChunk> {
|
||||
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<JobResponse> {
|
||||
return this.request<JobResponse>(`/jobs/${encodeURIComponent(id)}`);
|
||||
}
|
||||
|
||||
async createJob(request: JobCreateRequest): Promise<JobResponse> {
|
||||
return this.request<JobResponse>("/jobs", { method: "POST", body: request });
|
||||
}
|
||||
|
||||
async register(request: RegisterRequest): Promise<AuthSessionResponse> {
|
||||
return this.request<AuthSessionResponse>("/auth/register", { method: "POST", body: request });
|
||||
}
|
||||
|
||||
async login(request: LoginRequest): Promise<AuthSessionResponse> {
|
||||
return this.request<AuthSessionResponse>("/auth/login", { method: "POST", body: request });
|
||||
}
|
||||
|
||||
async logout(): Promise<void> {
|
||||
await this.request<void>("/auth/logout", { method: "POST", parseJson: false });
|
||||
}
|
||||
|
||||
async getCurrentUser(): Promise<CurrentUserResponse> {
|
||||
return this.request<CurrentUserResponse>("/users/current");
|
||||
}
|
||||
|
||||
async listUsers(): Promise<UserListResponse> {
|
||||
return this.request<UserListResponse>("/users");
|
||||
}
|
||||
|
||||
async createUser(request: UserCreateRequest): Promise<UserResponse> {
|
||||
return this.request<UserResponse>("/users", { method: "POST", body: request });
|
||||
}
|
||||
|
||||
async updateUser(id: string, request: UserUpdateRequest): Promise<UserResponse> {
|
||||
return this.request<UserResponse>(`/users/${encodeURIComponent(id)}`, { method: "PUT", body: request });
|
||||
}
|
||||
|
||||
async updateCurrentUserProfile(request: UserProfileUpdateRequest): Promise<CurrentUserResponse> {
|
||||
return this.request<CurrentUserResponse>("/users/current/profile", { method: "PUT", body: request });
|
||||
}
|
||||
|
||||
async updateCurrentUserTheme(request: UserThemePreferenceRequest): Promise<UserThemePreferenceResponse> {
|
||||
return this.request<UserThemePreferenceResponse>("/users/current/theme", { method: "PUT", body: request });
|
||||
}
|
||||
|
||||
async getServerInstance(id: string): Promise<ServerInstanceResponse> {
|
||||
return this.request<ServerInstanceResponse>(`/server-instances/${encodeURIComponent(id)}`);
|
||||
}
|
||||
|
||||
async getPlatformResourceUsage(): Promise<PlatformResourceUsageResponse> {
|
||||
return this.request<PlatformResourceUsageResponse>("/metrics/platform");
|
||||
}
|
||||
|
||||
async listServerMetrics(): Promise<ServerMetricsListResponse> {
|
||||
return this.request<ServerMetricsListResponse>("/metrics/server-instances");
|
||||
}
|
||||
|
||||
async getServerConfig(id: string): Promise<ServerConfigResponse> {
|
||||
return this.request<ServerConfigResponse>(`/server-instances/${encodeURIComponent(id)}/config`);
|
||||
}
|
||||
|
||||
async previewServerConfigDiff(id: string, request: ServerConfigDiffPreviewRequest): Promise<ServerConfigDiffPreviewResponse> {
|
||||
return this.request<ServerConfigDiffPreviewResponse>(`/server-instances/${encodeURIComponent(id)}/config/diff`, {
|
||||
method: "POST",
|
||||
body: request
|
||||
});
|
||||
}
|
||||
|
||||
async approveServerConfigWrite(id: string, request: ServerConfigWriteApprovalRequest): Promise<ServerConfigWriteDispatchResponse> {
|
||||
return this.request<ServerConfigWriteDispatchResponse>(`/server-instances/${encodeURIComponent(id)}/config/approve`, {
|
||||
method: "POST",
|
||||
body: request
|
||||
});
|
||||
}
|
||||
|
||||
async dispatchFileOperation(request: FileOperationDispatchRequest): Promise<FileOperationDispatchResponse> {
|
||||
return this.request<FileOperationDispatchResponse>("/file-operations/dispatch", {
|
||||
method: "POST",
|
||||
body: request
|
||||
});
|
||||
}
|
||||
|
||||
async listLogStreams(): Promise<LogStreamListResponse> {
|
||||
return this.request<LogStreamListResponse>("/log-streams");
|
||||
}
|
||||
|
||||
async queryLogStream(request: LogStreamCursorRequest): Promise<LogStreamCursorResponse> {
|
||||
return this.request<LogStreamCursorResponse>("/log-streams/query", { method: "POST", body: request });
|
||||
}
|
||||
|
||||
async listAuditEvents(): Promise<AuditEventListResponse> {
|
||||
return this.request<AuditEventListResponse>("/audit-events");
|
||||
}
|
||||
|
||||
async suggestServerConfig(request: LlmConfigSuggestionRequest): Promise<LlmConfigSuggestionResponse> {
|
||||
return this.request<LlmConfigSuggestionResponse>("/ai/config-suggestions", { method: "POST", body: request });
|
||||
}
|
||||
|
||||
async invokeAI(request: AIInvocationRequest): Promise<AIInvocationResponse> {
|
||||
return this.request<AIInvocationResponse>("/ai/invocations", { method: "POST", body: request });
|
||||
}
|
||||
|
||||
async authorizePluginBridge(request: PluginBridgeAuthorizeRequest): Promise<PluginBridgeAuthorizeResponse> {
|
||||
return this.request<PluginBridgeAuthorizeResponse>("/plugin-bridge/authorize", {
|
||||
method: "POST",
|
||||
body: request
|
||||
});
|
||||
}
|
||||
|
||||
async executePluginBridge(request: PluginBridgeExecuteRequest): Promise<PluginBridgeExecuteResponse> {
|
||||
return this.request<PluginBridgeExecuteResponse>("/plugin-bridge/execute", {
|
||||
method: "POST",
|
||||
body: request
|
||||
});
|
||||
}
|
||||
|
||||
async listAiProviders(): Promise<AiProviderListResponse> {
|
||||
return this.request<AiProviderListResponse>("/ai-providers");
|
||||
}
|
||||
|
||||
async createAiProvider(request: AiProviderRequest): Promise<AiProviderResponse> {
|
||||
return this.request<AiProviderResponse>("/ai-providers", {
|
||||
method: "POST",
|
||||
body: request
|
||||
});
|
||||
}
|
||||
|
||||
async updateAiProvider(id: string, request: AiProviderUpdateRequest): Promise<AiProviderResponse> {
|
||||
return this.request<AiProviderResponse>(`/ai-providers/${encodeURIComponent(id)}`, {
|
||||
method: "PUT",
|
||||
body: request
|
||||
});
|
||||
}
|
||||
|
||||
async setAiProviderStatus(id: string, request: AiProviderStatusRequest): Promise<AiProviderResponse> {
|
||||
return this.request<AiProviderResponse>(`/ai-providers/${encodeURIComponent(id)}/status`, {
|
||||
method: "POST",
|
||||
body: request
|
||||
});
|
||||
}
|
||||
|
||||
async testAiProvider(id: string): Promise<AiProviderTestResponse> {
|
||||
return this.request<AiProviderTestResponse>(`/ai-providers/${encodeURIComponent(id)}/test`, {
|
||||
method: "POST"
|
||||
});
|
||||
}
|
||||
|
||||
async listAiProviderModels(id: string): Promise<AiProviderModelsResponse> {
|
||||
return this.request<AiProviderModelsResponse>(`/ai-providers/${encodeURIComponent(id)}/models`);
|
||||
}
|
||||
|
||||
private async request<T>(path: string, options: ApiRequestOptions = {}): Promise<T> {
|
||||
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<T>;
|
||||
}
|
||||
}
|
||||
|
||||
interface ApiRequestOptions {
|
||||
absolute?: boolean;
|
||||
method?: string;
|
||||
body?: unknown;
|
||||
init?: RequestInit;
|
||||
parseJson?: boolean;
|
||||
}
|
||||
|
||||
async function safeReadError(response: Response): Promise<ApiErrorResponse | null> {
|
||||
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);
|
||||
Reference in New Issue
Block a user