mirror of https://github.com/openclaw/openclaw.git
92 lines
2.4 KiB
TypeScript
92 lines
2.4 KiB
TypeScript
import { isPlainObject } from "../utils.js";
|
|
import { parseConfigPath, setConfigValueAtPath, unsetConfigValueAtPath } from "./config-paths.js";
|
|
import { isBlockedObjectKey } from "./prototype-keys.js";
|
|
import type { OpenClawConfig } from "./types.js";
|
|
|
|
type OverrideTree = Record<string, unknown>;
|
|
|
|
let overrides: OverrideTree = {};
|
|
|
|
function sanitizeOverrideValue(value: unknown, seen = new WeakSet<object>()): unknown {
|
|
if (Array.isArray(value)) {
|
|
return value.map((entry) => sanitizeOverrideValue(entry, seen));
|
|
}
|
|
if (!isPlainObject(value)) {
|
|
return value;
|
|
}
|
|
if (seen.has(value)) {
|
|
return {};
|
|
}
|
|
seen.add(value);
|
|
const sanitized: OverrideTree = {};
|
|
for (const [key, entry] of Object.entries(value)) {
|
|
if (entry === undefined || isBlockedObjectKey(key)) {
|
|
continue;
|
|
}
|
|
sanitized[key] = sanitizeOverrideValue(entry, seen);
|
|
}
|
|
seen.delete(value);
|
|
return sanitized;
|
|
}
|
|
|
|
function mergeOverrides(base: unknown, override: unknown): unknown {
|
|
if (!isPlainObject(base) || !isPlainObject(override)) {
|
|
return override;
|
|
}
|
|
const next: OverrideTree = { ...base };
|
|
for (const [key, value] of Object.entries(override)) {
|
|
if (value === undefined || isBlockedObjectKey(key)) {
|
|
continue;
|
|
}
|
|
next[key] = mergeOverrides((base as OverrideTree)[key], value);
|
|
}
|
|
return next;
|
|
}
|
|
|
|
export function getConfigOverrides(): OverrideTree {
|
|
return overrides;
|
|
}
|
|
|
|
export function resetConfigOverrides(): void {
|
|
overrides = {};
|
|
}
|
|
|
|
export function setConfigOverride(
|
|
pathRaw: string,
|
|
value: unknown,
|
|
): {
|
|
ok: boolean;
|
|
error?: string;
|
|
} {
|
|
const parsed = parseConfigPath(pathRaw);
|
|
if (!parsed.ok || !parsed.path) {
|
|
return { ok: false, error: parsed.error ?? "Invalid path." };
|
|
}
|
|
setConfigValueAtPath(overrides, parsed.path, sanitizeOverrideValue(value));
|
|
return { ok: true };
|
|
}
|
|
|
|
export function unsetConfigOverride(pathRaw: string): {
|
|
ok: boolean;
|
|
removed: boolean;
|
|
error?: string;
|
|
} {
|
|
const parsed = parseConfigPath(pathRaw);
|
|
if (!parsed.ok || !parsed.path) {
|
|
return {
|
|
ok: false,
|
|
removed: false,
|
|
error: parsed.error ?? "Invalid path.",
|
|
};
|
|
}
|
|
const removed = unsetConfigValueAtPath(overrides, parsed.path);
|
|
return { ok: true, removed };
|
|
}
|
|
|
|
export function applyConfigOverrides(cfg: OpenClawConfig): OpenClawConfig {
|
|
if (!overrides || Object.keys(overrides).length === 0) {
|
|
return cfg;
|
|
}
|
|
return mergeOverrides(cfg, overrides) as OpenClawConfig;
|
|
}
|