{"version":3,"file":"index.cjs","sources":["../src/paths.ts","../src/diffError.ts","../src/validate.ts","../src/setOperations.ts","../src/diffPatch.ts"],"sourcesContent":["const IS_DOTTABLE_RE = /^[A-Za-z_][A-Za-z0-9_]*$/\n\n/**\n * A segment of a path\n *\n * @public\n */\nexport type PathSegment =\n  | string // Property\n  | number // Array index\n  | {_key: string} // Array `_key` lookup\n  | [number | '', number | ''] // From/to array index\n\n/**\n * An array of path segments representing a path in a document\n *\n * @public\n */\nexport type Path = PathSegment[]\n\n/**\n * Converts an array path to a string path\n *\n * @param path - The array path to convert\n * @returns A stringified path\n * @internal\n */\nexport function pathToString(path: Path): string {\n  return path.reduce((target: string, segment: PathSegment, i: number) => {\n    if (Array.isArray(segment)) {\n      return `${target}[${segment.join(':')}]`\n    }\n\n    if (isKeyedObject(segment)) {\n      return `${target}[_key==\"${segment._key}\"]`\n    }\n\n    if (typeof segment === 'number') {\n      return `${target}[${segment}]`\n    }\n\n    if (typeof segment === 'string' && !IS_DOTTABLE_RE.test(segment)) {\n      return `${target}['${segment}']`\n    }\n\n    if (typeof segment === 'string') {\n      const separator = i === 0 ? '' : '.'\n      return `${target}${separator}${segment}`\n    }\n\n    throw new Error(`Unsupported path segment \"${segment}\"`)\n  }, '')\n}\n\n/**\n * An object (record) that has a `_key` property\n *\n * @internal\n */\nexport interface KeyedSanityObject {\n  [key: string]: unknown\n  _key: string\n}\n\nexport function isKeyedObject(obj: unknown): obj is KeyedSanityObject {\n  return typeof obj === 'object' && !!obj && '_key' in obj && typeof obj._key === 'string'\n}\n","import {type Path, pathToString} from './paths.js'\n\n/**\n * Represents an error that occurred during a diff process.\n * Contains `path`, `value` and `serializedPath` properties,\n * which is helpful for debugging and showing friendly messages.\n *\n * @public\n */\nexport class DiffError extends Error {\n  public path: Path\n  public value: unknown\n  public serializedPath: string\n\n  constructor(message: string, path: Path, value?: unknown) {\n    const serializedPath = pathToString(path)\n    super(`${message} (at '${serializedPath}')`)\n\n    this.path = path\n    this.serializedPath = serializedPath\n    this.value = value\n  }\n}\n","import {DiffError} from './diffError.js'\nimport type {Path} from './paths.js'\n\nconst idPattern = /^[a-z0-9][a-z0-9_.-]+$/i\nconst propPattern = /^[a-zA-Z_][a-zA-Z0-9_-]*$/\nconst propStartPattern = /^[a-z_]/i\n\n/**\n * Validate the given document/subtree for Sanity compatibility\n *\n * @param item - The document or subtree to validate\n * @param path - The path to the current item, for error reporting\n * @returns True if valid, throws otherwise\n * @internal\n */\nexport function validateDocument(item: unknown, path: Path = []): boolean {\n  if (Array.isArray(item)) {\n    return item.every((child, i) => {\n      if (Array.isArray(child)) {\n        throw new DiffError('Multi-dimensional arrays not supported', path.concat(i))\n      }\n\n      return validateDocument(child, path.concat(i))\n    })\n  }\n\n  if (typeof item === 'object' && item !== null) {\n    const obj = item as {[key: string]: any}\n    return Object.keys(obj).every(\n      (key) =>\n        validateProperty(key, obj[key], path) && validateDocument(obj[key], path.concat(key)),\n    )\n  }\n\n  return true\n}\n\n/**\n * Validate a property for Sanity compatibility\n *\n * @param property - The property to valide\n * @param value - The value of the property\n * @param path - The path of the property, for error reporting\n * @returns The property name, if valid\n * @internal\n */\nexport function validateProperty(property: string, value: unknown, path: Path): string {\n  if (!propStartPattern.test(property)) {\n    throw new DiffError('Keys must start with a letter (a-z)', path.concat(property), value)\n  }\n\n  if (!propPattern.test(property)) {\n    throw new DiffError(\n      'Keys can only contain letters, numbers and underscores',\n      path.concat(property),\n      value,\n    )\n  }\n\n  if (property === '_key' || property === '_ref' || property === '_type') {\n    if (typeof value !== 'string') {\n      throw new DiffError('Keys must be strings', path.concat(property), value)\n    }\n\n    if (!idPattern.test(value)) {\n      throw new DiffError('Invalid key - use less exotic characters', path.concat(property), value)\n    }\n  }\n\n  return property\n}\n","/// <reference lib=\"esnext\" />\n\nexport function difference<T>(source: Set<T>, target: Set<T>): Set<T> {\n  if ('difference' in Set.prototype) {\n    return source.difference(target)\n  }\n\n  const result = new Set<T>()\n  for (const item of source) {\n    if (!target.has(item)) {\n      result.add(item)\n    }\n  }\n  return result\n}\n\nexport function intersection<T>(source: Set<T>, target: Set<T>): Set<T> {\n  if ('intersection' in Set.prototype) {\n    return source.intersection(target)\n  }\n\n  const result = new Set<T>()\n  for (const item of source) {\n    if (target.has(item)) {\n      result.add(item)\n    }\n  }\n  return result\n}\n","import {makePatches, stringifyPatches} from '@sanity/diff-match-patch'\nimport {DiffError} from './diffError.js'\nimport {isKeyedObject, type KeyedSanityObject, type Path, pathToString} from './paths.js'\nimport {validateProperty} from './validate.js'\nimport {\n  type Patch,\n  type UnsetPatch,\n  type DiffMatchPatch,\n  type SanityPatchMutation,\n  type SanityPatchOperations,\n  type SanitySetPatchOperation,\n  type SanityUnsetPatchOperation,\n  type SanityInsertPatchOperation,\n  type SanityDiffMatchPatchOperation,\n} from './patches.js'\nimport {difference, intersection} from './setOperations.js'\n\n/**\n * Document keys that are ignored during diff operations.\n * These are system-managed fields that should not be included in patches on\n * top-level documents and should not be diffed with diff-match-patch.\n */\nconst SYSTEM_KEYS = ['_id', '_type', '_createdAt', '_updatedAt', '_rev']\n\n/**\n * Maximum size of strings to consider for diff-match-patch (1MB)\n * Based on testing showing consistently good performance up to this size\n */\nconst DMP_MAX_STRING_SIZE = 1_000_000\n\n/**\n * Maximum difference in string length before falling back to set operations (40%)\n * Above this threshold, likely indicates text replacement which can be slow\n */\nconst DMP_MAX_STRING_LENGTH_CHANGE_RATIO = 0.4\n\n/**\n * Minimum string size to apply change ratio check (10KB)\n * Small strings are always fast regardless of change ratio\n */\nconst DMP_MIN_SIZE_FOR_RATIO_CHECK = 10_000\n\n/**\n * An object (record) that _may_ have a `_key` property\n *\n * @internal\n */\nexport type SanityObject = KeyedSanityObject | Partial<KeyedSanityObject>\n\n/**\n * Represents a partial Sanity document (eg a \"stub\").\n *\n * @public\n */\nexport interface DocumentStub {\n  _id?: string\n  _type?: string\n  _rev?: string\n  _createdAt?: string\n  _updatedAt?: string\n  [key: string]: unknown\n}\n\n/**\n * Options for the patch generator\n *\n * @public\n */\nexport interface PatchOptions {\n  /**\n   * Document ID to apply the patch to.\n   *\n   * @defaultValue `undefined` - tries to extract `_id` from passed document\n   */\n  id?: string\n\n  /**\n   * Base path to apply the patch to - useful if diffing sub-branches of a document.\n   *\n   * @defaultValue `[]` - eg root of the document\n   */\n  basePath?: Path\n\n  /**\n   * Only apply the patch if the document revision matches this value.\n   * If the property is the boolean value `true`, it will attempt to extract\n   * the revision from the document `_rev` property.\n   *\n   * @defaultValue `undefined` (do not apply revision check)\n   */\n  ifRevisionID?: string | true\n}\n\n/**\n * Generates an array of mutations for Sanity, based on the differences between\n * the two passed documents/trees.\n *\n * @param source - The first document/tree to compare\n * @param target - The second document/tree to compare\n * @param opts - Options for the diff generation\n * @returns Array of mutations\n * @public\n */\nexport function diffPatch(\n  source: DocumentStub,\n  target: DocumentStub,\n  options: PatchOptions = {},\n): SanityPatchMutation[] {\n  const id = options.id || (source._id === target._id && source._id)\n  const revisionLocked = options.ifRevisionID\n  const ifRevisionID = typeof revisionLocked === 'boolean' ? source._rev : revisionLocked\n  const basePath = options.basePath || []\n  if (!id) {\n    throw new Error(\n      '_id on source and target not present or differs, specify document id the mutations should be applied to',\n    )\n  }\n\n  if (revisionLocked === true && !ifRevisionID) {\n    throw new Error(\n      '`ifRevisionID` is set to `true`, but no `_rev` was passed in item A. Either explicitly set `ifRevisionID` to a revision, or pass `_rev` as part of item A.',\n    )\n  }\n\n  if (basePath.length === 0 && source._type !== target._type) {\n    throw new Error(`_type is immutable and cannot be changed (${source._type} => ${target._type})`)\n  }\n\n  const operations = diffItem(source, target, basePath, [])\n  return serializePatches(operations).map((patchOperations, i) => ({\n    patch: {\n      id,\n      // only add `ifRevisionID` to the first patch\n      ...(i === 0 && ifRevisionID && {ifRevisionID}),\n      ...patchOperations,\n    },\n  }))\n}\n\n/**\n * Generates an array of patch operation objects for Sanity, based on the\n * differences between the two passed values\n *\n * @param source - The source value to start off with\n * @param target - The target value that the patch operations will aim to create\n * @param basePath - An optional path that will be prefixed to all subsequent patch operations\n * @returns Array of mutations\n * @public\n */\nexport function diffValue(\n  source: unknown,\n  target: unknown,\n  basePath: Path = [],\n): SanityPatchOperations[] {\n  return serializePatches(diffItem(source, target, basePath))\n}\n\nfunction diffItem(\n  source: unknown,\n  target: unknown,\n  path: Path = [],\n  patches: Patch[] = [],\n): Patch[] {\n  if (source === target) {\n    return patches\n  }\n\n  if (typeof source === 'string' && typeof target === 'string') {\n    diffString(source, target, path, patches)\n    return patches\n  }\n\n  if (Array.isArray(source) && Array.isArray(target)) {\n    diffArray(source, target, path, patches)\n    return patches\n  }\n\n  if (isRecord(source) && isRecord(target)) {\n    diffObject(source, target, path, patches)\n    return patches\n  }\n\n  if (target === undefined) {\n    patches.push({op: 'unset', path})\n    return patches\n  }\n\n  patches.push({op: 'set', path, value: target})\n  return patches\n}\n\nfunction diffObject(\n  source: Record<string, unknown>,\n  target: Record<string, unknown>,\n  path: Path,\n  patches: Patch[],\n) {\n  const atRoot = path.length === 0\n  const aKeys = Object.keys(source)\n    .filter(atRoot ? isNotIgnoredKey : yes)\n    .map((key) => validateProperty(key, source[key], path))\n\n  const aKeysLength = aKeys.length\n  const bKeys = Object.keys(target)\n    .filter(atRoot ? isNotIgnoredKey : yes)\n    .map((key) => validateProperty(key, target[key], path))\n\n  const bKeysLength = bKeys.length\n\n  // Check for deleted items\n  for (let i = 0; i < aKeysLength; i++) {\n    const key = aKeys[i]\n    if (!(key in target)) {\n      patches.push({op: 'unset', path: path.concat(key)})\n    }\n  }\n\n  // Check for changed items\n  for (let i = 0; i < bKeysLength; i++) {\n    const key = bKeys[i]\n    diffItem(source[key], target[key], path.concat([key]), patches)\n  }\n\n  return patches\n}\n\nfunction diffArray(source: unknown[], target: unknown[], path: Path, patches: Patch[]) {\n  if (isUniquelyKeyed(source) && isUniquelyKeyed(target)) {\n    return diffArrayByKey(source, target, path, patches)\n  }\n\n  return diffArrayByIndex(source, target, path, patches)\n}\n\nfunction diffArrayByIndex(source: unknown[], target: unknown[], path: Path, patches: Patch[]) {\n  // Check for new items\n  if (target.length > source.length) {\n    patches.push({\n      op: 'insert',\n      position: 'after',\n      path: path.concat([-1]),\n      items: target.slice(source.length).map(nullifyUndefined),\n    })\n  }\n\n  // Check for deleted items\n  if (target.length < source.length) {\n    const isSingle = source.length - target.length === 1\n    const unsetItems = source.slice(target.length)\n\n    // If we have unique array keys, we'll want to unset by key, as this is\n    // safer in a realtime, collaborative setting\n    if (isUniquelyKeyed(unsetItems)) {\n      patches.push(\n        ...unsetItems.map(\n          (item): UnsetPatch => ({op: 'unset', path: path.concat({_key: item._key})}),\n        ),\n      )\n    } else {\n      patches.push({\n        op: 'unset',\n        path: path.concat([isSingle ? target.length : [target.length, '']]),\n      })\n    }\n  }\n\n  // Check for illegal array contents\n  for (let i = 0; i < target.length; i++) {\n    if (Array.isArray(target[i])) {\n      throw new DiffError('Multi-dimensional arrays not supported', path.concat(i), target[i])\n    }\n  }\n\n  const overlapping = Math.min(source.length, target.length)\n  const segmentA = source.slice(0, overlapping)\n  const segmentB = target.slice(0, overlapping)\n\n  for (let i = 0; i < segmentA.length; i++) {\n    diffItem(segmentA[i], nullifyUndefined(segmentB[i]), path.concat(i), patches)\n  }\n\n  return patches\n}\n\n/**\n * Diffs two arrays of keyed objects by their `_key` properties.\n *\n * This approach is preferred over index-based diffing for collaborative editing scenarios\n * because it generates patches that are more resilient to concurrent modifications.\n * When multiple users edit the same array simultaneously, key-based patches have better\n * conflict resolution characteristics than index-based patches.\n *\n * The function handles three main operations:\n * 1. **Reordering**: When existing items change positions within the array\n * 2. **Content changes**: When the content of existing items is modified\n * 3. **Insertions/Deletions**: When items are added or removed from the array\n *\n * @param source - The original array with keyed objects\n * @param target - The target array with keyed objects\n * @param path - The path to this array within the document\n * @param patches - Array to accumulate generated patches\n * @returns The patches array with new patches appended\n */\nfunction diffArrayByKey(\n  source: KeyedSanityObject[],\n  target: KeyedSanityObject[],\n  path: Path,\n  patches: Patch[],\n) {\n  // Create lookup maps for efficient key-based access to array items\n  const sourceItemsByKey = new Map(source.map((item) => [item._key, item]))\n  const targetItemsByKey = new Map(target.map((item) => [item._key, item]))\n\n  // Categorize keys by their presence in source vs target arrays\n  const sourceKeys = new Set(sourceItemsByKey.keys())\n  const targetKeys = new Set(targetItemsByKey.keys())\n  const keysRemovedFromSource = difference(sourceKeys, targetKeys)\n  const keysAddedToTarget = difference(targetKeys, sourceKeys)\n  const keysInBothArrays = intersection(sourceKeys, targetKeys)\n\n  // Handle reordering of existing items within the array.\n  // We detect reordering by comparing the relative positions of keys that exist in both arrays,\n  // excluding keys that were added or removed (since they don't participate in reordering).\n  const sourceKeysStillPresent = Array.from(difference(sourceKeys, keysRemovedFromSource))\n  const targetKeysAlreadyPresent = Array.from(difference(targetKeys, keysAddedToTarget))\n\n  // Track which keys need to be reordered by comparing their relative positions\n  const keyReorderOperations: {sourceKey: string; targetKey: string}[] = []\n\n  for (let i = 0; i < keysInBothArrays.size; i++) {\n    const keyAtPositionInSource = sourceKeysStillPresent[i]\n    const keyAtPositionInTarget = targetKeysAlreadyPresent[i]\n\n    // If different keys occupy the same relative position, a reorder is needed\n    if (keyAtPositionInSource !== keyAtPositionInTarget) {\n      keyReorderOperations.push({\n        sourceKey: keyAtPositionInSource,\n        targetKey: keyAtPositionInTarget,\n      })\n    }\n  }\n\n  // Generate reorder patch if any items changed positions\n  if (keyReorderOperations.length) {\n    patches.push({\n      op: 'reorder',\n      path,\n      snapshot: source,\n      reorders: keyReorderOperations,\n    })\n  }\n\n  // Process content changes for items that exist in both arrays\n  for (const key of keysInBothArrays) {\n    diffItem(sourceItemsByKey.get(key), targetItemsByKey.get(key), [...path, {_key: key}], patches)\n  }\n\n  // Remove items that no longer exist in the target array\n  for (const keyToRemove of keysRemovedFromSource) {\n    patches.push({op: 'unset', path: [...path, {_key: keyToRemove}]})\n  }\n\n  // Insert new items that were added to the target array\n  // We batch consecutive insertions for efficiency and insert them at the correct positions\n  if (keysAddedToTarget.size) {\n    let insertionAnchorKey: string // The key after which we'll insert pending items\n    let itemsPendingInsertion: unknown[] = []\n\n    const flushPendingInsertions = () => {\n      if (itemsPendingInsertion.length) {\n        patches.push({\n          op: 'insert',\n          // Insert after the anchor key if we have one, otherwise insert at the beginning\n          ...(insertionAnchorKey\n            ? {position: 'after', path: [...path, {_key: insertionAnchorKey}]}\n            : {position: 'before', path: [...path, 0]}),\n          items: itemsPendingInsertion,\n        })\n      }\n    }\n\n    // Walk through the target array to determine where new items should be inserted\n    for (const key of targetKeys) {\n      if (keysAddedToTarget.has(key)) {\n        // This is a new item - add it to the pending insertion batch\n        itemsPendingInsertion.push(targetItemsByKey.get(key)!)\n      } else if (keysInBothArrays.has(key)) {\n        // This is an existing item - flush any pending insertions before it\n        flushPendingInsertions()\n        insertionAnchorKey = key\n        itemsPendingInsertion = []\n      }\n    }\n\n    // Flush any remaining insertions at the end\n    flushPendingInsertions()\n  }\n\n  return patches\n}\n\n/**\n * Determines whether to use diff-match-patch or fallback to a `set` operation\n * when creating a patch to transform a `source` string to `target` string.\n *\n * `diffMatchPatch` patches are typically preferred to `set` operations because\n * they handle conflicts better (when multiple editors work simultaneously) by\n * preserving the user's intended and allowing for 3-way merges.\n *\n * **Heuristic rationale:**\n *\n * Perf analysis revealed that string length has minimal impact on small,\n * keystroke-level changes, but large text replacements (high change ratio) can\n * trigger worst-case algorithm behavior. The 40% change ratio threshold is a\n * simple heuristic that catches problematic replacement scenarios while\n * allowing the algorithm to excel at insertions and deletions.\n *\n * **Performance characteristics (tested on M2 MacBook Pro):**\n *\n * *Keystroke-level editing (most common use case):*\n * - Small strings (1KB-10KB): 0ms for 1-5 keystrokes, consistently sub-millisecond\n * - Medium strings (50KB-200KB): 0ms for 1-5 keystrokes, consistently sub-millisecond\n * - 10 simultaneous keystrokes: ~12ms on 100KB strings\n *\n * *Copy-paste operations (less frequent):*\n * - Small copy-paste operations (<50KB): 0-10ms regardless of string length\n * - Large insertions/deletions (50KB+): 0-50ms (excellent performance)\n * - Large text replacements (50KB+): 70ms-2s+ (can be slow due to algorithm complexity)\n *\n * **Algorithm details:**\n * Uses Myers' diff algorithm with O(ND) time complexity where N=text length and D=edit distance.\n * Includes optimizations: common prefix/suffix removal, line-mode processing, and timeout protection.\n *\n *\n * **Test methodology:**\n * - Generated realistic word-based text patterns\n * - Simulated actual editing behaviors (keystrokes vs copy-paste)\n * - Measured performance across string sizes from 1KB to 10MB\n * - Validated against edge cases including repetitive text and scattered changes\n *\n * @param source - The previous version of the text\n * @param target - The new version of the text\n * @returns true if diff-match-patch should be used, false if fallback to set operation\n *\n * @example\n * ```typescript\n * // Keystroke editing - always fast\n * shouldUseDiffMatchPatch(largeDoc, largeDocWithTypo) // true, ~0ms\n *\n * // Small paste - always fast\n * shouldUseDiffMatchPatch(doc, docWithSmallInsertion) // true, ~0ms\n *\n * // Large replacement - potentially slow\n * shouldUseDiffMatchPatch(article, completelyDifferentArticle) // false, use set\n * ```\n *\n * Compatible with @sanity/diff-match-patch@3.2.0\n */\nexport function shouldUseDiffMatchPatch(source: string, target: string): boolean {\n  const maxLength = Math.max(source.length, target.length)\n\n  // Always reject strings larger than our tested size limit\n  if (maxLength > DMP_MAX_STRING_SIZE) {\n    return false\n  }\n\n  // For small strings, always use diff-match-patch regardless of change ratio\n  // Performance testing showed these are always fast (<10ms)\n  if (maxLength < DMP_MIN_SIZE_FOR_RATIO_CHECK) {\n    return true\n  }\n\n  // Calculate the change ratio to detect large text replacements\n  // High ratios indicate replacement scenarios which can trigger slow algorithm paths\n  const lengthDifference = Math.abs(target.length - source.length)\n  const changeRatio = lengthDifference / maxLength\n\n  // If change ratio is high, likely a replacement operation that could be slow\n  // Fall back to set operation for better user experience\n  if (changeRatio > DMP_MAX_STRING_LENGTH_CHANGE_RATIO) {\n    return false\n  }\n\n  // All other cases: use diff-match-patch\n  // This covers keystroke editing and insertion/deletion scenarios which perform excellently\n  return true\n}\n\nfunction getDiffMatchPatch(source: string, target: string, path: Path): DiffMatchPatch | undefined {\n  const last = path.at(-1)\n  // don't use diff-match-patch for system keys\n  if (typeof last === 'string' && last.startsWith('_')) return undefined\n  if (!shouldUseDiffMatchPatch(source, target)) return undefined\n\n  try {\n    // Using `makePatches(string, string)` directly instead of the multi-step approach e.g.\n    // `stringifyPatches(makePatches(cleanupEfficiency(makeDiff(source, target))))`.\n    // this is because `makePatches` internally handles diff generation and\n    // automatically applies both `cleanupSemantic()` and `cleanupEfficiency()`\n    // when beneficial, resulting in cleaner code with near identical performance and\n    // better error handling.\n    // [source](https://github.com/sanity-io/diff-match-patch/blob/v3.2.0/src/patch/make.ts#L67-L76)\n    //\n    // Performance validation (M2 MacBook Pro):\n    // Both approaches measured at identical performance:\n    // - 10KB strings: 0-1ms total processing time\n    // - 100KB strings: 0-1ms total processing time\n    // - Individual step breakdown: makeDiff(0ms) + cleanup(0ms) + makePatches(0ms) + stringify(~1ms)\n    const strPatch = stringifyPatches(makePatches(source, target))\n    return {op: 'diffMatchPatch', path, value: strPatch}\n  } catch (err) {\n    // Fall back to using regular set patch\n    return undefined\n  }\n}\n\nfunction diffString(source: string, target: string, path: Path, patches: Patch[]) {\n  const dmp = getDiffMatchPatch(source, target, path)\n  patches.push(dmp ?? {op: 'set', path, value: target})\n  return patches\n}\n\nfunction isNotIgnoredKey(key: string) {\n  return SYSTEM_KEYS.indexOf(key) === -1\n}\n\n// mutually exclusive operations\ntype SanityPatchOperation =\n  | SanitySetPatchOperation\n  | SanityUnsetPatchOperation\n  | SanityInsertPatchOperation\n  | SanityDiffMatchPatchOperation\n\nfunction serializePatches(patches: Patch[], curr?: SanityPatchOperation): SanityPatchOperations[] {\n  const [patch, ...rest] = patches\n  if (!patch) return curr ? [curr] : []\n\n  switch (patch.op) {\n    case 'set':\n    case 'diffMatchPatch': {\n      // TODO: reconfigure eslint to use @typescript-eslint/no-unused-vars\n      // eslint-disable-next-line no-unused-vars\n      type CurrentOp = Extract<SanityPatchOperation, {[K in typeof patch.op]: {}}>\n      const emptyOp = {[patch.op]: {}} as CurrentOp\n\n      if (!curr) return serializePatches(patches, emptyOp)\n      if (!(patch.op in curr)) return [curr, ...serializePatches(patches, emptyOp)]\n\n      Object.assign((curr as CurrentOp)[patch.op], {[pathToString(patch.path)]: patch.value})\n      return serializePatches(rest, curr)\n    }\n    case 'unset': {\n      const emptyOp = {unset: []}\n      if (!curr) return serializePatches(patches, emptyOp)\n      if (!('unset' in curr)) return [curr, ...serializePatches(patches, emptyOp)]\n\n      curr.unset.push(pathToString(patch.path))\n      return serializePatches(rest, curr)\n    }\n    case 'insert': {\n      if (curr) return [curr, ...serializePatches(patches)]\n\n      return [\n        {\n          insert: {\n            [patch.position]: pathToString(patch.path),\n            items: patch.items,\n          },\n        } as SanityInsertPatchOperation,\n        ...serializePatches(rest),\n      ]\n    }\n    case 'reorder': {\n      if (curr) return [curr, ...serializePatches(patches)]\n\n      // REORDER STRATEGY: Two-phase approach to avoid key collisions\n      //\n      // Problem: Direct key swaps can cause collisions. For example, swapping A↔B:\n      // - Set A's content to B: ✓\n      // - Set B's content to A: ✗ (A's content was already overwritten)\n      //\n      // Solution: Use temporary keys as an intermediate step\n      // Phase 1: Move all items to temporary keys with their final content\n      // Phase 2: Update just the _key property to restore the final keys\n\n      // Phase 1: Move items to collision-safe temporary keys\n      const tempKeyOperations: SanityPatchOperations = {}\n      tempKeyOperations.set = {}\n\n      for (const {sourceKey, targetKey} of patch.reorders) {\n        const temporaryKey = `__temp_reorder_${sourceKey}__`\n        const finalContentForThisPosition =\n          patch.snapshot[getIndexForKey(patch.snapshot, targetKey)]\n\n        Object.assign(tempKeyOperations.set, {\n          [pathToString([...patch.path, {_key: sourceKey}])]: {\n            ...finalContentForThisPosition,\n            _key: temporaryKey,\n          },\n        })\n      }\n\n      // Phase 2: Update _key properties to restore the intended final keys\n      const finalKeyOperations: SanityPatchOperations = {}\n      finalKeyOperations.set = {}\n\n      for (const {sourceKey, targetKey} of patch.reorders) {\n        const temporaryKey = `__temp_reorder_${sourceKey}__`\n\n        Object.assign(finalKeyOperations.set, {\n          [pathToString([...patch.path, {_key: temporaryKey}, '_key'])]: targetKey,\n        })\n      }\n\n      return [tempKeyOperations, finalKeyOperations, ...serializePatches(rest)]\n    }\n    default: {\n      return []\n    }\n  }\n}\n\nfunction isUniquelyKeyed(arr: unknown[]): arr is KeyedSanityObject[] {\n  const seenKeys = new Set<string>()\n\n  for (const item of arr) {\n    // Each item must be a keyed object with a _key property\n    if (!isKeyedObject(item)) return false\n\n    // Each _key must be unique within the array\n    if (seenKeys.has(item._key)) return false\n\n    seenKeys.add(item._key)\n  }\n\n  return true\n}\n\n// Cache to avoid recomputing key-to-index mappings for the same array\nconst keyToIndexCache = new WeakMap<KeyedSanityObject[], Record<string, number>>()\n\nfunction getIndexForKey(keyedArray: KeyedSanityObject[], targetKey: string) {\n  const cachedMapping = keyToIndexCache.get(keyedArray)\n  if (cachedMapping) return cachedMapping[targetKey]\n\n  // Build a mapping from _key to array index\n  const keyToIndexMapping = keyedArray.reduce<Record<string, number>>(\n    (mapping, {_key}, arrayIndex) => {\n      mapping[_key] = arrayIndex\n      return mapping\n    },\n    {},\n  )\n\n  keyToIndexCache.set(keyedArray, keyToIndexMapping)\n\n  return keyToIndexMapping[targetKey]\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === 'object' && !!value && !Array.isArray(value)\n}\n\n/**\n * Simplify returns `null` if the value given was `undefined`. This behavior\n * is the same as how `JSON.stringify` works so this is relatively expected\n * behavior.\n */\nfunction nullifyUndefined(item: unknown) {\n  if (item === undefined) return null\n  return item\n}\n\nfunction yes(_: unknown) {\n  return true\n}\n"],"names":["stringifyPatches","makePatches"],"mappings":"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"}