Repository navigation
Conversation
|
Found 7 issues this PR may fix:
🤖 Generated with Claude Code |
|
Of the listed issues, this PR directly fixes #19748: installing undici is now sufficient to get the real package for the bare specifier. The others (#27783, #7920, #21944, #14498, #4474) are reports about the builtin shim itself, which is unchanged here and still applies when undici is not installed. After this lands, |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Essentials Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 10 included reviews per hour; 0 remain after this review. WalkthroughChangesBare Undici resolution
Suggested reviewers: Priority: ➖ Normal Severity of issue fixed: Medium Merge Risk: ⚪ Minimal · up to Bare undici imports now prefer an installed package while retaining the builtin shim as fallback. No concrete merge-blocking risk is established for the current change. 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/jsc/VirtualMachine.rs`:
- Around line 4084-4103: The alias resolution probes in both runtime resolvers
incorrectly treat resolver failures as missing packages. In
src/jsc/VirtualMachine.rs lines 4084-4103 and src/runtime/jsc_hooks.rs lines
4977-4996, split the ResultUnion match so Failure(e) immediately returns
Err(e.into()), while only Pending and NotFound use the existing alias.path
fallback.
In `@test/js/first_party/undici/undici-prefer-installed.test.ts`:
- Around line 65-84: Add an ESM fallback test alongside the existing CJS test in
the “without an installed undici” case, using a main.mjs entry point and an
import-based probe. Assert that the builtin shim resolves and exposes the
expected request and MockAgent APIs, with the same empty-stderr and
successful-exit expectations as the existing CJS path.
- Around line 9-25: Add a test in the undici resolution suite covering bun build
with --target=bun, verifying that a user-written "undici" specifier remains
mapped to the installed package rather than the builtin shim. Keep the existing
runtime require.resolve and Next.js compatibility alias assertions unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: dfe03831-02a4-401c-aff5-1b71fa670d87
📒 Files selected for processing (10)
src/bundler/bundle_v2.rssrc/bundler/linker.rssrc/jsc/RuntimeTranspilerStore.rssrc/jsc/VirtualMachine.rssrc/resolve_builtins/HardcodedModule.rssrc/runtime/jsc_hooks.rstest/js/bun/util/fuzzy-wuzzy.test.tstest/js/first_party/undici/undici-prefer-installed.test.tstest/js/first_party/undici/undici-primordials.test.tstest/js/first_party/undici/undici.test.ts
|
This PR may be a duplicate of:
🤖 Generated with Claude Code |
|
Updated 10:59 PM PT - Sep 8th, 2026
✅ @robobun, your commit 7b56d60ba487286f1137242b83fc39cf286f6493 passed in 🧪 To try this PR locally: bunx bun-pr 36102That installs a local version of the PR into your bun-36102 --bun |
|
Not a duplicate, but related: #30561 removes the shim entirely, so a missing install becomes "Cannot find module" and the next/dist/compiled/undici alias goes away. This PR is the non-breaking variant: the installed package wins when present, the shim remains the fallback otherwise, and the Next.js compat alias keeps pointing at the shim. If maintainers prefer full removal, #30561 supersedes this; otherwise this one keeps existing programs working. |
The shim's registry key is now internal:undici, so a resolved key never re-resolves into node_modules. Bare undici is an ordinary package at every lookup site. The resolver probes node_modules without auto-install and returns the shim key when nothing is installed.
903e055 to
50ac9d4
Compare
…des the installed undici @remix-run/node in the corpus requires undici. bun build --target=bun now bundles the installed package instead of leaving the shim external, so the payload grows on every platform alike (nine CI lanes agree on these values).
|
The four review findings above (HTTPContext keep-alive guard, ImportMetaObject destroy, FileReader pause, Bun.write byte count) were real, but they describe an intermediate push (903e055) whose squash accidentally reverted merged main commits. That head was replaced. The current head 7b56d60 changes only the 14 undici-related files against main, so those four commits (#41987, #42023, #42038, #42066) are intact. I replied on each thread and resolved it. |
|
Two housekeeping notes. Added "Fixes #17799" to the body. The maintainer note on #36098 (#36098 (comment)) names this PR as the fix for that request and tracks it there. My earlier comment above left that as a maintainer call, and the call has since been made. Compatibility data for review: #30561 (closed in favor of this PR) carried an integration suite for the real package, written by @galenzo17. I ran that suite against undici 6.21.3 loaded from That suite is not folded in here. |
…t-in npm package replacements (#42718) ### Problem - `docs/guides/http/hot.mdx:7` says "When any module or file changes, Bun re-runs the file." `bun --hot` watches only the entry file and the files it imports. An edit to `.env`, `bunfig.toml`, or `tsconfig.json` triggers no reload. - `docs/runtime/watch-mode.mdx:124` shows `Reloaded 1 times` first. The sample logs before it increments, so the first line is `Reloaded 0 times`. - No docs page says that Bun resolves `undici`, `node-fetch`, `ws`, and other npm specifiers to built-in modules, even when the package is installed. ### Fix - `hot.mdx`: say what `--hot` watches, name three files it does not watch, and say to restart Bun for those. - `watch-mode.mdx`: the output sample starts at `Reloaded 0 times`. - `module-resolution.mdx`: new section "Built-in replacements for npm packages". It lists every third-party specifier in the alias table (`src/resolve_builtins/HardcodedModule.rs:746-799`), what each loads, how subpaths and `require.resolve()` behave, and what `bun build` does per target. - Verified: I ran every claim on a release build of main (`1.4.3-canary.1+09bb54630`). Output is in Notes. `prettier --check` passes. ### Background - `--hot` adds a file to the watcher when the module loader loads it, and skips `node_modules`. Bun reads `.env` and `bunfig.toml` at startup, outside the module loader. - The alias table maps a specifier to a built-in module before the resolver looks at `node_modules`. It applies when the target is `bun`: the runtime and `bun build --target=bun`. - #36102 (open) makes bare `undici` prefer the installed package. If it lands, the `undici` row changes with it. <details><summary>Notes</summary> No hunk overlaps #30912 (`watch-mode.mdx` lines 91-99 and 146-153) or #38408 (`module-resolution.mdx` line 309 and below). **`--hot` triggers.** `server.ts` is the sample from `watch-mode.mdx:104-116`, with `.env`, `tsconfig.json`, and `bunfig.toml` in the same directory. A driver script edits one file, waits, and counts the `Reloaded` lines. ``` [after start] lines=1 [after .env edit] lines=1 [after tsconfig edit] lines=1 [after bunfig edit] lines=1 [after server.ts edit 1] lines=2 [after server.ts edit 2] lines=3 --- out.log Reloaded 0 times Reloaded 1 times Reloaded 2 times ``` **Resolution.** `node_modules/{undici,node-fetch,ws,isomorphic-fetch}` each hold a stub package that exports `{ fromNodeModules: true }`. ``` $ bun b.cjs undici resolve: undici fromNodeModules: false node-fetch resolve: node-fetch fromNodeModules: false ws resolve: ws fromNodeModules: false isomorphic-fetch resolve: isomorphic-fetch fromNodeModules: false undici/package.json -> /tmp/dv/undici-check/node_modules/undici/package.json $ node b.cjs undici resolve: /tmp/dv/undici-check/node_modules/undici/index.js fromNodeModules: true ... ``` `require.resolve()` for every specifier in the table: ``` @vercel/fetch -> @vercel/fetch isomorphic-fetch -> isomorphic-fetch node-fetch -> node-fetch undici -> undici utf-8-validate -> utf-8-validate ws -> ws ws/lib/websocket -> ws abort-controller -> abort-controller abort-controller/polyfill -> abort-controller next/dist/compiled/ws -> ws next/dist/compiled/node-fetch -> node-fetch next/dist/compiled/undici -> undici undici/package.json -> /tmp/dv/undici-check/node_modules/undici/package.json ws/package.json -> /tmp/dv/undici-check/node_modules/ws/package.json ``` `import.meta.resolve("undici")` and `import.meta.resolve("node-fetch")` return `undici` and `node-fetch`. **What the built-in modules do.** A local `Bun.serve` answers `direct:<path>`. ``` undici.Request/Response/Headers/FormData/File/WebSocket === the globals: true (each) undici.fetch === Bun.fetch: true undici.fetch with dead ProxyAgent -> 200 direct:/x global fetch after setGlobalDispatcher(dead proxy) -> direct:/x Agent has dispatch/close/destroy/compose: undefined,undefined,undefined,undefined undici.request -> 200 body is Readable: true direct:/x undici.stream() / pipeline() / connect() / upgrade() -> This function is not yet implemented in Bun node-fetch res instanceof Response: true | body is Readable: true | buffer(): function | headers.raw(): function abort-controller default === AbortController: true, .AbortSignal === AbortSignal: true utf-8-validate: function, returns true for Buffer.from("hi") ``` `ws`: `WebSocket` wraps the global `WebSocket` (`src/js/thirdparty/ws.js:312`). `WebSocketServer` uses `node:http` and `server.upgrade()` (`ws.js:1373`, `ws.js:1566`). `utf-8-validate` exports `jsBufferConstructorFunction_isUtf8` (`src/jsc/modules/UTF8ValidateModule.h:16`), the function behind `isUtf8` in `node:buffer`. **`bun build`.** The entry imports `fetch` from `undici` and the default export of `node-fetch`, with the stub packages installed. ``` --target=bun keeps import { fetch as f1 } from "undici"; import f2 from "node-fetch"; --target=node bundles node_modules/undici/index.js and node_modules/node-fetch/index.js --target=browser bundles node_modules/undici/index.js and node_modules/node-fetch/index.js ``` The `bun test` rewrite of `@jest/globals` and `vitest` to `bun:test` uses the same table. It is already in `docs/guides/test/migrate-from-jest.mdx:19` and is not repeated here. </details>
…t-in npm package replacements (oven-sh#42718) ### Problem - `docs/guides/http/hot.mdx:7` says "When any module or file changes, Bun re-runs the file." `bun --hot` watches only the entry file and the files it imports. An edit to `.env`, `bunfig.toml`, or `tsconfig.json` triggers no reload. - `docs/runtime/watch-mode.mdx:124` shows `Reloaded 1 times` first. The sample logs before it increments, so the first line is `Reloaded 0 times`. - No docs page says that Bun resolves `undici`, `node-fetch`, `ws`, and other npm specifiers to built-in modules, even when the package is installed. ### Fix - `hot.mdx`: say what `--hot` watches, name three files it does not watch, and say to restart Bun for those. - `watch-mode.mdx`: the output sample starts at `Reloaded 0 times`. - `module-resolution.mdx`: new section "Built-in replacements for npm packages". It lists every third-party specifier in the alias table (`src/resolve_builtins/HardcodedModule.rs:746-799`), what each loads, how subpaths and `require.resolve()` behave, and what `bun build` does per target. - Verified: I ran every claim on a release build of main (`1.4.3-canary.1+09bb54630`). Output is in Notes. `prettier --check` passes. ### Background - `--hot` adds a file to the watcher when the module loader loads it, and skips `node_modules`. Bun reads `.env` and `bunfig.toml` at startup, outside the module loader. - The alias table maps a specifier to a built-in module before the resolver looks at `node_modules`. It applies when the target is `bun`: the runtime and `bun build --target=bun`. - oven-sh#36102 (open) makes bare `undici` prefer the installed package. If it lands, the `undici` row changes with it. <details><summary>Notes</summary> No hunk overlaps oven-sh#30912 (`watch-mode.mdx` lines 91-99 and 146-153) or oven-sh#38408 (`module-resolution.mdx` line 309 and below). **`--hot` triggers.** `server.ts` is the sample from `watch-mode.mdx:104-116`, with `.env`, `tsconfig.json`, and `bunfig.toml` in the same directory. A driver script edits one file, waits, and counts the `Reloaded` lines. ``` [after start] lines=1 [after .env edit] lines=1 [after tsconfig edit] lines=1 [after bunfig edit] lines=1 [after server.ts edit 1] lines=2 [after server.ts edit 2] lines=3 --- out.log Reloaded 0 times Reloaded 1 times Reloaded 2 times ``` **Resolution.** `node_modules/{undici,node-fetch,ws,isomorphic-fetch}` each hold a stub package that exports `{ fromNodeModules: true }`. ``` $ bun b.cjs undici resolve: undici fromNodeModules: false node-fetch resolve: node-fetch fromNodeModules: false ws resolve: ws fromNodeModules: false isomorphic-fetch resolve: isomorphic-fetch fromNodeModules: false undici/package.json -> /tmp/dv/undici-check/node_modules/undici/package.json $ node b.cjs undici resolve: /tmp/dv/undici-check/node_modules/undici/index.js fromNodeModules: true ... ``` `require.resolve()` for every specifier in the table: ``` @vercel/fetch -> @vercel/fetch isomorphic-fetch -> isomorphic-fetch node-fetch -> node-fetch undici -> undici utf-8-validate -> utf-8-validate ws -> ws ws/lib/websocket -> ws abort-controller -> abort-controller abort-controller/polyfill -> abort-controller next/dist/compiled/ws -> ws next/dist/compiled/node-fetch -> node-fetch next/dist/compiled/undici -> undici undici/package.json -> /tmp/dv/undici-check/node_modules/undici/package.json ws/package.json -> /tmp/dv/undici-check/node_modules/ws/package.json ``` `import.meta.resolve("undici")` and `import.meta.resolve("node-fetch")` return `undici` and `node-fetch`. **What the built-in modules do.** A local `Bun.serve` answers `direct:<path>`. ``` undici.Request/Response/Headers/FormData/File/WebSocket === the globals: true (each) undici.fetch === Bun.fetch: true undici.fetch with dead ProxyAgent -> 200 direct:/x global fetch after setGlobalDispatcher(dead proxy) -> direct:/x Agent has dispatch/close/destroy/compose: undefined,undefined,undefined,undefined undici.request -> 200 body is Readable: true direct:/x undici.stream() / pipeline() / connect() / upgrade() -> This function is not yet implemented in Bun node-fetch res instanceof Response: true | body is Readable: true | buffer(): function | headers.raw(): function abort-controller default === AbortController: true, .AbortSignal === AbortSignal: true utf-8-validate: function, returns true for Buffer.from("hi") ``` `ws`: `WebSocket` wraps the global `WebSocket` (`src/js/thirdparty/ws.js:312`). `WebSocketServer` uses `node:http` and `server.upgrade()` (`ws.js:1373`, `ws.js:1566`). `utf-8-validate` exports `jsBufferConstructorFunction_isUtf8` (`src/jsc/modules/UTF8ValidateModule.h:16`), the function behind `isUtf8` in `node:buffer`. **`bun build`.** The entry imports `fetch` from `undici` and the default export of `node-fetch`, with the stub packages installed. ``` --target=bun keeps import { fetch as f1 } from "undici"; import f2 from "node-fetch"; --target=node bundles node_modules/undici/index.js and node_modules/node-fetch/index.js --target=browser bundles node_modules/undici/index.js and node_modules/node-fetch/index.js ``` The `bun test` rewrite of `@jest/globals` and `vitest` to `bun:test` uses the same table. It is already in `docs/guides/test/migrate-from-jest.mdx:19` and is not repeated here. </details>
|
Additional version coverage from a Windows x64 downstream audit: Bun 1.4.2 (744846f), installed undici 8.12.1, Wrangler 4.151.0 and direct Miniflare 5.20261001.0-alpha still hit this. Our Wrangler subprocess temporarily copies the installed implementation into the builtin module object; Worker/HTTPS smoke tests pass with that override. We support preferring the installed package as proposed here, and will remove that half of our preload after a released Bun passes the same startup/request/reconfiguration/disposal checks. The separate global-fetch override needs independent validation even after module resolution is fixed; see #39250 and #39247. This is a reproduction on released Bun, not a claim that we tested this PR's Bun build. |
## Why On 2026-10-15 (noon EDT) nodejs/undici published eight repository-level security advisories (`gh api "repos/nodejs/undici/security-advisories"`). They are fixed in 6.29.1 / 7.30.1 / 8.12.2, all published 2026-10-15. They are **not yet in GitHub's global advisory database** (`gh api "advisories?ecosystem=npm&affects=undici@7.29.0"` lists only the older 2026-09 batch), so Dependabot and Renovate do not flag them. This repo pins undici through `overrides.undici`, locked at 7.29.0, which is inside the vulnerable range of **all eight** (each is `< 7.30.1` on the 7.x line, with a lower bound between 7.0.0 and 7.18.0): | Advisory | Severity | What | |---|---|---| | [GHSA-xjj6-f33q-929c](GHSA-xjj6-f33q-929c) | high | DoS via unhandled error on excessive content-encodings | | [GHSA-4w7w-5xrc-9h26](GHSA-4w7w-5xrc-9h26) | high | cache poisoning and cross-user disclosure via cross-origin redirects | | [GHSA-2m5v-pch6-74hx](GHSA-2m5v-pch6-74hx) | high | TLS certificate validation bypass via dropped tls options in Agent | | [GHSA-qrxm-fqhp-jwvm](GHSA-qrxm-fqhp-jwvm) | high | DoS via TLS 1.2 certificate-changing renegotiation | | [GHSA-4qv8-2p9j-2685](GHSA-4qv8-2p9j-2685) | medium | DoS via unbounded memory in the EventSource parser | | [GHSA-f72v-6w45-q472](GHSA-f72v-6w45-q472) | medium | Subresource Integrity bypass via non-lowercase algorithm tokens | | [GHSA-9fm3-97px-rjf6](GHSA-9fm3-97px-rjf6) | medium | WebSocket client DoS via unbounded automatic PONG buffering | | [GHSA-55wc-3pg8-jfw6](GHSA-55wc-3pg8-jfw6) | medium | DoS via unhandled exception in the decompress interceptor | 7.29.0 was also still inside the **ten advisories fixed in 7.29.1** that GitHub's global database lists from 2026-09-28 and 2026-09-29 (`gh api "advisories?ecosystem=npm&affects=undici@7.29.0"`): two high (GHSA-rfgv-xxqx-mfg5, GHSA-w293-vg96-wgc3), five medium and three low. 7.30.1 contains those fixes too. Approved by roshne on 2026-10-19 (US Eastern): one PR per repo, undici only. Not from the Dependency Dashboard; no checkbox ticked. Rackbops/Tooling#1362 is the same fix for Tooling's worker. ## What changed | Item | Before | After | |---|---|---| | `package.json` `overrides.undici` | `^7.29.0` | `^7.30.1` | | `bun.lock` undici | 7.29.0 | **7.30.1** (integrity matches the registry) | - Still the 7.x line, as before. undici 8 is the closed, declined PR #148 and is not part of this change. - The override forces this one copy onto every consumer: `discord.js` and `@discordjs/rest` declare `undici ^6.27.0`, and the `@discordjs/rest` copy nested under `@discordjs/ws` pins `6.24.1`. That pre-existing choice is unchanged; `bun.lock` still has a single `undici` entry. - Diff: `package.json` (1 line) and `bun.lock` (the override line and the undici entry). - **What this does and does not change at runtime (found in review, reproduced).** On Bun 1.4.3 a bare `undici` specifier does not necessarily load `node_modules/undici`: in this worktree `bun -e "console.log(require.resolve('undici'))"` prints `undici` (not a file path) even though `require('undici/package.json').version` is `7.30.1`, and the same holds when resolving from `node_modules/@discordjs/rest`. That points to Bun's built-in `undici` module taking precedence for a bare import (compare oven-sh/bun#17799 and the unmerged oven-sh/bun#36102). If so, the bot's `@discordjs/rest` calls (`request`, `Headers`, `FormData`) and `discord.js`'s `fetch` run on Bun's built-in module today, not on the package version, and this bump protects the lockfile, the typecheck/test tooling and any Node-based use, and takes effect on the bot as soon as Bun resolves the installed package. `docs/research/2026-09-03-ci-github-actions.md` (lines 366-377) says the override does govern those imports; this probe suggests that is not the case on 1.4.3, and I did not change that doc. The gateway uses `ws`, not undici, so the WebSocket advisory (GHSA-9fm3) does not reach the bot through discord.js either. The bot's own HTTP (`github.ts`, `update.ts`, `docker.ts`, `plugins/index.ts`) is Bun-native `fetch` and sets no undici agent. ## Local checks (CI `ci.yml`; Bun 1.4.3, the `packageManager` pin) - `bun install --frozen-lockfile` at the root and in `ops/admin`: exit 0. - `bun run check`, `bunx tsc --noEmit -p ops/tsconfig.json`, and `bun run check` in `ops/admin`: all exit 0. - `bun test ./src ./test ./ops/admin ./ops/docker-compose.test.ts`: **3534 pass, 22 skip, 0 fail** (3556 tests, 53 files). ## Mutation Setting `overrides.undici` back to `^7.29.0` without relocking makes `bun install --frozen-lockfile` fail: `error: lockfile had changes, but lockfile is frozen` / `note: overrides in package.json changed since bun.lock was saved`. Restoring the file makes the frozen install pass again. ## Unverified locally - The unscoped `bun test` and `bun test --randomize` that CI runs (the unscoped run hangs locally on bash-spawning ops tests); tests that skip on Windows or without `docker compose` / `jq`. - The `docker-build` job (Docker is not running here): CI only. - Behaviour of the live bot against Discord on 7.30.1: not exercised; no bot was started. ## Review gate Round 1 of the three-reviewer gate (author plus two read-only adversarial reviewers, both on the merged state of all four undici PRs). Reviewer A (upstream release notes vs this code): SOUND as a diff, one major finding on this body's claims. Reviewer B (claims vs diff): SOUND, minor wording findings. Dispositions: 1. A major / B minor, reproduced: the body said the override "governs what discord.js / @discordjs/rest resolve ... where the TLS, content-encoding and WebSocket advisories would bite". On Bun 1.4.3 a bare `undici` import likely resolves to Bun's built-in module (probe above), and the WebSocket advisory cannot bite because the gateway is `ws`. Fixed in this body (the diff is correct either way: harmless if the built-in wins, what is needed once Bun resolves the package). 2. B, minor, reproduced: GHSA-3wwx-pv8p-q78v in the ten-advisory batch was published 2026-09-28 (5:42 pm EDT), the other nine on 2026-09-29. Body corrected; the pushed commit message still says 2026-09-29 and is not amended. 3. A, note: 7.29.1/7.30.0/7.30.1 release notes show no breaking change for what this repo imports (`request`, `Headers`, `FormData`, `fetch`); 7.30.1 `connect.js` defaults `allowH2` to false, so the REST path stays HTTP/1.1. 7.30.x does change a decompress-interceptor default ("disable size limit by default"), which nothing here uses. Both fixes were wording only, so no second round was run. Reviewers verified: one `undici@7.30.1` entry in `bun.lock` (the nested `@discordjs/ws/@discordjs/rest` pin of 6.24.1 collapses into it), integrity matches the registry, no bundled copy in `node_modules`, `ops/admin/bun.lock` has only `undici-types`, CI green on this PR (checks and docker-build). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Problem
undicispecifier to its builtin shim even when the real package is installed.require.resolve("undici")returns the stringundici. The shim'sDispatcher,AgentandRetryAgentare empty classes, sonew RetryAgent(new Agent()).compose(...)throwsagent.compose is not a function.src/resolve_builtins/HardcodedModule.rsmapsundicito the shim, and the shim's registry key is alsoundici, the npm name.Fixes #17799. Fixes #36098. Fixes #42084.
Fix
internal:undici(one special case insrc/codegen/bundle-modules.ts). The bareundicialias is removed, soundiciis an ordinary package at every lookup site.next/dist/compiled/undicistill maps to the shim.Alias::fallback(name)names the builtin that stands in for a package. The resolver consults it after a node_modules probe with auto-install disabled. Only NotFound falls back. Bun never auto-installs undici.import()result a second time with no referrer, soimport("next/dist/compiled/undici")now gives the shim like the static import does.undiciis no longer reported byisBuiltin,builtinModulesorprocess.getBuiltinModule.bun build --target=bunbundles an installed undici and printsinternal:undiciwhen none is installed.undici. Not taken: the compile builtin set and the bake resolver would then need the fallback too, and a bundle that pins what it saw at build time is deterministic.test/js/first_party/undici/undici-prefer-installed.test.ts(12 tests, 10 fail on main). Other suites in Notes.Background
HardcodedModule::Alias) maps specifiers such asnode:fsandwsto builtin module keys. The key is what the module loader fetches.GlobalCache::disabletells the resolver to look in node_modules only. The other modes can read the global package cache or install from the registry.next/dist/compiled/undicialready rewritten toundici.Notes
bundler_bytecode_portable.test.ts: thelibraries.jssnapshot moved on every platform, because@remix-run/nodein that corpus requiresundiciandbun build --target=bunnow bundles the installed copy. The new hashes are the ones the CI lanes agree on.undici.test.ts,undici-primordials.test.ts,node-module-module.test.js,fuzzy-wuzzy.test.ts,bundler_compile.test.ts,transpiler-cache.test.ts,import-meta-resolve.test.mjs,import-meta.test.js,builtin-esm-lazy-exports.test.ts.prefer_installedflag on the alias entry and patched each lookup site. A self-review found that the shim keyundiciwas re-resolved bymoduleLoaderImportModuleinto the installed package for dynamic imports, and that three lookup sites (bake production resolve, macros, the compile builtin set) were left unpatched. The key rename removes both problems.ws,node-fetch, ...) are unchanged.Alias::fallbackextends to them if wanted.dispatch,compose,close,destroy) is out of scope. It is tracked in undici: implement dispatch(), close() and destroy() on the shim dispatchers #39250, undici shim:Poollacksdispatch()/close()/destroy(), breaking miniflare + workerd (wrangler dev, @cloudflare/vite-plugin) #39247, SupportundiciProxyAgent #4474 and @elastic/elasticsearch@8.11.0 not working due to missing undici.Pool.request #7920.fuzzy-wuzzy.test.tspasses its undici entry locally. The file aborts later in theBundescribe on a valkey debug assertion (self.is_subscriber()) that this diff does not touch.no test proof · iteration 6 · platform-specific test(s) that do not run on this machine, deferring to CI, which covers all platforms: test/js/node/module/node-module-module.test.js, test/js/bun/util/fuzzy-wuzzy.test.ts, test/bundler/bundler_bytecode_portable.test.ts