Index: node_modules/immer/src/plugins/patches.ts
===================================================================
--- node_modules/immer/src/plugins/patches.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
+++ node_modules/immer/src/plugins/patches.ts	(revision a762898ecd37a452c782821d4c2c4955c6ed2521)
@@ -0,0 +1,317 @@
+import {immerable} from "../immer"
+import {
+	ImmerState,
+	Patch,
+	SetState,
+	ProxyArrayState,
+	MapState,
+	ProxyObjectState,
+	PatchPath,
+	get,
+	each,
+	has,
+	getArchtype,
+	getPrototypeOf,
+	isSet,
+	isMap,
+	loadPlugin,
+	ArchType,
+	die,
+	isDraft,
+	isDraftable,
+	NOTHING,
+	errors
+} from "../internal"
+
+export function enablePatches() {
+	const errorOffset = 16
+	if (process.env.NODE_ENV !== "production") {
+		errors.push(
+			'Sets cannot have "replace" patches.',
+			function(op: string) {
+				return "Unsupported patch operation: " + op
+			},
+			function(path: string) {
+				return "Cannot apply patch, path doesn't resolve: " + path
+			},
+			"Patching reserved attributes like __proto__, prototype and constructor is not allowed"
+		)
+	}
+
+	const REPLACE = "replace"
+	const ADD = "add"
+	const REMOVE = "remove"
+
+	function generatePatches_(
+		state: ImmerState,
+		basePath: PatchPath,
+		patches: Patch[],
+		inversePatches: Patch[]
+	): void {
+		switch (state.type_) {
+			case ArchType.Object:
+			case ArchType.Map:
+				return generatePatchesFromAssigned(
+					state,
+					basePath,
+					patches,
+					inversePatches
+				)
+			case ArchType.Array:
+				return generateArrayPatches(state, basePath, patches, inversePatches)
+			case ArchType.Set:
+				return generateSetPatches(
+					(state as any) as SetState,
+					basePath,
+					patches,
+					inversePatches
+				)
+		}
+	}
+
+	function generateArrayPatches(
+		state: ProxyArrayState,
+		basePath: PatchPath,
+		patches: Patch[],
+		inversePatches: Patch[]
+	) {
+		let {base_, assigned_} = state
+		let copy_ = state.copy_!
+
+		// Reduce complexity by ensuring `base` is never longer.
+		if (copy_.length < base_.length) {
+			// @ts-ignore
+			;[base_, copy_] = [copy_, base_]
+			;[patches, inversePatches] = [inversePatches, patches]
+		}
+
+		// Process replaced indices.
+		for (let i = 0; i < base_.length; i++) {
+			if (assigned_[i] && copy_[i] !== base_[i]) {
+				const path = basePath.concat([i])
+				patches.push({
+					op: REPLACE,
+					path,
+					// Need to maybe clone it, as it can in fact be the original value
+					// due to the base/copy inversion at the start of this function
+					value: clonePatchValueIfNeeded(copy_[i])
+				})
+				inversePatches.push({
+					op: REPLACE,
+					path,
+					value: clonePatchValueIfNeeded(base_[i])
+				})
+			}
+		}
+
+		// Process added indices.
+		for (let i = base_.length; i < copy_.length; i++) {
+			const path = basePath.concat([i])
+			patches.push({
+				op: ADD,
+				path,
+				// Need to maybe clone it, as it can in fact be the original value
+				// due to the base/copy inversion at the start of this function
+				value: clonePatchValueIfNeeded(copy_[i])
+			})
+		}
+		for (let i = copy_.length - 1; base_.length <= i; --i) {
+			const path = basePath.concat([i])
+			inversePatches.push({
+				op: REMOVE,
+				path
+			})
+		}
+	}
+
+	// This is used for both Map objects and normal objects.
+	function generatePatchesFromAssigned(
+		state: MapState | ProxyObjectState,
+		basePath: PatchPath,
+		patches: Patch[],
+		inversePatches: Patch[]
+	) {
+		const {base_, copy_} = state
+		each(state.assigned_!, (key, assignedValue) => {
+			const origValue = get(base_, key)
+			const value = get(copy_!, key)
+			const op = !assignedValue ? REMOVE : has(base_, key) ? REPLACE : ADD
+			if (origValue === value && op === REPLACE) return
+			const path = basePath.concat(key as any)
+			patches.push(op === REMOVE ? {op, path} : {op, path, value})
+			inversePatches.push(
+				op === ADD
+					? {op: REMOVE, path}
+					: op === REMOVE
+					? {op: ADD, path, value: clonePatchValueIfNeeded(origValue)}
+					: {op: REPLACE, path, value: clonePatchValueIfNeeded(origValue)}
+			)
+		})
+	}
+
+	function generateSetPatches(
+		state: SetState,
+		basePath: PatchPath,
+		patches: Patch[],
+		inversePatches: Patch[]
+	) {
+		let {base_, copy_} = state
+
+		let i = 0
+		base_.forEach((value: any) => {
+			if (!copy_!.has(value)) {
+				const path = basePath.concat([i])
+				patches.push({
+					op: REMOVE,
+					path,
+					value
+				})
+				inversePatches.unshift({
+					op: ADD,
+					path,
+					value
+				})
+			}
+			i++
+		})
+		i = 0
+		copy_!.forEach((value: any) => {
+			if (!base_.has(value)) {
+				const path = basePath.concat([i])
+				patches.push({
+					op: ADD,
+					path,
+					value
+				})
+				inversePatches.unshift({
+					op: REMOVE,
+					path,
+					value
+				})
+			}
+			i++
+		})
+	}
+
+	function generateReplacementPatches_(
+		baseValue: any,
+		replacement: any,
+		patches: Patch[],
+		inversePatches: Patch[]
+	): void {
+		patches.push({
+			op: REPLACE,
+			path: [],
+			value: replacement === NOTHING ? undefined : replacement
+		})
+		inversePatches.push({
+			op: REPLACE,
+			path: [],
+			value: baseValue
+		})
+	}
+
+	function applyPatches_<T>(draft: T, patches: readonly Patch[]): T {
+		patches.forEach(patch => {
+			const {path, op} = patch
+
+			let base: any = draft
+			for (let i = 0; i < path.length - 1; i++) {
+				const parentType = getArchtype(base)
+				let p = path[i]
+				if (typeof p !== "string" && typeof p !== "number") {
+					p = "" + p
+				}
+
+				// See #738, avoid prototype pollution
+				if (
+					(parentType === ArchType.Object || parentType === ArchType.Array) &&
+					(p === "__proto__" || p === "constructor")
+				)
+					die(errorOffset + 3)
+				if (typeof base === "function" && p === "prototype")
+					die(errorOffset + 3)
+				base = get(base, p)
+				if (typeof base !== "object") die(errorOffset + 2, path.join("/"))
+			}
+
+			const type = getArchtype(base)
+			const value = deepClonePatchValue(patch.value) // used to clone patch to ensure original patch is not modified, see #411
+			const key = path[path.length - 1]
+			switch (op) {
+				case REPLACE:
+					switch (type) {
+						case ArchType.Map:
+							return base.set(key, value)
+						/* istanbul ignore next */
+						case ArchType.Set:
+							die(errorOffset)
+						default:
+							// if value is an object, then it's assigned by reference
+							// in the following add or remove ops, the value field inside the patch will also be modifyed
+							// so we use value from the cloned patch
+							// @ts-ignore
+							return (base[key] = value)
+					}
+				case ADD:
+					switch (type) {
+						case ArchType.Array:
+							return key === "-"
+								? base.push(value)
+								: base.splice(key as any, 0, value)
+						case ArchType.Map:
+							return base.set(key, value)
+						case ArchType.Set:
+							return base.add(value)
+						default:
+							return (base[key] = value)
+					}
+				case REMOVE:
+					switch (type) {
+						case ArchType.Array:
+							return base.splice(key as any, 1)
+						case ArchType.Map:
+							return base.delete(key)
+						case ArchType.Set:
+							return base.delete(patch.value)
+						default:
+							return delete base[key]
+					}
+				default:
+					die(errorOffset + 1, op)
+			}
+		})
+
+		return draft
+	}
+
+	// optimize: this is quite a performance hit, can we detect intelligently when it is needed?
+	// E.g. auto-draft when new objects from outside are assigned and modified?
+	// (See failing test when deepClone just returns obj)
+	function deepClonePatchValue<T>(obj: T): T
+	function deepClonePatchValue(obj: any) {
+		if (!isDraftable(obj)) return obj
+		if (Array.isArray(obj)) return obj.map(deepClonePatchValue)
+		if (isMap(obj))
+			return new Map(
+				Array.from(obj.entries()).map(([k, v]) => [k, deepClonePatchValue(v)])
+			)
+		if (isSet(obj)) return new Set(Array.from(obj).map(deepClonePatchValue))
+		const cloned = Object.create(getPrototypeOf(obj))
+		for (const key in obj) cloned[key] = deepClonePatchValue(obj[key])
+		if (has(obj, immerable)) cloned[immerable] = obj[immerable]
+		return cloned
+	}
+
+	function clonePatchValueIfNeeded<T>(obj: T): T {
+		if (isDraft(obj)) {
+			return deepClonePatchValue(obj)
+		} else return obj
+	}
+
+	loadPlugin("Patches", {
+		applyPatches_,
+		generatePatches_,
+		generateReplacementPatches_
+	})
+}
