import type { ErrorObject } from "ajv"; import { ErrorCodes, errorShape, formatValidationErrors } from "../protocol/index.js"; import { formatForLog } from "../ws-log.js"; import type { RespondFn } from "./types.js"; type ValidatorFn = ((value: unknown) => boolean) & { errors?: ErrorObject[] | null; }; export function respondInvalidParams(params: { respond: RespondFn; method: string; validator: ValidatorFn; }) { params.respond( false, undefined, errorShape( ErrorCodes.INVALID_REQUEST, `invalid ${params.method} params: ${formatValidationErrors(params.validator.errors)}`, ), ); } export async function respondUnavailableOnThrow(respond: RespondFn, fn: () => Promise) { try { await fn(); } catch (err) { respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, formatForLog(err))); } } export function uniqueSortedStrings(values: unknown[]) { return [...new Set(values.filter((v) => typeof v === "string"))] .map((v) => v.trim()) .filter(Boolean) .toSorted(); } export function safeParseJson(value: string | null | undefined): unknown { if (typeof value !== "string") { return undefined; } const trimmed = value.trim(); if (!trimmed) { return undefined; } try { return JSON.parse(trimmed) as unknown; } catch { return { payloadJSON: value }; } } export function respondUnavailableOnNodeInvokeError( respond: RespondFn, res: T, ): res is T & { ok: true } { if (res.ok) { return true; } const nodeError = res.error && typeof res.error === "object" ? (res.error as { code?: unknown; message?: unknown }) : null; const nodeCode = typeof nodeError?.code === "string" ? nodeError.code.trim() : ""; const nodeMessage = typeof nodeError?.message === "string" && nodeError.message.trim().length > 0 ? nodeError.message.trim() : "node invoke failed"; const message = nodeCode ? `${nodeCode}: ${nodeMessage}` : nodeMessage; respond( false, undefined, errorShape(ErrorCodes.UNAVAILABLE, message, { details: { nodeError: res.error ?? null }, }), ); return false; }