import {z} from 'zod' export type GetApiClusterTelemetryArgs = {details_level?: number | undefined, timeout?: number | undefined}; export type GetApiClusterTelemetryOptions = {baseUrl?: string | undefined, apiKey?: string | undefined, fetch?: typeof fetch | undefined}; export const hardwareUsage = z.object({cpu: z.number().int().gte(0), payload_io_read: z.number().int().gte(0), payload_io_write: z.number().int().gte(0), payload_index_io_read: z.number().int().gte(0), payload_index_io_write: z.number().int().gte(0), vector_io_read: z.number().int().gte(0), vector_io_write: z.number().int().gte(0)}); export const modelUsage = z.object({tokens: z.number().int().gte(0)}); export const inferenceUsage = z.object({models: z.record(z.string(), modelUsage)}); export const usage = z.object({hardware: z.union([hardwareUsage, z.unknown()]).optional(), inference: z.union([inferenceUsage, z.unknown()]).optional()}); export const shardKey = z.union([z.string(), z.number().int().gte(0)]); export const replicaState = z.enum(["Active", "Dead", "Partial", "Initializing", "Listener", "PartialSnapshot", "Recovery", "Resharding", "ReshardingScaleDown", "ActiveRead", "ManualRecovery"]); export const shardStatus = z.enum(["green", "yellow", "grey", "red"]); export const shardCleanStatusProgressTelemetry = z.object({deleted_points: z.number().int().gte(0)}); export const shardCleanStatusFailedTelemetry = z.object({reason: z.string()}); export const shardCleanStatusTelemetry = z.union([z.enum(["started", "done", "cancelled"]), z.object({progress: shardCleanStatusProgressTelemetry}), z.object({failed: shardCleanStatusFailedTelemetry})]); export const partialSnapshotTelemetry = z.object({ongoing_create_snapshot_requests: z.number().int().gte(0), is_recovering: z.boolean(), recovery_timestamp: z.number().int().gte(0)}); export const distributedReplicaTelemetry = z.object({peer_id: z.number().int().gte(0), state: replicaState, status: z.union([shardStatus, z.unknown()]).optional(), total_optimized_points: z.number().int().gte(0).nullable().optional(), vectors_size_bytes: z.number().int().gte(0).nullable().optional(), payloads_size_bytes: z.number().int().gte(0).nullable().optional(), num_points: z.number().int().gte(0).nullable().optional(), num_vectors: z.number().int().gte(0).nullable().optional(), num_vectors_by_name: z.record(z.string(), z.number().int().gte(0)).nullable().optional(), shard_cleaning_status: z.union([shardCleanStatusTelemetry, z.unknown()]).optional(), partial_snapshot: z.union([partialSnapshotTelemetry, z.unknown()]).optional()}); export const distributedShardTelemetry = z.object({id: z.number().int().gte(0), key: z.union([shardKey, z.unknown()]).optional(), replicas: z.array(distributedReplicaTelemetry)}); export const reshardingDirection = z.enum(["up", "down"]); export const reshardingInfo = z.object({direction: reshardingDirection, shard_id: z.number().int().gte(0), peer_id: z.number().int().gte(0), shard_key: z.union([shardKey, z.unknown()]).optional()}); export const shardTransferMethod = z.enum(["stream_records", "snapshot", "wal_delta", "resharding_stream_records"]); export const shardTransferInfo = z.object({shard_id: z.number().int().gte(0), to_shard_id: z.number().int().gte(0).nullable().optional(), from: z.number().int().gte(0), to: z.number().int().gte(0), sync: z.boolean(), method: z.union([shardTransferMethod, z.unknown()]).optional(), comment: z.string().nullable().optional()}); export const distributedCollectionTelemetry = z.object({id: z.string(), shards: z.array(distributedShardTelemetry).nullable().optional(), reshardings: z.array(reshardingInfo).nullable().optional(), shard_transfers: z.array(shardTransferInfo).nullable().optional()}); export const stateRole = z.enum(["Follower", "Candidate", "Leader", "PreCandidate"]); export const consensusThreadStatus = z.union([z.object({consensus_thread_status: z.literal("working"), last_update: z.string()}), z.object({consensus_thread_status: z.literal("stopped")}), z.object({consensus_thread_status: z.literal("stopped_with_err"), err: z.string()})]); export const distributedPeerDetails = z.object({version: z.string(), role: z.union([stateRole, z.unknown()]).optional(), is_voter: z.boolean(), term: z.number().int().gte(0), commit: z.number().int().gte(0), num_pending_operations: z.number().int().gte(0), consensus_thread_status: consensusThreadStatus}); export const distributedPeerInfo = z.object({uri: z.string(), responsive: z.boolean(), details: z.union([distributedPeerDetails, z.unknown()]).optional()}); export const distributedClusterTelemetry = z.object({enabled: z.boolean(), number_of_peers: z.number().int().gte(0).nullable().optional(), peers: z.record(z.string(), distributedPeerInfo)}); export const distributedTelemetryData = z.object({collections: z.record(z.string(), distributedCollectionTelemetry), cluster: z.union([distributedClusterTelemetry, z.unknown()]).optional()}); export const getApiClusterTelemetryResponse = z.object({usage: z.union([usage, z.unknown()]).optional(), time: z.number().optional(), status: z.string().optional(), result: distributedTelemetryData.optional()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Collect cluster telemetry data * * GET /cluster/telemetry * * Also accepts auth: bearerAuth */ export const getApiClusterTelemetry = async (args: GetApiClusterTelemetryArgs, options?: GetApiClusterTelemetryOptions) => { const {baseUrl = "http://localhost:6333", fetch: fetchFn = fetch, apiKey} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.details_level != null) query.append("details_level", String(args.details_level)) if (args.timeout != null) query.append("timeout", String(args.timeout)) if (apiKey !== undefined) headers.set("api-key", apiKey) const url = `${baseUrl.replace(/\/+$/, '')}/cluster/telemetry${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(getApiClusterTelemetryResponse, await res.json()) };