install: consolidate the open package manager pull requests
What does this PR do?
It consolidates 597 open package manager pull requests into one reviewed change for Bun 1.5. Each was ported, taken in part, or left out with a reason. This is the complete change log: X -> Y = symptom on main -> behaviour now; a line without -> names a symptom that is gone; dep = dependency.
| absorbed | in part | not taken | obsolete | total | issues closed |
|---|---|---|---|---|---|
| 464 | 40 | 74 | 19 | 597 | 133 |
699 files, +150,684 / -85,553 (src 221 files +41,383 / -46,459, net -5,076).
Behaviour changes someone will notice
- Unknown long flags are errors in every package manager command and bunx (main:
bun install --network-timeout 100000adds the package100000). Drop the flag; bunx: tool flags go after the tool's name. InBUN_OPTIONSthey are skipped. bun ci/--frozen-lockfilefail (note: dependencies in package.json changed since bun.lock was saved) when a dep of the root or a workspace was added, removed, re-grouped or re-ranged. Equivalent spellings,file:directory rows (warning),trustedDependencies/patchedDependenciesedits pass. Runbun install, commit (#41931; refs #22689).file:folders are hard-linked real files (hoisted: was a symlink per file, their deps did not resolve). The folder's ownnode_modulesis not taken, exceptbundleDependencies. Linked, and trusted scripts run, once, not on every install. Declare or bundle what the folder needs;link:/ a workspace for a live link;--forcereruns scripts (#40628, #37127; fixes #13379).- Hoisted: what the previous
bun.lockplaced and the new one does not leavesnode_modules, with what only it needed and its bins; not under--filter, not what no lockfile placed (bun prune) (#29794, #44406). - One-time re-downloads: registry metadata (cache format bump),
file:/ URL tarballs, packages of registries on a port, path or http;bunxstarts a new cache. - Retries wait: a registry that refuses connections costs about 9 s before the install fails (main: at once).
BUN_CONFIG_HTTP_RETRY_BACKOFF=<ms>sets the first wait. - Dep names over 255 bytes per component are refused (main: a 4,100-byte name in a manifest aborts), as are the names under Security.
- Workspace's symlinked
node_modulesis replaced by a real directory, like links at@scope,.bin,.bun/**(main wrote and deleted through them). Only the rootnode_moduleslink is followed: link the root, not members (#42039). "trustedDependencies": []kept the default trusted list off only on the install that createdbun.lock-> always, also in a checkout without the workspace that declares it; written tobun.lock(one line; Bun 1.4 honours it, drops it at its next save) (#44765).!dir/**inworkspacesalso removesdir, as npm; negated entries work in every spelling (!./pkg,!pkg/) and position, add no members;bun run --filter/--workspacesfollow them (#43401, #43400; fixes #43399).bun pm lslists what is on disk, exits 1 withoutnode_modules; isolated: a dep of the root only if its link exists (#38923; fixes #38909).- Linker sticks: while
node_modules/.bunexists, a command that names no linker keeps the isolated layout (main: lays hoisted over it). Back:--linker=hoistedor deletenode_modules. NODE_ENV=development/test:bun installreads the.envfilesbun runreads, not the production ones.--provenance,--provenance-file,publishConfig.provenance,NPM_CONFIG_PROVENANCE,provenance=truein.npmrcare errors (main: published without it). Unset them or publish with npm (#30522; refs #18611).packageExtensionsadds a key tobun.lock, a trailing section tobun.lockb, only when an extension added something; older versions load both.- Fresh resolves pick differently (locked versions stay): see Resolver; Overrides. glibc hosts stop installing
-muslvariants (--libc='*'for both). - New
warn:lines: incorrect peers, deprecated versions, skipped required deps, stale / misplacedpatchedDependencies, unreadable config files, retries, unusable hashes. - Dep's script finds its own
.bin, then the inheritedPATH, then shared.bins, so an untrusted package'snodebin cannot run inside a trusted script. Cost: a globalnode-gypwins over the project's, for dep scripts only (#44488). - If
bun installitself is killed while a trusted dep's script runs, the next install calls the package installed (registry packages: as main;file:folders, local tarballs: the rerun on every install hid it).bun install --force(#42001).
Decisions that need the maintainer's confirmation
- Frozen installs start failing (2). Of 241
bun.lockbfiles from this repo's release tags, 6 that pass on main fail here (4 real drift). - A frozen install with only a foreign lockfile writes nothing: no
bun.lock, no package.json edit, one note (#38804). Reverses #38333. - Changes 1, 9 (teams on 1.4 and 1.5 see the
[]line come and go), 10, 11, 12 (removinglinker = "isolated"no longer switches a tree), 14, 18. - The
packageExtensionslockfile key (15): without it an edited or removed extension cannot be told from the package's own deps. #43104 / #43209 are out for needing a key. - Scripts that run now and did not: #41803 (its opposite #41866 is out), #41845, #39443, #43913, #42001, #38780,
bunx --trust. No longer: root scripts under--dry-run; under frozen, scripts of an installed package trusted after the lockfile was saved (main: every frozen install; now a plain install once, frozen never, silently). - No state file, so a killed install goes unnoticed (19). The complete fix is one bit or list per project, read once per install.
- Tarball cache entries named by integrity; full manifests by package name for
libc; #38813; +1renameatper linked package (#38783); a token survives only an http -> https redirect on one hostname (#38001); #39603 flips a row of #38867. - Hoisted thread pool on macOS: on; CI only, no stress run.
- Open: mask URLs in source excerpts under a diagnostic (not done); should
bun pm packfollow a symlinkednode_modules(it does, #41925).
New features and flags
- Yarn Berry migration (on main since): here package.json is written just before
bun.lockand only if that is saved;link:stayslink:;libcis honoured (#40057) link:./dir,link:../x, absolute paths: symlink to that directory, relative to the declaring package.json, as Yarn / pnpm;link:foostays abun linkname (#40025; fixes #4719, #5045)packageExtensionsin the root package.json adds missing deps / peers to registry packages, can mark a peer optional (#40053)bun pm cache pack <file>/unpack <file>: the cache entries a lockfile needs as one file (CI); unpack adds what is missing, refuses a damaged pack whole (#40012)bun pm cache prune [--max-age <days>] [--dry-run]: drops cache entries older than 30 days, not the global store (#42592)bun pm fetch: downloads all deps (pinned git too) into the cache; nonode_modules, scripts or lockfile write (#29509)bun publish --recursive/--filter <pattern>: packs the selected workspaces, publishes deps first, skips private and already published ones; the first failure ends the run (#41292)bun update --depth 0: direct deps only, transitive ones stay locked (#41720; fixes #41625)bun prune --check: exit 1 when anything would be removed (#39216)minimumReleaseAgeExcludestakesname@version; new--minimum-release-age-excludes a,b@1.2.3;bun audit fixhonours the list (#37909, #42803; fixes #28967, #42799)minimumReleaseAgeaccepts90m,12 hours,3d,2 weeks;nan/infare config errors;0no longer fetches full manifests (#30529)libc: on Linux only the glibc or musl variant of an optional native package is installed; recorded inbun.lock;--libcoverrides (#38797; fixes #16282)bunx --cwd <dir>(#28669; fixes #28668)bunx --env-file <file>(main:unrecognised dependency format: @.env); notbun --env-file F x pkg(#35599; fixes #12430, #17759)bunx --minimum-release-age, part of its cache key (#30751; fixes #30748)--env-file,--no-env-file, bunfigenv = falsefor all package manager commands (main:--env-file ci.envadded the packageci.env) (#36672; fixes #12011, #31450)npm-shrinkwrap.jsonis migrated like package-lock.json (#38861)- Deprecated versions are reported: one line per direct dep, one for the rest, all with
--verbose(#35457; fixes #6883) bun add -d | --optional | --peer <pkg>moves a package another group lists;--save-prodmoves it back (#36284; fixes #4852, #5714)bun audit fixreports and rewrites theoverridesrule that holds a vulnerable version (#38785)bun pm pkg set/delete: arrays (append, index), bracketed names (exports[./package.json]) (#38025; fixes #22035)--dry-runforbun link,unlink,pm version,pm cache rm,pm trust,pm pkg,pm migrate(main: they wrote) (#41690)bun publishhonourspublishConfig.registryandpublishConfig["@scope:registry"](#38322; fixes #18670)- Auto-install reads registries and credentials from
.npmrc(main:@corp/xcame from the default registry) (#44754) NPM_CONFIG_USERCONFIGnames the user.npmrc, asactions/setup-nodesets it (#38047)Cache-Control: no-cache,no-store,max-ageunder 300 s on registry metadata (#41644)- Workspace can depend on the root package with
workspace:*, also for pack / publish (#36594; fixes #2773, #5176) "gypfile": falseturns off the implicitnode-gyp rebuild; a trusted tarball, git,file:package withbinding.gypand no scripts is built like a registry one (#43913; fixes #43903)- Scripts get
npm_package_name/version/jsonof their own package,npm_config_local_prefix,npm_package_config_*,npm_lifecycle_event,npm_lifecycle_script; inheritednpm_package_*are dropped (#36690, #38110; fixes #12752) - Hoisted linker links packages on up to 8 threads, whatever
node_modulesholds (nothing, a part, other versions,--force) and after a download; not on Windows;file:/link:/ workspace / trusted deps, bins and scripts stay on the main thread; everything in today's order, scripts too; a cold install is no faster (#29496)
Security
- Registry URL that is not http(s) (
htps://, no scheme):pm view,whoami,publish,audit,pm diffsent the token there over plain TCP; a badBUN_CONFIG_REGISTRYfell back to another registry with the token -> error, no request, on every route (#41662, #41773) - Token,
_auth, user or password with CR, LF, NUL could inject headers, as could--otp,--user-agent-> refused (#37458, #41661) token = "$NPM_TOKEN"with the variable unset sent the literal text -> warning, nothing sent (#41049)- Passwords and tokens in registry, tarball, git URLs were printed in errors, warnings, summaries,
--verbose,pm ls/why/view/diff,audit, migrations -> masked (#38977, #38997, #38817) - Control characters from manifests, lockfiles, registry answers reached the terminal (
pm view,licenses,untrusted,audit, resolutions, bin names, errors) -> escaped (#38536, #38631, #39358, #38525) - Dep names
.bin,node_modules, a bare@scope, with control characters, empty or scope-only were installed or requested -> refused; skipped with a warning in a third party's manifest (#44439, #38615, #43331, #41735) - Registry, git or tarball package could
link:a directory, use a local.tgzof the project or afile:path that leaves it -> refused at resolve and install time (#39023, #38986, #43101) - Dep's own
npm:alias could replace a same-named direct dep of the root; an alias in a refused or stale lockfile kept redirecting -> the root's dep wins; loaders register no aliases (#44412, #44294) - Frozen install asked the registry for a range that
bun.locklinks to a workspace missing on disk (dependency confusion) -> fails without a request (#43471) - Global store: a trusted package's script could modify shared deps;
pm trustran scripts in the store, saw nothing under isolated -> its closure is project-local (#40239, #35106) - Failing script of an optional workspace /
link:dep deleted that folder -> only what the linker placed goes (#43226) bun prune,update,deduperemoved packages behind a symlinked workspacenode_modules-> prune refuses (exit 1), the others skip it (#44484; fixes #44669)bun add -g,link,unlinkreplaced or deleted foreign files in the global bin directory -> only what Bun made (#39745)bun pm cache rmcould delete the project, home or Bun's directory (an emptyBUN_INSTALL_CACHE_DIRmeant the project) -> refused (#39750)- Project's bunfig.toml could point
globalDir/globalBinDiranywhere -> ignored with a warning (#41775) bunxinstalled into the shared temp directory, where another user'snode_modules/ package.json was loaded -><cache>/.bunx-<uid>, 0700 (#44393, #31447)- Applying a patch followed symlinks and wrote through hard links -> refused (#32677)
- Tarball could make Bun allocate the disk or memory its headers claim; sparse members keep their holes (#36542)
minimumReleaseAge: an exact version passed when only the abbreviated manifest was cached; so did a publish time that is not a date (#38659, #43307)BUN_CONFIG_NO_VERIFY=0turned verification off,=1did not -> off only for1ortrue(#38310)- Manifest hash Bun cannot use skipped verification silently -> warning (#38484)
bun audittook a malformed registry answer for a clean audit -> failed audit; a scoped registry is named and skipped (#38557)- Pack: keys of a bundled dep that are not package names pulled in outside files;
**/a/bpatterns, a BOM, trailing spaces disabled ignore rules; a symlinked README was sent (#44902, #41531, #41871) bun publishpublished with"private": "true"or1-> any truthy value is private (#41664)- Auto-install read a package.json version from the wrong buffer, an alias could redirect other packages (#42839)
Install core
- Killed or failed install left a half-linked package that later installs accepted -> linked in a staging directory, renamed into place (#38783; fixes #43256)
- Switching hoisted <-> isolated left a mixed tree -> whole tree replaced, workspaces'
node_modulestoo (#38779) - Each linker switch kept a copy of the old tree in
node_modules/.old_modules-<hex>-> deleted after the install;bun prunecollects old ones --dry-runran root lifecycle scripts and wroteyarn.lock(#38830)- bunfig
[install] dryRun = truewas ignored -> honoured, also by publish,pm pack, prune, dedupe,audit fix(#34979) - Empty package.json (root or member) deleted the lockfile, exit 0 -> error, lockfile kept (#39666)
- Download that failed for an optional dep was skipped (exit 0) although another dep or a non-optional peer needs it ->
error: failed to download <name>@<version>, exit 1 (#43197, #43219; fixes #43214) --offlinefailed on what is below an optional dep it had skipped -> only misses still reachable are errors (#43185)--offlineexited 0 without a required dep of an optional package installed in one place, missing in another- Required direct dep left out for
os/cpuwas silent -> warning;bun addreports it as skipped (#41956) --production/--omit=devfailed on aworkspace:,link:,file:devDependency whose target is missing -> left out (#36704; fixes #14134, #15102)--productioninstalled, and ran scripts of, a devDependency that is also an optional peer;bun prune --productionremoves it (#42040)- Commands that only read package.json opened it for writing -> work on a read-only file (#38745)
$TMPDIRon another file system than the cache kept a probe file per install (#38859)bun add,remove,update,patchrewrote a package.json in which nothing changedInfinity/NaNwere written into package.json ->null(#41743)- Relative
--cwdwas applied twice bybun update,link,unlink,why(#31154; fixes #31152) - Warnings from native code appeared at exit -> flushed when printed, also from Workers (#43004; fixes #42989)
bun --bun runworked only for the first user of a shared machine ->nodeshim directory per user (#35565; fixes #7504)
Resolver and version picking
- Range picked a deprecated version (
@types/*stubs under*) -> prefers one that is not, like npm; a locked version stays untilbun update(#36630; fixes #7571, #25314) bun add pkginstalled a deprecatedlatest-> highest release that is not deprecated;pkg@lateststill follows the tag (#40317; fixes #40310)- Missing or dangling
dist-tags.latestfailed add, install,update --latest, hid the package fromoutdated/update -i-> highest release, with a warning (#36671; fixes #12041) *,npm:pkg,npm:pkg@*skipped a prereleaselatest-> follow the tag, like npm (#39774)- Wide range (
*,>=1) nested the newest version -> shares a resolved version that satisfies it;bun updateno longer re-adds whatbun deduperemoved (#38770) 1.0.0 || ^2.0.0,=2.5.0 <2resolved as their first exact version (#30076)>=0.5 0was read as alternatives -> intersection, like npm (#32993)^,~, x-ranges admitted prereleases of their upper bound (pkg@>=5.0.0-alpha.0 <8overrode^4) -> end at<X.Y.Z-0(#43102; fixes #41371)- Exact prerelease met a range that does not admit it (
overrideskeys) (#43150; fixes #43138) >1meant>1.0.0->>=2.0.0;>1.2->>=1.3.0, like node-semver (#43253)<x,<*,>x,>*matched everything -> nothing;^x,~xmatch any version (#43258)- Version number above 2^64-1 was read as 0 -> invalid (#42458)
Bun.semver.satisfies()was true for"",1.2.3.4,1.2.3 junk(#32998)satisfies("1.0.0+build-1", "^1.0.0")was false;< =1was misreadpkg@2x,1beta,1.2xwere read as ranges -> dist-tags (#35259; fixes #19065)- Words starting with
ssh/httpwere read as URLs -> dist-tags (#37133) - Leading whitespace in a version literal (tag, folder, tarball,
npm:,catalog:) broke the install, lost a pin inbun add --catalog, or panicked (#38331, #38309) - Version published after the manifest was cached failed for up to 5 minutes -> manifest fetched again once (#39790)
- Root dep edited to another package (
npm:alias) under a range the old version fits kept the old package (#41774) - Plain dep got a same-named
npm:alias's package outside its range (#43267) - New dep that follows an
npm:alias asked for a garbled name (GET /1.0.0no-deps - 404) (#43515; fixes #23264) file:andlink:on one directory became one package (#38114)file:folder in bothdependenciesanddevDependencieswas duplicated (#41833)- Editing package.json re-downloaded GitHub / tarball deps, re-fetched git ones that
bun.lockresolves (#37142) - Registry package that bundles a
file:../xdep failed to install (#43125) - Bundled dep's dep took a slot the bundling package resolves through (#38848; fixes #29263)
bundleDependencieswere kept from one dependency group of a manifest only (#38857)- Tarball, folder or git package whose own
nameis invalid was installed under it -> refused (#38633) - Folder, tarball, git packages without a
namegot broken lockfile rows -> named after their source (#38681; fixes #17060) - Dangling
node_modulessymlink was a resolver error -> missing module; isolated: a failed optional dep goes with the links to it (#38756)
Hoisted linker
- overlayfs: a replaced package of a lower layer kept its old files beside the new ones, exit 0
- Install over an existing
node_moduleshung when the OS refused the pool's first thread bun pruneleft the.old-<random>of a killed install- macOS: clonefile kept a file already at the destination -> replaced (a nested package could hold two versions' files)
- Package was hoisted next to an out-of-range version of its peer (#36300; fixes #20376)
- Dep nested under a package with
bundledDependenciesresolved the bundled version (#43377; fixes #43351) - After a version bump the old version of a transitive dep stayed at the root (#41053)
- Required peer that a migrated lockfile left unbound stayed unbound (#39343)
- Tree saved after a ranged peer gained a higher candidate differed from the next install's (#38767)
file:override on a registry package's or transitive dep was not linked or resolved from the wrong directory -> from the project root, linked with its deps (#38994, #44339; fixes #44299)- One
file:folder that cannot be hard-linked (EXDEV) switched all later packages to copyfile (#40663) - Failed optional dep left its
.binlinks (#44931)
Isolated linker, global store
node_modulesor entry that is a mount point (Docker volume) is kept and reset in placebun add -gnever linked bins into the global bin directory (#30451; fixes #28597, #30450)- Optional dep whose tarball cannot be downloaded or is corrupt failed the install -> skipped with a warning, also
--offline(#43229; fixes #43212) node_modules/.bun/node_moduleschanged between installs of one lockfile withnpm:aliases -> links named by the dep, one layout (#40356; fixes #40355)- Packages that are peers of each other were installed twice (#29345; fixes #29343)
- Missing
link:target was accepted -> install fails, as hoisted (#38045) - Registry package's own
file:./vendor/xdep failed -> linked from inside the package (#38856) - Workspace's scripts ran before the root's deps and bins were there -> after everything else; a bin such a script writes is linked for every dependent (#44868)
- Empty directory, or one without package.json, in a link slot stayed (#41453)
- Store names of non-ASCII paths were garbled (#40719)
- Package used under its name and an alias got bins for one dependent only (#44446)
--omit=peerdropped a peer an ancestor provides;bun prune --omit=peeragrees (#41416)- Files deleted from a
file:folder stayed in its copy (#37138) - Links of a renamed or removed workspace stayed in
node_modules(both linkers) (#38511) bun pruneleft dangling links to removed optional / peer deps in store entries (#42625)- Switching the global install's linker removed
bun linkregistrations (#43582) - Global store: a package whose peer is typed by the project's
@types/*was shared, TypeScript missed the types -> project-local (#36796; fixes #36795) - Ranged peer whose auto-installed version drops out of the saved tree was linked to nothing (#38768)
Bins
- Hoisted: with
--silenta failed bin link exited 0 and saved the lockfile -> 1, nothing saved (#44997, #44958) - Every install recreated
.binlinks, failed withEEXISTon a read-only up-to-date tree -> a right link is left alone (per bin: chmod 1 -> 0, unlink 1 -> 0, symlink 2 -> 1) (#36701, #20067; fixes #14736) - Several packages with one bin name: an arbitrary one won -> direct deps first, then registry / git / tarball before workspace,
file:,link:packages, then by name (#31416, #41867) - Isolated made bin targets 0777 ->
0777 & ~umask(#41509) - One bin that fails to link stopped the rest (#38972)
binentry whose value is not a string dropped the package's other commands (#43159; fixes #43148)- File system that refuses symlinks (EACCES / EPERM) failed the install -> one warning, no
.binlinks (#40161) - Bare
bun update -g/bun ci -glinked no bins; a reinstalled global package gets its command back (#43384) bun pm migrate/pm trustwrote uninitialised bin bytes intobun.lockb(#37581)
bun.lock, bun.lockb
- Corrupt or crafted
bun.lockbcrashed or hung install,pm ls,why,outdated-> validated at load, refused with a warning; files by Bun 0.x are normalised and keep loading (#32753, #39720) - Two strings whose hashes collide became one in the lockfile (#41642)
- Root
file:or registry dep named like a workspace made Bun write a lockfile it refuses (Duplicate package path) -> the member beatsfile:; a registry range it does not satisfy gets the root slot (#37245, #37248) - Root alias of the registry package named like a workspace dropped the workspace (#43567)
file:paths from the lockfile were resolved from the wrong directory afterbun updateor an override removal (#38850)- Re-resolving install dropped packages
bun.lockholds only through optional peers (#39002) - Package printed at several paths got its edges from the wrong row (#39347)
- Re-saving moved a bundled peer off its entry's version, and a peer nothing satisfies (#38837, #38892)
bun addinstalled nothing whenbun.lockrepeats a dependency line (#43271)--lockfile-onlysaved after an error;--silentfailed on abun.lockit ignores (#44364)bun.lock,bun.lockb,yarn.lockignored the umask (yarn.lock0666) (#41808)bun <path>.lockbprinted the directory's lockfile, read.env, needed package.json -> prints the given file (git textconv works) (#44870)git+git://resolutions did not load back frombun.lock(#38798)bun pm migrate/pm trustwrote anotherconfigVersion/patchedDependenciesthan install; yarn entries without#sha1(#41908; fixes #38193)- Absolute or over-long workspace path in
bun.lock/ pnpm-lock.yaml crashed or counted as pruned (#43405) bun install --yarnrewrote an unchangedyarn.lockevery time
--frozen-lockfile, bun ci
bun cifailed in a workspace when nothing changed (member with a script and alatestrow); one member's edit moved pins elsewhere -> members are compared row by row, keep their pins (#44919; fixes #26070)- Version the lockfile pins was blocked by
minimumReleaseAge(#40032; fixes #40031) - After a migration with a root postinstall, or
pm migratetobun.lockb, the next frozen install failed on the meta hash (#44501) - With both
overridesandresolutionsonlyoverridesapplied -> both; a lockfile without those rules fails frozen, 1.4's too (#38811) - Direct dep pinned outside its unchanged range (one-sided merge) was installed, frozen passed -> re-resolved; frozen fails (#43375; fixes #43795)
Migrations (npm, pnpm, Yarn v1)
- Yarn Berry: a range
yarn.lockhas no key for is the workspace that satisfies it; Yarn's ownpackageExtensions;resolutionskeyed on an alias; a name in several groups of a workspace;catalog:in an extension;%xxin a folder name; clearer refusals (#45052) - Yarn v1, npm: a dep the lockfile has no entry for is reported (#45052)
- npm: a scope registry with a path and no trailing slash gave
InvalidNPMLockfile(#38698) - npm: a package's own
file:directory was resolved from the project; one that climbs out is skipped (#38990) - npm: a
file:directory copied by--install-linksfailed with EISDIR (#43103) - pnpm:
pnpm-workspace.yamlwas read only with a migratable lockfile;bun patch --committhen segfaulted (#38754) - pnpm: the
pnpmblock was removed from package.json -> kept, fields copied (#38775) - pnpm:
onlyBuiltDependencieswas lost ->trustedDependencies; isolated reports blocked scripts (#38780) - pnpm: importer rows differed from a package.json parse, the next install rewrote
bun.lock(#38791) - pnpm: only used catalog entries were migrated (#38829)
- pnpm: non-string keys / values in
pnpm-workspace.yamlcrashed -> scalars copied as written (react: 18->"18") (#44470) - Read-only commands and failed installs wrote a migrated lockfile and package.json edits -> only a command that saves a lockfile (#38804)
- Yarn v1: workspace packages were dropped when the root has no deps (#38878)
- Yarn v1:
npm:alias packages were named after the tarball URL (#38948) - Yarn v1: registry entries without
resolvedfailed (#38985) - Yarn v1: an entry without a buildable resolution aborted the migration -> skipped with a warning (#39001)
Workspaces, catalogs
- Member without a
namefailed the install -> skipped (#38781; fixes #6317) - Dist-tag (
latest,"") on an unpublished sibling got a 404 -> links the workspace (#35468; fixes #4830) - Empty
workspace:spec linked the project into itself -> error; a glob like../*made the root its own member (#41653) - Workspace globs skipped symlinked member directories (#41567)
- Range linked to a workspace stayed linked after the root dropped it (#43468)
- Workspaces of a package.json in
/(orC:\) were not found (#43404) workspacesglob that fails named no path (#43517)bun update <name>rewroteworkspace:^,file:and other non-registry entries (#38847)bun add member@workspace:^lost the spelling (#38866)bun updateprinted no row, or another catalog's version, for a moved catalog entry (#38763)bun update -iupdated one of several catalogs defining a package -> a row per catalog (#36446)- Failed
catalog:dep always suggestedbun add --catalog-> only where that works (#44638) npm run <script> -w <ws>/--workspacesinside a script recursed forever -> runs the workspace's script (#33800; fixes #22719, #24838, #33796, #41543)
Overrides, peers
- Auto-installed peer took the newest version of one asker -> newest that everyone asking accepts (#36646; fixes #8292, #15711)
*peers resolved by manifest arrival order -> after their siblings; unprovided peers in a fixed order (#37713)incorrect peer dependencywas checked against any copy in the tree, hoisted only, every install -> the copy each dependent resolves, both linkers, only when something was resolved (#41936; fixes #7403)- Peer that a
file:,link:, tarball or git dep provides was looked up in the registry (#33156) - Peer dependency on
bundownloaded thebunnpm package (80-170 MB) -> optional (#39757) minimumReleaseAgeblocking a peer or optional pin failed the install -> warning (#38995)bun update name@versionbound a peer row to a stale lockfile leftover (#38901)- Override replaced the link to a member of that name (#37271)
- Changing
overrides/ catalogs re-resolved rows a package no longer owns (#38849) bun update <name>left rows of a$nameoverride stale, frozen passed (#43981; fixes #43975)bun update --latestmoved versions an override selects;-rwrote"latest"into package.json (#44485)overrides/resolutionsthat are not objects were ignored -> error (#40729)- Keys
foo@catalog:,my-foo@npm:foo[@^1](Yarn) were ignored with a warning
Registries, credentials, .npmrc, bunfig
.npmrccredentials follow npm's key walk://host/covers paths below it,_authsent as written, a line reaches registries named by--registry/ env /$VAR, a tarball on another https host gets that host's line; a sibling or look-alike path inherits nothing;:443/:80keys keep working (#40423; fixes #28233, #30311, #30513, #40549)- Registry URL without a trailing slash lost its last path segment (#36294; fixes #5368, #14017, #16185, #20373)
user:pass@in a registry URL from an env var was dropped (#38834)user@/user:@sent nothing -> Basic auth with an empty password (#39063)- URL credentials were sent percent-encoded -> decoded (
p%40sssendsp@ss) (#39603) .npmrc:;/#comments were part of the value;ignore-scripts=1,=True, empty did nothing -> as npm (#41916).npmrckeys and values kept Unicode whitespace (#41714)--ca/--cafilewere shadowed by a config file'scafile-> one setting, a later layer replaces both (#41898)-gcommands ignoredglobalDirfrom--configand~/.bunfig.toml(#35454; fixes #4553; refs #12886)~incache.dir,globalDir,globalBinDir,cafilewas a literal directory (#36667; fixes #10152, #26715)[install.cache] disable = truestill cached manifests (#36219)- Unreadable
.npmrc/ bunfig.toml was skipped silently -> warning (#41693) bun publish,pm whoami,audit,pm view,pm diffignoredhttp_proxyandNODE_TLS_REJECT_UNAUTHORIZED=0(#38075, #38093)bun pm whoamisent a stub CI name -> the real vendor (ci/github-actions) (#40805)
Network, retries
- Retries came at once, one network error halved concurrency -> 250 ms doubling to 10 s with jitter,
Retry-After, 429 / 408 retried, certificate errors not (#40009) - Timed-out request was retried silently -> a warning per retry (#35168)
BUN_CONFIG_MAX_HTTP_REQUESTSwas ignored (#38744)- Help and docs said
--network-concurrencydefaults to 48 -> 64 (#38759)
Cache, tarballs, extraction
- Process could exit before the manifests it fetched were cached:
--offlineright after an install could fail file:/ URL tarballs were cached by path or URL, two projects or branches got each other's package -> by the integrity inbun.lock(#39016)file:/ URL tarball deps were reinstalled on every run (hoisted) -> verified by a.bun-tag(#35576; fixes #8260)--force,bun update, re-adding the same path / URL kept old bytes or the old hash -> direct tarball deps are fetched again (#31868; fixes #31864)- Re-extraction leaked the displaced cache folder; extraction directories stayed in
$TMPDIR(#38702, #33979; fixes #33977; refs #28062) - Two registries on one host (port, path, http) shared cache entries (#41636)
- Concurrent installs sharing a cache deleted each other's entries (ENOENT without
RENAME_EXCHANGE, NFS) -> first writer wins (#36229; fixes #36227) - Gzip trailer was not verified (since 1.3.14) -> a damaged tarball fails; also
Bun.Archive(#41503) - Body that is not gzip installed as an empty package; a tarball without package.json stayed in the cache
- Query string / fragment of a tarball URL ended up in the extraction folder name (#39011)
github:tarballs extracted symlink entries -> skipped, like npm (#31481)- Rewriting a cached manifest unlinked it first -> atomic replace (#38916)
--no-verifycached unchecked bytes under the lockfile's hash, for all projects -> own key; isolated kept such a copy
git, GitHub, folder deps
- Cached git dep never saw tags / branches pushed later;
bun updatefollows moved refs (#35566; fixes #11548, #13769, #15336, #18947) git+ssh://git@host:2222/..lost its port in the ssh fallback (#36932; fixes #36931)deploy@host:org/repo.gitbecamegit@deploy@host(#35026)bun add name@git+ssh://host/repo.gitlost the alias for hosts other than GitHub (#36687; fixes #13891)github:o/r#feat%2Fxsilently installed the default branch; an escaped owner / repo is an error (#43172)- Optional git dep that cannot be cloned or lacks the ref failed the install -> skipped with a warning, also when locked (#43076, #43352; fixes #43350)
- Several
github:/ git refs on one commit, or afile:folder declared by several packages, failed with EEXIST or wrote a lockfile Bun refuses -> one package (#42640, #42545) - Concurrent cold installs replaced each other's git cache folder (#42656)
GIT_DIR(git hooks) made install andbun creatework on another repository -> 13 git variables are not passed on (#41715)file:folders declared by git / tarball packages were resolved from the project (#38816)- Bare word or
git@host/pathwas handed togit cloneas a local path; a URL could be read as an option bun link -g/unlink -gfailed;bun link -g <name>removed the registration ->-gis ignored (#33142; fixes #21397, #33141)
Lifecycle scripts, trust
- Hoisted: beyond
--concurrent-scripts, the next script waited for all running ones to end -> for one - Failed or unstartable script left other packages in place whose scripts never ran, and never would -> removed
trustedDependenciesentry added to a member after the first install did nothing -> its blocked scripts run once (#41803)- Isolated: a package trusted after it was installed never ran its scripts (#41845)
- Package installed through an
npm:alias could not be trusted consistently -> by its real name in package.json,--trust,pm trust,bun.lock(#39443) bun pm untrusted/trust/ls --trustedfollowed a stale lockfile, knew nothing withbun.lockb-> read package.json (#41933, #34327)pm untrusted/trustlisted and reran workspace members (#41513)- Failing script of a package both optional and required deleted the package, exit 0 -> install fails (#43218; fixes #43211)
--concurrent-scriptsdid not apply to the isolated linker (#42445; fixes #42421)- bunfig
concurrentScriptsbeat--concurrent-scripts(#42422) - Node-gyp shim was unreachable when the temp directory falls back to the cache (#38098; fixes #38079)
--helpsaid dep scripts never run ->--ignore-scriptsalso skips trusted ones (#38893)bun pm -g untrustedsuggestedbun pm trust->bun pm -g trust(#44663)- After a failed script, a half-deleted git / tarball / patched package counted as installed
Security scanner, audit
- Scanner saw registry packages only -> every resolved dep (git, GitHub, tarball,
file:,link:), URLs without userinfo / query; a fatal advisory stops them before install and scripts (#37590) --production/--omit=devfailed when the scanner is a devDependency (#31031; fixes #31028)- Scanner process loaded
.envitself -> gets the install's environment, follows--env-file,--no-env-file,env = false(#44845) bun audit fixcould downgrade into an older major (#39317)bun audit --helplacked--production,--omit,--dry-run,--cwd(#38836)
add, remove, update, outdated, link
- Hoisted:
bun remove foodeleted thenode_modules/fooanother workspace has for"foo": "npm:bar" link,install <pkg>,install --analyze,update -i,removeexited 0 afterFailed to install N packages-> 1 (#44989)bun add ../pathfrom below package.json,bun install -g .resolved from the wrong directory -> the cwd (#43348, #36623; fixes #5682)bun add <folder | tarball | git url>of a declared package wrote it twice (#43380; fixes #8031)- First
bun add -gused a package.json above the global directory (~/package.json) (#30659; fixes #40683) bun add --dry-runin an empty directory created package.json (#36694; fixes #13244)bun removereordered package.json keys -> order, tabs, final newline kept (#35586; fixes #7215, #9351)bun remove -gleft dangling links in the globalnode_modules/.bin, deleted foreign dangling links in the bin directory (#43403)bun update <name>blanked an optional / peer range no version satisfies (#43195)bun updatethat only rewrites package.json said(no changes)(#38918; fixes #38908)bun update -irepeated its prompt on mouse clicks and in short terminals (#39683)update -i/outdatedtables were sized in bytes -> display width (CJK, emoji), cells escaped (#43333, #43236)outdated/update -iused the lockfile's ranges -> package.json's (#42005)bun outdated a bneeded all patterns to match -> union;!patternremoves (#43309)outdated/whyknew an aliased dep by one name -> either, both printed (#43338)- Coloured version diff dropped the build tag, left a tag that only grows (
rc.1->rc.10) dim; long prerelease tags were garbled (#38688, #38649) minimumReleaseAgeerror swapped range and name (#37895)bun link/unlink --helpdescribed a wrong--savedefault (#38915)
bun pm, why, info
bun pm pkg getof several values altered one with a}in it, left a key unescaped (#45061)bun pm cache rm --cache-dir <dir>cleared the global cache -><dir>; project config still cannot redirect itbun pm bin -g/pm ls -gfailed before any global install -> work, write nothing (#36622; fixes #6382, #7501, #13019)bun pm cache rmsays when the global store goes with the cache; docs name--forcefor stale manifests (#43667)bun pm versionsaw no repository in worktrees / submodules (.gitis a file) (#41754)bun pm version prereleaseoverflowed above 2^32; versions npm calls invalid were accepted (#42459)bun pm view pkg@tag/pm diffusedlatestfor an unknown dist-tag -> error listing the tags (#42063)bun pm,pm --help, an unknown subcommand printed three help texts, unindented, withoutpm diffandls -g-> one (#39487, #43314, #43098; fixes #43310)bun pm bin -gsaidnot in $PATHfor an entry with a trailing slash (#28773; refs #28771)bun whyprinted a package's dependents at every occurrence (exponential) -> once, repeats*deduped(#37922)bun why name@versionfailed for exact / scoped names, ignored a workspace's version (#43284, #43290; fixes #43288)bun why: no-match error on stdout -> stderr (#43287; fixes #43285)bun why: branch left open after the last visible workspace dependent (#43292; fixes #43291)bun why: a cycle back to the queried package is*circularat its first repeat (#43300; fixes #43295)bun why: a root package.json withoutnamewas missing as a dependent (#43277)bun why: a peer dependent was shown under the wrong copy (#41941)
pack, publish
workspace:/catalog:versions came frombun.lock(stale, or failed without one) -> the package.json files; no lockfile is read (#38813; fixes #20477, #20829)workspace:aliases and directories were published as written ->npm:aliases; the workspace's version (#38788, #38835)!patternin.npmignorecould not re-include files below an excluded directory (#36699; fixes #15602)- Relative
--destination,--filename,bun publish ./x.tgzwere resolved from the package root -> the cwd (#38739, #38704) - Failed pack left a partial tarball,
publish --dry-rundeleted an existing one, a FIFO--filenamehung -> built in memory, written once complete (#38721) - File names that are not UTF-8 were mangled, two became one entry (#38715)
- File systems whose readdir reports
DT_UNKNOWNlost entries (#38716) binpaths naming no file,.., a trailing slash indirectories.binbroke pack; an emptybinhiddirectories.bin(#38720)- File under several
binnames was packed several times (#41291) - Directory, bin or bundled dep that is there but unreadable was left out silently -> exit 1 (#44400, #44873)
bun publishaccepted aversionthat is not semver -> refused after the scripts;v1.0.0goes out as1.0.0(#43142)
bun patch
--commitfrom a workspace member flipped the root package.json's final newline to the member's- Patch adding a file in a new directory failed with
EACCESfor non-root users (#33573; fixes #13330, #33571, #38569) - Hunks were applied by line number, wrote wrong text when the file had moved;
-U0hunks landed a line off -> placed by context likegit apply;hunk #N does not applyfails the install (#41733, #41695; fixes #38879) - Old-style diffs whose hunks delete lines starting with
-- a/were misparsed (#34870) - Failed copy, missing cache entry, missing git or failed
git diffleft a partial or nonode_modules/<pkg>-> staged copy, everything put back (#43188, #43160; fixes #43164) bun patchdropped the package's bundled and nested deps,--commitrecorded them as deleted (#43178)bun patchof a bundled dep deleted the bundled copy -> refused (#43199)bun patchof afile:folder,link:or workspace package damagednode_modules-> refused (#43223; fixes #43200)bun patch <path>replaced a folder with another version -> refused when the version is not locked (#43367; fixes #43353)npm:alias could not be named by its package; a secondbun patch <alias>lost the first patch (#43382)- Isolated:
bun patch <transitive>made a straynode_modules/<name>-> edits the store entry (#43383) bun patchreplaced workspace links and symlinks above the package, could write into the global store -> links stay; anything under the cache is refused (#43406)--commiton a patched package wrote.bun-tagfiles and cache paths into the patch, read/etc/gitconfig(#44349; fixes #19327, #44320)--commit: a new binary file became empty, a changed one was skipped, exit 0 -> commit fails- Member's
patchedDependencieswere ignored silently -> warning (#39869) - Isolated:
bun patchreplacednode_modules/<pkg>by a directory that could not load its deps -> edits a copy in the store entry, the link stays; global store:--commitrestores the link (#43365)
bunx
bunx pkg@latestrelinked everything each run, a day-old tree was refreshed every run -> once; served with a warning when the registry gives no answer (#41226; fixes #23597, #41211)- Several
bunx <pkg>at once corrupted the shared install -> file lock (#37851; fixes #37830) directories.binwas resolved from the wrong directory (#39096)
bun create
- Windows: a GitHub template silently overwrote files (its conflict list was always empty) and wrote through junctions -> listed;
--forcereplaces the link bun create <local template> <dir>deleted an existing directory -> merges, lists conflicts (links in the destination too), overwrites only with--force(#36351; fixes #27948, #36341)git init/ commit raced tasks and install -> finished first; the first commit holds exactly the template (#41342; fixes #36953)bun-createtasks ran without a shell, not at all without deps, failures ignored -> run like package.json scripts, withnpm_package_name; a failing task stops with its exit code (#41598, #38955)- Failed nested
bun installwas ignored -> exits with its code (#38485) - Absolute template path crashed -> local folder;
.,.., an empty name are refused (#41770) bun create ./Component.tsxoverwrote your stylesheet,styles/globals.css,lib/utils.ts-> kept and listed;--forceoverwrites (#44668)- Template's package.json indentation was lost (#36965; fixes #36964)
- Missing-export hint printed
{{}}(#37847)
Auto-install
- Timers and I/O callbacks ran inside
require(),import(),Bun.resolveSync()while a package was fetched -> the thread waits; git deps are no longer cloned at run time (#36159; fixes #43842) - Second version (
pkg@2afterpkg@1) with the manifest in the disk cache failed withUnexpected(#36659; fixes #10411) - Failed lookup failed until the process exited -> a 404 stands as long as a cached manifest (5 min, or its
Cache-Control); any other failure is asked again once the event loop has gone around (#42883) - Failed download limited
fetch()to 4 concurrent requests for the rest of the process (#42945) --prefer-offlinestill asked the registry -> cached manifest (#36776)- Resolve errors did not say why (#38180)
- bunfig
install.preferworked forbun run <file>only -> alsobun <file>,bun test - Dep whose name or version has a JSON escape fell back to
latest
Completions, installer
- Second completions line was added to a
.zshrcthat already sources~/.bun/_bun(#35561; fixes #10897) - fish completions went to
/etcwhen~/.config/fish/completionsis missing (#41659) - install.ps1: the
another bun.exe is already in PATHcheck never fired (#38567)
Crashes, panics, hangs
- Hang until out of memory on a dependency cycle ->
dependency cycle cannot be laid out in node_modules, exit 1; a bundled back-edge installs (#38976) - Hang: a dangling
node_modules/@scopesymlink (hoisted) - Hang:
--concurrent-scripts=0-> the default (#42379) - Hang: isolated, a tarball URL that cannot be requested (
ftp://) (#39672) - Hang: isolated, cold cache, a git dep that is scp-form, a peer, from
overridesor spelled differently inbun.lock; after a failed clone / checkout (#44448, #37156, #43075) - Panic: paths that do not fit the path buffer in both linkers' walks,
link:targets, long linked names,<alias>/package.json->ENAMETOOLONG/Invalid dependency name(#37424, #37400, #38369, #38571, #38575) - Panic: over-long
--cafile,--cwd,add --filter;$BUN_INSTALL/$HOMEwith-g; bunx bin names; pnpmlink:/file:paths; progress bar names (#41702, #38413, #37394, #43537, #38558) - Abort of all package manager commands,
bun run,bunxin a cwd within 13 bytes ofPATH_MAX->ENAMETOOLONG, or the file counts as unreadable (#42502) - Panic:
outdated,update,update -ion abun.lockwithoutpackages(#41647) - Segfault: package.json nested ~8,400 levels; a deep YAML alias chain in pnpm / Berry files
- Panic: all
bunxinstall flags at once - Use-after-free in
bun add --trustand at the end of an isolated install (#31245, #39640) Bad system callon Android / Termux (openat2,fchmodat2under seccomp) (#39084)
Windows
- Bins whose shebang uses
env -Sdid not run (#31391; refs #22422, #27924, #31387) .bunxshims broke when the package is on another drive (#38018)bun removeleft.bunx/.exeshims (#35585; refs #11970)bun installfailed in the root of a drive (#43437; refs #29273)EINVAL: Failed to replace old lockfileon exFAT / FAT32 (#33029; refs #10169)- Concurrently published cache entry was deleted; renames failed while a virus scanner holds a new file -> retried for 5 s (
BUN_INSTALL_WINDOWS_RENAME_RETRY_MS) (#33884, #35568; refs #11250, #28062) bunx.exewas written when the hard link fails ->bunx.cmd(#35686)
Performance
User-space instructions of bun install (perf stat, median of 3, millions), generated project of N packages, loopback registry; warm = nothing to do, relink = cache + lockfile, no node_modules.
| main N=400 | branch N=400 | main N=1600 | branch N=1600 | |
|---|---|---|---|---|
| hoisted warm | 22.5 | 20.3 | 146.5 | 80.1 |
| hoisted relink | 24.5 | 21.6 | 150.3 | 83.3 |
| hoisted cold | 121.0 | 122.2 | 511.2 | 474.6 |
System calls per package (strace -c, slope between 100 and 300 packages of 31 files). Per run: a few more lstat (change 8), one read per file: directory dep.
| main | this branch | |
|---|---|---|
| hoisted cold | 215.96 | 211.95 |
| hoisted relink | 72.00 | 70.00 |
| hoisted warm | 4.00 | 4.00 |
Quadratic scans in the bun.lock workspace parse, yarn.lock printer (#34537) and Yarn v1 migration (#37244) are gone; no allocator heap per cached package.json (#44610).
| main | this branch | |
|---|---|---|
bun pm hash, 32,000 workspaces (ms) | 6,914 | 236 |
bun pm migrate, Yarn v1, 20,000 entries (ms) | 24,210 | 270 |
peak RSS of bun install, 2,100 workspaces (KB) | 90,840 | 34,728 |
hoisted, 1,000 packages x 30 files, cache, no node_modules, 8 cores, wall (ms) | 381 | 120 |
| same, 4 cores | 383 | 174 |
| same, 2 cores | 222 | 162 |
same, node_modules lacks half, 8 cores | 140 | 54 |
| same, 4 cores | 174 | 65 |
| same, 2 cores | 161 | 107 |
same, no cache, no node_modules, 8 cores | 363 | 394 |
| same, 4 cores | 418 | 401 |
| same, 2 cores | 477 | 541 |
Internal, no user-visible effect
- Earlier fold of 171 PRs is the first layer; 12 of them were taken out again (#39403)
- One implementation each: trusted set, required-dep predicate, failed-optional discard, bin linking, package.json walk,
--cwd, cache publish, specifier -> version (was 4), lockfile writer, registry request pack()consumes its context; onebinding.gyppredicate; Yarn v1 migrator 2,032 -> 888 lines, nounsafe(#37670, #43912, #37539, #38303, #37865)- Debug builds: opt-in stack dump,
nodeshim directory kept, manifest cross-check deleted (#37335, #37384, #43170) - Binary size pass (outlined helpers, shared flag tables, index sorts): +464 KB -> see Performance; dead auto-install disk scan removed.
unsafein src/install: 585 -> 540
Test-only PRs
- verdaccio replaced by a registry on
Bun.serve(on main since): #44055 - No public network: #35035 #35377 #35384 #36717 #36718 #36721 #36889 #38185 #38467 #39022 #39655 #40087 #40538 #40956 #42800 #42802 #43289 (fixes #43286)
- Concurrent, a cache per test: #38464 #38504 #40095 #40635 #39646 #40198 #40450 #39956 #39740 #41110
- Exact output / lockfile / layout (nested-overrides, bun-add-filter, lockfile-sync, frozen-lockfile-pruned, pm-licenses, isolated-relink): #39648 #39746 #40452 #40454 #40456 #41118
- Flake causes removed (stdin / pty races, racing ranges, cold manifest cache, un-awaited matchers): #34175 #41401 #41591 #38858 #39190 #38627 #37333 #33279
- Faster (streaming-extract, git-deps, npm-arborist): #35915 #40447 #40977
- New guards (
..tarball entries, Bun's ownbun.lockpasses frozen, hoisted layouts, what a linker verifies): #37431 #42384 #43878 #41864 - Harness (
isRoot, peak RSS,pm trustCPU test on Windows): #39232 #43192 #35626 (refs #11252)
Taken in part (what is in. Not: what is not)
- #19637: opt-in
bunx --trust(runs the scripts of the package and its whole closure). Not: trust by default - #29794: change 4. Not: removing a stale copy no lockfile placed (
bun prune) - #30522: change 14. Not: signing; #15601 open (refs #18611)
- #31327: a junk integrity in a v2+
bun.lockis an error. Not: pinning a computed sha512; refusing an empty integrity under frozen - #32022: 10 helpers redone on current code, 26 of 28 pinning tests. Not: non-install parts
- #35253:
bun createwithout a git identity stages the files, says the commit was skipped. Not: a made-up author - #35807:
npm_config_ignore_scripts=trueturns scripts off. Not:false/0turning them on over a config file - #36387: false
Workspace name already existson a hash collision. Not: the same fortrustedDependenciesnames (one stays blocked) (refs #36386) - #36973: docs of the store layout as it is. Not: a stability promise
- #38001: a token survives an http -> https redirect on one hostname. Not: another port (still stripped) (refs #15516)
- #38832: its forced-arrival-order tests, expecting one copy (#38770). Not: its two-copies policy
- #39505: cold generics -> runtime flags in summary printer,
pack, lockfile read. Not: typed arrays, coverage - #39886: an override on a peer was lost behind a same-named root
npm:alias. Not: a peer without an override shares the alias (react->npm:@preact/compat) - #40053: features, change 15. Not:
[install.packageExtensions]in bunfig;pnpm.packageExtensionswithout a migration;catalog:values (ignored, warning) - #40110: warning for a
patchedDependencieskey that matches no installed version. Not: failing frozen - #41724: moot for tarballs (named by integrity). Not: new names for bare git clones
- #41759: a package.json in a sticky shared directory above the cwd (
/tmp) is ignored, with a warning. Not: the owner rule - #41863:
pm pkg set --jsonwith a value that is not JSON is an error, nothing is written. Not: strict JSON (0x10,.5are normalised) - #41921: Linux: a script no longer outlives a killed install. Not: signal forwarding; macOS
- #41925: symlinked bins /
directories.binare neither packed nor listed. Not: race-proof opener, Windows, a symlinkednode_modules - #41931: change 2. Not: failing on trusted / patched edits or equivalent spellings (refs #22689)
- #42001: after a failed script the next install reruns it and what it blocked. Not: change 18
- #42030: a plain install re-reads a
file:directory's package.json. Not: failing frozen (warns) - #42039: change 8;
bun prunerefuses a linked.bun. Not: the root link (on purpose); a package's own directory on a warm run - #42052:
bun pm view/info: no project needed, several fields, npm paths (maintainers[0].name), semver-sortedversions,bin:,DEPRECATED. Not: new--jsonerrors (refs #20673) - #42139: npmrc.test.ts: isolation per case, concurrent. Not: exact pins
- #42400:
pm diffcompares a folder of this project as pack publishes it. Not: folders of other projects - #42597: nothing of the project's
.envreaches install'sgit. Not: proxy / TLS variables from.env - #43067: the 255-byte name bound, the install cases. Not: the repo-wide sweep
- #43375: which package owns an override row; direct deps outside their range. Not: transitive rows
- #43556:
bun patchnever writes into the global store. Not: a project-local copy that installs keep - #43581: a registry package's peer / optional edge to a workspace missing on disk is dropped. Not: the pre-flight report
- #43793: the walker looks at link entries; the
@scopehang. Not: materialising symlinked cache entries; #43788 unverified - #44058: Windows:
nodeshim next to bun.exe when%TEMP%is on another drive (never run). Not: a missing%TEMP%(warning) (refs #44033) - #44406: change 4. Not: a copy no loaded lockfile names
- #44488: a dep's script finds its own
.bin, thenPATH, then shared.bin: another package's bin cannot shadownode/sh. Not: bins per script owner - #44641: its install test and docs hunk. Not: 13 HTTP / fetch test files
- #44793: Windows: the launcher of a
.cmd/.batbin (any case) refuses cmd.exe special characters. Not:bun run <bin>.cmd - #44798: a
node_modulesa git dep commits is dropped unless it bundles (then without links). Not: bundled closure only - #44847: a workspace's
node_modulesis reset when only the root's was deleted. Not: moving stale directories aside; a marker
Not taken
- #20178: the isolated linker covers it; #6850 open
- #28515: prints the repo URL, no changelog
- #29512:
bun pm sbom: own PR - #30289: a
bun linkname would override every project - #30340: checks after the fetch, fails open
- #30582: config surface without demand
- #30863 #40976 #43643: not install: install.sh,
bun upgrade - #31585 #41750 #43144 #43242 #44509: not install:
Bun.Archive - #31979 #37596 #37646 #37678 #39165 #40312: refactor nothing needs
- #33113: needs a Windows measurement
- #33972: masks a flake; cause gone with #37713
- #35105: distrusts the cache directory
- #35371: borrow refactor, no longer applies
- #35571: re-lays existing monorepos; #9838 open
- #35602: false positives, harmful advice
- #36081: needs the public registry
- #36464: stale; weakens lockfile parsing
- #36476: the next step after this PR
- #36556: reverses an earlier hardening
- #36557: its code is deleted (#44393)
- #36587: restores a dead warning
- #36631: contradicts a landed test; #7869 open
- #36682: the typo already gets a clear error
- #36688: a landed test pins the opposite; #13509 open
- #36696: own feature (config root for bunx / create); #13247, #5361 open
- #36888 #39741 #39742 #39957 #40639: test rewrite without measurable gain
- #37143: cause removed by #44919
- #37551: part of #40284
- #37644 #38365 #39206 #39936 #40855 #44031 #44425: not install (transpiler,
bun run,Bun.write, pipe reader, repo-wide) - #38741: lockfile v2 has shipped
- #38777: follows links out; main case gone with change 3
- #38810: turned down earlier; #10297 open
- #38814: draft; rows grow per path
- #39217: little demand
- #39499: codemod for an unlanded change
- #39724: refuses installable tarballs; see #41503
- #40045: 16 public JSON formats: own PR
- #40073: test flag that hides a race
- #40277: second store layout
- #40284: stacked on branches that have not landed (needs new task, request and archive types in six other crates); follows separately
- #40300: Windows bunx.exe identity; #40298 open
- #40717: opposite of #36690
- #40753: loosens default-trust hardening
- #41764: subset of #43322
- #41866: opposite of #41803
- #43104: needs a new
bun.lockkey - #43209: needs #43104's key
- #43322: breaking; realpath per workspace
- #44117: stacked on #44058
- #44621 #44809 #44813: draft
- #44622: changes patch hash and cache names; #25932 open
Obsolete (on main via the PR in brackets, or moot): #18582 (the Zig build is gone) #35542 (#38333) #35603 (#41854) #36352 (verdaccio is gone) #36670 (#38269) #36977 (#40010; --tarball-dir, #7956 stay open) #37126 (#40734) #37137 (#38269) #37250 (#38333) #37616 (#40734) #37925 (#37426) #38648 (#40063) #38671 (#39229) #38687 (#40406) #38776 (#38796) #38869 (#41302) #38891 (verdaccio is gone) #40766 (verdaccio is gone) #41667 (#42881)
Fixed issues
Fixes #2773. Fixes #4553. Fixes #4719. Fixes #4830. Fixes #4852. Fixes #5045. Fixes #5176. Fixes #5368. Fixes #5682. Fixes #5714. Fixes #6317.
Fixes #6382. Fixes #6883. Fixes #7215. Fixes #7403. Fixes #7501. Fixes #7504. Fixes #7571. Fixes #8031. Fixes #8260. Fixes #8292. Fixes #9351.
Fixes #10152. Fixes #10411. Fixes #10897. Fixes #11548. Fixes #12011. Fixes #12041. Fixes #12430. Fixes #12752. Fixes #13019. Fixes #13244. Fixes #13330.
Fixes #13379. Fixes #13769. Fixes #13891. Fixes #14017. Fixes #14134. Fixes #14736. Fixes #15102. Fixes #15336. Fixes #15602. Fixes #15711. Fixes #16185.
Fixes #16282. Fixes #17060. Fixes #17759. Fixes #18670. Fixes #18947. Fixes #19065. Fixes #19327. Fixes #20373. Fixes #20376. Fixes #20477. Fixes #20829.
Fixes #21397. Fixes #22035. Fixes #22719. Fixes #23264. Fixes #23597. Fixes #24838. Fixes #25314. Fixes #26070. Fixes #26715. Fixes #27948. Fixes #28233.
Fixes #28597. Fixes #28668. Fixes #28967. Fixes #29263. Fixes #29343. Fixes #30311. Fixes #30450. Fixes #30513. Fixes #30748. Fixes #31028. Fixes #31152.
Fixes #31450. Fixes #31864. Fixes #33141. Fixes #33571. Fixes #33796. Fixes #33977. Fixes #36227. Fixes #36341. Fixes #36795. Fixes #36931. Fixes #36953.
Fixes #36964. Fixes #37830. Fixes #38079. Fixes #38193. Fixes #38569. Fixes #38879. Fixes #38908. Fixes #38909. Fixes #40031. Fixes #40310. Fixes #40355.
Fixes #40549. Fixes #40683. Fixes #41211. Fixes #41371. Fixes #41543. Fixes #41625. Fixes #42421. Fixes #42799. Fixes #42989. Fixes #43138. Fixes #43148.
Fixes #43164. Fixes #43200. Fixes #43211. Fixes #43212. Fixes #43214. Fixes #43256. Fixes #43285. Fixes #43286. Fixes #43288. Fixes #43291. Fixes #43295.
Fixes #43310. Fixes #43350. Fixes #43351. Fixes #43353. Fixes #43399. Fixes #43795. Fixes #43842. Fixes #43903. Fixes #43975. Fixes #44299. Fixes #44320.
Fixes #44669.
Expected fixed, first exercised by CI (Windows; close by hand): #28062 #11250 #11970 #29273 #10169 #22422 #27924 #31387 #11252 #28771 #44033 #12886
Covered by a PR taken in part (close by hand): #18611 #36386 #15516 #22689 #20673
Credits
- @Jarred-Sumner: #39403 (the earlier fold), #20067, #31245, #31416, #33884, #37590, the design of #31447, part of #31327.
- @MarshallOfSound: #40057, #40025, #40053, #40012, #40009.
- @alii: #45052, #45051, #40423, #31481, #33279, helpers of #32022, half of #39505, review findings in #35259 #35468 #35586 #38047.
- @dylan-conway: #19637 (opt-in), the order-dependent shapes of #36476 (tests here), the off-by-one fixes of #33113, the objection behind #37138.
- @nikelborm: #41291.
How did you verify your code works?
- Suite (offline, root): main's tests on main 146 files, 9,099 pass, 306 fail; this branch 174 files, 16,067 pass, 42 fail; 6,277 passing tests are new, 268 that fail on main pass. Of the 42, 40 fail on main too; 1 needs Docker, 1 test deps.
- Absorbed = a test here covers the claim, passes here, fails on main. Exceptions: test-only PRs, guards, performance PRs (measured); by reading only: #39640 #37335 (no test possible), #34175 (Docker), #38858 #39190 #41401 #41591 (flakes), #40447 #39740, the refactors.
- Randomized differential: 600 generated projects (every dep kind, both linkers, both lockfile formats) through installs, edits, prune, patch, damage, kills; all output compared. First install succeeds: 545 -> 559. Projects that violate an invariant:
| main | this branch | |
|---|---|---|
| repeated install rewrites files | 265 | 10 |
| repeated install reports work | 101 | 2 |
| repeated install changes the tree | 22 | 3 |
| lockfile depends on manifest arrival order | 57 | 0 |
| exit code depends on the linker | 20 | 0 |
| writes outside the project | 21 | 0 |
| declared dep cannot be resolved | 13 | 1 |
| dep resolves to a wrong version | 4 | 0 |
| frozen / relink / cold cache fails on its own lockfile | 7 | 0 |
| package.json rewritten with the same bytes | 7 | 0 |
| crash or hang | 3 | 0 |
| dangling symlink | 2 | 0 |
| bin not executable | 2 | 2 |
| leftovers in the temp directory | 230 | 1 |
| tree or exit code after kill + reinstall differs (timing) | 3 | 4 |
- Credentials: 805 requests with main, this branch, npm 11.17.0: 534 as main; 170 wider (npm too in 140, 30 deliberate); 82 narrower; 19 another credential. 142 non-http(s) registry URLs x 16 routes: no request (main: 66).
- Secrets: a secret in every input of 698 projects x 6,490 commands, not masked: data asked for on stdout, source excerpts under a diagnostic, echoed arguments.
- Lockfiles: 90,000 mutated
bun.lockbx 7 commands: no crash or hang. - Version picking: npm-pick-manifest 11.0.3 over 200,000 generated pairs: differs only for a dangling written
latestand^1.0.0-a.0. - Debug + ASAN: 9 files (1,253 tests); 200 rounds of #31245's race. Two installs at once, 252 packages: tree right in 150 of 150 rounds, 2 of 300 exit 1 (main: 35 of 40 wrong, 69 of 80).
- Hoisted thread pool vs main thread, one binary: 704 generated projects, 8,800 fuzz cases, CPU starvation x 4 backends, 432 injected I/O errors, thread and fd limits, script order: equal.
Not verified:
- Windows, macOS: CI only. Android (#39084): a seccomp filter on Linux, no device.
- By script, no test:
--trustwith an alias, an aborted upgrade leaves no holes, two installs at once. overlayfs: a simulatedEXDEV. - Known limits: change 19.
Co-authored-by: nikelborm 29357907+nikelborm@users.noreply.github.com