import { normalizeProviderId } from "../agents/model-selection.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; import {
normalizeLowercaseStringOrEmpty,
normalizeOptionalLowercaseString,
normalizeOptionalString,
} from "../shared/string-coerce.js"; import type { ProviderAuthMethod, ProviderPlugin } from "./types.js";
function isPlainRecord(value: unknown): value is Record<string, unknown> { returnBoolean(value && typeof value === "object" && !Array.isArray(value));
}
// Guard config patches against prototype-pollution payloads if a patch ever // arrives from a JSON-parsed source that preserves these keys. const BLOCKED_MERGE_KEYS = new Set(["__proto__", "prototype", "constructor"]);
function sanitizeConfigPatchValue(value: unknown): unknown { if (Array.isArray(value)) { return value.map((entry) => sanitizeConfigPatchValue(entry));
} if (!isPlainRecord(value)) { return value;
}
const next: Record<string, unknown> = {}; for (const [key, nestedValue] of Object.entries(value)) { if (BLOCKED_MERGE_KEYS.has(key)) { continue;
}
next[key] = sanitizeConfigPatchValue(nestedValue);
} return next;
}
export function mergeConfigPatch<T>(base: T, patch: unknown): T { if (!isPlainRecord(base) || !isPlainRecord(patch)) { return sanitizeConfigPatchValue(patch) as T;
}
const next: Record<string, unknown> = { ...base }; for (const [key, value] of Object.entries(patch)) { if (BLOCKED_MERGE_KEYS.has(key)) { continue;
} const existing = next[key]; if (isPlainRecord(existing) && isPlainRecord(value)) {
next[key] = mergeConfigPatch(existing, value);
} else {
next[key] = sanitizeConfigPatchValue(value);
}
} return next as T;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.