Record project continuation changes
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Панель Secure Access Fabric</title>
|
||||
<script type="module" crossorigin src="/assets/index-Bx8KW1vY.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BLOAmgHn.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
+5589
-285
File diff suppressed because it is too large
Load Diff
+814
-3
@@ -1,5 +1,6 @@
|
||||
import type {
|
||||
AuditEvent,
|
||||
AuditSummary,
|
||||
AuthResult,
|
||||
BootstrapOwnerResult,
|
||||
Cluster,
|
||||
@@ -12,19 +13,49 @@ import type {
|
||||
FabricEntryPointNode,
|
||||
FabricEgressPool,
|
||||
FabricEgressPoolNode,
|
||||
FabricServiceChannelAdaptivePolicy,
|
||||
FabricServiceChannelBreadcrumbWindowPolicy,
|
||||
FabricServiceChannelPoolPolicy,
|
||||
FabricServiceChannelRecoveryPolicy,
|
||||
FabricServiceChannelRouteFeedbackObservation,
|
||||
FabricServiceChannelRouteRebuildAlertSilence,
|
||||
FabricServiceChannelRouteRebuildAttempt,
|
||||
FabricServiceChannelRouteRebuildHealthSummary,
|
||||
FabricServiceChannelRouteRebuildIncident,
|
||||
FabricServiceChannelRebuildInvestigationBreadcrumbs,
|
||||
ExpireFabricServiceChannelRouteFeedbackResult,
|
||||
FabricServiceChannelReadiness,
|
||||
FabricServiceChannelRebuildSnapshotMaintenanceHealth,
|
||||
FabricServiceChannelRebuildSnapshotWarmup,
|
||||
FabricServiceChannelLeaseMaintenance,
|
||||
FabricServiceChannelAccessTelemetry,
|
||||
FabricServiceChannelSchemaStatus,
|
||||
FabricTestingFlag,
|
||||
InstallationStatus,
|
||||
JoinRequest,
|
||||
MeshLink,
|
||||
MeshRouteIntent,
|
||||
NodeJoinToken,
|
||||
NodeHeartbeat,
|
||||
NodeSyntheticMeshConfig,
|
||||
NodeTelemetryObservation,
|
||||
NodeUpdatePlan,
|
||||
NodeUpdatePolicy,
|
||||
NodeUpdateStatus,
|
||||
NodeWorkloadDesiredState,
|
||||
OrganizationAdminSummary,
|
||||
Organization,
|
||||
OrganizationMembership,
|
||||
QoSPolicy,
|
||||
ReleaseVersion,
|
||||
Resource,
|
||||
RoleAssignment,
|
||||
UserAccount,
|
||||
VPNClientDiagnosticCommand,
|
||||
VPNClientDiagnosticStatus,
|
||||
VPNConnection,
|
||||
VPNConnectionLease,
|
||||
VPNPacketStats,
|
||||
WorkloadStatus,
|
||||
} from "../types";
|
||||
|
||||
@@ -69,6 +100,83 @@ export type CreateVPNConnectionPayload = {
|
||||
placementPolicy: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export type UpsertNodeUpdatePolicyPayload = {
|
||||
product: string;
|
||||
channel?: string;
|
||||
targetVersion?: string | null;
|
||||
strategy?: string;
|
||||
enabled?: boolean;
|
||||
rollbackAllowed?: boolean;
|
||||
healthWindowSeconds?: number;
|
||||
};
|
||||
|
||||
export type UpdateFabricServiceChannelRecoveryPolicyPayload = {
|
||||
hysteresisPenalty?: number;
|
||||
promotionMinSamples?: number;
|
||||
demotionFailureThreshold?: number;
|
||||
demotionDropThreshold?: number;
|
||||
demotionSlowThreshold?: number;
|
||||
demotionRebuildEnabled?: boolean;
|
||||
demotionFencedEnabled?: boolean;
|
||||
};
|
||||
|
||||
export type UpdateFabricServiceChannelAdaptivePolicyPayload = {
|
||||
maxParallelWindow?: number;
|
||||
bulkPressureChannelThreshold?: number;
|
||||
queuePressureHighWatermark?: number;
|
||||
queuePressureMaxInFlight?: number;
|
||||
classWindows?: Record<string, number>;
|
||||
};
|
||||
|
||||
export type UpdateFabricServiceChannelPoolPolicyPayload = {
|
||||
entryPoolNodeIds?: string[];
|
||||
exitPoolNodeIds?: string[];
|
||||
preferredEntryNodeId?: string;
|
||||
preferredExitNodeId?: string;
|
||||
selectionStrategy?: string;
|
||||
routeRebuild?: string;
|
||||
entryFailover?: string;
|
||||
exitFailover?: string;
|
||||
backendFallbackAllowed?: boolean;
|
||||
stickySession?: boolean;
|
||||
};
|
||||
|
||||
export type UpdateFabricServiceChannelBreadcrumbWindowPolicyPayload = {
|
||||
currentWindowSeconds?: number;
|
||||
historyWindowSeconds?: number;
|
||||
};
|
||||
|
||||
export type CreateOrganizationPayload = {
|
||||
slug: string;
|
||||
name: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export type CreateUserPayload = {
|
||||
email: string;
|
||||
password: string;
|
||||
platformRole?: string;
|
||||
};
|
||||
|
||||
export type CreateResourcePayload = {
|
||||
organizationId: string;
|
||||
name: string;
|
||||
address: string;
|
||||
protocol: string;
|
||||
secretRef?: string | null;
|
||||
certificateVerificationMode?: string;
|
||||
renderQualityProfile?: string;
|
||||
clipboardMode?: string;
|
||||
fileTransferMode?: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export type UpsertResourceSecretPayload = {
|
||||
username?: string;
|
||||
password?: string;
|
||||
domain?: string;
|
||||
};
|
||||
|
||||
export type CreateFabricEntryPointPayload = {
|
||||
name: string;
|
||||
endpointType: string;
|
||||
@@ -110,6 +218,12 @@ export class AdminApiClient {
|
||||
});
|
||||
}
|
||||
|
||||
async refresh(input: { refreshToken: string }): Promise<AuthResult> {
|
||||
return this.post<AuthResult>("/auth/refresh", {
|
||||
refresh_token: input.refreshToken,
|
||||
});
|
||||
}
|
||||
|
||||
async getInstallationStatus(): Promise<InstallationStatus> {
|
||||
const payload = await this.request<{ installation: InstallationStatus }>("/installation/status", {
|
||||
method: "GET",
|
||||
@@ -244,6 +358,13 @@ export class AdminApiClient {
|
||||
});
|
||||
}
|
||||
|
||||
async deleteClusterNode(clusterId: string, nodeId: string, reason: string): Promise<void> {
|
||||
await this.delete(`/clusters/${clusterId}/nodes/${nodeId}`, {
|
||||
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 ?? [];
|
||||
@@ -260,6 +381,18 @@ export class AdminApiClient {
|
||||
return payload.join_token;
|
||||
}
|
||||
|
||||
async listJoinTokens(clusterId: string): Promise<NodeJoinToken[]> {
|
||||
const payload = await this.get<{ join_tokens: NodeJoinToken[] }>(`/clusters/${clusterId}/join-tokens`);
|
||||
return payload.join_tokens ?? [];
|
||||
}
|
||||
|
||||
async revokeJoinToken(clusterId: string, tokenId: string): Promise<NodeJoinToken> {
|
||||
const payload = await this.post<{ join_token: NodeJoinToken }>(`/clusters/${clusterId}/join-tokens/${tokenId}/revoke`, {
|
||||
actor_user_id: this.actorUserId,
|
||||
});
|
||||
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,
|
||||
@@ -323,6 +456,49 @@ export class AdminApiClient {
|
||||
return payload.telemetry ?? [];
|
||||
}
|
||||
|
||||
async listReleaseVersions(clusterId: string, product = "rap-node-agent", channel = "dev"): Promise<ReleaseVersion[]> {
|
||||
const params = new URLSearchParams({ product, channel });
|
||||
const payload = await this.get<{ release_versions: ReleaseVersion[] }>(`/clusters/${clusterId}/updates/releases?${params.toString()}`);
|
||||
return payload.release_versions ?? [];
|
||||
}
|
||||
|
||||
async getNodeUpdatePlan(
|
||||
clusterId: string,
|
||||
nodeId: string,
|
||||
input: { product?: string; currentVersion?: string | null; os?: string; arch?: string; installType?: string; channel?: string },
|
||||
): Promise<NodeUpdatePlan> {
|
||||
const params = new URLSearchParams({
|
||||
product: input.product || "rap-node-agent",
|
||||
current_version: input.currentVersion || "",
|
||||
os: input.os || "linux",
|
||||
arch: input.arch || "amd64",
|
||||
install_type: input.installType || "docker",
|
||||
channel: input.channel || "dev",
|
||||
});
|
||||
const payload = await this.get<{ node_update_plan: NodeUpdatePlan }>(`/clusters/${clusterId}/nodes/${nodeId}/updates/plan?${params.toString()}`);
|
||||
return payload.node_update_plan;
|
||||
}
|
||||
|
||||
async upsertNodeUpdatePolicy(clusterId: string, nodeId: string, input: UpsertNodeUpdatePolicyPayload): Promise<NodeUpdatePolicy> {
|
||||
const payload = await this.put<{ node_update_policy: NodeUpdatePolicy }>(`/clusters/${clusterId}/nodes/${nodeId}/updates/policy`, {
|
||||
actor_user_id: this.actorUserId,
|
||||
product: input.product,
|
||||
channel: input.channel || "dev",
|
||||
target_version: input.targetVersion ?? null,
|
||||
strategy: input.strategy || "rolling",
|
||||
enabled: input.enabled ?? true,
|
||||
rollback_allowed: input.rollbackAllowed ?? true,
|
||||
health_window_seconds: input.healthWindowSeconds || 180,
|
||||
});
|
||||
return payload.node_update_policy;
|
||||
}
|
||||
|
||||
async listNodeUpdateStatuses(clusterId: string, nodeId: string, limit = 80): Promise<NodeUpdateStatus[]> {
|
||||
const params = new URLSearchParams({ actor_user_id: this.actorUserId, limit: String(limit) });
|
||||
const payload = await this.get<{ node_update_statuses: NodeUpdateStatus[] }>(`/clusters/${clusterId}/nodes/${nodeId}/updates/statuses?${params.toString()}`);
|
||||
return payload.node_update_statuses ?? [];
|
||||
}
|
||||
|
||||
async listFabricTestingFlags(): Promise<FabricTestingFlag[]> {
|
||||
const payload = await this.get<{ testing_flags: FabricTestingFlag[] }>("/fabric/testing-flags");
|
||||
return payload.testing_flags ?? [];
|
||||
@@ -374,6 +550,28 @@ export class AdminApiClient {
|
||||
return payload.mesh_links ?? [];
|
||||
}
|
||||
|
||||
async listRouteIntents(clusterId: string): Promise<MeshRouteIntent[]> {
|
||||
const params = new URLSearchParams({ actor_user_id: this.actorUserId });
|
||||
const payload = await this.get<{ route_intents: MeshRouteIntent[] }>(`/clusters/${clusterId}/mesh/route-intents?${params.toString()}`);
|
||||
return payload.route_intents ?? [];
|
||||
}
|
||||
|
||||
async expireRouteIntent(clusterId: string, routeIntentId: string, reason: string): Promise<MeshRouteIntent> {
|
||||
const payload = await this.post<{ route_intent: MeshRouteIntent }>(`/clusters/${clusterId}/mesh/route-intents/${routeIntentId}/expire`, {
|
||||
actor_user_id: this.actorUserId,
|
||||
reason,
|
||||
});
|
||||
return payload.route_intent;
|
||||
}
|
||||
|
||||
async disableRouteIntent(clusterId: string, routeIntentId: string, reason: string): Promise<MeshRouteIntent> {
|
||||
const payload = await this.post<{ route_intent: MeshRouteIntent }>(`/clusters/${clusterId}/mesh/route-intents/${routeIntentId}/disable`, {
|
||||
actor_user_id: this.actorUserId,
|
||||
reason,
|
||||
});
|
||||
return payload.route_intent;
|
||||
}
|
||||
|
||||
async getNodeSyntheticMeshConfig(clusterId: string, nodeId: string): Promise<NodeSyntheticMeshConfig> {
|
||||
const payload = await this.get<{ synthetic_mesh_config: NodeSyntheticMeshConfig }>(
|
||||
`/clusters/${clusterId}/nodes/${nodeId}/mesh/synthetic-config`,
|
||||
@@ -381,6 +579,443 @@ export class AdminApiClient {
|
||||
return payload.synthetic_mesh_config;
|
||||
}
|
||||
|
||||
async listFabricServiceChannelRouteFeedback(
|
||||
clusterId: string,
|
||||
input: { reporterNodeId?: string; routeId?: string; serviceClass?: string; feedbackStatus?: string; includeExpired?: boolean } = {},
|
||||
): Promise<FabricServiceChannelRouteFeedbackObservation[]> {
|
||||
const params = new URLSearchParams({ actor_user_id: this.actorUserId });
|
||||
if (input.reporterNodeId) {
|
||||
params.set("reporter_node_id", input.reporterNodeId);
|
||||
}
|
||||
if (input.routeId) {
|
||||
params.set("route_id", input.routeId);
|
||||
}
|
||||
if (input.serviceClass) {
|
||||
params.set("service_class", input.serviceClass);
|
||||
}
|
||||
if (input.feedbackStatus) {
|
||||
params.set("feedback_status", input.feedbackStatus);
|
||||
}
|
||||
if (input.includeExpired) {
|
||||
params.set("include_expired", "true");
|
||||
}
|
||||
const payload = await this.get<{ route_feedback: FabricServiceChannelRouteFeedbackObservation[] }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/route-feedback?${params.toString()}`,
|
||||
);
|
||||
return payload.route_feedback ?? [];
|
||||
}
|
||||
|
||||
async expireFabricServiceChannelRouteFeedback(
|
||||
clusterId: string,
|
||||
input: { routeId: string; reporterNodeId?: string; serviceClass?: string; reason?: string },
|
||||
): Promise<ExpireFabricServiceChannelRouteFeedbackResult> {
|
||||
const payload = await this.post<{ route_feedback_expire: ExpireFabricServiceChannelRouteFeedbackResult }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/route-feedback/expire`,
|
||||
{
|
||||
actor_user_id: this.actorUserId,
|
||||
route_id: input.routeId,
|
||||
reporter_node_id: input.reporterNodeId || "",
|
||||
service_class: input.serviceClass || "",
|
||||
reason: input.reason || "expired from admin fabric diagnostics",
|
||||
},
|
||||
);
|
||||
return payload.route_feedback_expire;
|
||||
}
|
||||
|
||||
async listFabricServiceChannelRouteRebuildAttempts(
|
||||
clusterId: string,
|
||||
input: {
|
||||
reporterNodeId?: string;
|
||||
routeId?: string;
|
||||
replacementRouteId?: string;
|
||||
serviceClass?: string;
|
||||
rebuildStatus?: string;
|
||||
rebuildRequestId?: string;
|
||||
generation?: string;
|
||||
feedbackSource?: string;
|
||||
feedbackChannelId?: string;
|
||||
feedbackViolationStatus?: string;
|
||||
enrichment?: "summary" | "deep";
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
} = {},
|
||||
): Promise<FabricServiceChannelRouteRebuildAttempt[]> {
|
||||
const params = new URLSearchParams({ actor_user_id: this.actorUserId });
|
||||
if (input.reporterNodeId) {
|
||||
params.set("reporter_node_id", input.reporterNodeId);
|
||||
}
|
||||
if (input.routeId) {
|
||||
params.set("route_id", input.routeId);
|
||||
}
|
||||
if (input.replacementRouteId) {
|
||||
params.set("replacement_route_id", input.replacementRouteId);
|
||||
}
|
||||
if (input.serviceClass) {
|
||||
params.set("service_class", input.serviceClass);
|
||||
}
|
||||
if (input.rebuildStatus) {
|
||||
params.set("rebuild_status", input.rebuildStatus);
|
||||
}
|
||||
if (input.rebuildRequestId) {
|
||||
params.set("rebuild_request_id", input.rebuildRequestId);
|
||||
}
|
||||
if (input.generation) {
|
||||
params.set("generation", input.generation);
|
||||
}
|
||||
if (input.feedbackSource) {
|
||||
params.set("feedback_source", input.feedbackSource);
|
||||
}
|
||||
if (input.feedbackChannelId) {
|
||||
params.set("feedback_channel_id", input.feedbackChannelId);
|
||||
}
|
||||
if (input.feedbackViolationStatus) {
|
||||
params.set("feedback_violation_status", input.feedbackViolationStatus);
|
||||
}
|
||||
if (input.enrichment) {
|
||||
params.set("enrichment", input.enrichment);
|
||||
}
|
||||
if (input.limit) {
|
||||
params.set("limit", String(input.limit));
|
||||
}
|
||||
if (input.offset) {
|
||||
params.set("offset", String(input.offset));
|
||||
}
|
||||
const payload = await this.get<{ rebuild_attempts: FabricServiceChannelRouteRebuildAttempt[] }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/rebuild-attempts?${params.toString()}`,
|
||||
);
|
||||
return payload.rebuild_attempts ?? [];
|
||||
}
|
||||
|
||||
async getFabricServiceChannelRouteRebuildHealthSummary(clusterId: string, input: { limit?: number } = {}): Promise<FabricServiceChannelRouteRebuildHealthSummary> {
|
||||
const params = new URLSearchParams({ actor_user_id: this.actorUserId });
|
||||
if (input.limit) {
|
||||
params.set("limit", String(input.limit));
|
||||
}
|
||||
const payload = await this.get<{ rebuild_health: FabricServiceChannelRouteRebuildHealthSummary }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/rebuild-health?${params.toString()}`,
|
||||
);
|
||||
return payload.rebuild_health;
|
||||
}
|
||||
|
||||
async getFabricServiceChannelReadiness(clusterId: string, input: { limit?: number } = {}): Promise<FabricServiceChannelReadiness> {
|
||||
const params = new URLSearchParams({ actor_user_id: this.actorUserId });
|
||||
if (input.limit) {
|
||||
params.set("limit", String(input.limit));
|
||||
}
|
||||
const payload = await this.get<{ fabric_service_channel_readiness: FabricServiceChannelReadiness }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/readiness?${params.toString()}`,
|
||||
);
|
||||
return payload.fabric_service_channel_readiness;
|
||||
}
|
||||
|
||||
async getFabricServiceChannelSchemaStatus(clusterId: string): Promise<FabricServiceChannelSchemaStatus> {
|
||||
const params = new URLSearchParams({ actor_user_id: this.actorUserId });
|
||||
const payload = await this.get<{ fabric_service_channel_schema_status: FabricServiceChannelSchemaStatus }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/schema-status?${params.toString()}`,
|
||||
);
|
||||
return payload.fabric_service_channel_schema_status;
|
||||
}
|
||||
|
||||
async getFabricServiceChannelRebuildSnapshotMaintenanceHealth(
|
||||
clusterId: string,
|
||||
input: { limit?: number; minAgeSeconds?: number; heartbeatThreshold?: number } = {},
|
||||
): Promise<FabricServiceChannelRebuildSnapshotMaintenanceHealth> {
|
||||
const params = new URLSearchParams({ actor_user_id: this.actorUserId });
|
||||
if (input.limit) {
|
||||
params.set("limit", String(input.limit));
|
||||
}
|
||||
if (input.minAgeSeconds) {
|
||||
params.set("min_age_seconds", String(input.minAgeSeconds));
|
||||
}
|
||||
if (input.heartbeatThreshold) {
|
||||
params.set("heartbeat_threshold", String(input.heartbeatThreshold));
|
||||
}
|
||||
const payload = await this.get<{ rebuild_snapshot_health: FabricServiceChannelRebuildSnapshotMaintenanceHealth }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/rebuild-snapshots/health?${params.toString()}`,
|
||||
);
|
||||
return payload.rebuild_snapshot_health;
|
||||
}
|
||||
|
||||
async warmupFabricServiceChannelRebuildSnapshots(
|
||||
clusterId: string,
|
||||
input: { limit?: number; staleAfterSeconds?: number } = {},
|
||||
): Promise<FabricServiceChannelRebuildSnapshotWarmup> {
|
||||
const payload = await this.post<{ rebuild_snapshot_warmup: FabricServiceChannelRebuildSnapshotWarmup }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/rebuild-snapshots/warmup`,
|
||||
{
|
||||
actor_user_id: this.actorUserId,
|
||||
limit: input.limit || 10,
|
||||
stale_after_seconds: input.staleAfterSeconds || 60,
|
||||
},
|
||||
);
|
||||
return payload.rebuild_snapshot_warmup;
|
||||
}
|
||||
|
||||
async getFabricServiceChannelLeaseMaintenance(
|
||||
clusterId: string,
|
||||
input: { limit?: number; includeExpired?: boolean } = {},
|
||||
): Promise<FabricServiceChannelLeaseMaintenance> {
|
||||
const params = new URLSearchParams({ actor_user_id: this.actorUserId });
|
||||
if (input.limit) {
|
||||
params.set("limit", String(input.limit));
|
||||
}
|
||||
if (input.includeExpired) {
|
||||
params.set("include_expired", "true");
|
||||
}
|
||||
const payload = await this.get<{ fabric_service_channel_lease_maintenance: FabricServiceChannelLeaseMaintenance }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/leases?${params.toString()}`,
|
||||
);
|
||||
return payload.fabric_service_channel_lease_maintenance;
|
||||
}
|
||||
|
||||
async cleanupFabricServiceChannelLeases(clusterId: string, input: { limit?: number } = {}): Promise<FabricServiceChannelLeaseMaintenance> {
|
||||
const payload = await this.post<{ fabric_service_channel_lease_maintenance: FabricServiceChannelLeaseMaintenance }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/leases/cleanup`,
|
||||
{
|
||||
actor_user_id: this.actorUserId,
|
||||
limit: input.limit || 100,
|
||||
},
|
||||
);
|
||||
return payload.fabric_service_channel_lease_maintenance;
|
||||
}
|
||||
|
||||
async getFabricServiceChannelAccessTelemetry(clusterId: string, input: { limit?: number } = {}): Promise<FabricServiceChannelAccessTelemetry> {
|
||||
const params = new URLSearchParams({ actor_user_id: this.actorUserId });
|
||||
if (input.limit) {
|
||||
params.set("limit", String(input.limit));
|
||||
}
|
||||
const payload = await this.get<{ fabric_service_channel_access_telemetry: FabricServiceChannelAccessTelemetry }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/access-telemetry?${params.toString()}`,
|
||||
);
|
||||
return payload.fabric_service_channel_access_telemetry;
|
||||
}
|
||||
|
||||
async listFabricServiceChannelRouteRebuildIncidents(clusterId: string, input: { limit?: number } = {}): Promise<FabricServiceChannelRouteRebuildIncident[]> {
|
||||
const params = new URLSearchParams({ actor_user_id: this.actorUserId });
|
||||
if (input.limit) {
|
||||
params.set("limit", String(input.limit));
|
||||
}
|
||||
const payload = await this.get<{ rebuild_incidents: FabricServiceChannelRouteRebuildIncident[] }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/rebuild-incidents?${params.toString()}`,
|
||||
);
|
||||
return payload.rebuild_incidents ?? [];
|
||||
}
|
||||
|
||||
async getFabricServiceChannelRebuildInvestigationBreadcrumbs(
|
||||
clusterId: string,
|
||||
input: { limit?: number; currentWindowSeconds?: number; historyWindowSeconds?: number } = {},
|
||||
): Promise<FabricServiceChannelRebuildInvestigationBreadcrumbs> {
|
||||
const params = new URLSearchParams({ actor_user_id: this.actorUserId });
|
||||
if (input.limit) {
|
||||
params.set("limit", String(input.limit));
|
||||
}
|
||||
if (input.currentWindowSeconds) {
|
||||
params.set("current_window_seconds", String(input.currentWindowSeconds));
|
||||
}
|
||||
if (input.historyWindowSeconds) {
|
||||
params.set("history_window_seconds", String(input.historyWindowSeconds));
|
||||
}
|
||||
const payload = await this.get<{ rebuild_investigation_breadcrumbs: FabricServiceChannelRebuildInvestigationBreadcrumbs }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/rebuild-investigations/breadcrumbs?${params.toString()}`,
|
||||
);
|
||||
return payload.rebuild_investigation_breadcrumbs;
|
||||
}
|
||||
|
||||
async recordFabricServiceChannelRouteRebuildInvestigation(
|
||||
clusterId: string,
|
||||
input: {
|
||||
reporterNodeId?: string;
|
||||
routeId?: string;
|
||||
serviceClass?: string;
|
||||
generation?: string;
|
||||
guardStatus?: string;
|
||||
incidentId?: string;
|
||||
feedbackSource?: string;
|
||||
feedbackChannelId?: string;
|
||||
feedbackViolationStatus?: string;
|
||||
drilldownSource?: string;
|
||||
reason?: string;
|
||||
},
|
||||
): Promise<void> {
|
||||
await this.post(`/clusters/${clusterId}/fabric/service-channels/rebuild-incidents/investigations`, {
|
||||
actor_user_id: this.actorUserId,
|
||||
reporter_node_id: input.reporterNodeId,
|
||||
route_id: input.routeId,
|
||||
service_class: input.serviceClass || "",
|
||||
generation: input.generation || "",
|
||||
guard_status: input.guardStatus || "",
|
||||
incident_id: input.incidentId || "",
|
||||
feedback_source: input.feedbackSource || "",
|
||||
feedback_channel_id: input.feedbackChannelId || "",
|
||||
feedback_violation_status: input.feedbackViolationStatus || "",
|
||||
drilldown_source: input.drilldownSource || "",
|
||||
reason: input.reason || "operator opened deep rebuild ledger",
|
||||
});
|
||||
}
|
||||
|
||||
async silenceFabricServiceChannelRouteRebuildAlert(
|
||||
clusterId: string,
|
||||
input: {
|
||||
incidentSource?: string;
|
||||
channelId?: string;
|
||||
reporterNodeId: string;
|
||||
routeId: string;
|
||||
guardStatus: string;
|
||||
generation?: string;
|
||||
reason?: string;
|
||||
ttlSeconds?: number;
|
||||
},
|
||||
): Promise<FabricServiceChannelRouteRebuildAlertSilence> {
|
||||
const payload = await this.post<{ rebuild_alert_silence: FabricServiceChannelRouteRebuildAlertSilence }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/rebuild-health/silences`,
|
||||
{
|
||||
actor_user_id: this.actorUserId,
|
||||
incident_source: input.incidentSource || "",
|
||||
channel_id: input.channelId || "",
|
||||
reporter_node_id: input.reporterNodeId,
|
||||
route_id: input.routeId,
|
||||
guard_status: input.guardStatus,
|
||||
generation: input.generation || "",
|
||||
reason: input.reason || "operator acknowledged rebuild alert",
|
||||
ttl_seconds: input.ttlSeconds || 21600,
|
||||
},
|
||||
);
|
||||
return payload.rebuild_alert_silence;
|
||||
}
|
||||
|
||||
async listFabricServiceChannelRouteRebuildAlertSilences(
|
||||
clusterId: string,
|
||||
): Promise<FabricServiceChannelRouteRebuildAlertSilence[]> {
|
||||
const params = new URLSearchParams({ actor_user_id: this.actorUserId });
|
||||
const payload = await this.get<{ rebuild_alert_silences: FabricServiceChannelRouteRebuildAlertSilence[] }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/rebuild-health/silences?${params.toString()}`,
|
||||
);
|
||||
return payload.rebuild_alert_silences ?? [];
|
||||
}
|
||||
|
||||
async unsilenceFabricServiceChannelRouteRebuildAlert(
|
||||
clusterId: string,
|
||||
silenceId: string,
|
||||
reason?: string,
|
||||
): Promise<FabricServiceChannelRouteRebuildAlertSilence> {
|
||||
const payload = await this.delete<{ rebuild_alert_silence: FabricServiceChannelRouteRebuildAlertSilence }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/rebuild-health/silences/${encodeURIComponent(silenceId)}`,
|
||||
{
|
||||
actor_user_id: this.actorUserId,
|
||||
reason: reason || "operator removed rebuild alert silence",
|
||||
},
|
||||
);
|
||||
return payload.rebuild_alert_silence;
|
||||
}
|
||||
|
||||
async getFabricServiceChannelRecoveryPolicy(clusterId: string): Promise<FabricServiceChannelRecoveryPolicy> {
|
||||
const params = new URLSearchParams({ actor_user_id: this.actorUserId });
|
||||
const payload = await this.get<{ fabric_service_channel_recovery_policy: FabricServiceChannelRecoveryPolicy }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/recovery-policy?${params.toString()}`,
|
||||
);
|
||||
return payload.fabric_service_channel_recovery_policy;
|
||||
}
|
||||
|
||||
async updateFabricServiceChannelRecoveryPolicy(
|
||||
clusterId: string,
|
||||
input: UpdateFabricServiceChannelRecoveryPolicyPayload,
|
||||
): Promise<FabricServiceChannelRecoveryPolicy> {
|
||||
const payload = await this.put<{ fabric_service_channel_recovery_policy: FabricServiceChannelRecoveryPolicy }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/recovery-policy`,
|
||||
{
|
||||
actor_user_id: this.actorUserId,
|
||||
hysteresis_penalty: input.hysteresisPenalty,
|
||||
promotion_min_samples: input.promotionMinSamples,
|
||||
demotion_failure_threshold: input.demotionFailureThreshold,
|
||||
demotion_drop_threshold: input.demotionDropThreshold,
|
||||
demotion_slow_threshold: input.demotionSlowThreshold,
|
||||
demotion_rebuild_enabled: input.demotionRebuildEnabled,
|
||||
demotion_fenced_enabled: input.demotionFencedEnabled,
|
||||
},
|
||||
);
|
||||
return payload.fabric_service_channel_recovery_policy;
|
||||
}
|
||||
|
||||
async getFabricServiceChannelAdaptivePolicy(clusterId: string): Promise<FabricServiceChannelAdaptivePolicy> {
|
||||
const params = new URLSearchParams({ actor_user_id: this.actorUserId });
|
||||
const payload = await this.get<{ fabric_service_channel_adaptive_policy: FabricServiceChannelAdaptivePolicy }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/adaptive-policy?${params.toString()}`,
|
||||
);
|
||||
return payload.fabric_service_channel_adaptive_policy;
|
||||
}
|
||||
|
||||
async updateFabricServiceChannelAdaptivePolicy(
|
||||
clusterId: string,
|
||||
input: UpdateFabricServiceChannelAdaptivePolicyPayload,
|
||||
): Promise<FabricServiceChannelAdaptivePolicy> {
|
||||
const payload = await this.put<{ fabric_service_channel_adaptive_policy: FabricServiceChannelAdaptivePolicy }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/adaptive-policy`,
|
||||
{
|
||||
actor_user_id: this.actorUserId,
|
||||
max_parallel_window: input.maxParallelWindow,
|
||||
bulk_pressure_channel_threshold: input.bulkPressureChannelThreshold,
|
||||
queue_pressure_high_watermark: input.queuePressureHighWatermark,
|
||||
queue_pressure_max_in_flight: input.queuePressureMaxInFlight,
|
||||
class_windows: input.classWindows,
|
||||
},
|
||||
);
|
||||
return payload.fabric_service_channel_adaptive_policy;
|
||||
}
|
||||
|
||||
async getFabricServiceChannelPoolPolicy(clusterId: string): Promise<FabricServiceChannelPoolPolicy> {
|
||||
const params = new URLSearchParams({ actor_user_id: this.actorUserId });
|
||||
const payload = await this.get<{ fabric_service_channel_pool_policy: FabricServiceChannelPoolPolicy }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/pool-policy?${params.toString()}`,
|
||||
);
|
||||
return payload.fabric_service_channel_pool_policy;
|
||||
}
|
||||
|
||||
async updateFabricServiceChannelPoolPolicy(
|
||||
clusterId: string,
|
||||
input: UpdateFabricServiceChannelPoolPolicyPayload,
|
||||
): Promise<FabricServiceChannelPoolPolicy> {
|
||||
const payload = await this.put<{ fabric_service_channel_pool_policy: FabricServiceChannelPoolPolicy }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/pool-policy`,
|
||||
{
|
||||
actor_user_id: this.actorUserId,
|
||||
entry_pool_node_ids: input.entryPoolNodeIds,
|
||||
exit_pool_node_ids: input.exitPoolNodeIds,
|
||||
preferred_entry_node_id: input.preferredEntryNodeId,
|
||||
preferred_exit_node_id: input.preferredExitNodeId,
|
||||
selection_strategy: input.selectionStrategy,
|
||||
route_rebuild: input.routeRebuild,
|
||||
entry_failover: input.entryFailover,
|
||||
exit_failover: input.exitFailover,
|
||||
backend_fallback_allowed: input.backendFallbackAllowed,
|
||||
sticky_session: input.stickySession,
|
||||
},
|
||||
);
|
||||
return payload.fabric_service_channel_pool_policy;
|
||||
}
|
||||
|
||||
async getFabricServiceChannelBreadcrumbWindowPolicy(clusterId: string): Promise<FabricServiceChannelBreadcrumbWindowPolicy> {
|
||||
const params = new URLSearchParams({ actor_user_id: this.actorUserId });
|
||||
const payload = await this.get<{ fabric_service_channel_breadcrumb_window_policy: FabricServiceChannelBreadcrumbWindowPolicy }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/breadcrumb-window-policy?${params.toString()}`,
|
||||
);
|
||||
return payload.fabric_service_channel_breadcrumb_window_policy;
|
||||
}
|
||||
|
||||
async updateFabricServiceChannelBreadcrumbWindowPolicy(
|
||||
clusterId: string,
|
||||
input: UpdateFabricServiceChannelBreadcrumbWindowPolicyPayload,
|
||||
): Promise<FabricServiceChannelBreadcrumbWindowPolicy> {
|
||||
const payload = await this.put<{ fabric_service_channel_breadcrumb_window_policy: FabricServiceChannelBreadcrumbWindowPolicy }>(
|
||||
`/clusters/${clusterId}/fabric/service-channels/breadcrumb-window-policy`,
|
||||
{
|
||||
actor_user_id: this.actorUserId,
|
||||
current_window_seconds: input.currentWindowSeconds,
|
||||
history_window_seconds: input.historyWindowSeconds,
|
||||
},
|
||||
);
|
||||
return payload.fabric_service_channel_breadcrumb_window_policy;
|
||||
}
|
||||
|
||||
async listQoSPolicies(clusterId: string): Promise<QoSPolicy[]> {
|
||||
const payload = await this.get<{ qos_policies: QoSPolicy[] }>(`/clusters/${clusterId}/mesh/qos-policies`);
|
||||
return payload.qos_policies ?? [];
|
||||
@@ -519,6 +1154,46 @@ export class AdminApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
async getVPNPacketStats(clusterId: string, vpnConnectionId: string): Promise<VPNPacketStats> {
|
||||
const payload = await this.get<{ vpn_packet_stats: VPNPacketStats }>(
|
||||
`/clusters/${clusterId}/vpn-connections/${vpnConnectionId}/tunnel/stats`,
|
||||
);
|
||||
return payload.vpn_packet_stats ?? {};
|
||||
}
|
||||
|
||||
async getVPNClientDiagnosticStatus(clusterId: string, deviceId: string): Promise<VPNClientDiagnosticStatus | null> {
|
||||
if (!deviceId.trim()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const payload = await this.get<{ vpn_client_diagnostic_status: VPNClientDiagnosticStatus }>(
|
||||
`/clusters/${clusterId}/vpn/client-diagnostics/${encodeURIComponent(deviceId.trim())}/status`,
|
||||
);
|
||||
return payload.vpn_client_diagnostic_status ?? null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async listVPNClientDiagnosticStatuses(clusterId: string): Promise<VPNClientDiagnosticStatus[]> {
|
||||
const payload = await this.get<{ vpn_client_diagnostic_statuses: VPNClientDiagnosticStatus[] }>(
|
||||
`/clusters/${clusterId}/vpn/client-diagnostics`,
|
||||
);
|
||||
return payload.vpn_client_diagnostic_statuses ?? [];
|
||||
}
|
||||
|
||||
async enqueueVPNClientDiagnosticCommand(
|
||||
clusterId: string,
|
||||
deviceId: string,
|
||||
command: Record<string, unknown>,
|
||||
): Promise<VPNClientDiagnosticCommand> {
|
||||
const payload = await this.post<{ vpn_client_diagnostic_command: VPNClientDiagnosticCommand }>(
|
||||
`/clusters/${clusterId}/vpn/client-diagnostics/${encodeURIComponent(deviceId.trim())}/commands`,
|
||||
command,
|
||||
);
|
||||
return payload.vpn_client_diagnostic_command;
|
||||
}
|
||||
|
||||
async expireStaleVPNLeases(clusterId: string): Promise<VPNConnectionLease[]> {
|
||||
const payload = await this.post<{ expired_leases: VPNConnectionLease[] }>(
|
||||
`/clusters/${clusterId}/vpn-connection-leases/expire-stale`,
|
||||
@@ -529,9 +1204,47 @@ export class AdminApiClient {
|
||||
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 listAudit(
|
||||
clusterId: string,
|
||||
input: {
|
||||
eventTypes?: string[];
|
||||
targetTypes?: string[];
|
||||
correlation?: string;
|
||||
limit?: number;
|
||||
} = {},
|
||||
): Promise<AuditEvent[]> {
|
||||
return (await this.listAuditDetailed(clusterId, input)).events;
|
||||
}
|
||||
|
||||
async listAuditDetailed(
|
||||
clusterId: string,
|
||||
input: {
|
||||
eventTypes?: string[];
|
||||
targetTypes?: string[];
|
||||
correlation?: string;
|
||||
limit?: number;
|
||||
} = {},
|
||||
): Promise<{ events: AuditEvent[]; summary?: AuditSummary }> {
|
||||
const params = new URLSearchParams({ limit: String(input.limit || 100) });
|
||||
for (const eventType of input.eventTypes || []) {
|
||||
if (eventType) {
|
||||
params.append("event_type", eventType);
|
||||
}
|
||||
}
|
||||
for (const targetType of input.targetTypes || []) {
|
||||
if (targetType) {
|
||||
params.append("target_type", targetType);
|
||||
}
|
||||
}
|
||||
if (input.correlation) {
|
||||
params.set("correlation", input.correlation);
|
||||
}
|
||||
const payload = await this.get<{ audit_events: AuditEvent[]; audit_summary?: AuditSummary }>(`/clusters/${clusterId}/audit?${params.toString()}`);
|
||||
return { events: payload.audit_events ?? [], summary: payload.audit_summary };
|
||||
}
|
||||
|
||||
clusterEventsURL(clusterId: string): string {
|
||||
return `${this.baseUrl}/clusters/${encodeURIComponent(clusterId)}/events?actor_user_id=${encodeURIComponent(this.actorUserId)}`;
|
||||
}
|
||||
|
||||
async getOrganizationAdminSummary(organizationId: string): Promise<OrganizationAdminSummary> {
|
||||
@@ -541,6 +1254,96 @@ export class AdminApiClient {
|
||||
return payload.admin_summary;
|
||||
}
|
||||
|
||||
async listOrganizations(): Promise<Organization[]> {
|
||||
const payload = await this.request<{ organizations: Organization[] }>(
|
||||
`/organizations?user_id=${encodeURIComponent(this.actorUserId)}`,
|
||||
{ method: "GET" },
|
||||
);
|
||||
return payload.organizations ?? [];
|
||||
}
|
||||
|
||||
async createOrganization(input: CreateOrganizationPayload): Promise<Organization> {
|
||||
const payload = await this.post<{ organization: Organization }>("/organizations/", {
|
||||
actor_user_id: this.actorUserId,
|
||||
slug: input.slug,
|
||||
name: input.name,
|
||||
metadata: input.metadata || {},
|
||||
});
|
||||
return payload.organization;
|
||||
}
|
||||
|
||||
async listUsers(): Promise<UserAccount[]> {
|
||||
const payload = await this.get<{ users: UserAccount[] }>("/users/");
|
||||
return payload.users ?? [];
|
||||
}
|
||||
|
||||
async createUser(input: CreateUserPayload): Promise<UserAccount> {
|
||||
const payload = await this.post<{ user: UserAccount }>("/users/", {
|
||||
actor_user_id: this.actorUserId,
|
||||
email: input.email,
|
||||
password: input.password,
|
||||
platform_role: input.platformRole || "user",
|
||||
});
|
||||
return payload.user;
|
||||
}
|
||||
|
||||
async listOrganizationMemberships(organizationId: string): Promise<OrganizationMembership[]> {
|
||||
const payload = await this.request<{ memberships: OrganizationMembership[] }>(
|
||||
`/organizations/${organizationId}/memberships?user_id=${encodeURIComponent(this.actorUserId)}`,
|
||||
{ method: "GET" },
|
||||
);
|
||||
return payload.memberships ?? [];
|
||||
}
|
||||
|
||||
async addOrganizationMembership(organizationId: string, input: { userId: string; roleId: string }): Promise<OrganizationMembership> {
|
||||
const payload = await this.post<{ membership: OrganizationMembership }>(`/organizations/${organizationId}/memberships`, {
|
||||
actor_user_id: this.actorUserId,
|
||||
user_id: input.userId,
|
||||
role_id: input.roleId,
|
||||
});
|
||||
return payload.membership;
|
||||
}
|
||||
|
||||
async listResources(organizationId?: string): Promise<Resource[]> {
|
||||
const params = new URLSearchParams({ user_id: this.actorUserId });
|
||||
if (organizationId) {
|
||||
params.set("organization_id", organizationId);
|
||||
}
|
||||
const payload = await this.request<{ resources: Resource[] }>(`/resources?${params.toString()}`, { method: "GET" });
|
||||
return payload.resources ?? [];
|
||||
}
|
||||
|
||||
async createResource(input: CreateResourcePayload): Promise<Resource> {
|
||||
const payload = await this.post<{ resource: Resource }>("/resources/", {
|
||||
actor_user_id: this.actorUserId,
|
||||
organization_id: input.organizationId,
|
||||
name: input.name,
|
||||
address: input.address,
|
||||
protocol: input.protocol || "rdp",
|
||||
secret_ref: input.secretRef || null,
|
||||
certificate_verification_mode: input.certificateVerificationMode || "strict",
|
||||
render_quality_profile: input.renderQualityProfile || "balanced",
|
||||
clipboard_mode: input.clipboardMode || "disabled",
|
||||
file_transfer_mode: input.fileTransferMode || "disabled",
|
||||
metadata: input.metadata || {},
|
||||
});
|
||||
return payload.resource;
|
||||
}
|
||||
|
||||
async upsertResourceSecret(resourceId: string, input: UpsertResourceSecretPayload): Promise<void> {
|
||||
await this.put(`/resources/${resourceId}/secret`, {
|
||||
actor_user_id: this.actorUserId,
|
||||
payload: {
|
||||
username: input.username || "",
|
||||
password: input.password || "",
|
||||
domain: input.domain || "",
|
||||
},
|
||||
metadata: {
|
||||
source: "web-admin",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private async get<T>(path: string): Promise<T> {
|
||||
const separator = path.includes("?") ? "&" : "?";
|
||||
return this.request<T>(`${path}${separator}actor_user_id=${encodeURIComponent(this.actorUserId)}`, {
|
||||
@@ -564,6 +1367,14 @@ export class AdminApiClient {
|
||||
});
|
||||
}
|
||||
|
||||
private async delete<T>(path: string, body: unknown): Promise<T> {
|
||||
return this.request<T>(path, {
|
||||
method: "DELETE",
|
||||
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) {
|
||||
|
||||
+478
-11
@@ -149,7 +149,14 @@ button.danger {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.sideRail {
|
||||
.portalShell {
|
||||
display: grid;
|
||||
grid-template-columns: 280px minmax(0, 1fr);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.sideRail,
|
||||
.portalRail {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
height: 100vh;
|
||||
@@ -160,6 +167,11 @@ button.danger {
|
||||
radial-gradient(circle at 20% 20%, rgba(184, 111, 35, 0.36), transparent 16rem);
|
||||
}
|
||||
|
||||
.portalRail button {
|
||||
width: 100%;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.brandMark {
|
||||
display: inline-grid;
|
||||
width: 58px;
|
||||
@@ -183,7 +195,8 @@ button.danger {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.sideRail h1 {
|
||||
.sideRail h1,
|
||||
.portalRail h1 {
|
||||
margin: 0 0 12px;
|
||||
font-size: clamp(2.3rem, 4vw, 4.2rem);
|
||||
line-height: 0.9;
|
||||
@@ -218,9 +231,15 @@ button.danger {
|
||||
padding: 28px 28px 54px;
|
||||
}
|
||||
|
||||
.topBar {
|
||||
.portalWorkspace {
|
||||
width: min(1280px, calc(100vw - 310px));
|
||||
padding: 28px 28px 54px;
|
||||
}
|
||||
|
||||
.topBar,
|
||||
.portalTop {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(260px, 360px) auto minmax(220px, auto);
|
||||
grid-template-columns: minmax(0, 1fr) minmax(260px, 360px) auto minmax(150px, auto) minmax(220px, auto);
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
padding: 28px;
|
||||
@@ -231,6 +250,10 @@ button.danger {
|
||||
backdrop-filter: blur(16px);
|
||||
}
|
||||
|
||||
.portalTop {
|
||||
grid-template-columns: minmax(0, 1fr) minmax(240px, 340px) auto;
|
||||
}
|
||||
|
||||
.clusterPicker {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
@@ -248,6 +271,25 @@ button.danger {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.refreshStatus {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
min-width: 150px;
|
||||
color: var(--muted);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 800;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.refreshStatus strong {
|
||||
color: var(--text);
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
.refreshStatus span {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.profilePanel {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
@@ -441,6 +483,69 @@ summary {
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.cardHead.compact {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.subPanel {
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
padding: 16px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.45);
|
||||
}
|
||||
|
||||
.portalInstallList {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.installTile {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
padding: 16px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 18px;
|
||||
color: var(--ink);
|
||||
background: rgba(255, 255, 255, 0.52);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.installTile:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.installTile strong {
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.installTile span,
|
||||
.installTile small {
|
||||
color: var(--muted);
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.primaryInstall {
|
||||
border-color: rgba(47, 111, 79, 0.35);
|
||||
background: rgba(47, 111, 79, 0.1);
|
||||
}
|
||||
|
||||
.portalRoadmap {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.portalRoadmap span {
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 14px;
|
||||
background: rgba(255, 255, 255, 0.48);
|
||||
color: var(--muted);
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.vpnCard {
|
||||
grid-template-columns: minmax(0, 1.2fr) minmax(220px, 0.8fr) auto;
|
||||
padding: 16px 0;
|
||||
@@ -476,7 +581,7 @@ summary {
|
||||
|
||||
.nodeListRow {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(240px, 1.2fr) auto minmax(110px, 0.55fr) minmax(130px, 0.7fr) auto auto;
|
||||
grid-template-columns: minmax(220px, 1.1fr) auto minmax(220px, 0.9fr) minmax(150px, 0.7fr) auto minmax(180px, 0.8fr) minmax(130px, 0.7fr) auto auto;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px;
|
||||
@@ -496,6 +601,43 @@ summary {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.runtimeBadges {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 5px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.runtimeBadges .pill {
|
||||
padding: 0.24rem 0.52rem;
|
||||
font-size: 0.68rem;
|
||||
}
|
||||
|
||||
.nodeEndpointCell {
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.nodeEndpointCell .pill {
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
padding: 0.28rem 0.58rem;
|
||||
font-size: 0.72rem;
|
||||
}
|
||||
|
||||
.nodeEndpointCell strong,
|
||||
.nodeEndpointCell small {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nodeEndpointCell small {
|
||||
color: var(--muted);
|
||||
font-size: 0.74rem;
|
||||
}
|
||||
|
||||
.functionList {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
@@ -513,6 +655,41 @@ summary {
|
||||
background: rgba(255, 255, 255, 0.42);
|
||||
}
|
||||
|
||||
.functionState {
|
||||
min-width: 96px;
|
||||
display: grid;
|
||||
gap: 2px;
|
||||
padding: 8px 10px;
|
||||
border-radius: 14px;
|
||||
background: rgba(16, 43, 35, 0.06);
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.functionState small {
|
||||
color: var(--muted);
|
||||
font-size: 0.68rem;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.functionState strong {
|
||||
font-size: 0.76rem;
|
||||
}
|
||||
|
||||
.functionState.good {
|
||||
background: rgba(36, 118, 84, 0.14);
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
.functionState.info {
|
||||
background: rgba(41, 80, 111, 0.12);
|
||||
color: var(--blue);
|
||||
}
|
||||
|
||||
.functionState.warn {
|
||||
background: rgba(175, 110, 46, 0.15);
|
||||
color: #8a4f19;
|
||||
}
|
||||
|
||||
.nodePanel {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
@@ -522,6 +699,111 @@ summary {
|
||||
background: rgba(255, 255, 255, 0.42);
|
||||
}
|
||||
|
||||
.nodeDetails {
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.nodeDetailGrid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.nodeMetricGrid {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.summaryChips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.inlineActions {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.stackedText {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.nodeTabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
padding: 8px 0;
|
||||
background: rgba(249, 247, 239, 0.94);
|
||||
}
|
||||
|
||||
.nodeTabs button {
|
||||
min-width: 92px;
|
||||
padding: 0.55rem 0.8rem;
|
||||
}
|
||||
|
||||
.nodeTabs button.active {
|
||||
color: #fffaf0;
|
||||
border-color: transparent;
|
||||
background: #36556c;
|
||||
}
|
||||
|
||||
.rawDetailsGrid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.rawBlock {
|
||||
min-width: 0;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.42);
|
||||
}
|
||||
|
||||
.rawBlock summary {
|
||||
cursor: pointer;
|
||||
padding: 10px 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.rawBlock pre {
|
||||
max-height: 320px;
|
||||
margin: 0;
|
||||
overflow: auto;
|
||||
padding: 0 12px 12px;
|
||||
font-size: 0.78rem;
|
||||
line-height: 1.45;
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.segmented {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.segmented button {
|
||||
min-width: 84px;
|
||||
padding: 0.52rem 0.85rem;
|
||||
}
|
||||
|
||||
.segmented button.active {
|
||||
color: #fffaf0;
|
||||
border-color: transparent;
|
||||
background: #36556c;
|
||||
}
|
||||
|
||||
.stateList {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
@@ -621,11 +903,21 @@ summary {
|
||||
background: rgba(47, 111, 79, 0.12);
|
||||
}
|
||||
|
||||
.pill.info {
|
||||
color: var(--steel);
|
||||
background: rgba(54, 85, 108, 0.1);
|
||||
}
|
||||
|
||||
.pill.bad {
|
||||
color: var(--red);
|
||||
background: rgba(177, 68, 52, 0.12);
|
||||
}
|
||||
|
||||
.pill.warn {
|
||||
color: var(--amber);
|
||||
background: rgba(184, 111, 35, 0.14);
|
||||
}
|
||||
|
||||
.membershipList {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@@ -691,7 +983,8 @@ summary {
|
||||
|
||||
.topologySvg {
|
||||
width: 100%;
|
||||
min-height: 440px;
|
||||
min-height: 520px;
|
||||
max-height: 78vh;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 22px;
|
||||
color: rgba(24, 32, 24, 0.42);
|
||||
@@ -750,12 +1043,25 @@ summary {
|
||||
stroke: var(--amber);
|
||||
}
|
||||
|
||||
.topologyLink.oneWay {
|
||||
color: var(--amber);
|
||||
stroke: var(--amber);
|
||||
stroke-dasharray: 4 7;
|
||||
}
|
||||
|
||||
.topologyLink.bad {
|
||||
color: var(--red);
|
||||
stroke: var(--red);
|
||||
stroke-dasharray: 10 8;
|
||||
}
|
||||
|
||||
.topologyLink.stale {
|
||||
color: var(--red);
|
||||
stroke: var(--red);
|
||||
stroke-dasharray: 2 8;
|
||||
opacity: 0.42;
|
||||
}
|
||||
|
||||
.topologyPlacementLink {
|
||||
stroke: var(--steel);
|
||||
stroke-width: 3;
|
||||
@@ -774,6 +1080,15 @@ summary {
|
||||
stroke: var(--amber);
|
||||
}
|
||||
|
||||
.topologyConfiguredLink {
|
||||
color: var(--steel);
|
||||
stroke: var(--steel);
|
||||
stroke-width: 2.5;
|
||||
stroke-linecap: round;
|
||||
stroke-dasharray: 4 7;
|
||||
opacity: 0.72;
|
||||
}
|
||||
|
||||
.topologyLinkLabel,
|
||||
.topologyNodeName,
|
||||
.topologyNodeMeta,
|
||||
@@ -834,6 +1149,7 @@ summary {
|
||||
}
|
||||
|
||||
.topologyNodeCircle.critical,
|
||||
.topologyNodeCircle.offline,
|
||||
.topologyNodeCircle.failed {
|
||||
stroke: var(--red);
|
||||
}
|
||||
@@ -884,6 +1200,22 @@ summary {
|
||||
border-color: var(--amber);
|
||||
}
|
||||
|
||||
.legendLine.oneWay {
|
||||
border-top-style: dashed;
|
||||
border-color: var(--amber);
|
||||
}
|
||||
|
||||
.legendLine.stale,
|
||||
.legendLine.problem {
|
||||
border-top-style: dashed;
|
||||
border-color: var(--red);
|
||||
}
|
||||
|
||||
.legendLine.configured {
|
||||
border-top-style: dashed;
|
||||
border-color: var(--steel);
|
||||
}
|
||||
|
||||
.serviceTags {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
@@ -944,13 +1276,25 @@ summary {
|
||||
.status.active,
|
||||
.status.approved,
|
||||
.status.healthy,
|
||||
.status.connected,
|
||||
.status.current,
|
||||
.status.running,
|
||||
.status.authoritative {
|
||||
background: var(--green);
|
||||
}
|
||||
|
||||
.status.outdated,
|
||||
.status.no_policy {
|
||||
background: var(--amber);
|
||||
}
|
||||
|
||||
.status.rejected,
|
||||
.status.failed,
|
||||
.status.critical,
|
||||
.status.missing,
|
||||
.status.offline,
|
||||
.status.stale,
|
||||
.status.unreachable,
|
||||
.status.disabled,
|
||||
.status.revoked {
|
||||
background: var(--red);
|
||||
@@ -996,6 +1340,23 @@ th {
|
||||
background: var(--green);
|
||||
}
|
||||
|
||||
.noticePanel.goodPanel {
|
||||
background: var(--green);
|
||||
}
|
||||
|
||||
.noticePanel.warnPanel {
|
||||
background: var(--amber);
|
||||
}
|
||||
|
||||
.noticePanel.badPanel {
|
||||
background: var(--red);
|
||||
}
|
||||
|
||||
.noticePanel .muted,
|
||||
.noticePanel .stateLine span {
|
||||
color: rgba(255, 255, 255, 0.78);
|
||||
}
|
||||
|
||||
.formGrid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(180px, 1fr));
|
||||
@@ -1060,10 +1421,30 @@ th {
|
||||
margin: 18px 0;
|
||||
}
|
||||
|
||||
.inlineForm input {
|
||||
.inlineForm input,
|
||||
.inlineForm select {
|
||||
flex: 1 1 320px;
|
||||
}
|
||||
|
||||
.diagnosticCommandPanel {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
margin: 12px 0 18px;
|
||||
padding: 14px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 18px;
|
||||
background: rgba(255, 255, 255, 0.42);
|
||||
}
|
||||
|
||||
.diagnosticCommandPanel label {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.diagnosticCommandPanel input {
|
||||
min-width: min(520px, 100%);
|
||||
}
|
||||
|
||||
.secretOnce {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
@@ -1087,16 +1468,19 @@ code {
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.consoleShell {
|
||||
.consoleShell,
|
||||
.portalShell {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.sideRail {
|
||||
.sideRail,
|
||||
.portalRail {
|
||||
position: relative;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.workspace {
|
||||
.workspace,
|
||||
.portalWorkspace {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -1105,7 +1489,10 @@ code {
|
||||
.grid.two,
|
||||
.controlBar,
|
||||
.topBar,
|
||||
.portalTop,
|
||||
.loginShell,
|
||||
.nodeDetailGrid,
|
||||
.rawDetailsGrid,
|
||||
.vpnCard {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
@@ -1121,11 +1508,91 @@ code {
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
body {
|
||||
background: #f4f1e7;
|
||||
}
|
||||
|
||||
button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
button {
|
||||
min-height: 46px;
|
||||
}
|
||||
|
||||
.workspace,
|
||||
.sideRail {
|
||||
.portalWorkspace,
|
||||
.sideRail,
|
||||
.portalRail {
|
||||
padding: 18px;
|
||||
}
|
||||
|
||||
.loginShell {
|
||||
align-items: start;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.loginCard {
|
||||
padding: 18px;
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.portalRail {
|
||||
height: auto;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.portalRail .brandMark,
|
||||
.portalRail .sideKicker,
|
||||
.portalRail .sideText {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.portalRail h1 {
|
||||
margin: 0;
|
||||
font-size: 2rem;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.portalTop,
|
||||
.card,
|
||||
.metric,
|
||||
.empty,
|
||||
.errorPanel,
|
||||
.noticePanel {
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.portalTop {
|
||||
padding: 18px;
|
||||
}
|
||||
|
||||
.portalTop h2 {
|
||||
font-size: 2rem;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.portalInstallList,
|
||||
.stack,
|
||||
.grid {
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.installTile {
|
||||
border-radius: 14px;
|
||||
}
|
||||
|
||||
.metric {
|
||||
min-height: 96px;
|
||||
}
|
||||
|
||||
.metric strong {
|
||||
font-size: 2.2rem;
|
||||
}
|
||||
|
||||
.formGrid,
|
||||
.signalStrip,
|
||||
.clusterCardMain,
|
||||
|
||||
@@ -148,6 +148,8 @@ export type CreatedJoinToken = {
|
||||
token: string;
|
||||
};
|
||||
|
||||
export type NodeJoinToken = Omit<CreatedJoinToken, "token">;
|
||||
|
||||
export type RoleAssignment = {
|
||||
id: string;
|
||||
cluster_id: string;
|
||||
@@ -168,9 +170,58 @@ export type AuditEvent = {
|
||||
target_type: string;
|
||||
target_id?: string | null;
|
||||
payload: Record<string, unknown>;
|
||||
correlation_hints?: AuditCorrelationHints;
|
||||
created_at: string;
|
||||
};
|
||||
|
||||
export type AuditCorrelationHints = {
|
||||
scope?: string;
|
||||
current_diagnostic_status?: string;
|
||||
breadcrumb_status?: string;
|
||||
breadcrumb_age_seconds?: number;
|
||||
breadcrumb_current_window_seconds?: number;
|
||||
breadcrumb_history_window_seconds?: number;
|
||||
feedback_breakdown?: FabricServiceChannelRouteRebuildFeedbackHealthBreakdown;
|
||||
rebuild_incident?: FabricServiceChannelRouteRebuildIncident;
|
||||
recommended_action?: string;
|
||||
};
|
||||
|
||||
export type AuditSummary = {
|
||||
total_count: number;
|
||||
counts_by_event_type?: Record<string, number>;
|
||||
counts_by_target_type?: Record<string, number>;
|
||||
counts_by_current_diagnostic_status?: Record<string, number>;
|
||||
counts_by_feedback_source?: Record<string, number>;
|
||||
counts_by_feedback_violation_status?: Record<string, number>;
|
||||
counts_by_breadcrumb_status?: Record<string, number>;
|
||||
correlated_count?: number;
|
||||
not_visible_count?: number;
|
||||
latest_at?: string;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelRebuildInvestigationBreadcrumbs = {
|
||||
cluster_id: string;
|
||||
events: AuditEvent[];
|
||||
summary: AuditSummary;
|
||||
current_window_seconds?: number;
|
||||
history_window_seconds?: number;
|
||||
current_count?: number;
|
||||
stale_count?: number;
|
||||
expired_count?: number;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelBreadcrumbWindowPolicy = {
|
||||
schema_version: string;
|
||||
fingerprint?: string;
|
||||
current_window_seconds: number;
|
||||
history_window_seconds: number;
|
||||
source: string;
|
||||
updated_by_user_id?: string | null;
|
||||
updated_at?: string;
|
||||
control_plane_only: boolean;
|
||||
production_forwarding: boolean;
|
||||
};
|
||||
|
||||
export type WorkloadStatus = {
|
||||
id: string;
|
||||
cluster_id: string;
|
||||
@@ -239,6 +290,90 @@ export type NodeTelemetryObservation = {
|
||||
observed_at: string;
|
||||
};
|
||||
|
||||
export type ReleaseArtifact = {
|
||||
id: string;
|
||||
release_id: string;
|
||||
cluster_id: string;
|
||||
product: string;
|
||||
version: string;
|
||||
os: string;
|
||||
arch: string;
|
||||
install_type: string;
|
||||
kind: string;
|
||||
url: string;
|
||||
sha256: string;
|
||||
size_bytes: number;
|
||||
signature?: string | null;
|
||||
metadata?: Record<string, unknown>;
|
||||
created_at: string;
|
||||
};
|
||||
|
||||
export type ReleaseVersion = {
|
||||
id: string;
|
||||
cluster_id: string;
|
||||
product: string;
|
||||
version: string;
|
||||
channel: string;
|
||||
status: string;
|
||||
compatibility?: Record<string, unknown>;
|
||||
changelog?: string | null;
|
||||
created_by_user_id?: string | null;
|
||||
created_at: string;
|
||||
artifacts?: ReleaseArtifact[];
|
||||
authority_payload?: Record<string, unknown>;
|
||||
authority_signature?: ClusterSignature;
|
||||
};
|
||||
|
||||
export type NodeUpdatePlan = {
|
||||
schema_version: string;
|
||||
cluster_id: string;
|
||||
node_id: string;
|
||||
product: string;
|
||||
current_version?: string;
|
||||
action: string;
|
||||
reason: string;
|
||||
target_version?: string;
|
||||
channel?: string;
|
||||
strategy?: string;
|
||||
rollback_allowed: boolean;
|
||||
health_window_seconds?: number;
|
||||
artifact?: ReleaseArtifact;
|
||||
authority_payload?: Record<string, unknown>;
|
||||
authority_signature?: ClusterSignature;
|
||||
production_forwarding: boolean;
|
||||
};
|
||||
|
||||
export type NodeUpdatePolicy = {
|
||||
id: string;
|
||||
cluster_id: string;
|
||||
node_id: string;
|
||||
product: string;
|
||||
channel: string;
|
||||
target_version?: string | null;
|
||||
strategy: string;
|
||||
enabled: boolean;
|
||||
rollback_allowed: boolean;
|
||||
health_window_seconds: number;
|
||||
updated_by_user_id?: string | null;
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
export type NodeUpdateStatus = {
|
||||
id: string;
|
||||
cluster_id: string;
|
||||
node_id: string;
|
||||
product: string;
|
||||
current_version?: string;
|
||||
target_version?: string;
|
||||
phase: string;
|
||||
status: string;
|
||||
attempt_id?: string;
|
||||
error_message?: string | null;
|
||||
rollback_version?: string | null;
|
||||
payload?: Record<string, unknown>;
|
||||
observed_at: string;
|
||||
};
|
||||
|
||||
export type MeshLink = {
|
||||
id: string;
|
||||
cluster_id: string;
|
||||
@@ -251,6 +386,23 @@ export type MeshLink = {
|
||||
observed_at: string;
|
||||
};
|
||||
|
||||
export type MeshRouteIntent = {
|
||||
id: string;
|
||||
cluster_id: string;
|
||||
source_selector: Record<string, unknown>;
|
||||
destination_selector: Record<string, unknown>;
|
||||
service_class: string;
|
||||
priority: number;
|
||||
status: string;
|
||||
lifecycle_status?: string;
|
||||
is_expired?: boolean;
|
||||
policy_expires_at?: string | null;
|
||||
policy: Record<string, unknown>;
|
||||
created_by_user_id?: string | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
export type PeerEndpointCandidate = {
|
||||
endpoint_id: string;
|
||||
node_id: string;
|
||||
@@ -330,6 +482,19 @@ export type RendezvousRelayPolicyReport = {
|
||||
export type RoutePathDecision = {
|
||||
decision_id: string;
|
||||
route_id: string;
|
||||
replacement_route_id?: string;
|
||||
rebuild_request_id?: string;
|
||||
rebuild_status?: string;
|
||||
rebuild_reason?: string;
|
||||
rebuild_attempt?: number;
|
||||
feedback_observation_id?: string;
|
||||
feedback_source?: string;
|
||||
feedback_observed_at?: string;
|
||||
feedback_expires_at?: string;
|
||||
feedback_channel_id?: string;
|
||||
feedback_resource_id?: string;
|
||||
feedback_violation_status?: string;
|
||||
feedback_violation_reason?: string;
|
||||
cluster_id: string;
|
||||
local_node_id: string;
|
||||
source_node_id: string;
|
||||
@@ -357,8 +522,15 @@ export type RoutePathDecisionReport = {
|
||||
schema_version: string;
|
||||
decision_mode: string;
|
||||
generation: string;
|
||||
recovery_policy?: FabricServiceChannelRecoveryPolicy;
|
||||
decision_count: number;
|
||||
replacement_decision_count: number;
|
||||
degraded_decision_count?: number;
|
||||
rebuild_request_count?: number;
|
||||
rebuild_applied_count?: number;
|
||||
recovery_hysteresis_count?: number;
|
||||
recovery_promoted_count?: number;
|
||||
recovery_demoted_count?: number;
|
||||
control_plane_only: boolean;
|
||||
production_forwarding: boolean;
|
||||
decisions?: RoutePathDecision[];
|
||||
@@ -379,6 +551,620 @@ export type SyntheticMeshRoute = {
|
||||
peer_directory_version?: string;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelRouteFeedbackObservation = {
|
||||
id?: string;
|
||||
cluster_id: string;
|
||||
reporter_node_id: string;
|
||||
route_id: string;
|
||||
service_class: string;
|
||||
feedback_status: string;
|
||||
score_adjustment: number;
|
||||
reasons?: string[];
|
||||
last_error?: string;
|
||||
consecutive_failures?: number;
|
||||
stall_count?: number;
|
||||
last_send_duration_ms?: number;
|
||||
payload?: Record<string, unknown>;
|
||||
observed_at: string;
|
||||
expires_at: string;
|
||||
retry_cooldown_until?: string;
|
||||
recovery_state?: string;
|
||||
recovery_hysteresis_active?: boolean;
|
||||
recovery_hysteresis_penalty?: number;
|
||||
recovery_promoted?: boolean;
|
||||
recovery_demoted?: boolean;
|
||||
recovery_reason?: string;
|
||||
observed_policy_fingerprint?: string;
|
||||
effective_policy_fingerprint?: string;
|
||||
observed_route_generation?: string;
|
||||
effective_route_generation?: string;
|
||||
provenance_missing?: boolean;
|
||||
stale_policy?: boolean;
|
||||
stale_generation?: boolean;
|
||||
stale_reason?: string;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelRouteRebuildAttempt = {
|
||||
id: string;
|
||||
cluster_id: string;
|
||||
reporter_node_id: string;
|
||||
service_class: string;
|
||||
route_id: string;
|
||||
replacement_route_id?: string;
|
||||
rebuild_request_id: string;
|
||||
rebuild_status: string;
|
||||
rebuild_reason?: string;
|
||||
rebuild_attempt?: number;
|
||||
decision_source: string;
|
||||
outcome: string;
|
||||
generation?: string;
|
||||
policy_fingerprint?: string;
|
||||
observed_policy_fingerprint?: string;
|
||||
observed_route_generation?: string;
|
||||
effective_route_generation?: string;
|
||||
feedback_status?: string;
|
||||
feedback_observation_id?: string;
|
||||
feedback_source?: string;
|
||||
feedback_observed_at?: string;
|
||||
feedback_expires_at?: string;
|
||||
feedback_channel_id?: string;
|
||||
feedback_resource_id?: string;
|
||||
feedback_violation_status?: string;
|
||||
feedback_violation_reason?: string;
|
||||
feedback_score_adjustment?: number;
|
||||
feedback_effective_score_adjustment?: number;
|
||||
feedback_reasons?: string[];
|
||||
last_error?: string;
|
||||
consecutive_failures?: number;
|
||||
stall_count?: number;
|
||||
last_send_duration_ms?: number;
|
||||
quality_window_sample_count?: number;
|
||||
quality_window_failure_count?: number;
|
||||
quality_window_drop_count?: number;
|
||||
quality_window_slow_count?: number;
|
||||
old_hops?: string[];
|
||||
replacement_hops?: string[];
|
||||
node_transition_status?: string;
|
||||
node_transition_generation?: string;
|
||||
node_transition_observed_at?: string;
|
||||
node_transition_matched?: boolean;
|
||||
node_route_generation_status?: string;
|
||||
node_route_generation_applied_at?: string;
|
||||
node_route_generation_withdrawn_at?: string;
|
||||
node_route_generation_matched?: boolean;
|
||||
post_rebuild_selected_route_id?: string;
|
||||
post_rebuild_send_packets?: number;
|
||||
post_rebuild_send_failures?: number;
|
||||
post_rebuild_send_flow_packets?: number;
|
||||
post_rebuild_send_flow_dropped?: number;
|
||||
guard_status?: string;
|
||||
guard_severity?: string;
|
||||
guard_reason?: string;
|
||||
guard_age_seconds?: number;
|
||||
guard_transition_deadline_seconds?: number;
|
||||
guard_traffic_deadline_seconds?: number;
|
||||
alert_silenced?: boolean;
|
||||
alert_silence_id?: string;
|
||||
alert_silence_reason?: string;
|
||||
alert_silenced_until?: string;
|
||||
alert_resurfaced?: boolean;
|
||||
alert_resurfaced_from_silence_id?: string;
|
||||
alert_resurfaced_previous_generation?: string;
|
||||
alert_resurfaced_previous_until?: string;
|
||||
timeline?: FabricServiceChannelRouteRebuildTimelineEvent[];
|
||||
payload?: Record<string, unknown>;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelRouteRebuildTimelineEvent = {
|
||||
stage: string;
|
||||
status: string;
|
||||
at?: string;
|
||||
route_id?: string;
|
||||
generation?: string;
|
||||
payload?: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelRouteRebuildHealthSummary = {
|
||||
cluster_id: string;
|
||||
observed_at: string;
|
||||
window_limit: number;
|
||||
total_attempts: number;
|
||||
good_count: number;
|
||||
warn_count: number;
|
||||
bad_count: number;
|
||||
unknown_count: number;
|
||||
active_bad_count: number;
|
||||
active_warn_count: number;
|
||||
silenced_count: number;
|
||||
resurfaced_count: number;
|
||||
applied_count: number;
|
||||
pending_count: number;
|
||||
access_route_decision_count?: number;
|
||||
access_replacement_count?: number;
|
||||
access_applied_count?: number;
|
||||
access_recovery_count?: number;
|
||||
access_no_safe_count?: number;
|
||||
counts_by_guard_status?: Record<string, number>;
|
||||
counts_by_guard_severity?: Record<string, number>;
|
||||
feedback_breakdowns?: FabricServiceChannelRouteRebuildFeedbackHealthBreakdown[];
|
||||
affected_reporter_node_ids?: string[];
|
||||
affected_route_ids?: string[];
|
||||
most_recent_bad_attempts?: FabricServiceChannelRouteRebuildAttempt[];
|
||||
resurfaced_attempts?: FabricServiceChannelRouteRebuildAttempt[];
|
||||
recommended_operator_action?: string;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelRouteRebuildFeedbackHealthBreakdown = {
|
||||
feedback_source?: string;
|
||||
feedback_channel_id?: string;
|
||||
feedback_violation_status?: string;
|
||||
total_count: number;
|
||||
good_count?: number;
|
||||
warn_count?: number;
|
||||
bad_count?: number;
|
||||
unknown_count?: number;
|
||||
active_warn_count?: number;
|
||||
active_bad_count?: number;
|
||||
silenced_count?: number;
|
||||
latest_observed_at?: string;
|
||||
affected_reporter_node_ids?: string[];
|
||||
affected_route_ids?: string[];
|
||||
};
|
||||
|
||||
export type FabricServiceChannelReadiness = {
|
||||
cluster_id: string;
|
||||
observed_at: string;
|
||||
status: string;
|
||||
reason: string;
|
||||
active_alert_count: number;
|
||||
active_bad_count: number;
|
||||
active_warn_count: number;
|
||||
resurfaced_count: number;
|
||||
silenced_count: number;
|
||||
missing_transition_count: number;
|
||||
missing_route_generation_count: number;
|
||||
missing_post_rebuild_traffic_count: number;
|
||||
unexpected_route_count: number;
|
||||
post_rebuild_degraded_count: number;
|
||||
blocking_reasons?: string[];
|
||||
degraded_reasons?: string[];
|
||||
recommended_operator_action?: string;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelSchemaStatus = {
|
||||
cluster_id: string;
|
||||
observed_at: string;
|
||||
status: string;
|
||||
reason: string;
|
||||
required_migration: string;
|
||||
required_check_count: number;
|
||||
passed_check_count: number;
|
||||
missing_check_count: number;
|
||||
required_checks: FabricServiceChannelSchemaCheck[];
|
||||
missing_checks?: FabricServiceChannelSchemaCheck[];
|
||||
recommended_operator_action?: string;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelSchemaCheck = {
|
||||
check_id: string;
|
||||
relation_name: string;
|
||||
column_name?: string;
|
||||
status: string;
|
||||
required_by: string;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelRebuildSnapshotWarmup = {
|
||||
cluster_id: string;
|
||||
observed_at: string;
|
||||
window_limit: number;
|
||||
stale_after_seconds: number;
|
||||
scanned_count: number;
|
||||
warmed_count: number;
|
||||
already_fresh_count: number;
|
||||
missing_snapshot_count: number;
|
||||
stale_snapshot_count: number;
|
||||
deferred_stale_count: number;
|
||||
error_count: number;
|
||||
status: string;
|
||||
reason: string;
|
||||
recommended_operator_action?: string;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelRebuildSnapshotMaintenanceHealth = {
|
||||
cluster_id: string;
|
||||
observed_at: string;
|
||||
status: string;
|
||||
reason: string;
|
||||
window_limit: number;
|
||||
min_age_seconds: number;
|
||||
heartbeat_threshold: number;
|
||||
recent_attempt_count: number;
|
||||
valid_snapshot_count: number;
|
||||
missing_snapshot_count: number;
|
||||
overdue_missing_snapshot_count: number;
|
||||
auto_warmup_event_count: number;
|
||||
auto_warmup_warmed_count: number;
|
||||
auto_warmup_already_fresh_count: number;
|
||||
auto_warmup_error_count: number;
|
||||
latest_auto_warmup_at?: string;
|
||||
nodes?: FabricServiceChannelRebuildSnapshotNodeHealth[];
|
||||
overdue_missing_snapshot_attempts?: FabricServiceChannelRouteRebuildAttempt[];
|
||||
recommended_operator_action?: string;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelRebuildSnapshotNodeHealth = {
|
||||
node_id: string;
|
||||
recent_attempt_count: number;
|
||||
valid_snapshot_count: number;
|
||||
missing_snapshot_count: number;
|
||||
overdue_missing_snapshot_count: number;
|
||||
heartbeat_after_attempt_count: number;
|
||||
last_heartbeat_at?: string;
|
||||
auto_warmup_event_count: number;
|
||||
auto_warmup_warmed_count: number;
|
||||
auto_warmup_error_count: number;
|
||||
latest_auto_warmup_at?: string;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelLeaseSummary = {
|
||||
cluster_id: string;
|
||||
channel_id: string;
|
||||
resource_id?: string;
|
||||
service_class: string;
|
||||
status: string;
|
||||
selected_entry_node_id?: string;
|
||||
selected_exit_node_id?: string;
|
||||
allowed_channels?: string[];
|
||||
primary_route_id?: string;
|
||||
primary_route_status?: string;
|
||||
data_plane?: FabricServiceChannelDataPlaneContract;
|
||||
force_backend_fallback: boolean;
|
||||
expired: boolean;
|
||||
issued_at: string;
|
||||
expires_at: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelLeaseMaintenance = {
|
||||
schema_version: string;
|
||||
cluster_id: string;
|
||||
status: string;
|
||||
reason: string;
|
||||
observed_at: string;
|
||||
active_count: number;
|
||||
expired_count: number;
|
||||
scanned_count: number;
|
||||
deleted_expired_count?: number;
|
||||
window_limit: number;
|
||||
recommended_operator_action?: string;
|
||||
leases?: FabricServiceChannelLeaseSummary[];
|
||||
};
|
||||
|
||||
export type FabricServiceChannelDataPlaneContract = {
|
||||
schema_version: string;
|
||||
mode: string;
|
||||
control_plane_transport: string;
|
||||
working_data_transport: string;
|
||||
steady_state_transport: string;
|
||||
backend_relay_policy: string;
|
||||
production_forwarding_required: boolean;
|
||||
service_neutral: boolean;
|
||||
protocol_agnostic: boolean;
|
||||
logical_flow_mode: string;
|
||||
required_flow_isolation_classes?: string[];
|
||||
route_selection_strategy: string;
|
||||
entry_failover_mode: string;
|
||||
exit_failover_mode: string;
|
||||
route_rebuild_mode: string;
|
||||
failure_detection_source: string;
|
||||
degraded_fallback_visibility: string;
|
||||
stable_contract_for_service_class?: string;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelAccessTelemetryNode = {
|
||||
node_id: string;
|
||||
node_name?: string;
|
||||
observed_at: string;
|
||||
total_accepted: number;
|
||||
signed_accepted: number;
|
||||
introspection_accepted: number;
|
||||
legacy_unsigned_accepted: number;
|
||||
backend_fallback_count: number;
|
||||
backend_fallback_blocked_count?: number;
|
||||
fabric_route_send_failure_count?: number;
|
||||
data_plane_contract_count?: number;
|
||||
last_data_plane_mode?: string;
|
||||
last_working_data_transport?: string;
|
||||
last_steady_state_transport?: string;
|
||||
last_backend_relay_policy?: string;
|
||||
last_logical_flow_mode?: string;
|
||||
last_data_plane_violation_status?: string;
|
||||
last_data_plane_violation_reason?: string;
|
||||
traffic_class_counts?: Record<string, number>;
|
||||
flow_channel_count?: number;
|
||||
flow_dropped?: number;
|
||||
flow_high_watermark?: number;
|
||||
flow_max_in_flight?: number;
|
||||
flow_health_status?: string;
|
||||
flow_health_reason?: string;
|
||||
recommended_parallel_windows?: Record<string, number>;
|
||||
adaptive_backpressure_active?: boolean;
|
||||
adaptive_backpressure_reason?: string;
|
||||
adaptive_policy_fingerprint?: string;
|
||||
last_accepted_at?: string;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelAccessTelemetryChannel = {
|
||||
channel_id: string;
|
||||
resource_id?: string;
|
||||
service_class: string;
|
||||
status: string;
|
||||
selected_entry_node_id?: string;
|
||||
selected_exit_node_id?: string;
|
||||
primary_route_id?: string;
|
||||
primary_route_status?: string;
|
||||
force_backend_fallback: boolean;
|
||||
entry_node_total_accepted: number;
|
||||
entry_node_introspection_accepted: number;
|
||||
entry_node_backend_fallback_count: number;
|
||||
entry_node_backend_fallback_blocked_count?: number;
|
||||
entry_node_fabric_route_send_failure_count?: number;
|
||||
entry_node_data_plane_contract_count?: number;
|
||||
entry_node_last_data_plane_mode?: string;
|
||||
entry_node_last_working_data_transport?: string;
|
||||
entry_node_last_steady_state_transport?: string;
|
||||
entry_node_last_backend_relay_policy?: string;
|
||||
entry_node_last_logical_flow_mode?: string;
|
||||
entry_node_last_data_plane_violation_status?: string;
|
||||
entry_node_last_data_plane_violation_reason?: string;
|
||||
entry_node_traffic_class_counts?: Record<string, number>;
|
||||
entry_node_flow_channel_count?: number;
|
||||
entry_node_flow_dropped?: number;
|
||||
entry_node_flow_high_watermark?: number;
|
||||
entry_node_flow_max_in_flight?: number;
|
||||
entry_node_flow_health_status?: string;
|
||||
entry_node_flow_health_reason?: string;
|
||||
entry_node_recommended_parallel_windows?: Record<string, number>;
|
||||
entry_node_adaptive_backpressure_active?: boolean;
|
||||
entry_node_adaptive_backpressure_reason?: string;
|
||||
entry_node_adaptive_policy_fingerprint?: string;
|
||||
route_feedback_status?: string;
|
||||
route_feedback_observed_at?: string;
|
||||
route_feedback_score_adjustment?: number;
|
||||
route_feedback_effective_score_adjustment?: number;
|
||||
route_feedback_reasons?: string[];
|
||||
route_quality_window_sample_count?: number;
|
||||
route_quality_window_failure_count?: number;
|
||||
route_quality_window_drop_count?: number;
|
||||
route_quality_window_slow_count?: number;
|
||||
last_send_duration_ms?: number;
|
||||
remediation_action?: string;
|
||||
remediation_reason?: string;
|
||||
remediation_route_id?: string;
|
||||
remediation_route_status?: string;
|
||||
remediation_guard_status?: string;
|
||||
remediation_guard_reason?: string;
|
||||
remediation_execution_status?: string;
|
||||
remediation_execution_reason?: string;
|
||||
remediation_execution_generation?: string;
|
||||
remediation_execution_observed_at?: string;
|
||||
route_decision_source?: string;
|
||||
route_decision_route_id?: string;
|
||||
route_decision_replacement_route_id?: string;
|
||||
route_decision_rebuild_status?: string;
|
||||
route_decision_rebuild_reason?: string;
|
||||
route_decision_generation?: string;
|
||||
route_decision_score_reasons?: string[];
|
||||
pool_policy_fingerprint?: string;
|
||||
data_plane?: FabricServiceChannelDataPlaneContract;
|
||||
remediation_command?: {
|
||||
schema_version: string;
|
||||
command_id: string;
|
||||
action: string;
|
||||
cluster_id: string;
|
||||
channel_id: string;
|
||||
resource_id?: string;
|
||||
service_class: string;
|
||||
entry_node_id?: string;
|
||||
exit_node_id?: string;
|
||||
primary_route_id?: string;
|
||||
replacement_route_id?: string;
|
||||
replacement_route_status?: string;
|
||||
pool_policy_fingerprint?: string;
|
||||
guard_status?: string;
|
||||
guard_reason?: string;
|
||||
execution_status?: string;
|
||||
execution_reason?: string;
|
||||
execution_generation?: string;
|
||||
execution_observed_at?: string;
|
||||
reason?: string;
|
||||
operator_action?: string;
|
||||
issued_at: string;
|
||||
expires_at: string;
|
||||
};
|
||||
recommended_operator_action?: string;
|
||||
expires_at: string;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelAccessTelemetry = {
|
||||
schema_version: string;
|
||||
cluster_id: string;
|
||||
status: string;
|
||||
reason: string;
|
||||
observed_at: string;
|
||||
node_count: number;
|
||||
reporting_node_count: number;
|
||||
total_accepted: number;
|
||||
signed_accepted: number;
|
||||
introspection_accepted: number;
|
||||
legacy_unsigned_accepted: number;
|
||||
backend_fallback_count: number;
|
||||
backend_fallback_blocked_count?: number;
|
||||
fabric_route_send_failure_count?: number;
|
||||
data_plane_contract_count?: number;
|
||||
last_data_plane_mode?: string;
|
||||
last_working_data_transport?: string;
|
||||
last_steady_state_transport?: string;
|
||||
last_backend_relay_policy?: string;
|
||||
last_logical_flow_mode?: string;
|
||||
last_data_plane_violation_status?: string;
|
||||
last_data_plane_violation_reason?: string;
|
||||
active_channel_count: number;
|
||||
degraded_fallback_channel_count: number;
|
||||
correlated_route_count: number;
|
||||
degraded_route_count: number;
|
||||
route_decision_channel_count?: number;
|
||||
replacement_decision_count?: number;
|
||||
applied_rebuild_decision_count?: number;
|
||||
recovery_decision_count?: number;
|
||||
no_safe_recovery_decision_count?: number;
|
||||
traffic_class_counts?: Record<string, number>;
|
||||
flow_channel_count?: number;
|
||||
flow_dropped?: number;
|
||||
flow_high_watermark?: number;
|
||||
flow_max_in_flight?: number;
|
||||
flow_health_status?: string;
|
||||
flow_health_reason?: string;
|
||||
recommended_parallel_windows?: Record<string, number>;
|
||||
adaptive_backpressure_active?: boolean;
|
||||
adaptive_backpressure_reason?: string;
|
||||
adaptive_policy_fingerprint?: string;
|
||||
latest_accepted_at?: string;
|
||||
nodes?: FabricServiceChannelAccessTelemetryNode[];
|
||||
active_channels?: FabricServiceChannelAccessTelemetryChannel[];
|
||||
recommended_operator_action?: string;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelRouteRebuildIncident = {
|
||||
fingerprint: string;
|
||||
cluster_id: string;
|
||||
reporter_node_id: string;
|
||||
route_id: string;
|
||||
service_class: string;
|
||||
generation?: string;
|
||||
incident_source?: string;
|
||||
channel_id?: string;
|
||||
guard_status: string;
|
||||
guard_severity: string;
|
||||
guard_reason?: string;
|
||||
attempt_count: number;
|
||||
first_seen_at: string;
|
||||
last_seen_at: string;
|
||||
latest_replacement_route_id?: string;
|
||||
latest_rebuild_status?: string;
|
||||
latest_outcome?: string;
|
||||
alert_silenced?: boolean;
|
||||
alert_resurfaced?: boolean;
|
||||
alert_resurfaced_from_silence_id?: string;
|
||||
alert_resurfaced_cause?: string;
|
||||
alert_resurfaced_previous_route_id?: string;
|
||||
alert_resurfaced_previous_channel_id?: string;
|
||||
alert_resurfaced_previous_generation?: string;
|
||||
alert_resurfaced_previous_until?: string;
|
||||
recommended_operator_action?: string;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelRouteRebuildAlertSilence = {
|
||||
id: string;
|
||||
cluster_id: string;
|
||||
incident_source?: string;
|
||||
channel_id?: string;
|
||||
reporter_node_id: string;
|
||||
route_id: string;
|
||||
display_route_id?: string;
|
||||
guard_status: string;
|
||||
generation?: string;
|
||||
reason?: string;
|
||||
created_by_user_id?: string | null;
|
||||
created_at: string;
|
||||
expires_at: string;
|
||||
payload?: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export type ExpireFabricServiceChannelRouteFeedbackResult = {
|
||||
cluster_id: string;
|
||||
reporter_node_id?: string;
|
||||
route_id: string;
|
||||
service_class?: string;
|
||||
expired_count: number;
|
||||
expired_at: string;
|
||||
cooldown_until: string;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelRouteFeedbackReport = {
|
||||
schema_version: string;
|
||||
generated_at: string;
|
||||
feedback_max_age_seconds: number;
|
||||
recovery_policy?: FabricServiceChannelRecoveryPolicy;
|
||||
observation_count: number;
|
||||
fenced_route_count: number;
|
||||
degraded_route_count: number;
|
||||
healthy_route_count: number;
|
||||
recovered_route_count?: number;
|
||||
recovery_hysteresis_count?: number;
|
||||
recovery_promoted_count?: number;
|
||||
recovery_demoted_count?: number;
|
||||
missing_provenance_count?: number;
|
||||
stale_policy_count?: number;
|
||||
stale_generation_count?: number;
|
||||
observations?: FabricServiceChannelRouteFeedbackObservation[];
|
||||
};
|
||||
|
||||
export type FabricServiceChannelRecoveryPolicy = {
|
||||
schema_version: string;
|
||||
fingerprint?: string;
|
||||
hysteresis_penalty: number;
|
||||
promotion_min_samples: number;
|
||||
demotion_failure_threshold: number;
|
||||
demotion_drop_threshold: number;
|
||||
demotion_slow_threshold: number;
|
||||
demotion_rebuild_enabled: boolean;
|
||||
demotion_fenced_enabled: boolean;
|
||||
source: string;
|
||||
updated_by_user_id?: string | null;
|
||||
updated_at?: string;
|
||||
control_plane_only: boolean;
|
||||
production_forwarding: boolean;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelAdaptivePolicy = {
|
||||
schema_version: string;
|
||||
fingerprint?: string;
|
||||
max_parallel_window: number;
|
||||
bulk_pressure_channel_threshold: number;
|
||||
queue_pressure_high_watermark: number;
|
||||
queue_pressure_max_in_flight: number;
|
||||
class_windows: Record<string, number>;
|
||||
source: string;
|
||||
updated_by_user_id?: string | null;
|
||||
updated_at?: string;
|
||||
control_plane_only: boolean;
|
||||
production_forwarding: boolean;
|
||||
};
|
||||
|
||||
export type FabricServiceChannelPoolPolicy = {
|
||||
schema_version: string;
|
||||
fingerprint?: string;
|
||||
entry_pool_node_ids?: string[];
|
||||
exit_pool_node_ids?: string[];
|
||||
preferred_entry_node_id?: string;
|
||||
preferred_exit_node_id?: string;
|
||||
selection_strategy: string;
|
||||
route_rebuild: string;
|
||||
entry_failover: string;
|
||||
exit_failover: string;
|
||||
backend_fallback_allowed: boolean;
|
||||
sticky_session: boolean;
|
||||
source: string;
|
||||
updated_by_user_id?: string | null;
|
||||
updated_at?: string;
|
||||
control_plane_only: boolean;
|
||||
production_forwarding: boolean;
|
||||
};
|
||||
|
||||
export type NodeSyntheticMeshConfig = {
|
||||
enabled: boolean;
|
||||
schema_version: string;
|
||||
@@ -398,6 +1184,28 @@ export type NodeSyntheticMeshConfig = {
|
||||
rendezvous_leases?: PeerRendezvousLease[];
|
||||
rendezvous_relay_policy?: RendezvousRelayPolicyReport;
|
||||
route_path_decisions?: RoutePathDecisionReport;
|
||||
service_channel_route_feedback?: FabricServiceChannelRouteFeedbackReport;
|
||||
service_channel_adaptive_policy?: FabricServiceChannelAdaptivePolicy;
|
||||
service_channel_remediation_commands?: FabricServiceChannelAccessTelemetryChannel["remediation_command"][];
|
||||
mesh_listener?: {
|
||||
schema_version: string;
|
||||
source: string;
|
||||
desired_state: string;
|
||||
listen_addr: string;
|
||||
listen_port_mode: string;
|
||||
auto_port_start?: number;
|
||||
auto_port_end?: number;
|
||||
advertise_endpoint?: string;
|
||||
advertise_transport?: string;
|
||||
connectivity_mode?: string;
|
||||
nat_type?: string;
|
||||
region?: string;
|
||||
config_version?: string;
|
||||
updated_by_user_id?: string;
|
||||
updated_at?: string;
|
||||
control_plane_only: boolean;
|
||||
production_forwarding: boolean;
|
||||
};
|
||||
routes: SyntheticMeshRoute[];
|
||||
production_forwarding: boolean;
|
||||
};
|
||||
@@ -489,6 +1297,53 @@ export type OrganizationAdminSummary = {
|
||||
topology_exposure: string;
|
||||
};
|
||||
|
||||
export type Organization = {
|
||||
id: string;
|
||||
slug: string;
|
||||
name: string;
|
||||
status: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
export type OrganizationMembership = {
|
||||
id: string;
|
||||
organization_id: string;
|
||||
user_id: string;
|
||||
role_id: string;
|
||||
status: string;
|
||||
invited_by_user_id?: string | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
export type UserAccount = {
|
||||
id: string;
|
||||
email: string;
|
||||
mfa_enabled: boolean;
|
||||
platform_role: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
export type Resource = {
|
||||
id: string;
|
||||
organization_id: string;
|
||||
name: string;
|
||||
address: string;
|
||||
protocol: string;
|
||||
secret_ref?: string | null;
|
||||
has_secret?: boolean;
|
||||
certificate_verification_mode: string;
|
||||
render_quality_profile?: string;
|
||||
clipboard_mode: string;
|
||||
file_transfer_mode: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
export type VPNConnection = {
|
||||
id: string;
|
||||
cluster_id: string;
|
||||
@@ -527,3 +1382,34 @@ export type VPNConnectionLease = {
|
||||
fenced_at?: string | null;
|
||||
metadata: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export type VPNPacketDirectionStats = {
|
||||
pushed: number;
|
||||
popped: number;
|
||||
dropped: number;
|
||||
queue_depth: number;
|
||||
last_push_size: number;
|
||||
last_pop_size: number;
|
||||
last_push_at?: string;
|
||||
last_pop_at?: string;
|
||||
};
|
||||
|
||||
export type VPNPacketStats = {
|
||||
client_to_gateway?: VPNPacketDirectionStats;
|
||||
gateway_to_client?: VPNPacketDirectionStats;
|
||||
};
|
||||
|
||||
export type VPNClientDiagnosticStatus = {
|
||||
cluster_id: string;
|
||||
device_id: string;
|
||||
payload: Record<string, unknown>;
|
||||
observed_at: string;
|
||||
};
|
||||
|
||||
export type VPNClientDiagnosticCommand = {
|
||||
id: string;
|
||||
cluster_id: string;
|
||||
device_id: string;
|
||||
payload: Record<string, unknown>;
|
||||
created_at: string;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user