Initial project snapshot

This commit is contained in:
2026-04-28 22:29:50 +03:00
commit 8ba0561f4f
365 changed files with 91832 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+609
View File
@@ -0,0 +1,609 @@
import type {
AuditEvent,
AuthResult,
BootstrapOwnerResult,
Cluster,
ClusterNodeGroup,
ClusterAdminSummary,
ClusterAuthorityState,
ClusterNode,
CreatedJoinToken,
FabricEntryPoint,
FabricEntryPointNode,
FabricEgressPool,
FabricEgressPoolNode,
FabricTestingFlag,
InstallationStatus,
JoinRequest,
MeshLink,
NodeHeartbeat,
NodeSyntheticMeshConfig,
NodeTelemetryObservation,
NodeWorkloadDesiredState,
OrganizationAdminSummary,
QoSPolicy,
RoleAssignment,
VPNConnection,
VPNConnectionLease,
WorkloadStatus,
} from "../types";
export type AdminClientConfig = {
baseUrl: string;
actorUserId: string;
};
type ApiErrorPayload = {
error?: {
code?: string;
message_key?: string;
fallback_message?: string;
trace_id?: string;
};
};
export type CreateClusterPayload = {
slug: string;
name: string;
region?: string | null;
};
export type UpdateClusterPayload = {
name: string;
status: string;
region?: string | null;
metadata?: Record<string, unknown>;
};
export type CreateVPNConnectionPayload = {
organizationId: string;
name: string;
protocolFamily: string;
targetEndpoint: Record<string, unknown>;
credentialRef?: string | null;
desiredState: string;
allowedNodePolicy: Record<string, unknown>;
routingUsage: unknown[];
routePolicy: Record<string, unknown>;
qosPolicy: Record<string, unknown>;
placementPolicy: Record<string, unknown>;
};
export type CreateFabricEntryPointPayload = {
name: string;
endpointType: string;
publicEndpoint?: string | null;
policy?: Record<string, unknown>;
metadata?: Record<string, unknown>;
};
export type CreateFabricEgressPoolPayload = {
name: string;
description?: string | null;
routeScope?: Record<string, unknown>;
policy?: Record<string, unknown>;
metadata?: Record<string, unknown>;
};
export type SetFabricEndpointNodePayload = {
status?: string;
priority?: number;
metadata?: Record<string, unknown>;
};
export class AdminApiClient {
private readonly baseUrl: string;
private readonly actorUserId: string;
constructor(config: AdminClientConfig) {
this.baseUrl = config.baseUrl.replace(/\/$/, "");
this.actorUserId = config.actorUserId.trim();
}
async login(input: { email: string; password: string; deviceLabel: string; trustDevice: boolean }): Promise<AuthResult> {
return this.post<AuthResult>("/auth/login", {
email: input.email,
password: input.password,
device_fingerprint: browserDeviceFingerprint(),
device_label: input.deviceLabel,
trust_device: input.trustDevice,
});
}
async getInstallationStatus(): Promise<InstallationStatus> {
const payload = await this.request<{ installation: InstallationStatus }>("/installation/status", {
method: "GET",
});
return payload.installation;
}
async bootstrapOwner(input: {
email: string;
password: string;
activationPayload?: unknown;
activationSignature?: string;
}): Promise<BootstrapOwnerResult> {
return this.post<BootstrapOwnerResult>("/installation/bootstrap-owner", {
email: input.email,
password: input.password,
activation_payload: input.activationPayload,
activation_signature: input.activationSignature || "",
});
}
async revokeAuthSession(input: { userId: string; authSessionId: string; reason: string }): Promise<void> {
await this.post("/auth/sessions/revoke", {
user_id: input.userId,
auth_session_id: input.authSessionId,
reason: input.reason,
});
}
async listClusters(): Promise<Cluster[]> {
const payload = await this.get<{ clusters: Cluster[] }>("/clusters");
return payload.clusters ?? [];
}
async createCluster(input: CreateClusterPayload): Promise<Cluster> {
const payload = await this.post<{ cluster: Cluster }>("/clusters/", {
actor_user_id: this.actorUserId,
slug: input.slug,
name: input.name,
region: input.region || null,
metadata: {},
});
return payload.cluster;
}
async updateCluster(clusterId: string, input: UpdateClusterPayload): Promise<Cluster> {
const payload = await this.put<{ cluster: Cluster }>(`/clusters/${clusterId}`, {
actor_user_id: this.actorUserId,
name: input.name,
status: input.status,
region: input.region || null,
metadata: input.metadata || {},
});
return payload.cluster;
}
async listClusterSummaries(): Promise<ClusterAdminSummary[]> {
const payload = await this.get<{ cluster_summaries: ClusterAdminSummary[] }>("/cluster-admin-summaries");
return payload.cluster_summaries ?? [];
}
async getClusterAuthority(clusterId: string): Promise<ClusterAuthorityState> {
const payload = await this.get<{ authority_state: ClusterAuthorityState }>(`/clusters/${clusterId}/authority`);
return payload.authority_state;
}
async updateClusterAuthority(
clusterId: string,
input: { authorityState: string; mutationMode: string; notes?: string | null },
): Promise<ClusterAuthorityState> {
const payload = await this.put<{ authority_state: ClusterAuthorityState }>(`/clusters/${clusterId}/authority`, {
actor_user_id: this.actorUserId,
authority_state: input.authorityState,
mutation_mode: input.mutationMode,
notes: input.notes || null,
});
return payload.authority_state;
}
async listNodes(clusterId: string): Promise<ClusterNode[]> {
const payload = await this.get<{ nodes: ClusterNode[] }>(`/clusters/${clusterId}/nodes`);
return payload.nodes ?? [];
}
async listNodeGroups(clusterId: string): Promise<ClusterNodeGroup[]> {
const payload = await this.get<{ node_groups: ClusterNodeGroup[] }>(`/clusters/${clusterId}/node-groups`);
return payload.node_groups ?? [];
}
async createNodeGroup(
clusterId: string,
input: { name: string; parentGroupId?: string | null; description?: string | null; sortOrder?: number },
): Promise<ClusterNodeGroup> {
const payload = await this.post<{ node_group: ClusterNodeGroup }>(`/clusters/${clusterId}/node-groups`, {
actor_user_id: this.actorUserId,
parent_group_id: input.parentGroupId || null,
name: input.name,
description: input.description || null,
sort_order: input.sortOrder || 0,
metadata: {},
});
return payload.node_group;
}
async assignNodeGroup(clusterId: string, nodeId: string, groupId?: string | null): Promise<ClusterNode> {
const payload = await this.put<{ node: ClusterNode }>(`/clusters/${clusterId}/nodes/${nodeId}/group`, {
actor_user_id: this.actorUserId,
group_id: groupId || null,
});
return payload.node;
}
async disableMembership(clusterId: string, nodeId: string, reason: string): Promise<void> {
await this.post(`/clusters/${clusterId}/nodes/${nodeId}/membership/disable`, {
actor_user_id: this.actorUserId,
reason,
});
}
async attachExistingNode(clusterId: string, nodeId: string, roles: string[]): Promise<ClusterNode> {
const payload = await this.post<{ node: ClusterNode }>(`/clusters/${clusterId}/nodes/${nodeId}/membership/attach`, {
actor_user_id: this.actorUserId,
roles,
});
return payload.node;
}
async revokeNodeIdentity(clusterId: string, nodeId: string, reason: string): Promise<void> {
await this.post(`/clusters/${clusterId}/nodes/${nodeId}/identity/revoke`, {
actor_user_id: this.actorUserId,
reason,
});
}
async listJoinRequests(clusterId: string): Promise<JoinRequest[]> {
const payload = await this.get<{ join_requests: JoinRequest[] }>(`/clusters/${clusterId}/join-requests`);
return payload.join_requests ?? [];
}
async createJoinToken(clusterId: string, input: { maxUses: number; ttlHours: number; scope: Record<string, unknown> }): Promise<CreatedJoinToken> {
const expiresAt = new Date(Date.now() + Math.max(input.ttlHours, 1) * 60 * 60 * 1000).toISOString();
const payload = await this.post<{ join_token: CreatedJoinToken }>(`/clusters/${clusterId}/join-tokens`, {
actor_user_id: this.actorUserId,
scope: input.scope,
expires_at: expiresAt,
max_uses: Math.max(input.maxUses, 1),
});
return payload.join_token;
}
async approveJoinRequest(clusterId: string, requestId: string): Promise<void> {
await this.post(`/clusters/${clusterId}/join-requests/${requestId}/approve`, {
actor_user_id: this.actorUserId,
ownership_type: "platform_managed",
});
}
async rejectJoinRequest(clusterId: string, requestId: string, reason: string): Promise<void> {
await this.post(`/clusters/${clusterId}/join-requests/${requestId}/reject`, {
actor_user_id: this.actorUserId,
reason,
});
}
async listNodeRoles(clusterId: string, nodeId: string): Promise<RoleAssignment[]> {
const payload = await this.get<{ role_assignments: RoleAssignment[] }>(
`/clusters/${clusterId}/nodes/${nodeId}/roles`,
);
return payload.role_assignments ?? [];
}
async assignRole(clusterId: string, nodeId: string, role: string, organizationId?: string): Promise<void> {
await this.setRoleStatus(clusterId, nodeId, role, "active", organizationId);
}
async setRoleStatus(clusterId: string, nodeId: string, role: string, status: "active" | "disabled" | "revoked", organizationId?: string): Promise<void> {
await this.post(`/clusters/${clusterId}/nodes/${nodeId}/roles`, {
actor_user_id: this.actorUserId,
organization_id: organizationId || null,
role,
status,
policy: {},
});
}
async listWorkloadStatuses(clusterId: string, nodeId: string): Promise<WorkloadStatus[]> {
const payload = await this.get<{ workload_statuses: WorkloadStatus[] }>(
`/clusters/${clusterId}/nodes/${nodeId}/workloads/status`,
);
return payload.workload_statuses ?? [];
}
async listDesiredWorkloads(clusterId: string, nodeId: string): Promise<NodeWorkloadDesiredState[]> {
const payload = await this.get<{ desired_workloads: NodeWorkloadDesiredState[] }>(
`/clusters/${clusterId}/nodes/${nodeId}/workloads/desired`,
);
return payload.desired_workloads ?? [];
}
async listNodeHeartbeats(clusterId: string, nodeId: string, limit = 100): Promise<NodeHeartbeat[]> {
const payload = await this.get<{ heartbeats: NodeHeartbeat[] }>(
`/clusters/${clusterId}/nodes/${nodeId}/heartbeats?limit=${limit}`,
);
return payload.heartbeats ?? [];
}
async listNodeTelemetry(clusterId: string, nodeId: string, limit = 120): Promise<NodeTelemetryObservation[]> {
const payload = await this.get<{ telemetry: NodeTelemetryObservation[] }>(
`/clusters/${clusterId}/nodes/${nodeId}/telemetry?limit=${limit}`,
);
return payload.telemetry ?? [];
}
async listFabricTestingFlags(): Promise<FabricTestingFlag[]> {
const payload = await this.get<{ testing_flags: FabricTestingFlag[] }>("/fabric/testing-flags");
return payload.testing_flags ?? [];
}
async updateFabricTestingFlag(input: {
scopeType: string;
scopeId?: string | null;
clusterId?: string | null;
enabled: boolean;
telemetryEnabled: boolean;
syntheticLinksEnabled: boolean;
historyRetentionHours: number;
metadata?: Record<string, unknown>;
}): Promise<FabricTestingFlag> {
const payload = await this.put<{ testing_flag: FabricTestingFlag }>("/fabric/testing-flags", {
actor_user_id: this.actorUserId,
scope_type: input.scopeType,
scope_id: input.scopeId || null,
cluster_id: input.clusterId || null,
enabled: input.enabled,
telemetry_enabled: input.telemetryEnabled,
synthetic_links_enabled: input.syntheticLinksEnabled,
history_retention_hours: input.historyRetentionHours,
metadata: input.metadata || {},
});
return payload.testing_flag;
}
async setDesiredWorkload(
clusterId: string,
nodeId: string,
serviceType: string,
input: { desiredState: string; runtimeMode: string; version?: string; config: Record<string, unknown>; environment: Record<string, unknown> },
): Promise<void> {
await this.put(`/clusters/${clusterId}/nodes/${nodeId}/workloads/${serviceType}/desired`, {
actor_user_id: this.actorUserId,
desired_state: input.desiredState,
version: input.version || null,
runtime_mode: input.runtimeMode,
artifact_ref: null,
config: input.config,
environment: input.environment,
});
}
async listMeshLinks(clusterId: string): Promise<MeshLink[]> {
const payload = await this.get<{ mesh_links: MeshLink[] }>(`/clusters/${clusterId}/mesh/links`);
return payload.mesh_links ?? [];
}
async getNodeSyntheticMeshConfig(clusterId: string, nodeId: string): Promise<NodeSyntheticMeshConfig> {
const payload = await this.get<{ synthetic_mesh_config: NodeSyntheticMeshConfig }>(
`/clusters/${clusterId}/nodes/${nodeId}/mesh/synthetic-config`,
);
return payload.synthetic_mesh_config;
}
async listQoSPolicies(clusterId: string): Promise<QoSPolicy[]> {
const payload = await this.get<{ qos_policies: QoSPolicy[] }>(`/clusters/${clusterId}/mesh/qos-policies`);
return payload.qos_policies ?? [];
}
async listFabricEntryPoints(clusterId: string): Promise<FabricEntryPoint[]> {
const payload = await this.get<{ entry_points: FabricEntryPoint[] }>(`/clusters/${clusterId}/fabric/entry-points`);
return payload.entry_points ?? [];
}
async createFabricEntryPoint(clusterId: string, input: CreateFabricEntryPointPayload): Promise<FabricEntryPoint> {
const payload = await this.post<{ entry_point: FabricEntryPoint }>(`/clusters/${clusterId}/fabric/entry-points`, {
actor_user_id: this.actorUserId,
name: input.name,
status: "active",
endpoint_type: input.endpointType || "client_access",
public_endpoint: input.publicEndpoint || null,
policy: input.policy || {},
metadata: input.metadata || {},
});
return payload.entry_point;
}
async listFabricEntryPointNodes(clusterId: string, entryPointId: string): Promise<FabricEntryPointNode[]> {
const payload = await this.get<{ entry_point_nodes: FabricEntryPointNode[] }>(
`/clusters/${clusterId}/fabric/entry-points/${entryPointId}/nodes`,
);
return payload.entry_point_nodes ?? [];
}
async setFabricEntryPointNode(
clusterId: string,
entryPointId: string,
nodeId: string,
input: SetFabricEndpointNodePayload = {},
): Promise<FabricEntryPointNode> {
const payload = await this.put<{ entry_point_node: FabricEntryPointNode }>(
`/clusters/${clusterId}/fabric/entry-points/${entryPointId}/nodes/${nodeId}`,
{
actor_user_id: this.actorUserId,
status: input.status || "active",
priority: input.priority || 100,
metadata: input.metadata || {},
},
);
return payload.entry_point_node;
}
async listFabricEgressPools(clusterId: string): Promise<FabricEgressPool[]> {
const payload = await this.get<{ egress_pools: FabricEgressPool[] }>(`/clusters/${clusterId}/fabric/egress-pools`);
return payload.egress_pools ?? [];
}
async createFabricEgressPool(clusterId: string, input: CreateFabricEgressPoolPayload): Promise<FabricEgressPool> {
const payload = await this.post<{ egress_pool: FabricEgressPool }>(`/clusters/${clusterId}/fabric/egress-pools`, {
actor_user_id: this.actorUserId,
name: input.name,
status: "active",
description: input.description || null,
route_scope: input.routeScope || {},
policy: input.policy || {},
metadata: input.metadata || {},
});
return payload.egress_pool;
}
async listFabricEgressPoolNodes(clusterId: string, egressPoolId: string): Promise<FabricEgressPoolNode[]> {
const payload = await this.get<{ egress_pool_nodes: FabricEgressPoolNode[] }>(
`/clusters/${clusterId}/fabric/egress-pools/${egressPoolId}/nodes`,
);
return payload.egress_pool_nodes ?? [];
}
async setFabricEgressPoolNode(
clusterId: string,
egressPoolId: string,
nodeId: string,
input: SetFabricEndpointNodePayload = {},
): Promise<FabricEgressPoolNode> {
const payload = await this.put<{ egress_pool_node: FabricEgressPoolNode }>(
`/clusters/${clusterId}/fabric/egress-pools/${egressPoolId}/nodes/${nodeId}`,
{
actor_user_id: this.actorUserId,
status: input.status || "active",
priority: input.priority || 100,
metadata: input.metadata || {},
},
);
return payload.egress_pool_node;
}
async listVPNConnections(clusterId: string): Promise<VPNConnection[]> {
const payload = await this.get<{ vpn_connections: VPNConnection[] }>(`/clusters/${clusterId}/vpn-connections`);
return payload.vpn_connections ?? [];
}
async createVPNConnection(clusterId: string, input: CreateVPNConnectionPayload): Promise<VPNConnection> {
const payload = await this.post<{ vpn_connection: VPNConnection }>(`/clusters/${clusterId}/vpn-connections`, {
actor_user_id: this.actorUserId,
organization_id: input.organizationId,
name: input.name,
target_endpoint: input.targetEndpoint,
protocol_family: input.protocolFamily,
credential_ref: input.credentialRef || null,
mode: "single_active",
desired_state: input.desiredState,
allowed_node_policy: input.allowedNodePolicy,
routing_usage: input.routingUsage,
route_policy: input.routePolicy,
qos_policy: input.qosPolicy,
placement_policy: input.placementPolicy,
metadata: {},
});
return payload.vpn_connection;
}
async updateVPNConnectionDesiredState(clusterId: string, vpnConnectionId: string, desiredState: string): Promise<VPNConnection> {
const payload = await this.put<{ vpn_connection: VPNConnection }>(
`/clusters/${clusterId}/vpn-connections/${vpnConnectionId}/desired-state`,
{
actor_user_id: this.actorUserId,
desired_state: desiredState,
},
);
return payload.vpn_connection;
}
async getActiveVPNLease(clusterId: string, vpnConnectionId: string): Promise<VPNConnectionLease | null> {
try {
const payload = await this.get<{ lease: VPNConnectionLease }>(
`/clusters/${clusterId}/vpn-connections/${vpnConnectionId}/leases/active`,
);
return payload.lease;
} catch {
return null;
}
}
async expireStaleVPNLeases(clusterId: string): Promise<VPNConnectionLease[]> {
const payload = await this.post<{ expired_leases: VPNConnectionLease[] }>(
`/clusters/${clusterId}/vpn-connection-leases/expire-stale`,
{
actor_user_id: this.actorUserId,
},
);
return payload.expired_leases ?? [];
}
async listAudit(clusterId: string): Promise<AuditEvent[]> {
const payload = await this.get<{ audit_events: AuditEvent[] }>(`/clusters/${clusterId}/audit?limit=100`);
return payload.audit_events ?? [];
}
async getOrganizationAdminSummary(organizationId: string): Promise<OrganizationAdminSummary> {
const payload = await this.get<{ admin_summary: OrganizationAdminSummary }>(
`/organizations/${organizationId}/admin-summary`,
);
return payload.admin_summary;
}
private async get<T>(path: string): Promise<T> {
const separator = path.includes("?") ? "&" : "?";
return this.request<T>(`${path}${separator}actor_user_id=${encodeURIComponent(this.actorUserId)}`, {
method: "GET",
});
}
private async post<T>(path: string, body: unknown): Promise<T> {
return this.request<T>(path, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
}
private async put<T>(path: string, body: unknown): Promise<T> {
return this.request<T>(path, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(body),
});
}
private async request<T>(path: string, init: RequestInit): Promise<T> {
const response = await fetch(`${this.baseUrl}${path}`, init);
if (!response.ok) {
let message = `Запрос завершился ошибкой HTTP ${response.status}`;
try {
const payload = (await response.json()) as ApiErrorPayload;
message = payload.error?.fallback_message || payload.error?.code || message;
} catch {
// Keep generic HTTP message if backend did not return JSON.
}
throw new Error(message);
}
return (await response.json()) as T;
}
}
function browserDeviceFingerprint(): string {
const key = "rap.webAdmin.deviceFingerprint";
const existing = localStorage.getItem(key);
if (existing) {
return existing;
}
const value = `web-admin-${createBrowserIdentifier()}`;
localStorage.setItem(key, value);
return value;
}
function createBrowserIdentifier(): string {
if (typeof globalThis.crypto?.randomUUID === "function") {
return globalThis.crypto.randomUUID();
}
if (typeof globalThis.crypto?.getRandomValues === "function") {
const bytes = new Uint8Array(16);
globalThis.crypto.getRandomValues(bytes);
bytes[6] = (bytes[6] & 0x0f) | 0x40;
bytes[8] = (bytes[8] & 0x3f) | 0x80;
const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
}
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
}
+10
View File
@@ -0,0 +1,10 @@
import React from "react";
import { createRoot } from "react-dom/client";
import { App } from "./App";
import "./styles.css";
createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
File diff suppressed because it is too large Load Diff
+529
View File
@@ -0,0 +1,529 @@
export type Cluster = {
id: string;
slug: string;
name: string;
status: string;
region?: string | null;
metadata?: Record<string, unknown>;
created_at: string;
updated_at?: string;
};
export type AuthUser = {
ID?: string;
id?: string;
Email?: string;
email?: string;
};
export type AuthSession = {
ID?: string;
id?: string;
};
export type AuthTokens = {
access_token: string;
access_token_expires_at: string;
refresh_token: string;
refresh_token_expires_at: string;
};
export type AuthResult = {
user: AuthUser;
auth_session: AuthSession;
tokens: AuthTokens;
};
export type InstallationStatus = {
bootstrapped: boolean;
authority_state: string;
install_id?: string;
bootstrapped_owner_email?: string;
bootstrapped_at?: string;
authority_mode: string;
strict_authority: boolean;
root_fingerprint?: string;
insecure_bootstrap_allowed: boolean;
};
export type BootstrapOwnerResult = {
installation: InstallationStatus;
user: AuthUser;
platform_role: string;
};
export type ClusterAuthorityState = {
cluster_id: string;
authority_state: string;
mutation_mode: string;
term: number;
notes?: string | null;
updated_by_user_id?: string | null;
updated_at: string;
};
export type ClusterNode = {
id: string;
owner_organization_id?: string | null;
node_key: string;
name: string;
ownership_type: string;
registration_status: string;
health_status: string;
version_state: string;
partition_state: string;
reported_version?: string | null;
last_seen_at?: string | null;
membership_status: string;
membership_metadata?: Record<string, unknown>;
node_group_id?: string | null;
node_group_name?: string | null;
created_at?: string;
updated_at?: string;
};
export type ClusterNodeGroup = {
id: string;
cluster_id: string;
parent_group_id?: string | null;
name: string;
description?: string | null;
sort_order: number;
metadata?: Record<string, unknown>;
created_by_user_id?: string | null;
created_at: string;
updated_at?: string;
};
export type JoinRequest = {
id: string;
cluster_id: string;
node_name: string;
node_fingerprint: string;
public_key?: string;
reported_capabilities: Record<string, unknown>;
reported_facts: Record<string, unknown>;
requested_roles: unknown[];
status: string;
reviewed_at?: string | null;
approved_node_id?: string | null;
rejection_reason?: string | null;
created_at: string;
updated_at?: string;
approval_payload?: Record<string, unknown>;
approval_signature?: ClusterSignature;
};
export type ClusterSignature = {
schema_version: string;
algorithm: string;
key_fingerprint: string;
signature: string;
signed_at: string;
};
export type ClusterAuthorityDescriptor = {
schema_version: string;
cluster_id: string;
authority_state: string;
key_algorithm: string;
public_key: string;
public_key_fingerprint: string;
created_at: string;
updated_at: string;
};
export type CreatedJoinToken = {
id: string;
cluster_id: string;
scope: Record<string, unknown>;
expires_at: string;
max_uses: number;
used_count: number;
status: string;
created_at: string;
revoked_at?: string | null;
authority_payload?: Record<string, unknown>;
authority_signature?: ClusterSignature;
token: string;
};
export type RoleAssignment = {
id: string;
cluster_id: string;
node_id: string;
organization_id?: string | null;
role: string;
status: string;
policy?: Record<string, unknown>;
assigned_at: string;
revoked_at?: string | null;
};
export type AuditEvent = {
id: string;
cluster_id?: string | null;
actor_user_id?: string | null;
event_type: string;
target_type: string;
target_id?: string | null;
payload: Record<string, unknown>;
created_at: string;
};
export type WorkloadStatus = {
id: string;
cluster_id: string;
node_id: string;
service_type: string;
reported_state: string;
runtime_mode: string;
version?: string | null;
status_payload?: Record<string, unknown>;
observed_at: string;
};
export type NodeWorkloadDesiredState = {
cluster_id: string;
node_id: string;
service_type: string;
desired_state: string;
version?: string | null;
runtime_mode: string;
artifact_ref?: string | null;
config?: Record<string, unknown>;
environment?: Record<string, unknown>;
updated_by_user_id?: string | null;
updated_at: string;
};
export type NodeHeartbeat = {
id: string;
cluster_id: string;
node_id: string;
health_status: string;
reported_version?: string | null;
capabilities?: Record<string, unknown>;
service_states?: Record<string, unknown>;
metadata?: Record<string, unknown>;
observed_at: string;
};
export type FabricTestingFlag = {
id: string;
scope_type: string;
scope_id?: string | null;
cluster_id?: string | null;
enabled: boolean;
telemetry_enabled: boolean;
synthetic_links_enabled: boolean;
history_retention_hours: number;
metadata?: Record<string, unknown>;
updated_by_user_id?: string | null;
updated_at: string;
};
export type NodeTelemetryObservation = {
id: string;
cluster_id: string;
node_id: string;
cpu_percent?: number | null;
memory_used_bytes?: number | null;
memory_total_bytes?: number | null;
disk_used_bytes?: number | null;
disk_total_bytes?: number | null;
network_rx_bytes?: number | null;
network_tx_bytes?: number | null;
process_count?: number | null;
payload?: Record<string, unknown>;
observed_at: string;
};
export type MeshLink = {
id: string;
cluster_id: string;
source_node_id: string;
target_node_id: string;
link_status: string;
latency_ms?: number | null;
quality_score?: number | null;
metadata?: Record<string, unknown>;
observed_at: string;
};
export type PeerEndpointCandidate = {
endpoint_id: string;
node_id: string;
transport: string;
address: string;
address_family?: string | null;
reachability: string;
nat_type?: string | null;
connectivity_mode: string;
region?: string | null;
priority: number;
policy_tags?: string[];
last_verified_at?: string | null;
metadata?: Record<string, unknown>;
};
export type PeerDirectoryEntry = {
node_id: string;
route_ids?: string[];
endpoint_count: number;
candidate_count: number;
connectivity_modes?: string[];
recovery_seed: boolean;
};
export type PeerRecoverySeed = {
node_id: string;
endpoint: string;
transport: string;
connectivity_mode?: string | null;
region?: string | null;
priority: number;
last_verified_at?: string | null;
metadata?: Record<string, unknown>;
};
export type PeerRendezvousLease = {
lease_id: string;
peer_node_id: string;
relay_node_id: string;
relay_endpoint: string;
transport: string;
connectivity_mode?: string | null;
route_ids?: string[];
allowed_channels?: string[];
priority: number;
control_plane_only: boolean;
issued_at: string;
expires_at: string;
reason?: string | null;
metadata?: Record<string, unknown>;
};
export type RendezvousRelayPolicyDecision = {
route_id?: string;
peer_node_id: string;
withdrawn_lease_id?: string;
stale_relay_node_id?: string;
selected_relay_id?: string;
selected_endpoint?: string;
score?: number;
reason: string;
score_reasons?: string[];
reporter_node_id?: string;
};
export type RendezvousRelayPolicyReport = {
schema_version: string;
scoring_mode: string;
feedback_max_age_seconds: number;
stale_relay_count: number;
withdrawn_lease_count: number;
replacement_lease_count: number;
decisions?: RendezvousRelayPolicyDecision[];
};
export type RoutePathDecision = {
decision_id: string;
route_id: string;
cluster_id: string;
local_node_id: string;
source_node_id: string;
destination_node_id: string;
original_hops: string[];
effective_hops: string[];
previous_hop_id?: string;
next_hop_id?: string;
local_role: string;
selected_relay_id?: string;
selected_relay_endpoint?: string;
stale_relay_node_id?: string;
rendezvous_lease_id?: string;
rendezvous_lease_reason?: string;
decision_source: string;
generation: string;
path_score?: number;
score_reasons?: string[];
control_plane_only: boolean;
production_forwarding: boolean;
expires_at: string;
};
export type RoutePathDecisionReport = {
schema_version: string;
decision_mode: string;
generation: string;
decision_count: number;
replacement_decision_count: number;
control_plane_only: boolean;
production_forwarding: boolean;
decisions?: RoutePathDecision[];
};
export type SyntheticMeshRoute = {
route_id: string;
cluster_id: string;
source_node_id: string;
destination_node_id: string;
hops: string[];
allowed_channels: string[];
expires_at: string;
max_ttl: number;
max_hops: number;
route_version?: string;
policy_version?: string;
peer_directory_version?: string;
};
export type NodeSyntheticMeshConfig = {
enabled: boolean;
schema_version: string;
cluster_id: string;
local_node_id: string;
authority_required: boolean;
cluster_authority?: ClusterAuthorityDescriptor;
authority_payload?: Record<string, unknown>;
authority_signature?: ClusterSignature;
config_version?: string;
peer_directory_version?: string;
policy_version?: string;
peer_endpoints: Record<string, string>;
peer_endpoint_candidates?: Record<string, PeerEndpointCandidate[]>;
peer_directory?: PeerDirectoryEntry[];
recovery_seeds?: PeerRecoverySeed[];
rendezvous_leases?: PeerRendezvousLease[];
rendezvous_relay_policy?: RendezvousRelayPolicyReport;
route_path_decisions?: RoutePathDecisionReport;
routes: SyntheticMeshRoute[];
production_forwarding: boolean;
};
export type FabricEntryPoint = {
id: string;
cluster_id: string;
name: string;
status: string;
endpoint_type: string;
public_endpoint?: string | null;
policy?: Record<string, unknown>;
metadata?: Record<string, unknown>;
created_by_user_id?: string | null;
created_at: string;
updated_at?: string;
};
export type FabricEntryPointNode = {
entry_point_id: string;
cluster_id: string;
node_id: string;
status: string;
priority: number;
metadata?: Record<string, unknown>;
added_by_user_id?: string | null;
added_at: string;
};
export type FabricEgressPool = {
id: string;
cluster_id: string;
name: string;
status: string;
description?: string | null;
route_scope?: Record<string, unknown>;
policy?: Record<string, unknown>;
metadata?: Record<string, unknown>;
created_by_user_id?: string | null;
created_at: string;
updated_at?: string;
};
export type FabricEgressPoolNode = {
egress_pool_id: string;
cluster_id: string;
node_id: string;
status: string;
priority: number;
metadata?: Record<string, unknown>;
added_by_user_id?: string | null;
added_at: string;
};
export type QoSPolicy = {
id: string;
cluster_id: string;
service_class: string;
priority: number;
reliability_mode: string;
drop_policy: string;
bandwidth_policy?: Record<string, unknown>;
metadata?: Record<string, unknown>;
};
export type ClusterAdminSummary = {
cluster_id: string;
slug: string;
name: string;
status: string;
region?: string | null;
authority_state: string;
mutation_mode: string;
cluster_key_algorithm?: string | null;
cluster_key_fingerprint?: string | null;
node_count: number;
healthy_node_count: number;
pending_join_count: number;
active_role_assignment_count: number;
last_node_seen_at?: string | null;
};
export type OrganizationAdminSummary = {
organization_id: string;
resource_count: number;
active_session_count: number;
service_endpoints: Array<{ protocol: string; count: number }>;
connector_status: Record<string, unknown>;
topology_exposure: string;
};
export type VPNConnection = {
id: string;
cluster_id: string;
organization_id: string;
name: string;
target_endpoint: Record<string, unknown>;
protocol_family: string;
credential_ref?: string | null;
mode: string;
desired_state: string;
allowed_node_policy: Record<string, unknown>;
routing_usage: unknown[];
route_policy: Record<string, unknown>;
qos_policy: Record<string, unknown>;
placement_policy: Record<string, unknown>;
status: string;
metadata: Record<string, unknown>;
created_by_user_id?: string | null;
updated_by_user_id?: string | null;
created_at: string;
updated_at: string;
};
export type VPNConnectionLease = {
id: string;
vpn_connection_id: string;
cluster_id: string;
owner_node_id: string;
lease_generation: number;
fencing_token: string;
status: string;
acquired_at: string;
renewed_at: string;
expires_at: string;
released_at?: string | null;
fenced_at?: string | null;
metadata: Record<string, unknown>;
};
+1
View File
@@ -0,0 +1 @@
/// <reference types="vite/client" />