Contract-first API with DTOs, validation, and server-side OpenAPI post-processing
All checks were successful
CI / build (push) Successful in 1m27s
CI / docker (push) Successful in 2m6s
CI / deploy (push) Successful in 30s

Add dedicated request/response DTOs for all controllers, replacing raw
JsonNode parameters with validated types. Move OpenAPI path-prefix stripping
and ProcessorNode children injection into OpenApiCustomizer beans so the
spec served at /api/v1/api-docs is already clean — eliminating the need for
the ui/scripts/process-openapi.mjs post-processing script.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-14 15:33:37 +01:00
parent 50bb22d6f6
commit 465f210aee
43 changed files with 1561 additions and 509 deletions

View File

@@ -1,10 +1,15 @@
{
"openapi": "3.1.0",
"info": {
"title": "OpenAPI definition",
"version": "v0"
"title": "Cameleer3 Server API",
"version": "1.0"
},
"servers": [],
"security": [
{
"bearer": []
}
],
"tags": [
{
"name": "Agent SSE",
@@ -26,6 +31,10 @@
"name": "Ingestion",
"description": "Data ingestion endpoints"
},
{
"name": "Authentication",
"description": "Login and token refresh endpoints"
},
{
"name": "OIDC Config Admin",
"description": "OIDC provider configuration (ADMIN only)"
@@ -94,7 +103,7 @@
"content": {
"*/*": {
"schema": {
"type": "object"
"$ref": "#/components/schemas/OidcAdminConfigResponse"
}
}
}
@@ -111,7 +120,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/OidcConfigRequest"
"$ref": "#/components/schemas/OidcAdminConfigRequest"
}
}
},
@@ -123,7 +132,7 @@
"content": {
"*/*": {
"schema": {
"type": "object"
"$ref": "#/components/schemas/OidcAdminConfigResponse"
}
}
}
@@ -133,7 +142,7 @@
"content": {
"*/*": {
"schema": {
"type": "object"
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -378,8 +387,9 @@
"/auth/refresh": {
"post": {
"tags": [
"ui-auth-controller"
"Authentication"
],
"summary": "Refresh access token",
"operationId": "refresh",
"requestBody": {
"content": {
@@ -393,11 +403,21 @@
},
"responses": {
"200": {
"description": "OK",
"description": "Token refreshed",
"content": {
"*/*": {
"schema": {
"type": "object"
"$ref": "#/components/schemas/AuthTokenResponse"
}
}
}
},
"401": {
"description": "Invalid refresh token",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -408,8 +428,9 @@
"/auth/oidc/callback": {
"post": {
"tags": [
"oidc-auth-controller"
"Authentication"
],
"summary": "Exchange OIDC authorization code for JWTs",
"operationId": "callback",
"requestBody": {
"content": {
@@ -423,11 +444,41 @@
},
"responses": {
"200": {
"description": "OK",
"description": "Authentication successful",
"content": {
"*/*": {
"schema": {
"type": "object"
"$ref": "#/components/schemas/AuthTokenResponse"
}
}
}
},
"401": {
"description": "OIDC authentication failed",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"403": {
"description": "Account not provisioned",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"404": {
"description": "OIDC not configured or disabled",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/AuthTokenResponse"
}
}
}
@@ -438,8 +489,9 @@
"/auth/login": {
"post": {
"tags": [
"ui-auth-controller"
"Authentication"
],
"summary": "Login with local credentials",
"operationId": "login",
"requestBody": {
"content": {
@@ -453,11 +505,21 @@
},
"responses": {
"200": {
"description": "OK",
"description": "Login successful",
"content": {
"*/*": {
"schema": {
"type": "object"
"$ref": "#/components/schemas/AuthTokenResponse"
}
}
}
},
"401": {
"description": "Invalid credentials",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -487,7 +549,7 @@
"content": {
"application/json": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/AgentRefreshRequest"
}
}
},
@@ -499,7 +561,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/AgentRefreshResponse"
}
}
}
@@ -509,7 +571,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/AgentRefreshResponse"
}
}
}
@@ -519,7 +581,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/AgentRefreshResponse"
}
}
}
@@ -577,7 +639,7 @@
"content": {
"application/json": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandRequest"
}
}
},
@@ -589,7 +651,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandSingleResponse"
}
}
}
@@ -599,7 +661,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandSingleResponse"
}
}
}
@@ -609,7 +671,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandSingleResponse"
}
}
}
@@ -665,7 +727,7 @@
"content": {
"application/json": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/AgentRegistrationRequest"
}
}
},
@@ -677,7 +739,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/AgentRegistrationResponse"
}
}
}
@@ -687,7 +749,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -697,7 +759,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/AgentRegistrationResponse"
}
}
}
@@ -727,7 +789,7 @@
"content": {
"application/json": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandRequest"
}
}
},
@@ -739,7 +801,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandBroadcastResponse"
}
}
}
@@ -749,7 +811,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandBroadcastResponse"
}
}
}
@@ -769,7 +831,7 @@
"content": {
"application/json": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandRequest"
}
}
},
@@ -781,7 +843,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandBroadcastResponse"
}
}
}
@@ -791,7 +853,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/CommandBroadcastResponse"
}
}
}
@@ -812,7 +874,7 @@
"content": {
"*/*": {
"schema": {
"type": "object"
"$ref": "#/components/schemas/OidcTestResult"
}
}
}
@@ -822,7 +884,7 @@
"content": {
"*/*": {
"schema": {
"type": "object"
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -941,7 +1003,17 @@
],
"responses": {
"200": {
"description": "OK",
"description": "Execution detail found",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/ExecutionDetail"
}
}
}
},
"404": {
"description": "Execution not found",
"content": {
"*/*": {
"schema": {
@@ -981,7 +1053,20 @@
],
"responses": {
"200": {
"description": "OK",
"description": "Snapshot data",
"content": {
"*/*": {
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
},
"404": {
"description": "Snapshot not found",
"content": {
"*/*": {
"schema": {
@@ -1018,9 +1103,14 @@
"200": {
"description": "Diagram rendered successfully",
"content": {
"*/*": {
"image/svg+xml": {
"schema": {
"type": "object"
"type": "string"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/DiagramLayout"
}
}
}
@@ -1041,16 +1131,37 @@
"/auth/oidc/config": {
"get": {
"tags": [
"oidc-auth-controller"
"Authentication"
],
"summary": "Get OIDC config for SPA login flow",
"operationId": "getConfig_1",
"responses": {
"200": {
"description": "OK",
"description": "OIDC configuration",
"content": {
"*/*": {
"schema": {
"type": "object"
"$ref": "#/components/schemas/OidcPublicConfigResponse"
}
}
}
},
"404": {
"description": "OIDC not configured or disabled",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/OidcPublicConfigResponse"
}
}
}
},
"500": {
"description": "Failed to retrieve OIDC provider metadata",
"content": {
"*/*": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -1082,7 +1193,10 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"type": "array",
"items": {
"$ref": "#/components/schemas/AgentInstanceResponse"
}
}
}
}
@@ -1092,7 +1206,7 @@
"content": {
"*/*": {
"schema": {
"type": "string"
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
@@ -1252,8 +1366,9 @@
}
}
},
"OidcConfigRequest": {
"OidcAdminConfigRequest": {
"type": "object",
"description": "OIDC configuration update request",
"properties": {
"enabled": {
"type": "boolean"
@@ -1281,6 +1396,51 @@
}
}
},
"ErrorResponse": {
"type": "object",
"description": "Error response",
"properties": {
"message": {
"type": "string"
}
},
"required": [
"message"
]
},
"OidcAdminConfigResponse": {
"type": "object",
"description": "OIDC configuration for admin management",
"properties": {
"configured": {
"type": "boolean"
},
"enabled": {
"type": "boolean"
},
"issuerUri": {
"type": "string"
},
"clientId": {
"type": "string"
},
"clientSecretSet": {
"type": "boolean"
},
"rolesClaim": {
"type": "string"
},
"defaultRoles": {
"type": "array",
"items": {
"type": "string"
}
},
"autoSignup": {
"type": "boolean"
}
}
},
"SearchRequest": {
"type": "object",
"properties": {
@@ -1373,7 +1533,19 @@
"diagramContentHash": {
"type": "string"
}
}
},
"required": [
"agentId",
"correlationId",
"diagramContentHash",
"durationMs",
"endTime",
"errorMessage",
"executionId",
"routeId",
"startTime",
"status"
]
},
"SearchResultExecutionSummary": {
"type": "object",
@@ -1396,7 +1568,13 @@
"type": "integer",
"format": "int32"
}
}
},
"required": [
"data",
"limit",
"offset",
"total"
]
},
"RefreshRequest": {
"type": "object",
@@ -1406,6 +1584,22 @@
}
}
},
"AuthTokenResponse": {
"type": "object",
"description": "JWT token pair",
"properties": {
"accessToken": {
"type": "string"
},
"refreshToken": {
"type": "string"
}
},
"required": [
"accessToken",
"refreshToken"
]
},
"CallbackRequest": {
"type": "object",
"properties": {
@@ -1428,6 +1622,165 @@
}
}
},
"AgentRefreshRequest": {
"type": "object",
"description": "Agent token refresh request",
"properties": {
"refreshToken": {
"type": "string"
}
},
"required": [
"refreshToken"
]
},
"AgentRefreshResponse": {
"type": "object",
"description": "Refreshed access token",
"properties": {
"accessToken": {
"type": "string"
}
},
"required": [
"accessToken"
]
},
"CommandRequest": {
"type": "object",
"description": "Command to send to agent(s)",
"properties": {
"type": {
"type": "string",
"description": "Command type: config-update, deep-trace, or replay"
},
"payload": {
"type": "object",
"description": "Command payload JSON"
}
},
"required": [
"type"
]
},
"CommandSingleResponse": {
"type": "object",
"description": "Result of sending a command to a single agent",
"properties": {
"commandId": {
"type": "string"
},
"status": {
"type": "string"
}
},
"required": [
"commandId",
"status"
]
},
"AgentRegistrationRequest": {
"type": "object",
"description": "Agent registration payload",
"properties": {
"agentId": {
"type": "string"
},
"name": {
"type": "string"
},
"group": {
"type": "string",
"default": "default"
},
"version": {
"type": "string"
},
"routeIds": {
"type": "array",
"items": {
"type": "string"
}
},
"capabilities": {
"type": "object",
"additionalProperties": {
"type": "object"
}
}
},
"required": [
"agentId",
"name"
]
},
"AgentRegistrationResponse": {
"type": "object",
"description": "Agent registration result with JWT tokens and SSE endpoint",
"properties": {
"agentId": {
"type": "string"
},
"sseEndpoint": {
"type": "string"
},
"heartbeatIntervalMs": {
"type": "integer",
"format": "int64"
},
"serverPublicKey": {
"type": "string"
},
"accessToken": {
"type": "string"
},
"refreshToken": {
"type": "string"
}
},
"required": [
"accessToken",
"agentId",
"refreshToken",
"serverPublicKey",
"sseEndpoint"
]
},
"CommandBroadcastResponse": {
"type": "object",
"description": "Result of broadcasting a command to multiple agents",
"properties": {
"commandIds": {
"type": "array",
"items": {
"type": "string"
}
},
"targetCount": {
"type": "integer",
"format": "int32"
}
},
"required": [
"commandIds"
]
},
"OidcTestResult": {
"type": "object",
"description": "OIDC provider connectivity test result",
"properties": {
"status": {
"type": "string"
},
"authorizationEndpoint": {
"type": "string"
}
},
"required": [
"authorizationEndpoint",
"status"
]
},
"ExecutionStats": {
"type": "object",
"properties": {
@@ -1471,7 +1824,19 @@
"type": "integer",
"format": "int64"
}
}
},
"required": [
"activeCount",
"avgDurationMs",
"failedCount",
"p99LatencyMs",
"prevAvgDurationMs",
"prevFailedCount",
"prevP99LatencyMs",
"prevTotalCount",
"totalCount",
"totalToday"
]
},
"StatsTimeseries": {
"type": "object",
@@ -1482,7 +1847,10 @@
"$ref": "#/components/schemas/TimeseriesBucket"
}
}
}
},
"required": [
"buckets"
]
},
"TimeseriesBucket": {
"type": "object",
@@ -1511,7 +1879,15 @@
"type": "integer",
"format": "int64"
}
}
},
"required": [
"activeCount",
"avgDurationMs",
"failedCount",
"p99DurationMs",
"time",
"totalCount"
]
},
"ExecutionDetail": {
"type": "object",
@@ -1561,7 +1937,22 @@
"$ref": "#/components/schemas/ProcessorNode"
}
}
}
},
"required": [
"agentId",
"correlationId",
"diagramContentHash",
"durationMs",
"endTime",
"errorMessage",
"errorStackTrace",
"exchangeId",
"executionId",
"processors",
"routeId",
"startTime",
"status"
]
},
"ProcessorNode": {
"type": "object",
@@ -1595,9 +1986,171 @@
},
"errorStackTrace": {
"type": "string"
},
"children": {
"type": "array",
"items": {
"$ref": "#/components/schemas/ProcessorNode"
}
}
},
"required": [
"children",
"diagramNodeId",
"durationMs",
"endTime",
"errorMessage",
"errorStackTrace",
"processorId",
"processorType",
"startTime",
"status"
]
},
"DiagramLayout": {
"type": "object",
"properties": {
"width": {
"type": "number",
"format": "double"
},
"height": {
"type": "number",
"format": "double"
},
"nodes": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PositionedNode"
}
},
"edges": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PositionedEdge"
}
}
}
},
"PositionedEdge": {
"type": "object",
"properties": {
"sourceId": {
"type": "string"
},
"targetId": {
"type": "string"
},
"label": {
"type": "string"
},
"points": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "number",
"format": "double"
}
}
}
}
},
"PositionedNode": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"label": {
"type": "string"
},
"type": {
"type": "string"
},
"x": {
"type": "number",
"format": "double"
},
"y": {
"type": "number",
"format": "double"
},
"width": {
"type": "number",
"format": "double"
},
"height": {
"type": "number",
"format": "double"
}
}
},
"OidcPublicConfigResponse": {
"type": "object",
"description": "OIDC configuration for SPA login flow",
"properties": {
"issuer": {
"type": "string"
},
"clientId": {
"type": "string"
},
"authorizationEndpoint": {
"type": "string"
},
"endSessionEndpoint": {
"type": "string",
"description": "Present if the provider supports RP-initiated logout"
}
},
"required": [
"authorizationEndpoint",
"clientId",
"issuer"
]
},
"AgentInstanceResponse": {
"type": "object",
"description": "Agent instance summary",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"group": {
"type": "string"
},
"status": {
"type": "string"
},
"routeIds": {
"type": "array",
"items": {
"type": "string"
}
},
"registeredAt": {
"type": "string",
"format": "date-time"
},
"lastHeartbeat": {
"type": "string",
"format": "date-time"
}
},
"required": [
"group",
"id",
"lastHeartbeat",
"name",
"registeredAt",
"routeIds",
"status"
]
},
"SseEmitter": {
"type": "object",
"properties": {
@@ -1632,7 +2185,22 @@
"type": "string",
"format": "date-time"
}
}
},
"required": [
"createdAt",
"displayName",
"email",
"provider",
"roles",
"userId"
]
}
},
"securitySchemes": {
"bearer": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT"
}
}
}

View File

@@ -1,12 +1,6 @@
import { useQuery } from '@tanstack/react-query';
import { api } from '../client';
import type {
SearchRequest,
ExecutionStats,
ExecutionSummary,
StatsTimeseries,
ExecutionDetail,
} from '../schema-types';
import type { SearchRequest } from '../types';
export function useExecutionStats(timeFrom: string | undefined, timeTo: string | undefined) {
return useQuery({
@@ -21,7 +15,7 @@ export function useExecutionStats(timeFrom: string | undefined, timeTo: string |
},
});
if (error) throw new Error('Failed to load stats');
return data as unknown as ExecutionStats;
return data!;
},
enabled: !!timeFrom,
placeholderData: (prev) => prev,
@@ -37,7 +31,7 @@ export function useSearchExecutions(filters: SearchRequest, live = false) {
body: filters,
});
if (error) throw new Error('Search failed');
return data as unknown as { data: ExecutionSummary[]; total: number; offset: number; limit: number };
return data!;
},
placeholderData: (prev) => prev,
refetchInterval: live ? 5_000 : false,
@@ -58,7 +52,7 @@ export function useStatsTimeseries(timeFrom: string | undefined, timeTo: string
},
});
if (error) throw new Error('Failed to load timeseries');
return data as unknown as StatsTimeseries;
return data!;
},
enabled: !!timeFrom,
placeholderData: (prev) => prev,
@@ -74,7 +68,7 @@ export function useExecutionDetail(executionId: string | null) {
params: { path: { executionId: executionId! } },
});
if (error) throw new Error('Failed to load execution detail');
return data as unknown as ExecutionDetail;
return data!;
},
enabled: !!executionId,
});
@@ -96,7 +90,7 @@ export function useProcessorSnapshot(
},
);
if (error) throw new Error('Failed to load snapshot');
return data as unknown as Record<string, string>;
return data!;
},
enabled: !!executionId && index !== null,
});

View File

@@ -1,80 +1,47 @@
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { config } from '../../config';
import { useAuthStore } from '../../auth/auth-store';
export interface OidcConfigResponse {
configured: boolean;
enabled?: boolean;
issuerUri?: string;
clientId?: string;
clientSecretSet?: boolean;
rolesClaim?: string;
defaultRoles?: string[];
autoSignup?: boolean;
}
export interface OidcConfigRequest {
enabled: boolean;
issuerUri: string;
clientId: string;
clientSecret: string;
rolesClaim: string;
defaultRoles: string[];
autoSignup: boolean;
}
interface TestResult {
status: string;
authorizationEndpoint: string;
}
async function adminFetch<T>(path: string, options?: RequestInit): Promise<T> {
const token = useAuthStore.getState().accessToken;
const res = await fetch(`${config.apiBaseUrl}${path}`, {
...options,
headers: {
'Content-Type': 'application/json',
...(token ? { Authorization: `Bearer ${token}` } : {}),
...options?.headers,
},
});
if (res.status === 204) return undefined as T;
const body = await res.json();
if (!res.ok) throw new Error(body.message || `Request failed (${res.status})`);
return body as T;
}
import { api } from '../client';
import type { OidcAdminConfigRequest } from '../types';
export function useOidcConfig() {
return useQuery<OidcConfigResponse>({
return useQuery({
queryKey: ['admin', 'oidc'],
queryFn: () => adminFetch('/admin/oidc'),
queryFn: async () => {
const { data, error } = await api.GET('/admin/oidc');
if (error) throw new Error('Failed to load OIDC config');
return data!;
},
});
}
export function useSaveOidcConfig() {
const qc = useQueryClient();
return useMutation({
mutationFn: (data: OidcConfigRequest) =>
adminFetch<OidcConfigResponse>('/admin/oidc', {
method: 'PUT',
body: JSON.stringify(data),
}),
mutationFn: async (body: OidcAdminConfigRequest) => {
const { data, error } = await api.PUT('/admin/oidc', { body });
if (error) throw new Error('Failed to save OIDC config');
return data!;
},
onSuccess: () => qc.invalidateQueries({ queryKey: ['admin', 'oidc'] }),
});
}
export function useTestOidcConnection() {
return useMutation({
mutationFn: () =>
adminFetch<TestResult>('/admin/oidc/test', { method: 'POST' }),
mutationFn: async () => {
const { data, error } = await api.POST('/admin/oidc/test');
if (error) throw new Error('OIDC test failed');
return data!;
},
});
}
export function useDeleteOidcConfig() {
const qc = useQueryClient();
return useMutation({
mutationFn: () =>
adminFetch<void>('/admin/oidc', { method: 'DELETE' }),
mutationFn: async () => {
const { error } = await api.DELETE('/admin/oidc');
if (error) throw new Error('Failed to delete OIDC config');
},
onSuccess: () => qc.invalidateQueries({ queryKey: ['admin', 'oidc'] }),
});
}

View File

@@ -1,31 +0,0 @@
import type { components } from './schema';
type Require<T> = {
[K in keyof T]-?: T[K] extends (infer U)[]
? Require<U>[]
: T[K] extends object | undefined
? Require<NonNullable<T[K]>>
: NonNullable<T[K]>;
};
export type ExecutionSummary = Require<components['schemas']['ExecutionSummary']>;
export type SearchRequest = components['schemas']['SearchRequest'];
export type ExecutionDetail = Require<components['schemas']['ExecutionDetail']>;
export type ExecutionStats = Require<components['schemas']['ExecutionStats']>;
export type StatsTimeseries = Require<components['schemas']['StatsTimeseries']>;
export type TimeseriesBucket = Require<components['schemas']['TimeseriesBucket']>;
export type UserInfo = Require<components['schemas']['UserInfo']>;
export type ProcessorNode = Require<components['schemas']['ProcessorNode']> & {
children?: ProcessorNode[];
};
export interface AgentInstance {
id: string;
applicationName: string;
group: string;
status: string;
routeIds: string[];
registeredAt: string;
lastHeartbeat: string;
}

404
ui/src/api/schema.d.ts vendored
View File

@@ -127,6 +127,7 @@ export interface paths {
};
get?: never;
put?: never;
/** Refresh access token */
post: operations["refresh"];
delete?: never;
options?: never;
@@ -143,6 +144,7 @@ export interface paths {
};
get?: never;
put?: never;
/** Exchange OIDC authorization code for JWTs */
post: operations["callback"];
delete?: never;
options?: never;
@@ -159,6 +161,7 @@ export interface paths {
};
get?: never;
put?: never;
/** Login with local credentials */
post: operations["login"];
delete?: never;
options?: never;
@@ -418,6 +421,7 @@ export interface paths {
path?: never;
cookie?: never;
};
/** Get OIDC config for SPA login flow */
get: operations["getConfig_1"];
put?: never;
post?: never;
@@ -509,7 +513,8 @@ export interface components {
RolesRequest: {
roles?: string[];
};
OidcConfigRequest: {
/** @description OIDC configuration update request */
OidcAdminConfigRequest: {
enabled?: boolean;
issuerUri?: string;
clientId?: string;
@@ -518,6 +523,21 @@ export interface components {
defaultRoles?: string[];
autoSignup?: boolean;
};
/** @description Error response */
ErrorResponse: {
message: string;
};
/** @description OIDC configuration for admin management */
OidcAdminConfigResponse: {
configured?: boolean;
enabled?: boolean;
issuerUri?: string;
clientId?: string;
clientSecretSet?: boolean;
rolesClaim?: string;
defaultRoles?: string[];
autoSignup?: boolean;
};
SearchRequest: {
status?: string;
/** Format: date-time */
@@ -542,32 +562,37 @@ export interface components {
limit?: number;
};
ExecutionSummary: {
executionId?: string;
routeId?: string;
agentId?: string;
status?: string;
executionId: string;
routeId: string;
agentId: string;
status: string;
/** Format: date-time */
startTime?: string;
startTime: string;
/** Format: date-time */
endTime?: string;
endTime: string;
/** Format: int64 */
durationMs?: number;
correlationId?: string;
errorMessage?: string;
diagramContentHash?: string;
durationMs: number;
correlationId: string;
errorMessage: string;
diagramContentHash: string;
};
SearchResultExecutionSummary: {
data?: components["schemas"]["ExecutionSummary"][];
data: components["schemas"]["ExecutionSummary"][];
/** Format: int64 */
total?: number;
total: number;
/** Format: int32 */
offset?: number;
offset: number;
/** Format: int32 */
limit?: number;
limit: number;
};
RefreshRequest: {
refreshToken?: string;
};
/** @description JWT token pair */
AuthTokenResponse: {
accessToken: string;
refreshToken: string;
};
CallbackRequest: {
code?: string;
redirectUri?: string;
@@ -576,89 +601,190 @@ export interface components {
username?: string;
password?: string;
};
/** @description Agent token refresh request */
AgentRefreshRequest: {
refreshToken: string;
};
/** @description Refreshed access token */
AgentRefreshResponse: {
accessToken: string;
};
/** @description Command to send to agent(s) */
CommandRequest: {
/** @description Command type: config-update, deep-trace, or replay */
type: string;
/** @description Command payload JSON */
payload?: Record<string, never>;
};
/** @description Result of sending a command to a single agent */
CommandSingleResponse: {
commandId: string;
status: string;
};
/** @description Agent registration payload */
AgentRegistrationRequest: {
agentId: string;
name: string;
/** @default default */
group: string;
version?: string;
routeIds?: string[];
capabilities?: {
[key: string]: Record<string, never>;
};
};
/** @description Agent registration result with JWT tokens and SSE endpoint */
AgentRegistrationResponse: {
agentId: string;
sseEndpoint: string;
/** Format: int64 */
heartbeatIntervalMs?: number;
serverPublicKey: string;
accessToken: string;
refreshToken: string;
};
/** @description Result of broadcasting a command to multiple agents */
CommandBroadcastResponse: {
commandIds: string[];
/** Format: int32 */
targetCount?: number;
};
/** @description OIDC provider connectivity test result */
OidcTestResult: {
status: string;
authorizationEndpoint: string;
};
ExecutionStats: {
/** Format: int64 */
totalCount?: number;
totalCount: number;
/** Format: int64 */
failedCount?: number;
failedCount: number;
/** Format: int64 */
avgDurationMs?: number;
avgDurationMs: number;
/** Format: int64 */
p99LatencyMs?: number;
p99LatencyMs: number;
/** Format: int64 */
activeCount?: number;
activeCount: number;
/** Format: int64 */
totalToday?: number;
totalToday: number;
/** Format: int64 */
prevTotalCount?: number;
prevTotalCount: number;
/** Format: int64 */
prevFailedCount?: number;
prevFailedCount: number;
/** Format: int64 */
prevAvgDurationMs?: number;
prevAvgDurationMs: number;
/** Format: int64 */
prevP99LatencyMs?: number;
prevP99LatencyMs: number;
};
StatsTimeseries: {
buckets?: components["schemas"]["TimeseriesBucket"][];
buckets: components["schemas"]["TimeseriesBucket"][];
};
TimeseriesBucket: {
/** Format: date-time */
time?: string;
time: string;
/** Format: int64 */
totalCount?: number;
totalCount: number;
/** Format: int64 */
failedCount?: number;
failedCount: number;
/** Format: int64 */
avgDurationMs?: number;
avgDurationMs: number;
/** Format: int64 */
p99DurationMs?: number;
p99DurationMs: number;
/** Format: int64 */
activeCount?: number;
activeCount: number;
};
ExecutionDetail: {
executionId?: string;
routeId?: string;
agentId?: string;
status?: string;
executionId: string;
routeId: string;
agentId: string;
status: string;
/** Format: date-time */
startTime?: string;
startTime: string;
/** Format: date-time */
endTime?: string;
endTime: string;
/** Format: int64 */
durationMs?: number;
correlationId?: string;
exchangeId?: string;
errorMessage?: string;
errorStackTrace?: string;
diagramContentHash?: string;
processors?: components["schemas"]["ProcessorNode"][];
durationMs: number;
correlationId: string;
exchangeId: string;
errorMessage: string;
errorStackTrace: string;
diagramContentHash: string;
processors: components["schemas"]["ProcessorNode"][];
};
ProcessorNode: {
processorId?: string;
processorType?: string;
status?: string;
processorId: string;
processorType: string;
status: string;
/** Format: date-time */
startTime?: string;
startTime: string;
/** Format: date-time */
endTime?: string;
endTime: string;
/** Format: int64 */
durationMs?: number;
diagramNodeId?: string;
errorMessage?: string;
errorStackTrace?: string;
durationMs: number;
diagramNodeId: string;
errorMessage: string;
errorStackTrace: string;
children: components["schemas"]["ProcessorNode"][];
};
DiagramLayout: {
/** Format: double */
width?: number;
/** Format: double */
height?: number;
nodes?: components["schemas"]["PositionedNode"][];
edges?: components["schemas"]["PositionedEdge"][];
};
PositionedEdge: {
sourceId?: string;
targetId?: string;
label?: string;
points?: number[][];
};
PositionedNode: {
id?: string;
label?: string;
type?: string;
/** Format: double */
x?: number;
/** Format: double */
y?: number;
/** Format: double */
width?: number;
/** Format: double */
height?: number;
};
/** @description OIDC configuration for SPA login flow */
OidcPublicConfigResponse: {
issuer: string;
clientId: string;
authorizationEndpoint: string;
/** @description Present if the provider supports RP-initiated logout */
endSessionEndpoint?: string;
};
/** @description Agent instance summary */
AgentInstanceResponse: {
id: string;
name: string;
group: string;
status: string;
routeIds: string[];
/** Format: date-time */
registeredAt: string;
/** Format: date-time */
lastHeartbeat: string;
};
SseEmitter: {
/** Format: int64 */
timeout?: number;
};
UserInfo: {
userId?: string;
provider?: string;
email?: string;
displayName?: string;
roles?: string[];
userId: string;
provider: string;
email: string;
displayName: string;
roles: string[];
/** Format: date-time */
createdAt?: string;
createdAt: string;
};
};
responses: never;
@@ -715,7 +841,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": Record<string, never>;
"*/*": components["schemas"]["OidcAdminConfigResponse"];
};
};
};
@@ -729,7 +855,7 @@ export interface operations {
};
requestBody: {
content: {
"application/json": components["schemas"]["OidcConfigRequest"];
"application/json": components["schemas"]["OidcAdminConfigRequest"];
};
};
responses: {
@@ -739,7 +865,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": Record<string, never>;
"*/*": components["schemas"]["OidcAdminConfigResponse"];
};
};
/** @description Invalid configuration */
@@ -748,7 +874,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": Record<string, never>;
"*/*": components["schemas"]["ErrorResponse"];
};
};
};
@@ -926,13 +1052,22 @@ export interface operations {
};
};
responses: {
/** @description OK */
/** @description Token refreshed */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": Record<string, never>;
"*/*": components["schemas"]["AuthTokenResponse"];
};
};
/** @description Invalid refresh token */
401: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": components["schemas"]["ErrorResponse"];
};
};
};
@@ -950,13 +1085,40 @@ export interface operations {
};
};
responses: {
/** @description OK */
/** @description Authentication successful */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": Record<string, never>;
"*/*": components["schemas"]["AuthTokenResponse"];
};
};
/** @description OIDC authentication failed */
401: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": components["schemas"]["ErrorResponse"];
};
};
/** @description Account not provisioned */
403: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": components["schemas"]["ErrorResponse"];
};
};
/** @description OIDC not configured or disabled */
404: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": components["schemas"]["AuthTokenResponse"];
};
};
};
@@ -974,13 +1136,22 @@ export interface operations {
};
};
responses: {
/** @description OK */
/** @description Login successful */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": Record<string, never>;
"*/*": components["schemas"]["AuthTokenResponse"];
};
};
/** @description Invalid credentials */
401: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": components["schemas"]["ErrorResponse"];
};
};
};
@@ -996,7 +1167,7 @@ export interface operations {
};
requestBody: {
content: {
"application/json": string;
"application/json": components["schemas"]["AgentRefreshRequest"];
};
};
responses: {
@@ -1006,7 +1177,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": string;
"*/*": components["schemas"]["AgentRefreshResponse"];
};
};
/** @description Invalid or expired refresh token */
@@ -1015,7 +1186,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": string;
"*/*": components["schemas"]["AgentRefreshResponse"];
};
};
/** @description Agent not found */
@@ -1024,7 +1195,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": string;
"*/*": components["schemas"]["AgentRefreshResponse"];
};
};
};
@@ -1067,7 +1238,7 @@ export interface operations {
};
requestBody: {
content: {
"application/json": string;
"application/json": components["schemas"]["CommandRequest"];
};
};
responses: {
@@ -1077,7 +1248,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": string;
"*/*": components["schemas"]["CommandSingleResponse"];
};
};
/** @description Invalid command payload */
@@ -1086,7 +1257,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": string;
"*/*": components["schemas"]["CommandSingleResponse"];
};
};
/** @description Agent not registered */
@@ -1095,7 +1266,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": string;
"*/*": components["schemas"]["CommandSingleResponse"];
};
};
};
@@ -1137,7 +1308,7 @@ export interface operations {
};
requestBody: {
content: {
"application/json": string;
"application/json": components["schemas"]["AgentRegistrationRequest"];
};
};
responses: {
@@ -1147,7 +1318,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": string;
"*/*": components["schemas"]["AgentRegistrationResponse"];
};
};
/** @description Invalid registration payload */
@@ -1156,7 +1327,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": string;
"*/*": components["schemas"]["ErrorResponse"];
};
};
/** @description Missing or invalid bootstrap token */
@@ -1165,7 +1336,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": string;
"*/*": components["schemas"]["AgentRegistrationResponse"];
};
};
};
@@ -1181,7 +1352,7 @@ export interface operations {
};
requestBody: {
content: {
"application/json": string;
"application/json": components["schemas"]["CommandRequest"];
};
};
responses: {
@@ -1191,7 +1362,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": string;
"*/*": components["schemas"]["CommandBroadcastResponse"];
};
};
/** @description Invalid command payload */
@@ -1200,7 +1371,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": string;
"*/*": components["schemas"]["CommandBroadcastResponse"];
};
};
};
@@ -1214,7 +1385,7 @@ export interface operations {
};
requestBody: {
content: {
"application/json": string;
"application/json": components["schemas"]["CommandRequest"];
};
};
responses: {
@@ -1224,7 +1395,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": string;
"*/*": components["schemas"]["CommandBroadcastResponse"];
};
};
/** @description Invalid command payload */
@@ -1233,7 +1404,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": string;
"*/*": components["schemas"]["CommandBroadcastResponse"];
};
};
};
@@ -1253,7 +1424,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": Record<string, never>;
"*/*": components["schemas"]["OidcTestResult"];
};
};
/** @description Provider unreachable or misconfigured */
@@ -1262,7 +1433,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": Record<string, never>;
"*/*": components["schemas"]["ErrorResponse"];
};
};
};
@@ -1325,7 +1496,7 @@ export interface operations {
};
requestBody?: never;
responses: {
/** @description OK */
/** @description Execution detail found */
200: {
headers: {
[name: string]: unknown;
@@ -1334,6 +1505,15 @@ export interface operations {
"*/*": components["schemas"]["ExecutionDetail"];
};
};
/** @description Execution not found */
404: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": components["schemas"]["ExecutionDetail"];
};
};
};
};
getProcessorSnapshot: {
@@ -1348,7 +1528,7 @@ export interface operations {
};
requestBody?: never;
responses: {
/** @description OK */
/** @description Snapshot data */
200: {
headers: {
[name: string]: unknown;
@@ -1359,6 +1539,17 @@ export interface operations {
};
};
};
/** @description Snapshot not found */
404: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": {
[key: string]: string;
};
};
};
};
};
renderDiagram: {
@@ -1378,7 +1569,8 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": Record<string, never>;
"image/svg+xml": string;
"application/json": components["schemas"]["DiagramLayout"];
};
};
/** @description Diagram not found */
@@ -1401,13 +1593,31 @@ export interface operations {
};
requestBody?: never;
responses: {
/** @description OK */
/** @description OIDC configuration */
200: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": Record<string, never>;
"*/*": components["schemas"]["OidcPublicConfigResponse"];
};
};
/** @description OIDC not configured or disabled */
404: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": components["schemas"]["OidcPublicConfigResponse"];
};
};
/** @description Failed to retrieve OIDC provider metadata */
500: {
headers: {
[name: string]: unknown;
};
content: {
"*/*": components["schemas"]["ErrorResponse"];
};
};
};
@@ -1429,7 +1639,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": string;
"*/*": components["schemas"]["AgentInstanceResponse"][];
};
};
/** @description Invalid status filter */
@@ -1438,7 +1648,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": string;
"*/*": components["schemas"]["ErrorResponse"];
};
};
};

17
ui/src/api/types.ts Normal file
View File

@@ -0,0 +1,17 @@
import type { components } from './schema';
export type ExecutionSummary = components['schemas']['ExecutionSummary'];
export type SearchRequest = components['schemas']['SearchRequest'];
export type ExecutionDetail = components['schemas']['ExecutionDetail'];
export type ExecutionStats = components['schemas']['ExecutionStats'];
export type StatsTimeseries = components['schemas']['StatsTimeseries'];
export type TimeseriesBucket = components['schemas']['TimeseriesBucket'];
export type UserInfo = components['schemas']['UserInfo'];
export type ProcessorNode = components['schemas']['ProcessorNode'];
export type AgentInstance = components['schemas']['AgentInstanceResponse'];
export type OidcAdminConfigResponse = components['schemas']['OidcAdminConfigResponse'];
export type OidcAdminConfigRequest = components['schemas']['OidcAdminConfigRequest'];
export type OidcTestResult = components['schemas']['OidcTestResult'];
export type OidcPublicConfigResponse = components['schemas']['OidcPublicConfigResponse'];
export type AuthTokenResponse = components['schemas']['AuthTokenResponse'];
export type ErrorResponse = components['schemas']['ErrorResponse'];