Files
govoplan-connectors/webui/src/api/governedConnectors.ts
T

205 lines
5.2 KiB
TypeScript

import { apiFetch, apiPath, type ApiSettings } from "@govoplan/core-webui";
export type GovernedConnectorSpecification = {
provider: string;
protocol: string;
capabilities: string[];
input_schema: Record<string, unknown>;
output_schema: Record<string, unknown>;
mapping: {
version: string;
rules: Array<{
source: string;
target: string;
required?: boolean;
default?: unknown;
}>;
};
validation_rules: Array<{
kind: "required" | "one_of" | "unique";
field: string;
values?: unknown[];
severity: "warning" | "error";
code: string;
message: string;
}>;
dry_run: {
supported: boolean;
simulation_supported: boolean;
sample_rows: Array<Record<string, unknown>>;
max_items: number;
redacted_fields: string[];
};
audit: {
event_prefix: string;
expected_events: string[];
evidence_fields: string[];
};
privacy_classification: "public" | "internal" | "confidential" | "restricted";
retention_class: string;
operational_limits: Record<string, unknown>;
retry_policy: Record<string, unknown>;
};
export type ConnectorDefinition = {
id: string;
definition_key: string;
name: string;
description?: string | null;
status: string;
current_revision: number;
source_package?: string | null;
local_definition: boolean;
definition_hash: string;
specification: GovernedConnectorSpecification;
updated_at: string;
};
export type ConnectorConfiguration = {
id: string;
definition_id: string;
definition_key: string;
definition_name: string;
name: string;
status: "draft" | "active" | "disabled";
endpoint_url?: string | null;
credential_ref?: string | null;
base_definition_revision: number;
latest_definition_revision: number;
update_available: boolean;
local_overrides: Record<string, unknown>;
protected_paths: string[];
effective_configuration: GovernedConnectorSpecification;
effective_hash: string;
resource_revision: number;
ambiguity_policy: "manual_review" | "quarantine" | "reject";
updated_at: string;
};
export type ConnectorRun = {
id: string;
configuration_id: string;
mode: "dry_run" | "simulation";
idempotency_key: string;
status: string;
review_state: string;
definition_revision: number;
configuration_revision: number;
configuration_hash: string;
input_hash: string;
summary: Record<string, number | boolean>;
effects: Array<Record<string, unknown>>;
diagnostics: Array<Record<string, unknown>>;
provenance: Record<string, unknown>;
reviewed_by?: string | null;
reviewed_at?: string | null;
review_reason?: string | null;
created_at: string;
};
export type ConnectorConfigurationDraft = {
name: string;
status: ConnectorConfiguration["status"];
endpoint_url: string;
credential_ref: string;
local_overrides: string;
ambiguity_policy: ConnectorConfiguration["ambiguity_policy"];
};
const ROOT = "/api/v1/connectors/governed";
export async function listConnectorDefinitions(
settings: ApiSettings
): Promise<ConnectorDefinition[]> {
const response = await apiFetch<{ items: ConnectorDefinition[] }>(
settings,
`${ROOT}/definitions`
);
return response.items;
}
export async function upsertConnectorDefinition(
settings: ApiSettings,
payload: Record<string, unknown>
): Promise<ConnectorDefinition> {
return apiFetch(settings, `${ROOT}/definitions`, {
method: "POST",
body: JSON.stringify(payload)
});
}
export async function listConnectorConfigurations(
settings: ApiSettings
): Promise<ConnectorConfiguration[]> {
const response = await apiFetch<{ items: ConnectorConfiguration[] }>(
settings,
`${ROOT}/configurations`
);
return response.items;
}
export function createConnectorConfiguration(
settings: ApiSettings,
payload: Record<string, unknown>
): Promise<ConnectorConfiguration> {
return apiFetch(settings, `${ROOT}/configurations`, {
method: "POST",
body: JSON.stringify(payload)
});
}
export function updateConnectorConfiguration(
settings: ApiSettings,
configurationId: string,
payload: Record<string, unknown>
): Promise<ConnectorConfiguration> {
return apiFetch(
settings,
`${ROOT}/configurations/${encodeURIComponent(configurationId)}`,
{ method: "PUT", body: JSON.stringify(payload) }
);
}
export async function listConnectorRuns(
settings: ApiSettings,
configurationId?: string
): Promise<ConnectorRun[]> {
const response = await apiFetch<{ items: ConnectorRun[] }>(
settings,
apiPath(`${ROOT}/runs`, {
configuration_id: configurationId || undefined,
limit: 100
})
);
return response.items;
}
export function executeConnectorRun(
settings: ApiSettings,
configurationId: string,
mode: "dry-runs" | "simulations",
payload: Record<string, unknown>
): Promise<ConnectorRun> {
return apiFetch(
settings,
`${ROOT}/configurations/${encodeURIComponent(configurationId)}/${mode}`,
{ method: "POST", body: JSON.stringify(payload) }
);
}
export function reviewConnectorRun(
settings: ApiSettings,
runId: string,
decision: "approved" | "rejected",
reason: string
): Promise<ConnectorRun> {
return apiFetch(
settings,
`${ROOT}/runs/${encodeURIComponent(runId)}/review`,
{
method: "POST",
body: JSON.stringify({ decision, reason })
}
);
}