Files
openclaw/src/gateway/config-diff.ts
Peter Steinberger 26312fd0b0 refactor: remove gateway and channel dead exports (#106038)
* refactor: remove gateway and channel dead exports

* style: format config reload test

* refactor: remove newly dead gateway exports

* test: preserve approval audience coverage

* refactor: preserve gateway contracts while pruning exports

* test: retain gateway regression coverage

* test: restore gateway policy coverage

* test: close dead-export CI gaps

* fix: reconcile dead exports with latest main

* refactor: remove newly dead gateway runner export

* test: remove private worker verifier coverage

* test: preserve weak secret docs coverage

* fix: avoid gateway health import cycle

* fix: preserve node pairing type contract

* style: format talk relay test

* fix: preserve gateway protocol generation contract

* chore: refresh dead export baseline

* fix: preserve loaded target compatibility exports

* fix: preserve plugin SDK declaration resolution

* chore: refresh dead export baseline

* chore: refresh dead export baseline

* test(gateway): derive private worker service options
2026-07-13 05:47:05 -07:00

57 lines
1.9 KiB
TypeScript

// Config path diff helper used by gateway mutation diagnostics.
import { isDeepStrictEqual } from "node:util";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { isPlainObject } from "../utils.js";
/** Return dotted config paths whose values differ between two config snapshots. */
export function diffConfigPaths(prev: unknown, next: unknown, prefix = ""): string[] {
if (prev === next) {
return [];
}
if (isPlainObject(prev) && isPlainObject(next)) {
const keys = new Set([...Object.keys(prev), ...Object.keys(next)]);
const paths: string[] = [];
for (const key of keys) {
const prevValue = prev[key];
const nextValue = next[key];
if (prevValue === undefined && nextValue === undefined) {
continue;
}
const childPrefix = prefix ? `${prefix}.${key}` : key;
const childPaths = diffConfigPaths(prevValue, nextValue, childPrefix);
if (childPaths.length > 0) {
paths.push(...childPaths);
}
}
return paths;
}
if (Array.isArray(prev) && Array.isArray(next)) {
// Arrays can contain object entries (for example memory.qmd.paths/scope.rules);
// compare structurally so identical values are not reported as changed.
if (isDeepStrictEqual(prev, next)) {
return [];
}
}
return [prefix || "<root>"];
}
/** Preserve startup-only restart boundaries hidden by whole-object config changes. */
export function diffGatewayReloadPaths(
prevConfig: OpenClawConfig,
nextConfig: OpenClawConfig,
): string[] {
const changedPaths = diffConfigPaths(prevConfig, nextConfig);
if (!changedPaths.includes("mcp")) {
return changedPaths;
}
// Adding or removing the whole `mcp` object collapses to the broad `mcp`
// path. Preserve the Apps boundary so the listener still restarts.
return [
...changedPaths,
...diffConfigPaths(
{ mcp: { apps: prevConfig.mcp?.apps } },
{ mcp: { apps: nextConfig.mcp?.apps } },
),
];
}