# immerjs/immer — codebase unpack

> Canonical page: https://codevetter.com/unpack/immer

This is a deterministic Repo Unpack scan of immerjs/immer — a structural map, not a review, security audit, or maintainer-endorsed description.

- Scanned commit: 061c2425e1c9dff89e4e4189d42af1b7839dfe0a (2026-08-19)
- Last upstream commit: chore(test): pin draft prototype-inspection behavior restored by #1271 (#1272)
- Generated by codevetter 1.15.0 on 2026-10-02
- 155 files scanned · 1.6 MB

Source inspection; upstream code and tests were not executed.

## Languages

- Markdown: 54 files
- TypeScript: 29 files
- JavaScript: 26 files
- JSON: 11 files
- YAML: 6 files
- HTML: 3 files
- CSS: 1 files

## Repository structure

- website/ — 57 files
- __tests__/ — 41 files
- src/ — 18 files
- .github/ — 8 files
- perf-testing/ — 7 files
- __performance_tests__/ — 6 files
- _site/ — 3 files
- .codesandbox/ — 1 files

Probable source entrypoint: `src/` (inferred from the tree, not upstream docs)

## Source layout — src/

- src/core/ — 5 files
- src/plugins/ — 3 files
- src/types/ — 4 files
- src/utils/ — 4 files
- src/immer.ts — 1 file
- src/internal.ts — 1 file

## Package

- package.json: immer v10.0.3-beta — 23 declared dependencies

## Structural health signals

Average score 8.5/10 across 48 files; 2 hotspots. These are deterministic review leads, not proof of a bug.

## Recent history

- 061c2425e1c9 (2026-08-19) chore(test): pin draft prototype-inspection behavior restored by #1271 (#1272)
- 955c5f5f3d5a (2026-08-19) docs: add typed custom produce function (#1239)
- 2f0ea7f3f0c0 (2026-08-19) docs: add zh-CN array methods translation (#1285)
- 9daf3cdad0d3 (2026-08-19) chore(deps): bump svgo from 2.8.2 to 2.8.3 in /website (#1291)
- 3405b656db5d (2026-08-19) chore(deps): bump postcss from 8.5.13 to 8.5.26 in /website (#1281)

## Overview

Immer is a JavaScript and TypeScript library that turns mutations inside a recipe callback into immutable state updates with structural sharing. It serves application developers using plain objects, arrays, and optionally Maps, Sets, or marked classes, including React and Redux state workflows. At commit 061c2425e1c9dff89e4e4189d42af1b7839dfe0a, its implementation combines revocable proxies, scope-owned finalization callbacks, optional patch generation, and an opt-in array-method interception plugin; separate packages provide documentation and performance tooling.

## System map

The principal runtime is an in-process state transformation library whose public entrypoint is src/immer.ts. Core modules manage proxies, execution scopes, snapshots, and finalization, while three optional plugins supply collection, patch, and array-method behavior. Distribution includes multiple JavaScript module formats and declarations; documentation and benchmarking have separate manifests and execution boundaries.
- src/immer.ts constructs one default Immer instance and exposes its produce method plus bound patch, configuration, and manual-draft methods; it also exports Immer for independent instances. — [src/immer.ts#L27-L55](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/immer.ts#L27-L55) [src/immer.ts#L62-L102](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/immer.ts#L62-L102) [src/immer.ts#L119-L123](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/immer.ts#L119-L123)
- src/internal.ts is the shared barrel connecting utility constants, errors, types, plugin interfaces, scopes, finalization, proxies, Immer, and current snapshots. — [src/internal.ts#L1-L11](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/internal.ts#L1-L11)
- Each producer scope owns draft references, optional forward/inverse patches, parent scope, finalization tracking sets, and its Immer instance; currentScope is module-level execution state. — [src/core/scope.ts#L19-L59](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/scope.ts#L19-L59)
- Package export conditions select legacy ESM for React Native, modern ESM for imports, and a CJS dispatcher for require, with dist/immer.d.ts supplied across these conditions. — [package.json#L5-L26](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/package.json#L5-L26) [tsup.config.ts#L73-L87](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/tsup.config.ts#L73-L87)
- tsup builds declarations, development ESM/CJS, legacy ESM targeting es2017, and minified production ESM/CJS; production builds replace NODE_ENV and mangle properties ending in an underscore. — [tsup.config.ts#L4-L52](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/tsup.config.ts#L4-L52) [tsup.config.ts#L54-L88](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/tsup.config.ts#L54-L88)
- The root package uses Yarn-oriented scripts for source tests, built-package tests, Flow checks, coverage, performance workloads, import-size reports, and semantic-release. — [package.json#L28-L42](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/package.json#L28-L42)
- The separate React/Docusaurus website serves documentation at routeBasePath '/', supports English and zh-CN, and deploys website/build to gh-pages through its public-docs workflow. — [website/package.json#L5-L21](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/website/package.json#L5-L21) [website/docusaurus.config.js#L13-L16](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/website/docusaurus.config.js#L13-L16) [website/docusaurus.config.js#L73-L80](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/website/docusaurus.config.js#L73-L80) [.github/workflows/docs-public.yml#L32-L41](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/.github/workflows/docs-public.yml#L32-L41)
- perf-testing is a private ESM package using Mitata and Rolldown; aliases connect its current-development comparison to ../dist/immer.mjs alongside historical Immer versions and alternative libraries. — [perf-testing/package.json#L1-L34](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/perf-testing/package.json#L1-L34) [perf-testing/rolldown.config.js#L1-L18](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/perf-testing/rolldown.config.js#L1-L18) [perf-testing/immutability-benchmarks.mjs#L4-L25](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/perf-testing/immutability-benchmarks.mjs#L4-L25)

## Feature catalog

The user-facing surface is primarily a library API for creating and examining immutable updates. Recipes support direct and curried calls, explicit replacement, manual draft lifecycles, and optional reversible patches. Collection support, class draftability, type helpers, configurable copying, and array interception extend that surface, while the website explains their usage.
- produce accepts a base value and recipe, validates callback arguments, drafts eligible objects, handles primitive inputs directly, and returns either the resulting state or a replacement. — [src/core/immerClass.ts#L99-L135](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L99-L135) [src/core/finalize.ts#L27-L60](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/finalize.ts#L27-L60)
- Curried produce captures a recipe and optional default base, then forwards later arguments and the caller's this context into recipe.call. — [src/core/immerClass.ts#L83-L96](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L83-L96)
- enablePatches activates produce listeners, produceWithPatches tuples, and applyPatches replay; Patch exposes add, remove, and replace operations with array-valued paths. — [src/immer.ts#L81-L86](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/immer.ts#L81-L86) [src/immer.ts#L121-L123](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/immer.ts#L121-L123) [src/core/immerClass.ts#L137-L150](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L137-L150) [src/types/types-external.ts#L88-L94](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/types/types-external.ts#L88-L94)
- createDraft opens a mutable draft without a recipe callback, and finishDraft finalizes only drafts marked manual, optionally reporting patches. — [src/core/immerClass.ts#L152-L170](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L152-L170) [website/docs/async.mdx#L36-L59](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/website/docs/async.mdx#L36-L59)
- enableMapSet supplies DraftMap and DraftSet implementations with mutation methods, iteration, nested value drafting, and revocation checks. — [src/plugins/mapset.ts#L34-L75](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/mapset.ts#L34-L75) [src/plugins/mapset.ts#L117-L172](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/mapset.ts#L117-L172) [src/plugins/mapset.ts#L244-L303](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/mapset.ts#L244-L303)
- enableArrayMethods intercepts seven mutating methods and selected read methods; filter, slice, find, and findLast return selected drafts, while concat and flat return base elements. — [src/plugins/arrayMethods.ts#L100-L156](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/arrayMethods.ts#L100-L156) [src/plugins/arrayMethods.ts#L440-L500](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/arrayMethods.ts#L440-L500)
- isDraft, isDraftable, original, and current inspect draft state; immerable marks custom instances or constructors as draftable, and nothing requests an undefined replacement. — [src/utils/common.ts#L27-L43](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/utils/common.ts#L27-L43) [src/utils/common.ts#L67-L73](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/utils/common.ts#L67-L73) [src/core/current.ts#L14-L18](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/current.ts#L14-L18) [src/utils/env.ts#L3-L18](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/utils/env.ts#L3-L18)
- Configuration APIs control auto-freezing, strict shallow copying, and strict iteration; Draft and Immutable recursively map types, while castDraft and castImmutable are runtime identity casts. — [src/core/immerClass.ts#L178-L202](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L178-L202) [src/types/types-external.ts#L31-L85](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/types/types-external.ts#L31-L85) [src/immer.ts#L104-L117](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/immer.ts#L104-L117)

## Data flow

Inputs enter as application-owned state and executable recipes, then become scope-owned drafts with lazily allocated copies. Writes record assignments and propagate modification flags toward parents; finalization substitutes ordinary values and preserves unchanged base references. Results and optional patch arrays leave through returns and listeners, with persistence delegated to the calling application in these inspected API paths.
- The draftability boundary accepts plain objects, arrays, marked instances or constructors, Maps, and Sets; other truthy object inputs to produce reach die(1). — [src/utils/common.ts#L33-L43](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/utils/common.ts#L33-L43) [src/core/immerClass.ts#L104-L135](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L104-L135)
- createProxy selects collection plugins or createProxyProxy, registers the draft in its scope, and shares the parent's callback array while recording the child's key. — [src/core/immerClass.ts#L234-L269](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L234-L269)
- objectTraps.get reads latest(state), creates a child draft only for eligible base or relocated references, and caches that draft in copy_; merely reading can allocate a copy without marking a change. — [src/core/proxy.ts#L125-L161](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/proxy.ts#L125-L161) [src/core/proxy.ts#L349-L358](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/proxy.ts#L349-L358)
- objectTraps.set ignores equal-value assignments under its presence checks, otherwise prepares a copy, marks ancestors changed, records assigned_ entries, and registers cross-reference handling. — [src/core/proxy.ts#L181-L215](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/proxy.ts#L181-L215) [src/core/proxy.ts#L340-L358](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/proxy.ts#L340-L358)
- Finalization returns base_ for unmodified drafts, drains registered callbacks for modified drafts, and updates parent references to finalized values before returning copy_. — [src/core/finalize.ts#L78-L98](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/finalize.ts#L78-L98) [src/core/finalize.ts#L169-L191](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/finalize.ts#L169-L191) [src/utils/common.ts#L185-L197](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/utils/common.ts#L185-L197)
- Patch generation uses assignment records for objects and Maps, index comparisons for arrays, and membership changes for Sets, producing corresponding inverse operations. — [src/plugins/patches.ts#L171-L234](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/patches.ts#L171-L234) [src/plugins/patches.ts#L237-L263](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/patches.ts#L237-L263) [src/plugins/patches.ts#L266-L307](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/patches.ts#L266-L307)
- applyPatches clones draftable patch values before dispatching writes; arrays use splice or push, Maps use set/delete, Sets use add/delete, and ordinary objects use property assignment/deletion. — [src/plugins/patches.ts#L352-L399](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/patches.ts#L352-L399) [src/plugins/patches.ts#L405-L417](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/patches.ts#L405-L417)
- processResult optionally deep-freezes eligible root results, revokes drafts, invokes the patch listener, and returns state; these core output boundaries contain no persistence operation. — [src/core/finalize.ts#L54-L60](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/finalize.ts#L54-L60) [src/core/finalize.ts#L100-L104](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/finalize.ts#L100-L104) [src/core/scope.ts#L74-L95](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/scope.ts#L74-L95)

## Behavior traces

Source inspection followed ordinary production, manual drafting, and patch replay end-to-end, plus startup, snapshots, collections, and array reordering. These traces describe execution order and meaningful branches rather than observed runtime results. They show where drafts are created, how outputs are finalized, and when user callbacks execute.
- Startup: src/immer.ts creates new Immer(), exposing its methods; instance defaults are autoFreeze_=true, useStrictShallowCopy_=false, and useStrictIteration_=false, while optional plugins require explicit enable calls. — [src/immer.ts#L27-L55](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/immer.ts#L27-L55) [src/immer.ts#L121-L123](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/immer.ts#L121-L123) [src/core/immerClass.ts#L47-L61](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L47-L61) [src/utils/plugins.ts#L46-L62](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/utils/plugins.ts#L46-L62)
- Recipe update: produce → isDraftable → enterScope → createProxy → createProxyProxy → recipe(proxy); nested reads draft lazily and writes call prepareCopy → markChanged → handleCrossReference. — [src/core/immerClass.ts#L104-L118](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L104-L118) [src/core/proxy.ts#L101-L104](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/proxy.ts#L101-L104) [src/core/proxy.ts#L150-L159](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/proxy.ts#L150-L159) [src/core/proxy.ts#L197-L214](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/proxy.ts#L197-L214)
- Recipe completion: successful execution leaves the scope, enables requested patch collection, then processResult → finalize → callback cleanup/patch generation → maybeFreeze → revokeScope → patchListener; a thrown recipe instead revokes in finally. — [src/core/immerClass.ts#L108-L118](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L108-L118) [src/core/finalize.ts#L49-L60](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/finalize.ts#L49-L60) [src/core/finalize.ts#L83-L104](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/finalize.ts#L83-L104) [src/core/scope.ts#L62-L79](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/scope.ts#L62-L79)
- Manual lifecycle: createDraft validates the base, snapshots it with current if already drafted, enters a scope, creates and marks a manual proxy, then leaves; finishDraft retrieves its owning scope and calls processResult. — [src/core/immerClass.ts#L152-L170](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L152-L170) [src/core/finalize.ts#L49-L60](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/finalize.ts#L49-L60)
- Patch round trip: produceWithPatches → produce with a listener → tuple capture; applyPatches scans backward for the last root replacement, skips earlier patches, then applies through the plugin directly to a draft or inside another produce. — [src/core/immerClass.ts#L137-L150](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L137-L150) [src/core/immerClass.ts#L205-L230](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L205-L230) [src/plugins/patches.ts#L328-L354](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/patches.ts#L328-L354)
- Snapshot: current rejects non-drafts, returns unchanged bases directly, temporarily marks modified drafts finalized to suppress drafting during copying, recursively snapshots children, and restores finalized_=false. — [src/core/current.ts#L15-L46](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/current.ts#L15-L46)
- Map update: createProxy selects proxyMap_ → DraftMap; get(key) lazily creates and caches a child draft, set(key,value) prepares a Map copy and records modification, and finalization callbacks replace nested draft references. — [src/core/immerClass.ts#L243-L258](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L243-L258) [src/plugins/mapset.ts#L64-L74](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/mapset.ts#L64-L74) [src/plugins/mapset.ts#L117-L131](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/mapset.ts#L117-L131) [src/core/finalize.ts#L169-L191](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/finalize.ts#L169-L191)
- Array reordering: objectTraps.get selects createMethodInterceptor → enterOperation → handleReorderingOperation → executeArrayMethod → native copy sort/reverse → markAllIndicesReassigned; later element reads detect relocated base references, and finally clears operationMethod. — [src/core/proxy.ts#L114-L122](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/proxy.ts#L114-L122) [src/plugins/arrayMethods.ts#L299-L317](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/arrayMethods.ts#L299-L317) [src/plugins/arrayMethods.ts#L340-L355](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/arrayMethods.ts#L340-L355) [src/core/proxy.ts#L295-L311](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/proxy.ts#L295-L311) [src/plugins/arrayMethods.ts#L158-L167](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/arrayMethods.ts#L158-L167) [src/plugins/arrayMethods.ts#L407-L410](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/arrayMethods.ts#L407-L410)

## Testing signals

Tests and CI were inspected, not executed; test existence is not a passing result. The inspected suite uses Vitest in Node, repeats core behavior across configuration combinations, and has a separate production-CJS test configuration. Coverage includes structural sharing, manual lifecycles, patch replay, collection behavior, and array regressions, but inspected scripts and configurations leave specific verification limits.
- Source tests use Vitest with Node environment, global test APIs, and __tests__ JavaScript/TypeScript discovery; coverage uses V8 with text and LCOV outputs, but no execution or coverage result was obtained. — [vitest.config.ts#L1-L15](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/vitest.config.ts#L1-L15)
- __tests__/base.js repeats its core suite across auto-freeze, strict-copy, and listener booleans, with one additional array-plugin configuration rather than a full plugin/configuration cross-product. — [__tests__/base.js#L38-L52](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/base.js#L38-L52) [__tests__/base.js#L89-L97](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/base.js#L89-L97)
- Core assertions check unchanged-root identity, structural sharing, deep-change propagation, plugin no-op identity, and reorder-then-mutate preservation with patch replay/reversal. — [__tests__/base.js#L100-L126](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/base.js#L100-L126) [__tests__/base.js#L295-L320](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/base.js#L295-L320) [__tests__/base.js#L435-L463](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/base.js#L435-L463)
- Patch fixtures assert exact patches, replay, and inverse restoration; dedicated cases assert that __proto__ traversal through objects and arrays throws without polluting unrelated objects. — [__tests__/patch.js#L79-L95](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/patch.js#L79-L95) [__tests__/patch.js#L1307-L1346](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/patch.js#L1307-L1346)
- Manual-draft tests exercise argument errors, immutable results, repeated finish rejection, and patch listeners; post-finish mutation checks are conditional on non-production mode, while plugins.js tests missing-plugin errors. — [__tests__/manual.js#L20-L77](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/manual.js#L20-L77) [__tests__/plugins.js#L1-L29](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/plugins.js#L1-L29)
- Production tests alias public source imports to the production CJS build, define USES_BUILD and production NODE_ENV, and use separate snapshots; their custom reporter can reset exitCode when its failure predicate and errors array are empty. — [vitest.config.build.ts#L4-L24](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/vitest.config.build.ts#L4-L24) [vitest.config.build.ts#L37-L48](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/vitest.config.build.ts#L37-L48) [vitest-custom-reporter.ts#L3-L16](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/vitest-custom-reporter.ts#L3-L16)
- TypeScript fixtures use compile-time assert signatures whose runtime body is an identity function; inspected Yarn/Vitest configuration does not explicitly enable checking those fixtures with tsc, while two reconciliation identity tests are explicitly skipped. — [__tests__/produce.ts#L53-L65](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/produce.ts#L53-L65) [__tests__/spec_ts.ts#L42-L53](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/spec_ts.ts#L42-L53) [package.json#L28-L35](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/package.json#L28-L35) [__tests__/regressions.js#L200-L227](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/regressions.js#L200-L227)
- Inspected CI runs Node 24 with frozen-lockfile install, yarn test, coverage, performance workloads, and Coveralls; this is one configured Node version, and the separate Mitata package is not invoked by those listed test steps. — [.github/workflows/test.yml#L13-L31](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/.github/workflows/test.yml#L13-L31) [package.json#L29-L35](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/package.json#L29-L35) [perf-testing/package.json#L6-L14](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/perf-testing/package.json#L6-L14)

## Risk map

These are source observations and maintenance risks, not confirmed vulnerabilities. Sensitive boundaries include executable recipes and accessors, externally supplied patch paths, documentation scripts, and release permissions. Core correctness depends on coupled scope, callback, and array-reference bookkeeping; the inspection is bounded and does not establish whole-repository security or test completeness.
- Patch application rejects reserved intermediate traversal keys for objects/arrays and function prototypes, but final-key writes use a separate dispatch; security edits must preserve and assess both boundaries rather than generalizing the traversal guard. — [src/plugins/patches.ts#L333-L381](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/patches.ts#L333-L381) [__tests__/patch.js#L1307-L1346](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/patch.js#L1307-L1346)
- Recipes execute caller code directly, strict copying reads own accessors, and proxy access can invoke prototype getters/setters; these APIs are executable object interactions rather than a sanitization boundary. — [src/core/immerClass.ts#L109-L115](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L109-L115) [src/utils/common.ts#L211-L234](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/utils/common.ts#L211-L234) [src/core/proxy.ts#L174-L179](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/proxy.ts#L174-L179) [src/core/proxy.ts#L314-L322](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/proxy.ts#L314-L322)
- Array interception passes base values into predicates and native copy operations; mutation inside intercepted callbacks or through concat/flat elements bypasses ordinary nested-draft tracking. — [src/plugins/arrayMethods.ts#L79-L80](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/arrayMethods.ts#L79-L80) [src/plugins/arrayMethods.ts#L448-L500](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/arrayMethods.ts#L448-L500) [website/docs/pitfalls.md#L91-L115](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/website/docs/pitfalls.md#L91-L115)
- Reordered arrays depend on allIndicesReassigned_ and baseRefs_ to draft relocated base objects; inserted objects containing drafts depend on string-keyed assignment records and cross-reference callbacks to avoid revoked proxies in results. — [src/core/proxy.ts#L295-L311](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/proxy.ts#L295-L311) [src/plugins/arrayMethods.ts#L194-L197](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/arrayMethods.ts#L194-L197) [src/plugins/arrayMethods.ts#L206-L232](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/arrayMethods.ts#L206-L232) [__tests__/base.js#L435-L463](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/base.js#L435-L463)
- Strict-iteration comments say the default is enabled, but Immer initializes useStrictIteration_=false; the constructor also accepts only boolean strict-copy config values although StrictMode includes 'class_only'. — [src/immer.ts#L72-L79](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/immer.ts#L72-L79) [src/core/immerClass.ts#L45-L61](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L45-L61) [src/core/immerClass.ts#L191-L202](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L191-L202)
- Manual drafts can miss application updates made while awaiting asynchronous work, and externally inserted objects are not automatically drafted; both usage traps are explicitly documented. — [website/docs/async.mdx#L40-L59](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/website/docs/async.mdx#L40-L59) [website/docs/pitfalls.md#L38-L54](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/website/docs/pitfalls.md#L38-L54) [src/core/proxy.ts#L148-L161](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/proxy.ts#L148-L161)
- The profiling analyzer reads a caller-selected filesystem path without a repo-root containment check and loads ../dist sourcemaps; these file reads belong to development tooling, while tsup separately writes distribution files. — [perf-testing/read-cpuprofile.js#L4-L17](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/perf-testing/read-cpuprofile.js#L4-L17) [perf-testing/read-cpuprofile.js#L51-L58](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/perf-testing/read-cpuprofile.js#L51-L58) [tsup.config.ts#L73-L87](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/tsup.config.ts#L73-L87)
- The documentation site loads external button/ad scripts and two analytics plugins; release CI grants contents, id-token, and pull-request write permissions and publishes only for immerjs/immer after tests/build. — [website/docusaurus.config.js#L61-L64](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/website/docusaurus.config.js#L61-L64) [website/docusaurus.config.js#L82-L94](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/website/docusaurus.config.js#L82-L94) [.github/workflows/release.yml#L11-L14](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/.github/workflows/release.yml#L11-L14) [.github/workflows/release.yml#L25-L36](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/.github/workflows/release.yml#L25-L36)

## Extension points

Extension mechanisms are concrete and mostly internal rather than a general third-party plugin API. The public library supports configurable instances and three enable functions, while internal typed interfaces connect implementations to scope behavior. Additional seams exist in draftable classes, producer abstractions, declaration mappings, packaging, documentation routing, and benchmark comparisons.
- New Immer instances provide independent auto-freeze, strict-copy, and iteration settings; produce is an instance arrow function, while the public singleton binds other exposed methods. — [src/core/immerClass.ts#L47-L61](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L47-L61) [src/core/immerClass.ts#L83-L96](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L83-L96) [src/immer.ts#L54-L79](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/immer.ts#L54-L79)
- The internal plugin registry has typed MapSet, Patches, and ArrayMethods slots; getPlugin rejects missing implementations and loadPlugin preserves the first loaded implementation. — [src/utils/plugins.ts#L14-L43](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/utils/plugins.ts#L14-L43) [src/utils/plugins.ts#L46-L77](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/utils/plugins.ts#L46-L77)
- Collection extension hooks return draft/state tuples and provide fixSetContents; createProxy dispatches Maps/Sets through these hooks, and finalization calls collection cleanup. — [src/utils/plugins.ts#L33-L37](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/utils/plugins.ts#L33-L37) [src/core/immerClass.ts#L243-L262](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L243-L262) [src/core/finalize.ts#L182-L190](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/finalize.ts#L182-L190)
- Array-method support plugs into objectTraps.get through detection and interceptor hooks; method Sets define dispatch, and registered handlers own operation flags, mutation bookkeeping, and return semantics. — [src/utils/plugins.ts#L39-L43](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/utils/plugins.ts#L39-L43) [src/core/proxy.ts#L114-L122](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/proxy.ts#L114-L122) [src/plugins/arrayMethods.ts#L100-L156](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/arrayMethods.ts#L100-L156) [src/plugins/arrayMethods.ts#L503-L507](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/arrayMethods.ts#L503-L507)
- Custom classes opt into drafting by defining the exported immerable symbol on an instance or constructor; strict shallow copying preserves their prototype using descriptor-based Object.create. — [src/utils/env.ts#L8-L16](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/utils/env.ts#L8-L16) [src/utils/common.ts#L33-L41](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/utils/common.ts#L33-L41) [src/utils/common.ts#L211-L234](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/utils/common.ts#L211-L234)
- Libraries can build producer abstractions on createDraft/finishDraft and consume PatchListener output; these hooks reuse the same scope finalization rather than requiring a separate state engine. — [website/docs/async.mdx#L36-L38](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/website/docs/async.mdx#L36-L38) [src/core/immerClass.ts#L152-L170](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L152-L170) [src/types/types-external.ts#L88-L94](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/types/types-external.ts#L88-L94)
- Public type behavior is concentrated in Draft, Immutable, IProduce, and IProduceWithPatches; distribution changes connect src/immer.ts exports to package conditions and tsup's format/declaration variants. — [src/types/types-external.ts#L58-L85](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/types/types-external.ts#L58-L85) [src/types/types-external.ts#L187-L225](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/types/types-external.ts#L187-L225) [src/types/types-external.ts#L234-L261](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/types/types-external.ts#L234-L261) [tsup.config.ts#L23-L52](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/tsup.config.ts#L23-L52)
- Website additions join explicit sidebar lists and Docusaurus plugins/routes; performance-provider additions join benchmark imports, the private package dependencies, and current-build aliases. — [website/sidebars.js#L1-L34](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/website/sidebars.js#L1-L34) [website/docusaurus.config.js#L73-L103](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/website/docusaurus.config.js#L73-L103) [perf-testing/immutability-benchmarks.mjs#L4-L25](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/perf-testing/immutability-benchmarks.mjs#L4-L25) [perf-testing/rolldown.config.js#L12-L16](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/perf-testing/rolldown.config.js#L12-L16)

## Contributor handoff

Begin with public exports and the scope/proxy/finalization chain, then inspect the plugin and tests relevant to the requested behavior. Tests and CI were inspected, not executed, and this bounded inventory supplies no passing result or measured speedup. Future implementation work should preserve the existing Yarn, formatting, packaging, and lifecycle conventions, with execution performed only under separate authorization.
- For core changes, read src/immer.ts, Immer.produce, scope management, proxy traps, and processResult together before editing; exports and state lifecycle span those files. — [src/immer.ts#L27-L55](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/immer.ts#L27-L55) [src/core/immerClass.ts#L83-L118](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L83-L118) [src/core/scope.ts#L74-L95](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/scope.ts#L74-L95) [src/core/finalize.ts#L27-L60](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/finalize.ts#L27-L60)
- Follow Prettier's tabs, no semicolons, double quotes, no trailing commas, and 80-column code formatting; package hooks apply pretty-quick to staged files. — [.prettierrc#L1-L20](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/.prettierrc#L1-L20) [package.json#L44-L47](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/package.json#L44-L47)
- When execution is authorized, start with the relevant suite through the existing test:src script and Vitest file filtering, then test:build for production CJS behavior; full test adds Flow checking. (inferred) — [package.json#L28-L35](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/package.json#L28-L35) [vitest.config.ts#L4-L8](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/vitest.config.ts#L4-L8) [vitest.config.build.ts#L4-L21](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/vitest.config.build.ts#L4-L21)
- Tests and CI were inspected only: configured source/build/Flow, coverage, and performance commands are verification plans, not evidence of passing tests, CI success, or benchmark improvements. — [package.json#L28-L35](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/package.json#L28-L35) [.github/workflows/test.yml#L21-L31](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/.github/workflows/test.yml#L21-L31) [perf-testing/package.json#L6-L14](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/perf-testing/package.json#L6-L14)
- Array edits must preserve no-op identity, drafting after reorder, inserted nested-draft cleanup, and patch round trips; targeted existing assertions cover these interacting invariants. — [__tests__/base.js#L295-L366](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/base.js#L295-L366) [__tests__/base.js#L435-L463](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/base.js#L435-L463) [src/plugins/arrayMethods.ts#L206-L232](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/plugins/arrayMethods.ts#L206-L232) [src/core/proxy.ts#L295-L311](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/proxy.ts#L295-L311)
- For type changes, inspect compile-time assertion helpers and the actual compiler command; runtime assert returns its first argument, and inspected Vitest configuration does not establish TypeScript fixture checking. — [__tests__/spec_ts.ts#L42-L53](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/spec_ts.ts#L42-L53) [__tests__/produce.ts#L53-L65](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/produce.ts#L53-L65) [vitest.config.ts#L3-L15](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/vitest.config.ts#L3-L15) [package.json#L28-L35](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/package.json#L28-L35)
- Treat underscore-suffixed internals and build aliases as packaging-sensitive: tsup mangles those properties, while base tests import src/internal and production tests alias public source imports to a built artifact. — [tsup.config.ts#L13-L20](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/tsup.config.ts#L13-L20) [__tests__/base.js#L15-L21](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/__tests__/base.js#L15-L21) [vitest.config.build.ts#L9-L24](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/vitest.config.build.ts#L9-L24)
- Before changing defaults or lifecycle semantics, reconcile comments with initialized values, preserve recipe exception revocation and listener timing, and account for documented tree, external-data, and nested-producer constraints. — [src/core/immerClass.ts#L48-L61](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L48-L61) [src/core/immerClass.ts#L108-L118](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/immerClass.ts#L108-L118) [src/core/finalize.ts#L54-L60](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/src/core/finalize.ts#L54-L60) [website/docs/pitfalls.md#L18-L71](https://github.com/immerjs/immer/blob/061c2425e1c9dff89e4e4189d42af1b7839dfe0a/website/docs/pitfalls.md#L18-L71)

Source repository: https://github.com/immerjs/immer
Full evidence corpus: https://github.com/Codevetter/codevetter/tree/main/benchmarks/repo-unpacks/immer.json

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
