/** A deep copy no plugin can change. Plugins read data through it, never the host's own objects. */ export function cloneAndFreeze(value: T): T { if (Array.isArray(value)) { return Object.freeze(value.map((entry) => cloneAndFreeze(entry))) as T; } if (value !== null && typeof value === "object") { return Object.freeze( Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, cloneAndFreeze(entry)])), ) as T; } return value; }