Files
rea/src/application/ClientConfigurationDocument.ts
T
morlutoandGitHub ed933d1893 feat(native): add investigation features (#486)
* feat(native): add UI and dispatch investigation workflows

* feat(ghidra): support macOS host validation

* docs: update native investigation capabilities

* feat(artifacts): decode compiled Interface Builder archives

* feat(ghidra): expose bounded p-code value flow

* test(ghidra): split host and cross-format verification

* fix(verify): follow complete result contracts

* refactor: remove unused authorization and schema helpers

* refactor: remove unused evidence result alias

* fix(ghidra): report jump-table evidence precisely

* fix(verify): align browser scenario fixture schema

* fix(setup): compare parsed client config structurally

* test(ghidra): verify AArch64 jump-table mappings

* fix(ghidra): recover AArch64 byte jump tables

* test(artifacts): verify compiled interface builder archives

* feat(native): trace UI actions through handlers

* fix(tests): update native trace and shutdown fixtures

* fix(verification): diagnose browser scenario failures

* fix(browser): wrap scenario snapshots in capture state

* fix(native): bind and bound investigation workflows

* fix(artifacts): preserve bounded interface builder evidence

* fix(ghidra): enforce admitted hosts and preflight tools

* fix(native): preserve trace cancellation and bounds

* test(application): expect bound analysis target evidence

* fix(native): preserve investigation bounds and cancellation

* fix(application): preserve bundle and unresolved trace evidence

* style(test): format artifact subject fixture
2026-09-30 00:41:05 +08:00

59 lines
2.1 KiB
TypeScript

import { parse as parseToml, stringify as stringifyToml } from "smol-toml";
import { isDeepStrictEqual } from "node:util";
import { z } from "zod";
import type { SetupClient } from "./SupportedClients.js";
/** Validated client document and its server table, preserving unrelated settings. */
export interface ClientConfigurationDocument {
readonly document: Record<string, unknown>;
readonly servers: Record<string, unknown>;
readonly serversKey: "mcp_servers" | "mcpServers";
}
const objectSchema = z.record(z.string(), z.unknown());
/** Compare parsed configuration values without depending on parser prototypes. */
export const clientConfigurationValuesEqual = (
left: unknown,
right: unknown,
): boolean =>
isDeepStrictEqual(
normalizeConfigurationValue(left),
normalizeConfigurationValue(right),
);
const normalizeConfigurationValue = (value: unknown): unknown => {
if (Array.isArray(value)) return value.map(normalizeConfigurationValue);
if (typeof value !== "object" || value === null || value instanceof Date)
return value;
return Object.fromEntries(
Object.entries(value)
.sort(([left], [right]) => left.localeCompare(right))
.map(([key, nested]) => [key, normalizeConfigurationValue(nested)]),
);
};
/** Parse the client format and reject malformed root or server-table values. */
export const parseClientConfiguration = (
text: string,
format: SetupClient["format"],
): ClientConfigurationDocument => {
const document = objectSchema.parse(
format === "toml" ? parseToml(text) : JSON.parse(text),
);
const serversKey = format === "toml" ? "mcp_servers" : "mcpServers";
const value = document[serversKey];
const servers = value === undefined ? {} : objectSchema.parse(value);
return { document, servers, serversKey };
};
/** Serialize a validated client document using the selected format. */
export const serializeClientConfiguration = (
document: Record<string, unknown>,
format: SetupClient["format"],
): string =>
format === "toml"
? stringifyToml(document)
: `${JSON.stringify(document, null, 2)}\n`;