{"_id":"@sanity/diff-patch","_rev":"72-00396a2a071d3c249675ca9f9237dd9f","name":"@sanity/diff-patch","dist-tags":{"latest":"7.0.0"},"versions":{"5.0.0":{"name":"@sanity/diff-patch","version":"5.0.0","keywords":["sanity","patch","diff","mutation","compare"],"author":{"name":"Sanity.io","email":"hello@sanity.io"},"license":"MIT","_id":"@sanity/diff-patch@5.0.0","maintainers":[{"name":"kmelve","email":"knut.melvaer@gmail.com"},{"name":"bjoerge","email":"bjoerge@gmail.com"},{"name":"rexxars","email":"espen@hovlandsdal.com"},{"name":"skogsmaskin","email":"per.kristian.nordnes@gmail.com"},{"name":"tonina","email":"zhelyazkova.tonina@gmail.com"},{"name":"mattcraig","email":"matt@sanity.io"},{"name":"joneidejohnsen","email":"jon@sanity.io"},{"name":"rubioz","email":"jarubc@gmail.com"},{"name":"robinpyon","email":"robin@robinpyon.com"},{"name":"mariuslundgard","email":"studio@mariuslundgard.com"},{"name":"sanity-io","email":"developers@sanity.io"},{"name":"evenw","email":"even@sanity.io"},{"name":"radhe_sanity","email":"radhe@sanity.io"},{"name":"rbotten","email":"rbotten@gmail.com"},{"name":"danielsgroves","email":"hello@danielgroves.net"},{"name":"judofyr","email":"judofyr@gmail.com"},{"name":"ryanblock","email":"rblock+npm@gmail.com"},{"name":"obliadp","email":"orjan@sanity.io"},{"name":"dcilke","email":"dain.cilke@gmail.com"},{"name":"madken","email":"kenneth.madsen@sanity.io"},{"name":"fredcarlsen","email":"fred@superbig.co"},{"name":"hermanw","email":"herman@sanity.io"},{"name":"tambet","email":"tambet.masik@gmail.com"},{"name":"sgulseth","email":"sgulseth@gmail.com"},{"name":"atombender","email":"npm@purefiction.net"},{"name":"simeonsanity","email":"simeon@sanity.io"},{"name":"stipsan","email":"stipsan@gmail.com"},{"name":"snorreeb","email":"snorre.e.brekke@gmail.com"},{"name":"rankers","email":"richardankers@gmail.com"},{"name":"rdunk","email":"rupert@rupertdunk.com"},{"name":"michael-sanity","email":"michael@sanity.io"},{"name":"vincentquigley","email":"vincent@sanity.io"},{"name":"ritasdias","email":"anarita151@gmail.com"},{"name":"kenjonespizza","email":"ken@sanity.io"},{"name":"rneatherway-sanity","email":"robin.neatherway@sanity.io"},{"name":"josh_sanity_io","email":"josh@sanity.io"},{"name":"cngonzalez-sanity","email":"carolina@sanity.io"},{"name":"jjburbridge","email":"jonathan.burbridge@sanity.io"},{"name":"tdfka_rick","email":"joshua.ellis18@gmail.com"},{"name":"svirs","email":"shur@sanity.io"},{"name":"ryanbonial-sanity","email":"ryan.bonial@sanity.io"},{"name":"indrek.karner","email":"indrek.karner@sanity.io"},{"name":"ash","email":"ashley@juice49.com"},{"name":"sergeisarviro","email":"sergei@sanity.io"},{"name":"refiito","email":"margus@sanity.io"},{"name":"drewsanity","email":"drew.lyton@sanity.io"},{"name":"kaspar.lippmaa.sanity","email":"kaspar.lippmaa@sanity.io"},{"name":"dam","email":"kristoferjoseph@gmail.com"},{"name":"simen.svale","email":"simen@sanity.io"},{"name":"tbeseda","email":"tbeseda@gmail.com"},{"name":"daniel.malmer","email":"daniel.malmer@sanity.io"},{"name":"jordanl17","email":"jordanl17@me.com"},{"name":"colepeters","email":"cole@colepeters.com"},{"name":"armandocerna","email":"armando@cerna.ca"},{"name":"joan_miralles_paez","email":"joan.miralles@sanity.io"},{"name":"christianhg","email":"services@groengaard.dk"},{"name":"pedro-sanity","email":"pedro@sanity.io"},{"name":"jwoods-sanity","email":"james.woods@sanity.io"},{"name":"ricokahler","email":"ricokahler@me.com"},{"name":"tiit.kass.saity","email":"tiit.kass@sanity.io"},{"name":"binoy14","email":"me@binoy.io"},{"name":"pauloborgesf","email":"paulo@sanity.io"},{"name":"ausha","email":"ausha@sanity.io"},{"name":"nuurtamo","email":"esa.nuurtamo@gmail.com"},{"name":"chrislarocquesanity","email":"chris.larocque@sanity.io"},{"name":"rostimelk","email":"hello@rosti.no"},{"name":"mattlewine.sanity","email":"matt.lewine@sanity.io"},{"name":"msfragala","email":"ms.fragala@gmail.com"},{"name":"adoprog","email":"adoprog@gmail.com"},{"name":"tonysanity","email":"tony.lepmets@sanity.io"},{"name":"mrmrs","email":"hi@mrmrs.cc"}],"dist":{"shasum":"028af6ff1dbdf24fa071e44a6ca6ce755a0cec71","tarball":"https://registry.npmjs.org/@sanity/diff-patch/-/diff-patch-5.0.0.tgz","fileCount":15,"integrity":"sha512-JASdNaZsxUFBx8GQ1sX2XehYhdhOcurh7KwzQ3cXgOTdjvIQyQcLwmMeYCsU/K26GiI81ODbCEb/C0c92t2Unw==","signatures":[{"sig":"MEQCIEa46yM4nxqoU+ogJMfWWDk3MheqD9Xa0qVG3P2cWljhAiBDm/cgPQRIM3LH7dJ5d9EbP5qLtTpW/wcJClNpcC5Z5Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":123210},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.2"},"exports":{".":{"import":"./dist/index.js","source":"./src/index.ts","default":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"gitHead":"fea3b6263f7efeeb65b780fac69171175f10ad71","scripts":{"lint":"eslint . && tsc --noEmit","test":"vitest --reporter=verbose","build":"pkg-utils build && pkg-utils --strict","clean":"rimraf dist coverage","coverage":"vitest --coverage","posttest":"npm run lint","prebuild":"npm run clean","prepublishOnly":"npm run build"},"_npmUser":{"name":"sanity-io","email":"developers@sanity.io"},"prettier":{"semi":false,"printWidth":100,"singleQuote":true,"bracketSpacing":false},"_npmVersion":"10.9.2","description":"Generates a set of Sanity patches needed to change an item (usually a document) from one shape to another","directories":{},"sideEffects":false,"_nodeVersion":"22.13.1","browserslist":"extends @sanity/browserslist-config","dependencies":{"@sanity/diff-match-patch":"^3.2.0"},"eslintConfig":{"extends":["sanity","sanity/typescript","prettier"],"parserOptions":{"sourceType":"module","ecmaVersion":9,"ecmaFeatures":{"modules":true}}},"_hasShrinkwrap":false,"packageManager":"pnpm@9.12.1","devDependencies":{"vite":"^5.4.14","eslint":"^8.57.1","rimraf":"^6.0.1","vitest":"^2.1.9","p-queue":"^8.1.0","prettier":"^3.4.2","typescript":"^5.7.3","@sanity/client":"^6.27.2","semantic-release":"^24.2.1","@sanity/pkg-utils":"^6.13.4","@vitest/coverage-v8":"2.1.3","eslint-config-sanity":"^6.0.0","eslint-config-prettier":"^8.10.0","rollup-plugin-visualizer":"^5.14.0","@typescript-eslint/parser":"^5.62.0","@sanity/semantic-release-preset":"^5.0.0","@typescript-eslint/eslint-plugin":"^5.62.0"},"_npmOperationalInternal":{"tmp":"tmp/diff-patch_5.0.0_1738718428737_0.5921562075714717","host":"s3://npm-registry-packages-npm-production"}},"6.0.0":{"name":"@sanity/diff-patch","version":"6.0.0","keywords":["sanity","patch","diff","mutation","compare"],"author":{"name":"Sanity.io","email":"hello@sanity.io"},"license":"MIT","_id":"@sanity/diff-patch@6.0.0","maintainers":[{"name":"kmelve","email":"knut.melvaer@gmail.com"},{"name":"bjoerge","email":"bjoerge@gmail.com"},{"name":"rexxars","email":"espen@hovlandsdal.com"},{"name":"skogsmaskin","email":"per.kristian.nordnes@gmail.com"},{"name":"tonina","email":"zhelyazkova.tonina@gmail.com"},{"name":"mattcraig","email":"matt@sanity.io"},{"name":"joneidejohnsen","email":"jon@sanity.io"},{"name":"rubioz","email":"jarubc@gmail.com"},{"name":"robinpyon","email":"robin@robinpyon.com"},{"name":"mariuslundgard","email":"studio@mariuslundgard.com"},{"name":"sanity-io","email":"developers@sanity.io"},{"name":"evenw","email":"even@sanity.io"},{"name":"radhe_sanity","email":"radhe@sanity.io"},{"name":"rbotten","email":"rbotten@gmail.com"},{"name":"danielsgroves","email":"hello@danielgroves.net"},{"name":"judofyr","email":"judofyr@gmail.com"},{"name":"ryanblock","email":"rblock+npm@gmail.com"},{"name":"obliadp","email":"orjan@sanity.io"},{"name":"dcilke","email":"dain.cilke@gmail.com"},{"name":"madken","email":"kenneth.madsen@sanity.io"},{"name":"fredcarlsen","email":"fred@superbig.co"},{"name":"hermanw","email":"herman@sanity.io"},{"name":"tambet","email":"tambet.masik@gmail.com"},{"name":"sgulseth","email":"sgulseth@gmail.com"},{"name":"atombender","email":"npm@purefiction.net"},{"name":"simeonsanity","email":"simeon@sanity.io"},{"name":"stipsan","email":"stipsan@gmail.com"},{"name":"snorreeb","email":"snorre.e.brekke@gmail.com"},{"name":"rankers","email":"richardankers@gmail.com"},{"name":"rdunk","email":"rupert@rupertdunk.com"},{"name":"michael-sanity","email":"michael@sanity.io"},{"name":"vincentquigley","email":"vincent@sanity.io"},{"name":"ritasdias","email":"anarita151@gmail.com"},{"name":"kenjonespizza","email":"ken@sanity.io"},{"name":"rneatherway-sanity","email":"robin.neatherway@sanity.io"},{"name":"josh_sanity_io","email":"josh@sanity.io"},{"name":"cngonzalez-sanity","email":"carolina@sanity.io"},{"name":"jjburbridge","email":"jonathan.burbridge@sanity.io"},{"name":"tdfka_rick","email":"joshua.ellis18@gmail.com"},{"name":"svirs","email":"shur@sanity.io"},{"name":"ryanbonial-sanity","email":"ryan.bonial@sanity.io"},{"name":"indrek.karner","email":"indrek.karner@sanity.io"},{"name":"ash","email":"ashley@juice49.com"},{"name":"sergeisarviro","email":"sergei@sanity.io"},{"name":"refiito","email":"margus@sanity.io"},{"name":"drewsanity","email":"drew.lyton@sanity.io"},{"name":"kaspar.lippmaa.sanity","email":"kaspar.lippmaa@sanity.io"},{"name":"dam","email":"kristoferjoseph@gmail.com"},{"name":"simen.svale","email":"simen@sanity.io"},{"name":"tbeseda","email":"tbeseda@gmail.com"},{"name":"daniel.malmer","email":"daniel.malmer@sanity.io"},{"name":"jordanl17","email":"jordanl17@me.com"},{"name":"colepeters","email":"cole@colepeters.com"},{"name":"armandocerna","email":"armando@cerna.ca"},{"name":"joan_miralles_paez","email":"joan.miralles@sanity.io"},{"name":"christianhg","email":"services@groengaard.dk"},{"name":"pedro-sanity","email":"pedro@sanity.io"},{"name":"jwoods-sanity","email":"james.woods@sanity.io"},{"name":"ricokahler","email":"ricokahler@me.com"},{"name":"tiit.kass.saity","email":"tiit.kass@sanity.io"},{"name":"binoy14","email":"me@binoy.io"},{"name":"pauloborgesf","email":"paulo@sanity.io"},{"name":"ausha","email":"ausha@sanity.io"},{"name":"chrislarocquesanity","email":"chris.larocque@sanity.io"},{"name":"rostimelk","email":"hello@rosti.no"},{"name":"mattlewine.sanity","email":"matt.lewine@sanity.io"},{"name":"msfragala","email":"ms.fragala@gmail.com"},{"name":"adoprog","email":"adoprog@gmail.com"},{"name":"tonysanity","email":"tony.lepmets@sanity.io"},{"name":"mrmrs","email":"hi@mrmrs.cc"},{"name":"betson","email":"ben.getson@gmail.com"},{"name":"georgedoescode","email":"georgedoescode@gmail.com"},{"name":"macdonst","email":"simon.macdonald@gmail.com"},{"name":"eoinsanity","email":"eoin.falconer@sanity.io"},{"name":"dashedstripes","email":"adamgrayscale@gmail.com"},{"name":"jmswrnr","email":"npm@jmswrnr.com"},{"name":"snocorp_sanity","email":"dave.sewell@sanity.io"},{"name":"mmgj","email":"controloptioncommand+npm@gmail.com"},{"name":"filmaj","email":"maj.fil@gmail.com"},{"name":"samhem","email":"sam.hemingway@sanity.io"},{"name":"gu-stav","email":"gu@stav.dev"},{"name":"patricksanity","email":"patrick.mccarthy@sanity.io"},{"name":"mads.mogenshoj","email":"mads.mogenshoj@sanity.io"},{"name":"sanitytom","email":"tom@sanity.io"},{"name":"sanity-cb","email":"charlie.brown@sanity.io"},{"name":"mm-sanity","email":"mark.michon@sanity.io"},{"name":"sanitykev","email":"kevin.green@sanity.io"},{"name":"victor.ayogu","email":"victor.ayogu@sanity.io"},{"name":"ryanbethel_sanity","email":"ryan.bethel@sanity.io"},{"name":"brianleroux","email":"b@brian.io"}],"homepage":"https://github.com/sanity-io/diff-patch#readme","bugs":{"url":"https://github.com/sanity-io/diff-patch/issues"},"dist":{"shasum":"5f83a7a036b1cd70a9babe88b6e24d69ac07963b","tarball":"https://registry.npmjs.org/@sanity/diff-patch/-/diff-patch-6.0.0.tgz","fileCount":16,"integrity":"sha512-oJ5kZQV6C/DAlcpRLEU7AcVWXrSPuJb3Z1TQ9tm/qZOVWJENwWln45jtepQEYolTIuGx9jUlhYUi3hGIkOt8RA==","signatures":[{"sig":"MEYCIQDI1VV/GMzjR3bF2rc7N5Mq1sUDp/Yu/+G/lmAbsn4ZfAIhAO7szR/0IYmH6TtTYBZc3vu+sbfqRpHVdzA20IkldeIT","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":154423},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","engines":{"node":">=18.2"},"exports":{".":{"import":"./dist/index.js","source":"./src/index.ts","default":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"gitHead":"353d963300710261ae682b9e9bebd74fd2fc57ed","scripts":{"lint":"eslint . && tsc --noEmit","test":"vitest --reporter=verbose","build":"pkg-utils build && pkg-utils --strict","clean":"rimraf dist coverage","coverage":"vitest --coverage","posttest":"npm run lint","prebuild":"npm run clean","prepublishOnly":"npm run build"},"_npmUser":{"name":"sanity-io","email":"developers@sanity.io"},"prettier":{"semi":false,"printWidth":100,"singleQuote":true,"bracketSpacing":false},"repository":{"url":"git+ssh://git@github.com/sanity-io/diff-patch.git","type":"git"},"_npmVersion":"10.9.2","description":"Generates a set of Sanity patches needed to change an item (usually a document) from one shape to another","directories":{},"sideEffects":false,"_nodeVersion":"22.16.0","browserslist":"extends @sanity/browserslist-config","dependencies":{"@sanity/diff-match-patch":"^3.2.0"},"eslintConfig":{"extends":["sanity","sanity/typescript","prettier"],"parserOptions":{"sourceType":"module","ecmaVersion":9,"ecmaFeatures":{"modules":true}}},"_hasShrinkwrap":false,"packageManager":"pnpm@9.12.1","devDependencies":{"vite":"^5.4.14","eslint":"^8.57.1","rimraf":"^6.0.1","vitest":"^2.1.9","p-queue":"^8.1.0","prettier":"^3.4.2","typescript":"^5.7.3","@sanity/client":"^6.27.2","semantic-release":"^24.2.1","@sanity/pkg-utils":"^6.13.4","@vitest/coverage-v8":"2.1.3","eslint-config-sanity":"^6.0.0","eslint-config-prettier":"^8.10.0","rollup-plugin-visualizer":"^5.14.0","@typescript-eslint/parser":"^5.62.0","@sanity/semantic-release-preset":"^5.0.0","@typescript-eslint/eslint-plugin":"^5.62.0"},"_npmOperationalInternal":{"tmp":"tmp/diff-patch_6.0.0_1749845273889_0.41108157765485753","host":"s3://npm-registry-packages-npm-production"}},"7.0.0":{"_id":"@sanity/diff-patch@7.0.0","dist":{"shasum":"1875867c6e3eff435688aea6493c157ad5819b37","tarball":"https://registry.npmjs.org/@sanity/diff-patch/-/diff-patch-7.0.0.tgz","fileCount":14,"integrity":"sha512-e/xGFPWtDN5ZafxtG/DcP4URBk3EPblR+Ett1pT3AmiViNLPkHfwnG/Jj4+DlHkvcKTSw6jebuGVEFkumAxHQg==","signatures":[{"sig":"MEQCIBo7YJGo+yTVRWHxPX1NI6XSi/xmaAtEN/zzPEhEscKdAiAmHxbkve2p84gD2g8FKo98j7aWTGp+lNMqTfrZhVuBHw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCLZbgnWMvSRulJVPasZhMPSGRR98y17onSbTHeNK+/HgIhAMOMCJJ8GWUiy3LsPUZGSAKr3Usj8w1QesuOjG51XSHC"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@sanity%2fdiff-patch@7.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":104080},"main":"./dist/index.js","name":"@sanity/diff-patch","type":"module","types":"./dist/index.d.ts","author":"Sanity.io <hello@sanity.io>","module":"./dist/index.js","engines":{"node":">=22.12.0"},"exports":{".":"./dist/index.js","./package.json":"./package.json"},"license":"MIT","scripts":{"lint":"oxlint --deny-warnings . && tsc --noEmit","test":"vitest run","build":"pkg-utils build && pkg-utils check --strict","check":"knip","clean":"rimraf dist coverage","format":"oxfmt --write .","release":"changeset publish","coverage":"vitest run --coverage","changeset":"changeset","test:watch":"vitest","format:check":"oxfmt --check .","version-packages":"changeset version && pnpm install --lockfile-only && oxfmt --write package.json"},"version":"7.0.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:fd698168-f440-4d23-9b6f-cec459ede6eb"}},"keywords":["compare","diff","mutation","patch","sanity"],"repository":{"url":"git+ssh://git@github.com/sanity-io/diff-patch.git","type":"git"},"description":"Generates a set of Sanity patches needed to change an item (usually a document) from one shape to another","directories":{},"maintainers":[{"name":"sanity-svc.npm","email":"svc.npm@sanity.io"},{"name":"sanity-io","email":"developers@sanity.io"}],"sideEffects":false,"browserslist":"extends @sanity/browserslist-config","dependencies":{"@sanity/diff-match-patch":"^3.2.1"},"publishConfig":{"provenance":true},"_hasShrinkwrap":false,"devDependencies":{"knip":"^6.37.0","vite":"^8.3.0","oxfmt":"^0.70.0","oxlint":"^1.85.0","rimraf":"^6.1.3","vitest":"^5.0.1","p-queue":"^9.3.3","typescript":"^7.0.2","@types/node":"^22.20.4","@sanity/client":"^8.6.2","@changesets/cli":"^3.0.3","@sanity/pkg-utils":"^13.0.2","@vitest/coverage-v8":"^5.0.1","@rexxars/bundle-stats":"^2.0.0","@changesets/changelog-github":"^1.0.1"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/diff-patch_7.0.0_1790102961150_0.5948906676933223"}}},"time":{"created":"2025-02-05T01:20:28.735Z","modified":"2026-09-22T18:49:21.611Z","5.0.0":"2025-02-05T01:20:28.914Z","6.0.0":"2025-06-13T20:07:54.093Z","7.0.0":"2026-09-22T18:49:21.228Z"},"author":"Sanity.io <hello@sanity.io>","license":"MIT","keywords":["compare","diff","mutation","patch","sanity"],"repository":{"url":"git+ssh://git@github.com/sanity-io/diff-patch.git","type":"git"},"description":"Generates a set of Sanity patches needed to change an item (usually a document) from one shape to another","maintainers":[{"name":"sanity-svc.npm","email":"svc.npm@sanity.io"},{"name":"sanity-io","email":"developers@sanity.io"}],"readme":"# @sanity/diff-patch\n\n[![Latest version](https://npmx.dev/api/registry/badge/version/@sanity/diff-patch?color=69E3EE)](https://npmx.dev/package/@sanity/diff-patch)\n[![Number of dependencies](https://npmx.dev/api/registry/badge/dependencies/@sanity/diff-patch?color=69E3EE)](https://npmx.dev/package/@sanity/diff-patch)\n[![Supported node versions](https://npmx.dev/api/registry/badge/engines/@sanity/diff-patch?color=69E3EE)](https://npmx.dev/package/@sanity/diff-patch)\n[![Downloads per month](https://npmx.dev/api/registry/badge/downloads/@sanity/diff-patch?color=69E3EE)](https://npmx.dev/package/@sanity/diff-patch)\n\nGenerate Sanity patch mutations by comparing two documents or values. This library creates conflict-resistant patches designed for collaborative editing environments where multiple users may be editing the same document simultaneously.\n\n## Objectives\n\n- **Conflict-resistant patches**: Generate operations that work well in 3-way merges and collaborative scenarios\n- **Performance**: Optimized for real-time, per-keystroke patch generation\n- **Intent preservation**: Capture the user's intended change rather than just the final state\n- **Reliability**: Consistent, well-tested behavior across different data types and editing patterns\n\nUsed internally by the Sanity App SDK for its collaborative editing system.\n\n## Installation\n\nRequires Node.js 22.12.0 or later. This package ships ES modules only.\n\nTo work on this repository, use Node.js 24 (`nvm use`) and the pnpm version specified in `package.json`.\n\n```bash\nnpm install @sanity/diff-patch\n```\n\n## API Reference\n\n### `diffPatch(source, target, options?)`\n\nGenerate patch mutations to transform a source document into a target document.\n\n**Parameters:**\n\n- `source: DocumentStub` - The original document\n- `target: DocumentStub` - The desired document state\n- `options?: PatchOptions` - Configuration options\n\n**Returns:** `SanityPatchMutation[]` - Array of patch mutations\n\n**Options:**\n\n```typescript\ninterface PatchOptions {\n  id?: string // Document ID (extracted from _id if not provided)\n  basePath?: Path // Base path for patches (default: [])\n  ifRevisionID?: string | true // Revision lock for optimistic updates\n}\n```\n\n**Example:**\n\n```js\nimport {diffPatch} from '@sanity/diff-patch'\n\nconst source = {\n  _id: 'movie-123',\n  _type: 'movie',\n  _rev: 'abc',\n  title: 'The Matrix',\n  year: 1999,\n}\n\nconst target = {\n  _id: 'movie-123',\n  _type: 'movie',\n  title: 'The Matrix Reloaded',\n  year: 2003,\n  director: 'The Wachowskis',\n}\n\nconst mutations = diffPatch(source, target, {ifRevisionID: true})\n// [\n//   {\n//     patch: {\n//       id: 'movie-123',\n//       ifRevisionID: 'abc',\n//       set: {\n//         title: 'The Matrix Reloaded',\n//         year: 2003,\n//         director: 'The Wachowskis'\n//       }\n//     }\n//   }\n// ]\n```\n\n### `diffValue(source, target, basePath?)`\n\nGenerate patch operations for values without document wrapper.\n\n**Parameters:**\n\n- `source: unknown` - The original value\n- `target: unknown` - The desired value state\n- `basePath?: Path` - Base path to prefix operations (default: [])\n\n**Returns:** `SanityPatchOperations[]` - Array of patch operations\n\n**Example:**\n\n```js\nimport {diffValue} from '@sanity/diff-patch'\n\nconst source = {\n  name: 'John',\n  tags: ['developer'],\n}\n\nconst target = {\n  name: 'John Doe',\n  tags: ['developer', 'typescript'],\n  active: true,\n}\n\nconst operations = diffValue(source, target)\n// [\n//   {\n//     set: {\n//       name: 'John Doe',\n//       'tags[1]': 'typescript',\n//       active: true\n//     }\n//   }\n// ]\n\n// With base path\nconst operations = diffValue(source, target, ['user', 'profile'])\n// [\n//   {\n//     set: {\n//       'user.profile.name': 'John Doe',\n//       'user.profile.tags[1]': 'typescript',\n//       'user.profile.active': true\n//     }\n//   }\n// ]\n```\n\n## Collaborative Editing Example\n\nThe library generates patches that preserve user intent and minimize conflicts in collaborative scenarios:\n\n```js\n// Starting document\nconst originalDoc = {\n  _id: 'blog-post-123',\n  _type: 'blogPost',\n  title: 'Getting Started with Sanity',\n  paragraphs: [\n    {\n      _key: 'intro',\n      _type: 'paragraph',\n      text: 'Sanity is a complete content operating system for modern applications.',\n    },\n    {\n      _key: 'benefits',\n      _type: 'paragraph',\n      text: 'It offers real-time collaboration and gives developers controll over the entire stack.',\n    },\n    {\n      _key: 'conclusion',\n      _type: 'paragraph',\n      text: 'Learning Sanity will help you take control of your content workflow.',\n    },\n  ],\n}\n\n// User A reorders paragraphs AND fixes a typo\nconst userAChanges = {\n  ...originalDoc,\n  paragraphs: [\n    {\n      _key: 'intro',\n      _type: 'paragraph',\n      text: 'Sanity is a complete content operating system for modern applications.',\n    },\n    {\n      _key: 'conclusion', // Moved conclusion before benefits\n      _type: 'paragraph',\n      text: 'Learning Sanity will help you take control of your content workflow.',\n    },\n    {\n      _key: 'benefits',\n      _type: 'paragraph',\n      text: 'It offers real-time collaboration and gives developers control over the entire stack.', // Fixed typo: \"controll\" → \"control\"\n    },\n  ],\n}\n\n// User B simultaneously improves the intro text\nconst userBChanges = {\n  ...originalDoc,\n  paragraphs: [\n    {\n      _key: 'intro',\n      _type: 'paragraph',\n      text: 'Sanity is a complete content operating system that gives developers control over the entire stack.', // Added more specific language about developer control\n    },\n    {\n      _key: 'benefits',\n      _type: 'paragraph',\n      text: 'It offers real-time collaboration and gives developers control over the entire stack.',\n    },\n    {\n      _key: 'conclusion',\n      _type: 'paragraph',\n      text: 'Learning Sanity will help you take control of your content workflow.',\n    },\n  ],\n}\n\n// Generate patches that capture each user's intent\nconst patchA = diffPatch(originalDoc, userAChanges)\nconst patchB = diffPatch(originalDoc, userBChanges)\n\n// Apply both patches - they merge successfully because they target different aspects\n// User A's reordering and typo fix + User B's content improvement both apply\nconst finalMergedResult = {\n  _id: 'blog-post-123',\n  _type: 'blogPost',\n  title: 'Getting Started with Sanity',\n  paragraphs: [\n    {\n      _key: 'intro',\n      _type: 'paragraph',\n      text: 'Sanity is a complete content operating system that gives developers control over the entire stack.', // ✅ User B's improvement\n    },\n    {\n      _key: 'conclusion', // ✅ User A's reordering\n      _type: 'paragraph',\n      text: 'Learning Sanity will help you take control of your content workflow.',\n    },\n    {\n      _key: 'benefits',\n      _type: 'paragraph',\n      text: 'It offers real-time collaboration and gives developers control over the entire stack.', // ✅ User A's typo fix\n    },\n  ],\n}\n```\n\n## Technical Details\n\n### String Diffing with diff-match-patch\n\nWhen comparing strings, the library attempts to use [diff-match-patch](https://www.sanity.io/docs/http-patches#diffmatchpatch-aTbJhlAJ) to generate granular text patches instead of simple replacements. This preserves editing intent and enables better conflict resolution.\n\n**Automatic selection criteria:**\n\n- **String size limit**: Strings larger than 1MB use `set` operations\n- **Change ratio threshold**: If >40% of text changes (determined by simple string length difference), uses `set` (indicates replacement vs. editing)\n- **Small text optimization**: Strings <10KB will always use diff-match-patch\n- **System key protection**: Properties starting with `_` (e.g. `_type`, `_key`) always use `set` operations as these are not typically edited by users\n\n**Performance rationale:**\n\nThese thresholds are based on performance testing of the underlying `@sanity/diff-match-patch` library on an M2 MacBook Pro:\n\n- **Keystroke editing**: 0ms for typical edits, sub-millisecond even on large strings\n- **Small insertions/pastes**: 0-10ms for content <50KB\n- **Large insertions/deletions**: 0-50ms for content >50KB\n- **Text replacements**: Can be 70ms-2s+ due to algorithm complexity\n\nThe 40% change ratio threshold catches problematic replacement scenarios while allowing the algorithm to excel at insertions, deletions, and small edits.\n\n**Migration from v5:**\n\nVersion 5 allowed configuring diff-match-patch behavior with `lengthThresholdAbsolute` and `lengthThresholdRelative` options. Version 6 removes these options in favor of tested defaults that provide consistent performance across real-world editing patterns. This allows us to change the behavior of this over time to better meet performance needs.\n\n### Array Handling\n\n**Keyed arrays**: Arrays containing objects with `_key` properties are diffed by key rather than index, producing more stable patches for collaborative editing.\n\n**Index-based arrays**: Arrays without keys are diffed by index position.\n\n**Undefined values**: When `undefined` values are encountered in arrays, they are converted to `null`. This follows the same behavior as `JSON.stringify()` and ensures consistent serialization. To remove undefined values before diffing:\n\n```js\nconst cleanArray = array.filter((item) => typeof item !== 'undefined')\n```\n\n### System Keys\n\nThe following keys are ignored at the root of the document when diffing a document as they are managed by Sanity:\n\n- `_id`\n- `_type`\n- `_createdAt`\n- `_updatedAt`\n- `_rev`\n\n### Error Handling\n\n- **Missing document ID**: Throws error if `_id` differs between documents and no explicit `id` option provided\n- **Immutable \\_type**: Throws error if attempting to change `_type` at document root\n- **Multi-dimensional arrays**: Not supported, throws `DiffError`\n- **Invalid revision**: Throws error if `ifRevisionID: true` but no `_rev` in source document\n\n## License\n\nMIT © [Sanity.io](https://sanity.io/)\n","readmeFilename":""}