function typedArrayConstructor(name) { return { Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array, }[name] || null; } function applyTypedRowDelta(current, delta) { if (!delta) return current; const Constructor = typedArrayConstructor(delta.constructorName); if (!Constructor) throw new Error(`Unsupported delta field type ${delta.constructorName}.`); if (delta.replace) return new Constructor(delta.replace); const target = ArrayBuffer.isView(current) && current.constructor?.name === delta.constructorName && current.length === delta.length ? current : new Constructor(delta.length); for (const row of delta.rows || []) target.set(row.values, row.start); return target; } function applyExactObjectDelta(target = {}, delta = {}, { cloneValues = true } = {}) { for (const key of delta.removed || []) delete target[key]; for (const [key, value] of Object.entries(delta.set || {})) target[key] = cloneValues ? structuredClone(value) : value; for (const [key, splice] of Object.entries(delta.arraySplices || {})) { const current = target[key]; if (!Array.isArray(current)) throw new Error(`Cannot apply array splice delta to non-array metadata key ${key}.`); const start = Math.max(0, Math.min(current.length, Math.floor(Number(splice?.start || 0)))); const deleteCount = Math.max(0, Math.min(current.length - start, Math.floor(Number(splice?.deleteCount || 0)))); const items = Array.isArray(splice?.items) ? splice.items : []; const inserted = cloneValues ? structuredClone(items) : items; target[key] = current.slice(0, start).concat(inserted, current.slice(start + deleteCount)); } return target; } export function applyCommittedWorldDelta(world, delta, { consumeMetadata = false, copyOnWrite = false } = {}) { if (!world || !delta) throw new Error("Committed mirror delta is missing."); if (world.width !== delta.width || world.height !== delta.height) { throw new Error(`Committed mirror dimensions changed unexpectedly (${world.width}x${world.height} -> ${delta.width}x${delta.height}).`); } for (const [name, fieldDelta] of Object.entries(delta.fields || {})) { if (fieldDelta.remove) delete world.fields[name]; else { const current = world.fields?.[name]; const writable = copyOnWrite && ArrayBuffer.isView(current) && !fieldDelta.replace ? new current.constructor(current) : current; world.fields[name] = applyTypedRowDelta(writable, fieldDelta); } } const generatedMask = copyOnWrite && delta.generatedMask && ArrayBuffer.isView(world.generatedMask) && !delta.generatedMask.replace ? new world.generatedMask.constructor(world.generatedMask) : world.generatedMask; world.generatedMask = applyTypedRowDelta(generatedMask, delta.generatedMask); if (delta.sourceMapDelta || delta.metaDelta) { // Clone all changed metadata in one graph. sourceMap diagnostics and // lastPatchResult often share the same seam/path objects; cloning each key // separately multiplied both allocation and retained heap. // postMessage already gives the main thread an isolated object graph, and // the Worker ACK consumes its retained delta exactly once. Those hot paths // can adopt the delta values directly instead of cloning every changed // feature/path/diagnostic a second time at peak memory. Keep clone-by-default // for reusable library callers. const exactValues = consumeMetadata ? { sourceSet: delta.sourceMapDelta?.set || {}, metaSet: delta.metaDelta?.set || {}, sourceArraySplices: delta.sourceMapDelta?.arraySplices || {}, metaArraySplices: delta.metaDelta?.arraySplices || {}, } : structuredClone({ sourceSet: delta.sourceMapDelta?.set || {}, metaSet: delta.metaDelta?.set || {}, sourceArraySplices: delta.sourceMapDelta?.arraySplices || {}, metaArraySplices: delta.metaDelta?.arraySplices || {}, }); if (delta.sourceMapDelta) { world.sourceMap = applyExactObjectDelta(world.sourceMap || {}, { ...delta.sourceMapDelta, set: exactValues.sourceSet, arraySplices: exactValues.sourceArraySplices, }, { cloneValues: false }); } if (delta.metaDelta) { applyExactObjectDelta(world, { ...delta.metaDelta, set: exactValues.metaSet, arraySplices: exactValues.metaArraySplices, }, { cloneValues: false }); } } else world.sourceMap = structuredClone(delta.sourceMap || {}); if (!delta.metaDelta) { for (const key of delta.removedMetaKeys || []) delete world[key]; for (const [key, value] of Object.entries(delta.meta || {})) world[key] = structuredClone(value); } return world; } export function materializeCommittedWorldDelta(baseWorld, delta, { consumeMetadata = false } = {}) { if (!baseWorld) throw new Error("Committed base world is missing."); // Patch previews are immutable views. Copy the world containers, then clone // only typed fields touched by row deltas. Exact metadata application replaces // changed roots/arrays, so untouched production metadata can remain shared. const previewWorld = { ...baseWorld, fields: { ...(baseWorld.fields || {}) }, sourceMap: { ...(baseWorld.sourceMap || {}) }, }; return applyCommittedWorldDelta(previewWorld, delta, { consumeMetadata, copyOnWrite: true }); } function cancellationError(message = "Committed world delta materialization cancelled.") { if (typeof DOMException === "function") return new DOMException(message, "AbortError"); const error = new Error(message); error.name = "AbortError"; return error; } async function cloneTypedArrayCooperatively(source, yieldControl, shouldCancel, chunkBytes) { if (!ArrayBuffer.isView(source) || source instanceof DataView) return source; const target = new source.constructor(source.length); const bytesPerElement = Math.max(1, source.BYTES_PER_ELEMENT || 1); const elementsPerChunk = Math.max(1, Math.floor(chunkBytes / bytesPerElement)); for (let offset = 0; offset < source.length; offset += elementsPerChunk) { if (shouldCancel()) throw cancellationError(); const end = Math.min(source.length, offset + elementsPerChunk); target.set(source.subarray(offset, end), offset); if (end < source.length) await yieldControl(); } return target; } async function applyTypedRowDeltaCooperatively(current, delta, options) { if (!delta) return current; const Constructor = typedArrayConstructor(delta.constructorName); if (!Constructor) throw new Error(`Unsupported delta field type ${delta.constructorName}.`); const { yieldControl, shouldCancel, chunkBytes } = options; if (delta.replace) { // The main thread owns transferred replacement buffers exclusively. Adopt // them directly instead of making a second full-size copy at peak memory. if (ArrayBuffer.isView(delta.replace) && delta.replace.constructor === Constructor) return delta.replace; return cloneTypedArrayCooperatively(new Constructor(delta.replace), yieldControl, shouldCancel, chunkBytes); } let target; if (ArrayBuffer.isView(current) && current.constructor?.name === delta.constructorName && current.length === delta.length) { target = await cloneTypedArrayCooperatively(current, yieldControl, shouldCancel, chunkBytes); } else { target = new Constructor(delta.length); } let bytesSinceYield = 0; for (const row of delta.rows || []) { if (shouldCancel()) throw cancellationError(); target.set(row.values, row.start); bytesSinceYield += row.values?.byteLength || 0; if (bytesSinceYield >= chunkBytes) { bytesSinceYield = 0; await yieldControl(); } } return target; } export async function materializeCommittedWorldDeltaCooperative(baseWorld, delta, { consumeMetadata = false, yieldControl = () => Promise.resolve(), shouldCancel = () => false, chunkBytes = 4 * 1024 * 1024, } = {}) { if (!baseWorld) throw new Error("Committed base world is missing."); if (!delta) throw new Error("Committed mirror delta is missing."); if (baseWorld.width !== delta.width || baseWorld.height !== delta.height) { throw new Error(`Committed mirror dimensions changed unexpectedly (${baseWorld.width}x${baseWorld.height} -> ${delta.width}x${delta.height}).`); } const previewWorld = { ...baseWorld, fields: { ...(baseWorld.fields || {}) }, sourceMap: { ...(baseWorld.sourceMap || {}) }, }; for (const [name, fieldDelta] of Object.entries(delta.fields || {})) { if (shouldCancel()) throw cancellationError(); if (fieldDelta.remove) delete previewWorld.fields[name]; else previewWorld.fields[name] = await applyTypedRowDeltaCooperatively(previewWorld.fields[name], fieldDelta, { yieldControl, shouldCancel, chunkBytes, }); await yieldControl(); } if (delta.generatedMask) { previewWorld.generatedMask = await applyTypedRowDeltaCooperatively(previewWorld.generatedMask, delta.generatedMask, { yieldControl, shouldCancel, chunkBytes, }); await yieldControl(); } if (shouldCancel()) throw cancellationError(); if (delta.sourceMapDelta || delta.metaDelta) { const exactValues = consumeMetadata ? { sourceSet: delta.sourceMapDelta?.set || {}, metaSet: delta.metaDelta?.set || {}, sourceArraySplices: delta.sourceMapDelta?.arraySplices || {}, metaArraySplices: delta.metaDelta?.arraySplices || {}, } : structuredClone({ sourceSet: delta.sourceMapDelta?.set || {}, metaSet: delta.metaDelta?.set || {}, sourceArraySplices: delta.sourceMapDelta?.arraySplices || {}, metaArraySplices: delta.metaDelta?.arraySplices || {}, }); if (delta.sourceMapDelta) { previewWorld.sourceMap = applyExactObjectDelta(previewWorld.sourceMap || {}, { ...delta.sourceMapDelta, set: exactValues.sourceSet, arraySplices: exactValues.sourceArraySplices, }, { cloneValues: false }); await yieldControl(); } if (shouldCancel()) throw cancellationError(); if (delta.metaDelta) { applyExactObjectDelta(previewWorld, { ...delta.metaDelta, set: exactValues.metaSet, arraySplices: exactValues.metaArraySplices, }, { cloneValues: false }); await yieldControl(); } } else { previewWorld.sourceMap = consumeMetadata ? (delta.sourceMap || {}) : structuredClone(delta.sourceMap || {}); } if (!delta.metaDelta) { for (const key of delta.removedMetaKeys || []) delete previewWorld[key]; for (const [key, value] of Object.entries(delta.meta || {})) { if (shouldCancel()) throw cancellationError(); previewWorld[key] = consumeMetadata ? value : structuredClone(value); await yieldControl(); } } return previewWorld; } function mixHashText(hash, text) { let value = hash >>> 0; for (let index = 0; index < text.length; index++) { value ^= text.charCodeAt(index); value = Math.imul(value, 16777619) >>> 0; } return value; } function mixHashValue(hash, value) { let next = hash >>> 0; if (value == null) return mixHashText(next, String(value)); if (ArrayBuffer.isView(value)) { next = mixHashText(next, `${value.constructor.name}:${value.length}:`); const bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength); for (let index = 0; index < bytes.length; index++) { next ^= bytes[index]; next = Math.imul(next, 16777619) >>> 0; } return next; } if (Array.isArray(value)) { next = mixHashText(next, `[${value.length}:`); for (const item of value) next = mixHashValue(next, item); return next; } if (value instanceof Map) { const entries = [...value.entries()].sort(([a], [b]) => String(a).localeCompare(String(b))); return mixHashValue(mixHashText(next, `Map:${entries.length}:`), entries); } if (value instanceof Set) return mixHashValue(mixHashText(next, `Set:${value.size}:`), [...value].sort()); if (typeof value === "object") { const keys = Object.keys(value).sort(); next = mixHashText(next, `{${keys.length}:`); for (const key of keys) { next = mixHashText(next, key); next = mixHashValue(next, value[key]); } return next; } return mixHashText(next, `${typeof value}:${String(value)}`); } export function hashCommittedWorld(world) { let hash = 2166136261 >>> 0; hash = mixHashText(hash, `${world?.width || 0}x${world?.height || 0}|${world?.originX || 0},${world?.originY || 0}`); for (const name of Object.keys(world?.fields || {}).sort()) { hash = mixHashText(hash, `|${name}:`); const field = world.fields[name]; if (!ArrayBuffer.isView(field)) continue; const bytes = new Uint8Array(field.buffer, field.byteOffset, field.byteLength); for (let index = 0; index < bytes.length; index++) { hash ^= bytes[index]; hash = Math.imul(hash, 16777619) >>> 0; } } if (ArrayBuffer.isView(world?.generatedMask)) { hash = mixHashText(hash, "|generatedMask:"); const bytes = new Uint8Array(world.generatedMask.buffer, world.generatedMask.byteOffset, world.generatedMask.byteLength); for (let index = 0; index < bytes.length; index++) { hash ^= bytes[index]; hash = Math.imul(hash, 16777619) >>> 0; } } hash = mixHashText(hash, "|sourceMap:"); hash = mixHashValue(hash, world?.sourceMap || {}); const meta = {}; for (const [key, value] of Object.entries(world || {})) { if (key === "fields" || key === "generatedMask" || key === "sourceMap") continue; meta[key] = value; } hash = mixHashText(hash, "|meta:"); hash = mixHashValue(hash, meta); return hash.toString(16).padStart(8, "0"); } async function cooperativeHashYield(state) { if (state.shouldAbort()) throw cancellationError("Committed world hash cancelled."); state.pending = 0; await state.yieldControl(); if (state.shouldAbort()) throw cancellationError("Committed world hash cancelled."); } async function mixHashTextAsync(hash, text, state) { let value = hash >>> 0; let index = 0; while (index < text.length) { const start = index; const capacity = Math.max(1, state.yieldEvery - state.pending); const end = Math.min(text.length, index + capacity); for (; index < end; index++) { value ^= text.charCodeAt(index); value = Math.imul(value, 16777619) >>> 0; } state.pending += end - start; if (state.pending >= state.yieldEvery) await cooperativeHashYield(state); } return value; } async function mixHashBytesAsync(hash, bytes, state) { let value = hash >>> 0; let index = 0; while (index < bytes.length) { const start = index; const capacity = Math.max(1, state.yieldEvery - state.pending); const end = Math.min(bytes.length, index + capacity); for (; index < end; index++) { value ^= bytes[index]; value = Math.imul(value, 16777619) >>> 0; } state.pending += end - start; if (state.pending >= state.yieldEvery) await cooperativeHashYield(state); } return value; } async function mixHashValueAsync(hash, value, state) { let next = hash >>> 0; if (state.shouldAbort()) throw cancellationError("Committed world hash cancelled."); if (value == null) return mixHashTextAsync(next, String(value), state); if (ArrayBuffer.isView(value)) { next = await mixHashTextAsync(next, `${value.constructor.name}:${value.length}:`, state); return mixHashBytesAsync(next, new Uint8Array(value.buffer, value.byteOffset, value.byteLength), state); } if (Array.isArray(value)) { next = await mixHashTextAsync(next, `[${value.length}:`, state); for (const item of value) next = await mixHashValueAsync(next, item, state); return next; } if (value instanceof Map) { const entries = [...value.entries()].sort(([a], [b]) => String(a).localeCompare(String(b))); next = await mixHashTextAsync(next, `Map:${entries.length}:`, state); return mixHashValueAsync(next, entries, state); } if (value instanceof Set) { next = await mixHashTextAsync(next, `Set:${value.size}:`, state); return mixHashValueAsync(next, [...value].sort(), state); } if (typeof value === "object") { const keys = Object.keys(value).sort(); next = await mixHashTextAsync(next, `{${keys.length}:`, state); for (const key of keys) { next = await mixHashTextAsync(next, key, state); next = await mixHashValueAsync(next, value[key], state); } return next; } return mixHashTextAsync(next, `${typeof value}:${String(value)}`, state); } // Bit-identical cooperative counterpart to hashCommittedWorld(). Yielding is // only inserted between chunks; byte/text order and FNV-1a arithmetic are // unchanged. This lets the main thread verify a transferred transactional // preview without creating an uncancellable multi-megabyte long task. export async function hashCommittedWorldAsync(world, { yieldEvery = 262_144, yieldControl = null, shouldAbort = () => false, } = {}) { const fallbackYield = () => { if (typeof globalThis.scheduler?.yield === "function") return globalThis.scheduler.yield(); return new Promise((resolve) => setTimeout(resolve, 0)); }; const state = { yieldEvery: Math.max(1, Math.floor(Number(yieldEvery) || 262_144)), pending: 0, shouldAbort: typeof shouldAbort === "function" ? shouldAbort : () => false, yieldControl: typeof yieldControl === "function" ? yieldControl : fallbackYield, }; if (state.shouldAbort()) throw cancellationError("Committed world hash cancelled."); let hash = 2166136261 >>> 0; hash = await mixHashTextAsync(hash, `${world?.width || 0}x${world?.height || 0}|${world?.originX || 0},${world?.originY || 0}`, state); for (const name of Object.keys(world?.fields || {}).sort()) { hash = await mixHashTextAsync(hash, `|${name}:`, state); const field = world.fields[name]; if (!ArrayBuffer.isView(field)) continue; hash = await mixHashBytesAsync(hash, new Uint8Array(field.buffer, field.byteOffset, field.byteLength), state); } if (ArrayBuffer.isView(world?.generatedMask)) { hash = await mixHashTextAsync(hash, "|generatedMask:", state); hash = await mixHashBytesAsync(hash, new Uint8Array(world.generatedMask.buffer, world.generatedMask.byteOffset, world.generatedMask.byteLength), state); } hash = await mixHashTextAsync(hash, "|sourceMap:", state); hash = await mixHashValueAsync(hash, world?.sourceMap || {}, state); const meta = {}; for (const [key, value] of Object.entries(world || {})) { if (key === "fields" || key === "generatedMask" || key === "sourceMap") continue; meta[key] = value; } hash = await mixHashTextAsync(hash, "|meta:", state); hash = await mixHashValueAsync(hash, meta, state); if (state.shouldAbort()) throw cancellationError("Committed world hash cancelled."); return hash.toString(16).padStart(8, "0"); }