mirror of
https://github.com/openclaw/openclaw.git
synced 2026-02-19 18:39:20 -05:00
fix (gateway/config): merge config.patch object arrays by id
This commit is contained in:
@@ -2,7 +2,48 @@ import { isPlainObject } from "../utils.js";
|
||||
|
||||
type PlainObject = Record<string, unknown>;
|
||||
|
||||
export function applyMergePatch(base: unknown, patch: unknown): unknown {
|
||||
type MergePatchOptions = {
|
||||
mergeObjectArraysById?: boolean;
|
||||
};
|
||||
|
||||
function isObjectWithStringId(value: unknown): value is Record<string, unknown> & { id: string } {
|
||||
if (!isPlainObject(value)) {
|
||||
return false;
|
||||
}
|
||||
return typeof value.id === "string" && value.id.length > 0;
|
||||
}
|
||||
|
||||
function mergeObjectArraysById(base: unknown[], patch: unknown[], options: MergePatchOptions) {
|
||||
if (!base.every(isObjectWithStringId) || !patch.every(isObjectWithStringId)) {
|
||||
return undefined;
|
||||
}
|
||||
const merged = [...base] as Array<Record<string, unknown> & { id: string }>;
|
||||
const indexById = new Map<string, number>();
|
||||
for (const [index, entry] of merged.entries()) {
|
||||
indexById.set(entry.id, index);
|
||||
}
|
||||
|
||||
for (const entry of patch) {
|
||||
const existingIndex = indexById.get(entry.id);
|
||||
if (existingIndex === undefined) {
|
||||
merged.push(structuredClone(entry));
|
||||
indexById.set(entry.id, merged.length - 1);
|
||||
continue;
|
||||
}
|
||||
merged[existingIndex] = applyMergePatch(merged[existingIndex], entry, options) as Record<
|
||||
string,
|
||||
unknown
|
||||
> & { id: string };
|
||||
}
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
export function applyMergePatch(
|
||||
base: unknown,
|
||||
patch: unknown,
|
||||
options: MergePatchOptions = {},
|
||||
): unknown {
|
||||
if (!isPlainObject(patch)) {
|
||||
return patch;
|
||||
}
|
||||
@@ -14,9 +55,16 @@ export function applyMergePatch(base: unknown, patch: unknown): unknown {
|
||||
delete result[key];
|
||||
continue;
|
||||
}
|
||||
if (options.mergeObjectArraysById && Array.isArray(result[key]) && Array.isArray(value)) {
|
||||
const mergedArray = mergeObjectArraysById(result[key] as unknown[], value, options);
|
||||
if (mergedArray) {
|
||||
result[key] = mergedArray;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (isPlainObject(value)) {
|
||||
const baseValue = result[key];
|
||||
result[key] = applyMergePatch(isPlainObject(baseValue) ? baseValue : {}, value);
|
||||
result[key] = applyMergePatch(isPlainObject(baseValue) ? baseValue : {}, value, options);
|
||||
continue;
|
||||
}
|
||||
result[key] = value;
|
||||
|
||||
@@ -342,7 +342,9 @@ export const configHandlers: GatewayRequestHandlers = {
|
||||
);
|
||||
return;
|
||||
}
|
||||
const merged = applyMergePatch(snapshot.config, parsedRes.parsed);
|
||||
const merged = applyMergePatch(snapshot.config, parsedRes.parsed, {
|
||||
mergeObjectArraysById: true,
|
||||
});
|
||||
const schemaPatch = loadSchemaWithPlugins();
|
||||
const restoredMerge = restoreRedactedValues(merged, snapshot.config, schemaPatch.uiHints);
|
||||
if (!restoredMerge.ok) {
|
||||
|
||||
Reference in New Issue
Block a user