/** * API Client entry point * Export configured API client, generated functions, and friendly aliases. */ type AxiosOptions unknown> = Parameters[2]; import { deleteClustersClusterId, deleteClustersClusterIdInstancesInstanceId, deleteRegistriesRegistryId, getClusters, getClustersClusterId, getClustersClusterIdHealth, getClustersClusterIdInstances, getClustersClusterIdInstancesInstanceId, getClustersClusterIdInstancesInstanceIdEntries, getMonitoringClusters, getMonitoringClustersClusterId, getMonitoringClustersClusterIdNodes, getMonitoringSummary, getRegistries, getRegistriesRegistryId, getRegistriesRegistryIdHealth, getRegistriesRegistryIdRepositories, getRegistriesRegistryIdRepositoriesRepositoryNameArtifacts, getRegistriesRegistryIdRepositoriesRepositoryNameArtifactsReference, getRegistriesRegistryIdRepositoriesRepositoryNameArtifactsReferenceValuesSchema, postAuthLogin, postAuthRefresh, postAuthRegister, postClusters, postClustersClusterIdInstances, postRegistries, putClustersClusterId, putClustersClusterIdInstancesInstanceId, putRegistriesRegistryId, } from './generated-orval/api'; import type { DeleteClustersClusterIdInstancesInstanceIdPathParameters, DeleteClustersClusterIdPathParameters, DeleteRegistriesRegistryIdPathParameters, GetClustersClusterIdInstancesInstanceIdPathParameters, GetClustersClusterIdInstancesPathParameters, GetRegistriesRegistryIdHealthPathParameters, GetRegistriesRegistryIdPathParameters, GetRegistriesRegistryIdRepositoriesPathParameters, GetRegistriesRegistryIdRepositoriesRepositoryNameArtifactsPathParameters, GetRegistriesRegistryIdRepositoriesRepositoryNameArtifactsReferencePathParameters, GetRegistriesRegistryIdRepositoriesRepositoryNameArtifactsReferenceValuesSchemaPathParameters, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoArtifactResponse as GeneratedArtifactResponse, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoAuthResponse as GeneratedAuthResponse, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoClusterMetricsResponse as GeneratedClusterMetricsResponse, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoClusterResponse as GeneratedClusterResponse, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoCreateClusterRequest as GeneratedCreateClusterRequest, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoCreateInstanceRequest as GeneratedCreateInstanceRequest, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoCreateRegistryRequest as GeneratedCreateRegistryRequest, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoInstanceEntryResponse as GeneratedInstanceEntry, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoInstanceResponse as GeneratedInstanceResponse, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoLoginRequest as GeneratedLoginRequest, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoMonitoringSummaryResponse as GeneratedMonitoringSummary, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoNodeMetricsResponse as GeneratedNodeMetricsResponse, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoRefreshTokenRequest as GeneratedRefreshTokenRequest, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoRegisterRequest as GeneratedRegisterRequest, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoRegistryHealthResponse as GeneratedRegistryHealthResponse, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoRegistryResponse as GeneratedRegistryResponse, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoRepositoryListResponse as GeneratedRepositoryListResponse, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoTagResponse as GeneratedTagResponse, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoUpdateClusterRequest as GeneratedUpdateClusterRequest, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoUpdateInstanceRequest as GeneratedUpdateInstanceRequest, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoUpdateRegistryRequest as GeneratedUpdateRegistryRequest, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoUserResponse as GeneratedUserResponse, PutClustersClusterIdInstancesInstanceIdPathParameters, PutClustersClusterIdPathParameters, PutRegistriesRegistryIdPathParameters, } from './generated-orval/api.schemas'; import { AXIOS_INSTANCE, customAxiosInstance } from './axios-mutator'; import { GithubComOcdpClusterServiceInternalAdapterInputHttpDtoInstanceResponseLastOperation as GeneratedInstanceLastOperationEnum, GithubComOcdpClusterServiceInternalAdapterInputHttpDtoInstanceResponseStatus as GeneratedInstanceStatusEnum, } from './generated-orval/api.schemas'; export { AXIOS_INSTANCE, customAxiosInstance, setAuthToken } from './axios-mutator'; export { keysToCamel, keysToSnake, snakeToCamel, camelToSnake } from '@/shared/utils/case-converter'; // Re-export raw generated APIs/types for advanced usages export * from './generated-orval/api'; export type * from './generated-orval/api.schemas'; // ---------- Friendly type aliases ---------- export type AuthResponse = GeneratedAuthResponse; export type RegisterBody = GeneratedRegisterRequest; export type AdminCreateUserRequest = RegisterBody & { role?: string; workspaceId?: string; namespace?: string; defaultClusterId?: string; quotaCpu?: string; quotaMemory?: string; quotaGpu?: string; quotaGpuMemory?: string; isActive?: boolean; mustChangePassword?: boolean; }; export type LoginBody = GeneratedLoginRequest; export type RefreshTokenBody = GeneratedRefreshTokenRequest; export type UserResponse = GeneratedUserResponse & { role?: string; workspaceId?: string; workspaceName?: string; namespace?: string; defaultClusterId?: string; quotaCpu?: string; quotaMemory?: string; quotaGpu?: string; quotaGpuMemory?: string; isActive?: boolean; mustChangePassword?: boolean; }; export type UpdateUserRequest = { role?: string; workspaceId?: string; namespace?: string; defaultClusterId?: string; quotaCpu?: string; quotaMemory?: string; quotaGpu?: string; quotaGpuMemory?: string; isActive?: boolean; mustChangePassword?: boolean; }; export type ValuesYamlResponse = { valuesYaml: string }; export type ClusterResponse = GeneratedClusterResponse; export type CreateClusterRequest = GeneratedCreateClusterRequest; export type UpdateClusterRequest = GeneratedUpdateClusterRequest; export type RegistryResponse = GeneratedRegistryResponse; export type CreateRegistryRequest = GeneratedCreateRegistryRequest; export type UpdateRegistryRequest = GeneratedUpdateRegistryRequest; export type RegistryHealthResponse = GeneratedRegistryHealthResponse; export type InstanceResponse = GeneratedInstanceResponse & { ownerId?: string; ownerUsername?: string; }; export type CreateInstanceRequest = GeneratedCreateInstanceRequest; export type UpdateInstanceRequest = GeneratedUpdateInstanceRequest; export type InstanceEntry = GeneratedInstanceEntry; export type InstanceDiagnosticsResponse = { instanceName?: string; namespace?: string; collectedAt?: string; pods?: Array<{ name?: string; namespace?: string; phase?: string; nodeName?: string; podIp?: string; hostIp?: string; restartCount?: number; containers?: Array<{ name?: string; image?: string; ready?: boolean; restartCount?: number; state?: string; reason?: string; message?: string; }>; conditions?: Array<{ type?: string; status?: string; reason?: string; message?: string }>; creationTimestamp?: string; }>; services?: Array<{ name?: string; namespace?: string; type?: string; clusterIP?: string; ports?: Array<{ name?: string; protocol?: string; port?: number; targetPort?: string; nodePort?: number }>; }>; events?: Array<{ type?: string; reason?: string; message?: string; involvedKind?: string; involvedName?: string; count?: number; firstTimestamp?: string; lastTimestamp?: string; }>; logs?: Array<{ pod?: string; container?: string; tailLines?: number; log?: string; error?: string }>; }; export const INSTANCE_STATUS = GeneratedInstanceStatusEnum; export type InstanceStatus = NonNullable; export const INSTANCE_LAST_OPERATION = GeneratedInstanceLastOperationEnum; export type InstanceLastOperation = NonNullable; export type ArtifactResponse = GeneratedArtifactResponse; export type ArtifactListItem = GeneratedTagResponse; export type ListRepositories200Item = | { name?: string; artifact_count?: number; artifactCount?: number; } | string; export type RepositoryListResponse = GeneratedRepositoryListResponse; export type ListArtifactsFilter = 'all' | 'chart' | 'image' | 'other'; export type ClusterMonitoring = GeneratedClusterMetricsResponse; export type ClusterMonitoringStatus = ClusterMonitoring['status']; export type MonitoringSummary = GeneratedMonitoringSummary; export type NodeMetricsResponse = GeneratedNodeMetricsResponse; // ---------- Friendly function aliases ---------- export const login = postAuthLogin; export const register = postAuthRegister; export const refreshAuth = postAuthRefresh; export const fetchAuthStatus = () => AXIOS_INSTANCE.get<{ needsSetup: boolean; hasUsers: boolean }>("/auth/status").then((r) => r.data); export const setupInitialAdmin = (data: { username: string; password: string; email?: string }) => AXIOS_INSTANCE.post<{ accessToken: string; refreshToken: string }>("/auth/setup", data).then((r) => r.data); export const listUsers = () => customAxiosInstance({ url: "/users", method: "GET" }); export const createUser = (data: AdminCreateUserRequest) => customAxiosInstance({ url: "/users", method: "POST", data }); export const updateUser = (userId: string, data: UpdateUserRequest) => customAxiosInstance({ url: `/users/${encodeURIComponent(userId)}`, method: "PUT", data }); export const deleteUser = (userId: string) => customAxiosInstance({ url: `/users/${encodeURIComponent(userId)}`, method: "DELETE" }); export const listClusters = getClusters; export const createCluster = postClusters; export const getCluster = getClustersClusterId; export const updateCluster = putClustersClusterId; export const deleteCluster = deleteClustersClusterId; export const getClusterHealth = getClustersClusterIdHealth; export const listInstances = getClustersClusterIdInstances; export const createInstance = postClustersClusterIdInstances; export const getInstance = getClustersClusterIdInstancesInstanceId; export const updateInstance = putClustersClusterIdInstancesInstanceId; export const deleteInstance = deleteClustersClusterIdInstancesInstanceId; export const listInstanceEntries = getClustersClusterIdInstancesInstanceIdEntries; export const scaleInstance = ( clusterId: string, instanceId: string, body: { replicas: number; workload?: string }, ) => { return customAxiosInstance<{ instance: InstanceResponse; replicas: number; message: string }>({ url: `/clusters/${encodeURIComponent(clusterId)}/instances/${encodeURIComponent(instanceId)}/scale`, method: "POST", data: body, }); }; export const getInstanceValuesDiff = ( clusterId: string, instanceId: string, ) => { return customAxiosInstance<{ current: Record; defaults: Record }>({ url: `/clusters/${encodeURIComponent(clusterId)}/instances/${encodeURIComponent(instanceId)}/values-diff`, method: "GET", }); }; export const getInstanceDiagnostics = ( params: { clusterId: string; instanceId: string }, options?: { tailLines?: number }, ) => customAxiosInstance({ url: `/clusters/${encodeURIComponent(params.clusterId)}/instances/${encodeURIComponent(params.instanceId)}/diagnostics`, method: "GET", params: options?.tailLines ? { tailLines: options.tailLines } : undefined, }); /** * Stream pod logs via SSE from the backend. * Returns an AbortController to cancel the stream at any time. */ export function streamInstanceLogs( clusterId: string, instanceId: string, pod: string, container: string, tailLines: number = 200, onLine: (line: string) => void, onDone: () => void, onError: (err: Error) => void, ): AbortController { const controller = new AbortController(); const baseUrl = AXIOS_INSTANCE.defaults.baseURL ?? "/api/v1"; const authHeader = AXIOS_INSTANCE.defaults.headers.common["Authorization"] as string | undefined; const params = new URLSearchParams({ pod, container, tailLines: String(tailLines) }); const url = `${baseUrl}/clusters/${encodeURIComponent(clusterId)}/instances/${encodeURIComponent(instanceId)}/logs/stream?${params}`; const headers: Record = { Accept: "text/event-stream" }; if (authHeader) { headers["Authorization"] = authHeader; } fetch(url, { headers, signal: controller.signal }) .then(async (response) => { if (!response.ok) { const text = await response.text().catch(() => response.statusText); onError(new Error(`HTTP ${response.status}: ${text}`)); return; } const reader = response.body?.getReader(); if (!reader) { onError(new Error("ReadableStream not supported")); return; } const decoder = new TextDecoder(); let buffer = ""; try { while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split("\n"); // Keep the last potentially-incomplete line in the buffer buffer = lines.pop() ?? ""; for (const line of lines) { const trimmed = line.trim(); if (!trimmed || !trimmed.startsWith("data:")) continue; const data = trimmed.slice(5).trim(); if (data === "[DONE]") { onDone(); return; } if (data.startsWith("[ERROR]")) { onError(new Error(data.slice(7).trim())); continue; } onLine(data); } } } catch (err: unknown) { if (err instanceof DOMException && err.name === "AbortError") { // Stream was intentionally cancelled - not an error return; } onError(err instanceof Error ? err : new Error(String(err))); } onDone(); }) .catch((err: unknown) => { if (err instanceof DOMException && err.name === "AbortError") { return; } onError(err instanceof Error ? err : new Error(String(err))); }); return controller; } export const listRegistries = getRegistries; export const createRegistry = postRegistries; export const getRegistry = getRegistriesRegistryId; export const updateRegistry = putRegistriesRegistryId; export const deleteRegistry = deleteRegistriesRegistryId; export const checkRegistryHealth = getRegistriesRegistryIdHealth; export const listRepositories = ( params: GetRegistriesRegistryIdRepositoriesPathParameters, options?: { artifactType?: 'chart' | 'all' }, ) => getRegistriesRegistryIdRepositories(params, { params: options?.artifactType ? { artifact_type: options.artifactType } : undefined, }); type ListArtifactsRequestOptions = AxiosOptions; export const listArtifacts = ( params: GetRegistriesRegistryIdRepositoriesRepositoryNameArtifactsPathParameters, options?: { filter?: ListArtifactsFilter }, axiosOptions?: ListArtifactsRequestOptions, ) => { const query = options?.filter && options.filter !== 'all' ? { media_type: options.filter } : undefined; return getRegistriesRegistryIdRepositoriesRepositoryNameArtifacts(params, query, axiosOptions); }; export const getArtifact = getRegistriesRegistryIdRepositoriesRepositoryNameArtifactsReference; export const getValuesSchema = getRegistriesRegistryIdRepositoriesRepositoryNameArtifactsReferenceValuesSchema; export const getValuesYaml = (params: GetValuesSchemaPathParameters) => customAxiosInstance({ url: `/registries/${encodeURIComponent(params.registryId)}/repositories/${encodeURIComponent(params.repositoryName)}/artifacts/${encodeURIComponent(params.reference)}/values-yaml`, method: "GET", }); export const listClusterMonitoring = getMonitoringClusters; export const getClusterMonitoring = getMonitoringClustersClusterId; export const getClusterNodeMetrics = getMonitoringClustersClusterIdNodes; export const getMonitoringSummaryData = getMonitoringSummary; // Re-export parameter types with friendly names for caller convenience export type DeleteClusterPathParameters = DeleteClustersClusterIdPathParameters; export type UpdateClusterPathParameters = PutClustersClusterIdPathParameters; export type ClusterInstancesPathParameters = GetClustersClusterIdInstancesPathParameters; export type InstancePathParameters = GetClustersClusterIdInstancesInstanceIdPathParameters; export type UpdateInstancePathParameters = PutClustersClusterIdInstancesInstanceIdPathParameters; export type DeleteInstancePathParameters = DeleteClustersClusterIdInstancesInstanceIdPathParameters; export type RegistryPathParameters = GetRegistriesRegistryIdPathParameters; export type UpdateRegistryPathParameters = PutRegistriesRegistryIdPathParameters; export type DeleteRegistryPathParameters = DeleteRegistriesRegistryIdPathParameters; export type RegistryHealthPathParameters = GetRegistriesRegistryIdHealthPathParameters; export type ListRepositoriesPathParameters = GetRegistriesRegistryIdRepositoriesPathParameters; export type ListArtifactsPathParameters = GetRegistriesRegistryIdRepositoriesRepositoryNameArtifactsPathParameters; export type ListArtifactsParams = { filter?: ListArtifactsFilter }; export type GetArtifactPathParameters = GetRegistriesRegistryIdRepositoriesRepositoryNameArtifactsReferencePathParameters; export type GetValuesSchemaPathParameters = GetRegistriesRegistryIdRepositoriesRepositoryNameArtifactsReferenceValuesSchemaPathParameters;